Loki clients
Send logs to Berserk with Grafana Alloy, Promtail or Vector
Berserk accepts Loki push requests at POST /loki/api/v1/push. Copy your installation's Loki Base URL from Settings → Endpoints. If the address is missing, ask your installation administrator for it. Use a Berserk ingest token as the bearer token; its routing determines the database and destination table. A Loki tenant header does not select a Berserk database.
Grafana Alloy
Add a loki.write component and connect your existing log source's forward_to to loki.write.berserk.receiver. The url takes the full push URL, including the path:
loki.write "berserk" {
endpoint {
url = "https://<your-loki-host>/loki/api/v1/push"
bearer_token = "<ingest token>"
remote_timeout = "30s"
}
}For example, a file source can feed this writer:
loki.source.file "app" {
targets = [{
__path__ = "/var/log/my-app/*.log",
service_name = "my-app",
}]
forward_to = [loki.write.berserk.receiver]
}Existing Promtail installations
Replace or add a client in your existing Promtail configuration. Keep your scrape_configs and positions file. This is a client fragment:
clients:
- url: https://<your-loki-host>/loki/api/v1/push
bearer_token: "<ingest token>"
timeout: 30sVector
Connect your existing log source to this sink by replacing my_logs. Vector's endpoint takes the base URL and appends the push path:
sinks:
berserk:
type: loki
inputs: [my_logs]
endpoint: https://<your-loki-host>
auth:
strategy: bearer
token: "<ingest token>"
labels:
service_name: my-app
encoding:
codec: text
request:
timeout_secs: 30Wire format and responses
Send Content-Type: application/json for a Loki push JSON envelope, with streams, stream labels and timestamp/string pairs. Timestamps are decimal nanoseconds encoded as strings. Arbitrary JSON log objects are not this envelope.
For Protobuf, use Content-Type: application/x-protobuf and Snappy block compression. The Snappy encoding is part of the Loki push format, without a Content-Encoding header. Alloy and Promtail provide this encoding themselves.
A successful request returns 204 with no body, or 202 with no body when the installation acknowledges before storage. An acknowledgment is not a query result; follow delivery semantics for retries and buffering.
Label mapping
Recognized labels become resource attributes; other labels become log record attributes. Severity labels set the record's severity, and exporter is discarded.
| Loki label | Berserk resource attribute |
|---|---|
service_name, service | service.name |
service_namespace | service.namespace |
service_instance_id, instance | service.instance.id |
namespace, pod, container, node_name | k8s.namespace.name, k8s.pod.name, k8s.container.name, k8s.node.name |
k8s_namespace_name, k8s_pod_name, k8s_container_name, k8s_cluster_name | Corresponding k8s.*.name attribute |
k8s_deployment_name, k8s_replicaset_name, k8s_statefulset_name, k8s_daemonset_name, k8s_cronjob_name, k8s_job_name, k8s_node_name | Corresponding k8s.*.name attribute |
container_name | container.name |
cloud_availability_zone, cloud_region | cloud.availability_zone, cloud.region |
deployment_environment_name | deployment.environment.name |
filename | log.file.path |
job supplies service.name when no explicit service label exists. A job of namespace/service also supplies service.namespace. level sets severity. Structured metadata becomes record attributes. Underscores become dots only where the resulting key starts with a recognized OpenTelemetry prefix: service., k8s., host., container., cloud., deployment., process., os., log., http., net. or telemetry.. Other keys retain their spelling.
Send and find a test log
Replace the host and token, then run this command. Its timestamp is generated when you run it:
curl --fail-with-body -w '\nHTTP %{http_code}\n' \
'https://<your-loki-host>/loki/api/v1/push' \
-H 'Authorization: Bearer <ingest token>' \
-H 'Content-Type: application/json' \
-d '{"streams":[{"stream":{"service_name":"ingest-test","level":"info"},"values":[["'"$(date +%s)"'000000000","Hello from Berserk"]]}]}'In Berserk, open the token's database and the destination table configured for logs. Use a recent time window and filter service.name == "ingest-test". If no record appears, check the token's routing in Settings → Databases → Tokens and the shipper's export errors.