Access logs
Server-side analytics from your nginx, Caddy or Traefik access logs. Ship them to MetrikStack with Vector or Fluent Bit, without changing your app.
You can send your web server's access logs to MetrikStack with Vector or Fluent Bit, without changing your application or edge config. The configurations below are complete and ready to adapt.
| Setup | Endpoint |
|---|---|
| nginx / Caddy / Traefik logs with Vector | POST /v1/logs/generic |
| bunny.net Log Forwarding through your own relay (advanced) | POST /v1/logs/bunny |
| nginx / Caddy / Traefik logs with Fluent Bit | POST /v1/logs/generic |
Both endpoints accept newline-delimited lines (Combined Log Format, or JSON
per line as produced by nginx escape=json, Caddy, or Traefik) or a JSON
array of strings. Fluent Bit's json_lines output wraps each line as {"log": "..."}; the endpoint unwraps log and message keys.
Create a source of kind logs (or edge_bunny for the Bunny relay) in the
dashboard to get an ingest token, used as METRIKSTACK_TOKEN below.
MetrikStack filters the requests: only GET/HEAD page requests count.
Assets, redirects and lines it can't parse are skipped and reported in the
response as skipped / unparsed. A page answered with 304 counts: that
is a returning visitor whose browser checked whether its copy of the page
is still current.
Framework data fetches (Next.js link prefetching and in-app navigation, Remix loaders) are skipped as well. On a single-page app a log therefore shows the first page of a visit but not the navigation after it; add the browser script if you need those pageviews.
Supported formats
- Combined Log Format (nginx, Apache-style default log)
- JSON lines: nginx (
log_format ... escape=json), Caddy's default JSON access log, Traefik's JSON access log - Bunny pipe-delimited Log Forwarding format, via
/v1/logs/bunny
nginx / Caddy / Traefik with Vector
# Vector: tail nginx/Caddy/Traefik access logs and ship them to the
# MetrikStack log endpoint. Lines are forwarded verbatim; the endpoint parses
# Combined Log Format and JSON-per-line automatically and skips assets.
#
# METRIKSTACK_TOKEN=in_... METRIKSTACK_ENDPOINT=https://api.metrikstack.com vector --config vector-nginx.toml
[sources.access_logs]
type = "file"
include = ["/var/log/nginx/access.log", "/var/log/caddy/access.log"]
read_from = "end"
[transforms.only_lines]
type = "remap"
inputs = ["access_logs"]
source = '''
# Keep only the raw line; drop Vector metadata.
. = { "message": .message }
'''
[sinks.metrikstack]
type = "http"
inputs = ["only_lines"]
uri = "${METRIKSTACK_ENDPOINT}/v1/logs/generic"
method = "post"
encoding.codec = "text"
framing.method = "newline_delimited"
compression = "gzip"
batch.max_events = 500
batch.timeout_secs = 5
request.headers.Authorization = "Bearer ${METRIKSTACK_TOKEN}"
request.retry_attempts = 3Advanced: your own relay for Bunny
Bunny can forward its log to MetrikStack directly, without a relay (see
Bunny). Run your own relay only if you want to buffer
the log yourself or send it to more than one destination. The relay receives
Bunny's syslog and posts the lines to POST /v1/logs/bunny with your ingest
token.
# Vector: receive bunny.net Log Forwarding (syslog, RFC 5424) on your own
# host and ship the raw Bunny log lines to the MetrikStack Bunny endpoint.
# Only needed if you want a relay of your own; Bunny can also forward to
# MetrikStack directly.
#
# In the bunny.net panel: Pull Zone -> Logging -> Log Forwarding -> point it
# at this host, port 6514, protocol "TCP encrypted". Log lines contain
# visitor IP addresses, so give the listener a certificate instead of
# accepting plain TCP. Bunny's default IP anonymization (last octet removed)
# can stay on; see the Bunny page for the effect on visitor counts.
[sources.bunny]
type = "syslog"
address = "0.0.0.0:6514"
mode = "tcp"
tls.enabled = true
tls.crt_file = "/etc/vector/tls/fullchain.pem"
tls.key_file = "/etc/vector/tls/privkey.pem"
[transforms.raw]
type = "remap"
inputs = ["bunny"]
source = '''
. = { "message": .message }
'''
[sinks.metrikstack]
type = "http"
inputs = ["raw"]
uri = "${METRIKSTACK_ENDPOINT}/v1/logs/bunny"
method = "post"
encoding.codec = "text"
framing.method = "newline_delimited"
compression = "gzip"
batch.max_events = 500
batch.timeout_secs = 5
request.headers.Authorization = "Bearer ${METRIKSTACK_TOKEN}"
request.retry_attempts = 3In the Log Forwarding form, enter your relay's hostname and port instead of
MetrikStack's, and leave the Token field empty: the relay authenticates with
the Authorization header.
Fluent Bit
# Fluent Bit: tail an access log and POST newline-delimited lines to the
# MetrikStack log endpoint.
#
# METRIKSTACK_TOKEN=in_... METRIKSTACK_HOST=api.metrikstack.com fluent-bit -c fluent-bit.conf
[SERVICE]
Flush 5
Daemon Off
Log_Level info
[INPUT]
Name tail
Path /var/log/nginx/access.log
Tag access
Read_from_Head Off
Skip_Long_Lines On
[OUTPUT]
Name http
Match access
Host ${METRIKSTACK_HOST}
Port 443
tls On
URI /v1/logs/generic
# Fluent Bit cannot emit raw text; the endpoint accepts a JSON array and
# Fluent Bit's json_lines with the "log" key. Use json_lines + the
# `log` field, which the endpoint unwraps.
Format json_lines
Header Authorization Bearer ${METRIKSTACK_TOKEN}
Retry_Limit 3Combining logs with other sources
Log lines can't carry a request_id, so when a site has a log source and
another source, pageviews are matched by the
fallback dedupe window: the same
site, visitor and path within 60 seconds counts once, whichever source
reports it first. If the log source is the site's only source, none of this
applies and every page request becomes a pageview.
Bunny
Bunny CDN analytics through Log Forwarding. Fill in one form in the bunny.net panel and every page request is counted, including cache hits.
How merging works
How MetrikStack counts a page load once when the browser script, a server SDK, a CDN or access logs all see it, using request ids and a dedupe window.