combined access log and a separate error log. This page tails both and ships them to Rootprint over OTLP with either the OpenTelemetry Collector or Vector. Records land in otel-logs-v0_9 tagged service.name: nginx, with access-log fields mapped to OpenTelemetry HTTP semantic conventions so they arrive as queryable attributes.
Prerequisites
- A running Rootprint instance and its base URL — you’ll substitute it for
<your-rootprint>. - A host running nginx that writes access and error logs to files. Stock nginx logs to
/var/log/nginx/on Debian/Ubuntu; the paths below assume those defaults. - A log agent that can read those files — the OpenTelemetry Collector or Vector.
- An ingest API key scoped to your target index. See API keys.
- OpenTelemetry Collector
- Vector
This config assumes the agent runs where it can read
/var/log/nginx.1
Confirm nginx is logging to file
Stock nginx writes
combined-format access logs to /var/log/nginx/access.log and error logs to /var/log/nginx/error.log. These defaults are what the config below expects. No nginx.conf changes are required.2
Configure the Collector
Replace
<your-rootprint> with your Rootprint base URL and <your-ingest-token> with the key from above.3
Grant read access to /var/log/nginx
/var/log/nginx/ with the adm group as the read-side convention. Add the user the Collector runs as to that adm group (the Debian/RPM Collector package creates otelcol-contrib).4
Start the Collector
Start (or restart) the Collector so it loads the config. Startup logs should show no config-parse or exporter errors.
5
Send a test request
6
Verify in Rootprint
Open Search, pick
otel-logs-v0_9, and query service_name:nginx. Records typically appear within 5–10 seconds.What you get in Rootprint
Both agents parse nginx’s stockcombined access log and error log format. Access-log fields are mapped to OpenTelemetry HTTP semantic conventions; error-log fields go to process and connection attributes. Both agents write to otel-logs-v0_9 with service.name: nginx.
The nginx.format discriminator ("access" or "error") lets one config handle both files: error-log entries get process.pid, thread.id, and nginx.connection_id; access-log entries get the full HTTP attribute set.
timeUnixNano is derived from the timestamp in each log line. If parsing fails, the agent’s read time is used as a fallback.
With the OpenTelemetry Collector, error-log context fields (client.address on error lines, server.address, nginx.server, and nginx.upstream) are not broken out into attributes (they remain in the record body); the Vector path extracts them via parse_nginx_log.
Useful searches
Run these in the Rootprint search box againstotel-logs-v0_9.
Every 5xx response nginx returned, across all sites:
nginx.upstream is populated by the Vector path only (the OTEL Collector keeps error-log context in the record body):
Troubleshooting
- Records arrive but
attributes.http.*are missing: the entry came fromerror.log(no access fields), by design. Filter access-log entries withattributes.nginx.format:access. bodylooks like a raw nginx line instead of a structured message: the access log is using a non-defaultlog_formatdirective innginx.conf. The parser expects nginx’s stock combined format. Either remove the customlog_formator extend the config to handle the alternate shape.severity_textis alwaysINFOeven for 5xx responses: by design. nginx’s combined access format has no severity field; both agents trust the source. Filter onattributes.http.response.status_code:>=500to surface server errors.- Ingest transport errors (
401,403,413,415): see OTLP reference → Response codes.
Related
- Send logs with Vector: generic Vector setup for tailing files on a host.
- Send Caddy logs: sibling page for Caddy.
- OTLP reference: endpoint URL, response codes, body limits.
- Indexes: the
otel-logs-v0_9schema, so you know what you can search.
