MetrikStack
Sources

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.

SetupEndpoint
nginx / Caddy / Traefik logs with VectorPOST /v1/logs/generic
bunny.net Log Forwarding through your own relay (advanced)POST /v1/logs/bunny
nginx / Caddy / Traefik logs with Fluent BitPOST /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 = 3

Advanced: 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 = 3

In 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  3

Combining 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.

On this page