Skip to main content
Hivenet Router writes one structured JSON audit record after each HTTP request completes. Audit records help operators investigate request outcomes, tenant activity, latency, model use, authentication failures, routing errors, and token consumption without storing prompt or response content.
Audit records still contain potentially sensitive metadata, including tenant identifiers, model names, source IP addresses, and request timing.Protect the files, restrict Loki and Grafana access, and define retention according to your organization’s legal and operational requirements.

What Hivenet Router audits

The audit middleware covers HTTP requests handled by the router, including:
  • inference requests under /v1/*
  • model-discovery requests
  • administration requests under /admin/*
  • authentication and quota failures
  • successful and unsuccessful backend responses
Hivenet Router deliberately skips:
  • GET /health liveness probes
  • CORS OPTIONS preflight requests
These high-frequency infrastructure requests do not carry useful inference or tenant information.

Audit record format

The default file is:
Each request produces one JSON object on one line:
The timestamp and values above are examples.

Audit fields

Request IDs

Hivenet Router accepts an incoming:
only when its value is a valid UUID. A valid UUID is preserved:
An absent, empty, or invalid value is replaced with a new UUID v4. The selected value is:
  • returned in the X-Request-ID response header
  • stored in the audit record
  • attached to the active trace span
This prevents arbitrary request-ID text from being injected into audit records.

Trace IDs

When OpenTelemetry tracing is active, trace_id contains the current span’s trace ID. Hivenet Router also returns a W3C:
response header when a valid trace context exists. Use either identifier to move between:
  • an application request
  • the JSONL audit record
  • Loki logs
  • a Tempo trace
When tracing is disabled or unavailable:

Tenant and key identity

For authenticated client requests:
comes from the key’s owner. For dynamic keys:
contains the stable registry entry ID. Static keys do not currently have a stable key ID, so their audit records normally contain:
In no-auth mode, successful API requests use:
Authentication failures happen before Hivenet Router can resolve a tenant or key, so those fields remain empty.
Audit records and Prometheus labels use different empty-key conventions.Static and no-auth audit records normally use an empty key_id, while tenant metrics use key_id="anonymous" for those requests.

Agent and provider identity

For a successful local inference request:
contains the selected agent’s libp2p peer ID. For external provider fallback, the value may identify the provider instead:
or:
The field remains empty when the request fails before an agent or provider is selected.

Token fields

For successful non-streaming chat requests, Hivenet Router records the usage available from the completed response. For streaming chat requests, Hivenet Router updates the audit values after the stream closes and the token meter has finished. Embedding and reranking requests currently record:
Requests rejected before inference may also contain zero token values.
Audit token values describe what Hivenet Router could account for during that request. Their precision depends on the backend response and the request type.

What is not logged

The dedicated audit record does not include:
  • prompt or message content
  • response or completion content
  • request body
  • response body
  • authorization header
  • raw API keys
  • provider credentials
  • complete HTTP headers
  • HTTP method
  • request path
Hivenet Router’s separate application log records method, path, status, latency, and client IP, but deliberately excludes the authorization header.
Metadata-only logging reduces content exposure but does not make the records anonymous.A model name, tenant ID, source IP, request time, or token count may still be personal, confidential, or commercially sensitive.

Error codes

When a request handler provides a specific Hivenet Router domain code, the audit record preserves it. Common inference codes include: When no more specific domain code was attached, the middleware derives a fallback code from the HTTP status: An oversized /v1/* request can be rejected with HTTP 413 before the normal inference-handler error path. In that case, treat status_code as authoritative; the audit error_code may be a broad status-derived value rather than a dedicated request-size code. Some administration endpoints return simpler endpoint-specific errors without attaching a domain code. Their audit record may therefore contain the broader status-derived value. See Error codes for the inference error reference.

Configure the file path

Set the case-sensitive environment variable:
Then start the router:
The parent directory is created automatically when possible. The file is opened for append when the router process starts.
Restart the router after changing HIVENET_ROUTER_AUDIT_LOG_PATH. The audit logger does not reopen the file dynamically after an environment change.

Fallback to stdout

If Hivenet Router cannot create the directory or open the file, the router still starts and writes audit JSON to standard output. It also writes an explanatory message to standard error:
This is useful for local development, but it can mix structured audit entries with application logs and change the expected Promtail pipeline. Check startup logs whenever the audit file remains empty.

Bare-metal permissions

Create a protected directory for a service running as hivenet-router:
Set the environment variable in the router service:
Hivenet Router creates the file when it starts. Its final permissions are affected by the process umask. With the hardened systemd unit from the bare-metal guide:
the requested file mode is reduced accordingly. Check the result:

Docker Compose pipeline

The repository’s Compose stack already connects the router’s audit file to Promtail. The router writes to a named volume:
Promtail mounts the same volume read-only:
The volume declaration is:
Start the full stack:
Check that the router writes records:
Check Promtail:
Check Loki readiness:

Promtail configuration

The repository separates application and audit logs into two jobs. The audit job reads only the JSONL file:
The resulting Loki stream selector is:
Promtail promotes these JSON fields to labels:
  • tenant_id
  • status_code
  • model
  • error_code
  • level
Other fields remain available through query-time JSON parsing.

Label-cardinality guidance

Tenant and model labels are useful for dashboards, but they increase the number of Loki streams. For a larger deployment, review whether these should remain indexed labels:
High numbers of tenants, models, or frequently changing label values can increase Loki memory and storage use. A lower-cardinality alternative is to label only stable fields such as:
and parse tenant and model at query time with:
Any pipeline change also requires corresponding dashboard-variable and query updates.

Query audit records

All audit records

Errors

You can also use the promoted label:

One tenant

One model

One request ID

request_id is not a Loki label, so parse the JSON field:

One trace

Slow requests

Authentication failures

Model-access failures

Provider fallback requests

Aggregate audit data

Request rate by status

Because status_code is a promoted label in the repository configuration, it remains available to the aggregation.

Error rate

Requests by model

Output tokens by tenant

Average latency by tenant

P95 latency

Use the Grafana audit dashboard

The provisioned dashboard is available at:
It includes:
  • recent request records
  • request rate by status
  • P95 latency
  • top models
  • error rate
Filters are available for:
  • tenant ID
  • status code
  • model
  • error code
See Grafana dashboards for provisioning and troubleshooting.

Correlate logs and traces

A practical investigation flow is:
  1. Obtain the request’s X-Request-ID or traceparent response header.
  2. Search the audit logs for request_id or trace_id.
  3. Inspect the status, tenant, model, agent, latency, and error code.
  4. Open the matching trace in Tempo.
  5. Review router application logs for the same request ID.
  6. Inspect Prometheus metrics for the selected agent and model.
For example:
The audit record provides the trace ID:
Use that value in Grafana Explore with the Tempo data source.

Source IP and proxies

The source_ip field comes from Gin’s client-IP resolution. Its accuracy depends on:
  • whether the router is reached directly
  • which reverse proxies are trusted
  • whether forwarding headers are replaced or preserved
  • whether clients can send spoofed forwarding headers
Do not treat source_ip as a verified user or tenant identity. When Hivenet Router sits behind a proxy:
  • restrict direct access to the router
  • configure the proxy to replace untrusted forwarding headers
  • review Gin’s trusted-proxy behavior for your deployment
  • test the value recorded in the audit file
Use authenticated tenant and key information for authorization and accountability.

Retention and rotation

Hivenet Router opens the audit file when the process starts and keeps the file descriptor open. A rotation method that renames the file and creates a new one can leave the router writing to the renamed file until restart. For a simple bare-metal setup, use copytruncate:
copytruncate has a small race window in which lines written during the copy and truncate operation can be lost.For stricter audit requirements, use a log-shipping and retention design that avoids local copy-and-truncate rotation, or restart the router as part of a controlled rename-based rotation.
The repository’s Loki configuration uses filesystem storage and does not set an explicit production retention period. For a production deployment, configure and test:
  • Loki retention
  • local audit-file retention
  • backup requirements
  • deletion workflows
  • access controls
  • storage capacity monitoring
Deleting the Docker loki_data volume removes the stored Loki data.

Privacy and governance

Audit logging can support operational investigations and evidence collection, but it does not by itself establish compliance with any law or standard. Before production use, decide:
  • which teams may access audit data
  • how long records are retained
  • whether source IP addresses should be stored
  • whether tenant and model names reveal sensitive information
  • how deletion and access requests are handled
  • whether records must be exported to a separate security system
  • how clock, integrity, backup, and incident procedures are controlled
Hivenet Router does not log prompt and response bodies in the dedicated audit record, but other components in the request path may have their own logging behavior. Review:
  • reverse proxies
  • inference backends
  • client applications
  • provider APIs
  • container logging
  • observability agents
as part of the complete data-flow assessment.

Troubleshooting

The audit file does not exist

Check the configured path:
Check the router logs for:
or:
Confirm that the router process can create the directory and file. For systemd:
Remove the test file afterward:

Audit JSON appears in application stdout

The file could not be opened, so Hivenet Router fell back to stdout. Correct the path or permissions, then restart the router.

Promtail does not ingest records

Check that the shared file is visible:
Inspect Promtail logs:
Check its positions file and Loki connection.

Loki has no audit stream

Query the labels API:
Then query the stream:
Check that Promtail uses:
rather than values from the older example configuration.

A field is empty

The field may not apply to that request. Examples:
  • auth failure: empty tenant and key
  • model-list request: empty model
  • pre-routing rejection: empty agent ID
  • no tracing: empty trace ID
  • static key: empty key ID
  • embedding or reranking: zero token counts

The request ID was replaced

Hivenet Router accepts only valid UUIDs in X-Request-ID. Use a UUID such as:
Other values are replaced with a generated UUID.

The source IP is unexpected

Check the proxy path and forwarding headers. The recorded value may be the proxy address or a header-derived address, depending on how the router is reached and configured.

Token totals are zero

Possible causes include:
  • the request failed before inference
  • it was an embedding or reranking request
  • the backend did not report usage
  • streaming usage could not be measured
  • the handler did not have token information for that route
Compare the audit record with the backend response and Prometheus tenant-token metrics.

Records continue in a rotated file

The router keeps the audit file open. Use copytruncate, or restart the router after a rename-based rotation so it opens the new path.

Next steps

Hardware metrics

Review the GPU, CPU, and memory data reported by agents.

Engine metrics

Understand cache, queue, latency, and throughput metrics by backend.

Error codes

Review the structured errors recorded in audit entries.