Installation
Deploy Hikari
Hikari runs as a Python/FastAPI service with a built web UI. Use the mock VictoriaLogs backend for local development, or point the service at your own VictoriaLogs deployment.
Local development
Copy the example environment and start the mock backend, API, and Vite UI.
Copy-Item .env.example .env
docker compose up mock-victorialogs api web
webhttp://localhost:5173apihttp://localhost:8000mock-victorialogshttp://localhost:9428To run the production-style combined image locally:
docker compose up hikari
Prebuilt container image
The OSS repository publishes a multi-architecture image to GitHub Container Registry.
ghcr.io/bradmb/hikari:latest
latest follows main. Version tags are published from Git tags that
match v*.*.*, and each build also gets a sha-... tag. For production,
pin a version tag or SHA tag instead of latest.
docker run --rm -p 8000:8000 `
-e HIKARI_VICTORIA_URL=https://victorialogs.example.com `
ghcr.io/bradmb/hikari:latest
Configuration
HIKARI_VICTORIA_URLVictoriaLogs base URL.HIKARI_VICTORIA_BEARER_TOKENOptional bearer token for VictoriaLogs.HIKARI_VICTORIA_HEADERSOptional JSON object of extra headers for VictoriaLogs.HIKARI_FIELD_MAPPINGS_FILEJSON file that defines canonical fields, facet aliases, and sidebar facets.HIKARI_FIELD_MAPPINGSOptional inline JSON override for field mappings.HIKARI_DEFAULT_PAGESets startup route for /. Use browse (default) or ai.HIKARI_FACET_PREVIEW_LIMITNumber of values shown per facet before the View more expander appears. Defaults to 10.OPENAI_API_KEYOptional key for natural-language query generation. Inject this directly from your platform's secret mechanism.HIKARI_OPENAI_API_KEY_SECRET_IDOptional AWS Secrets Manager secret ID for AWS deployments that load the OpenAI key at runtime.HIKARI_OPENAI_MODELModel used for natural-language query generation.
By default, HIKARI_DEFAULT_PAGE is browse, so the root path routes to
/browse. Set it to ai to route / to /ai.
Facet mapping
Hikari adapts to your log schema through config/field-mappings.json. This file
controls display fields, sidebar facets, MCP summary facets, and hidden query normalization.
Set HIKARI_FACET_PREVIEW_LIMIT to control how many values each facet shows
before the UI displays a View more expander. The default is 10.
Use aliases to map source fields into canonical Hikari facets. For example,
Windows or OpenTelemetry logs can populate service and host from
alternate field names:
{
"aliases": {
"service": ["service", "service.name", "service_name", "kubernetes.container_name"],
"host": ["host", "host.name", "host_name", "hostname", "kubernetes.pod_node_name"]
}
}
Hikari applies these mappings to backend VictoriaLogs requests with hidden LogsQL
copy pipes. Users still see clean queries like _time:15m service:="api",
while Hikari sends generated copies such as copy service_name as service and
copy host_name as host before loading rows, facets, field values, hit buckets,
live tail data, AI context, and MCP results.
Hikari expects canonical facet values to exist as stored VictoriaLogs fields. For severity, Hikari
maps structured fields such as severity_text, SeverityText, and
OpenTelemetry severity_number into the canonical level field. It can also
append configurable VictoriaLogs unpack_json and extract_regexp pipes for
common message-only level formats. The OSS mapping sets severity.defaultMissing to
info, so rows with no severity signal are normalized at query/display time, not rewritten
at ingestion. Prefer ingestion-time normalization for high-volume streams and very large deployments.
Use facets to choose the canonical groups shown in the sidebar and MCP summaries.
{
"facets": [
{ "field": "environment", "label": "Environment" },
{ "field": "service", "label": "Service", "summary": true },
{ "field": "host", "label": "Host", "summary": true },
{ "field": "level", "label": "Level", "summary": true },
{ "field": "kubernetes.pod_namespace", "key": "namespace", "label": "Namespace", "summary": true },
{ "field": "kubernetes.pod_name", "key": "pod", "label": "Pod", "summary": true }
]
}
The optional key gives MCP summaries a shorter name. Set summary: true
for facets that should appear in summarize_window and default get_facets
output.
Configure facets with Helm
The Helm chart creates a ConfigMap from fieldMappings.config and mounts it at
/app/config/field-mappings.json. The chart also sets
HIKARI_FIELD_MAPPINGS_FILE to that path.
fieldMappings:
enabled: true
config:
defaultFields:
- environment
- service
- service_name
- host
- host_name
- level
- kubernetes.pod_namespace
- kubernetes.pod_name
aliases:
service:
- service
- service.name
- service_name
- kubernetes.container_name
host:
- host
- host.name
- host_name
- hostname
- kubernetes.pod_node_name
level:
- level
- severity_text
- SeverityText
- severity
- Severity
- severity_number
- SeverityNumber
severity:
canonicalField: level
defaultMissing: info
textFields:
- level
- severity_text
- SeverityText
- severity
- Severity
numberFields:
- severity_number
- SeverityNumber
values:
error: [error, err, fatal, critical, crit, alert, emerg, e, f]
warning: [warning, warn, notice, w]
info: [info, information, informational, i]
debug: [debug, trace, verbose]
messageFilters:
error:
- _msg:~'"level"[[:space:]]*:[[:space:]]*"(error|err|fatal|critical|crit|alert|emerg)'
- _msg:~'[[](emerg|alert|crit|critical|error|err)[]]'
- _msg:~'^E[0-9]{4}'
- _msg:~'^F[0-9]{4}'
warning:
- _msg:~'"level"[[:space:]]*:[[:space:]]*"(warn|warning|notice)'
- _msg:~'[[](warn|warning|notice)[]]'
- _msg:~'^W[0-9]{4}'
info:
- _msg:~'"level"[[:space:]]*:[[:space:]]*"(info|information|informational)'
- _msg:~'^I[0-9]{4}'
debug:
- _msg:~'"level"[[:space:]]*:[[:space:]]*debug'
numberRanges:
debug: [1, 8]
info: [9, 12]
warning: [13, 16]
error: [17, 24]
extractPipes:
- unpack_json fields (level,severity,severity_text,severity_number,msg,message) keep_original_fields
- extract_regexp '^(?P<level>[IWEF])[0-9]{4}[[:space:]]' from _msg keep_original_fields
- extract_regexp '^(?P<level>INFO|WARN|WARNING|ERROR|ERR|DEBUG|TRACE|VERBOSE|FATAL|CRITICAL|emerg|alert|crit|critical|error|err|warn|warning|notice|info|debug|trace|verbose|fatal)[[:space:]:]' from _msg keep_original_fields
- extract_regexp '[[](?P<level>emerg|alert|crit|critical|error|err|warn|warning|notice|info|debug|trace)[]]' from _msg keep_original_fields
facets:
- field: environment
label: Environment
- field: service
label: Service
summary: true
- field: host
label: Host
summary: true
- field: level
label: Level
summary: true
- field: kubernetes.pod_namespace
key: namespace
label: Namespace
summary: true
- field: kubernetes.pod_name
key: pod
label: Pod
summary: true
helm upgrade --install hikari ./k8s/helm/hikari `
--namespace hikari `
--create-namespace `
--values ./hikari-values.yaml `
--set image.repository=ghcr.io/bradmb/hikari `
--set-string image.tag=latest `
--set env.facetPreviewLimit=10 `
--set env.victoriaUrl=http://victorialogs.example.svc:9428
Why am I not seeing levels?
Hikari reads level as its canonical severity field. It can map structured source fields
like severity_text and severity_number, and it can run configured
VictoriaLogs extraction pipes for common _msg formats. If
severity.defaultMissing is set, rows with no severity signal use that canonical level
at query/display time. If rows show unknown or appear to have the wrong level, first
inspect the fields stored in VictoriaLogs and the mapping file mounted into Hikari.
_time:15m | limit 1
_time:15m level:*
_time:15m severity_text:*
_time:15m severity_number:*
If the level only appears inside _msg or another message payload, add a matching
severity.extractPipes entry or update the collector/application logger to emit a
structured severity field before ingestion. For Kubernetes collectors, check the Fluent Bit
ConfigMaps and restart the DaemonSet after changing normalization.
kubectl -n victorialogs get configmap victorialogs-collector-fluent-bit -o yaml
kubectl -n victorialogs get configmap fluentbit-lua-scripts -o yaml
kubectl -n victorialogs rollout restart daemonset/victorialogs-collector-fluent-bit
kubectl -n victorialogs rollout status daemonset/victorialogs-collector-fluent-bit
Kubernetes
Install the included Helm chart with the GHCR image or your own image registry.
helm upgrade --install hikari ./k8s/helm/hikari `
--namespace hikari `
--create-namespace `
--set image.repository=ghcr.io/bradmb/hikari `
--set-string image.tag=latest `
--set env.victoriaUrl=http://victorialogs.example.svc:9428
Optional AI search only needs OPENAI_API_KEY. In Kubernetes, inject it from a
Kubernetes Secret or your platform's native secret mechanism. AWS Secrets Manager is supported
as an opt-in integration, but it is not required.
helm upgrade --install hikari ./k8s/helm/hikari `
--namespace hikari `
--set env.openAiSecretName=hikari-openai `
--set env.openAiSecretKey=OPENAI_API_KEY
Verify the rollout and health endpoint.
kubectl -n hikari rollout status deployment/hikari
kubectl -n hikari port-forward deployment/hikari 8000:8000
curl http://localhost:8000/health
Bring your own authentication
Hikari does not include end-user authentication or authorization. The safest deployment is to keep it off the public Internet and expose it only on an internal network.
If you need external access, put the UI, API, and MCP endpoint behind your own access layer. Common options include Cloudflare Access, Tailscale, WireGuard, Teleport, OAuth2 Proxy, Pomerium, an SSO-aware reverse proxy, or a cloud provider private application gateway.
Protect MCP access the same way you protect the UI. MCP tools can query logs, discover fields, and return operational data.
Deployment targets
Hikari is a Python/FastAPI application packaged as a container. Deploy it on a container platform, VM, or Kubernetes cluster.
Troubleshooting
- Check
/healthto confirm the active VictoriaLogs URL and default query. - Confirm the API container or pod can reach
HIKARI_VICTORIA_URL. - If a host or service is missing from facets, add its source field to
aliasesin the field mapping config. - For MCP capability failures, use HTTP transport and
/mcp. - AI features are hidden unless
OPENAI_API_KEYis configured, or the optional AWS Secrets Manager ID resolves to a key.