Skip to main content
Collect JSON access logs from Nginx with an OpenTelemetry collector and send them to ClickHouse Observability. Use the demo dataset to try the integration without an existing Nginx installation.

Prerequisites

  • A ClickHouse Observability service
  • Docker to run the collector commands below, or an existing OpenTelemetry Collector Contrib deployment
  • For your own logs, an existing Nginx installation, permission to edit its configuration, and access to its log files from the collector
To try the integration without setting up Nginx or collecting your own logs, use the demo dataset. It includes a standalone collector configuration for the sample data.

Connection details

Open ClickHouse Observability and go to Team Settings → Data → Managed Telemetry. Copy your OTLP HTTP endpoint and API key. You can use Copy connection details to copy the configuration, or Reveal key to view the masked key.For the OTLP exporter examples below, set these variables in the terminal where you will run the collector:
Replace the placeholders with the exact endpoint, including its port, and API key from your service. Use the base HTTP endpoint without a /v1/logs suffix; the exporter appends the signal path.
The endpoint must be reachable from the collector container. For a collector running on your Docker Desktop host, use host.docker.internal instead of localhost. On Linux, use a shared Docker network and the destination container’s name, or another reachable host address.

Integration with existing Nginx

Run a collector on a host that can read your Nginx access logs. The collector parses the logs and forwards them to your service’s OTLP HTTP endpoint.
1

Configure Nginx log format

Configure Nginx to write JSON access logs in nginx.conf.The nginx.conf file is typically located at:
  • Linux (apt/yum): /etc/nginx/nginx.conf
  • macOS (Homebrew): /usr/local/etc/nginx/nginx.conf or /opt/homebrew/etc/nginx/nginx.conf
  • Docker: Configuration is usually mounted as a volume
Add the following directives inside your existing http block. Keep the rest of your configuration, and replace any existing access_log directive for the same file:
This format uses the same field names as the demo dataset, including request, which contains the method, URI, and HTTP version. upstream_response_time is kept as a string because Nginx can report multiple upstream timings. The demo dataset contains a single numeric value for this field.Validate the configuration with nginx -t, then reload Nginx using your deployment’s normal procedure. If a server or location block overrides access_log, update that directive to use json_combined too.
2

Configure the collector

Get your connection details and set the endpoint and API-key environment variables in the terminal where you will run the collector. Save the following complete configuration as nginx-monitoring.yaml:
This configuration reads new JSON access-log entries, preserves their original timestamps, and sets service.name to nginx. It forwards logs to your OTLP HTTP endpoint using the authentication settings above. Nginx error logs require a separate parser and are not included.
3

Run the collector

The following command assumes the log directory is /var/log/nginx on the Docker host. Adjust the host side of the log mount if your files are elsewhere. For containerized Nginx, mount its shared log volume into the collector instead.From the directory containing nginx-monitoring.yaml, run:
The collector runs in the foreground and must have permission to read the mounted log files. Leave it running and generate a few requests to Nginx from another terminal or browser so it writes new access-log entries.
4

Verify logs in ClickHouse Observability

  1. Open Search in your UI and select Logs.
  2. Filter for ServiceName:nginx and select a time range covering your requests.
  3. Expand an entry and select Column Values to check fields such as request, request_time, and upstream_response_time under LogAttributes.
The following example shows the same view using the demo dataset, with ServiceName:nginx-demo:

Demo dataset

The sample dataset contains 14,743 JSON access-log entries with successful requests, errors, and upstream response timings. You need Docker and a ClickHouse Observability service. Set the connection environment variables before starting, and keep the downloaded file and configuration in the same directory.
1

Download the sample dataset

2

Create test collector configuration

Save the following complete configuration as nginx-demo.yaml. The collector reads the downloaded access logs and forwards them to your OTLP endpoint.
The demo-only transform/demo_timestamps processor shifts the sample’s timestamps to roughly the past 24 hours, ending two minutes before ingestion, while retaining its traffic pattern. The original time_local attribute and log body stay unchanged. Omit this processor for your own Nginx logs so their original timestamps are preserved.
The standalone collector examples use OpenTelemetry Collector Contrib 0.161.0, the version used to validate these configurations.
3

Run the demo collector

From the directory containing access.log and nginx-demo.yaml, run the OpenTelemetry Collector Contrib image:
Leave this terminal open while you verify ingestion. Both mounted files must be readable by the container. After the logs appear, press Ctrl+C to stop the demo collector. Running it again re-ingests the dataset with newly shifted timestamps because this demo does not persist file offsets.
4

Verify logs in ClickHouse Observability

Once the collector is running:
  1. Open your UI.
  2. Navigate to Search, select Logs, and filter for ServiceName:nginx-demo.
  3. Set the time range to Last 2 days to include the full shifted dataset.
Expand a log entry and select Column Values to inspect the parsed fields under LogAttributes.

Dashboards and visualization

Import a dashboard for request counts, errors, status codes, and average upstream response time.
1

Download the dashboard configuration

.
2

Import the pre-built dashboard

  1. Open ClickHouse Observability and navigate to Dashboards.
  2. Click Import in the upper-right corner.
  1. Upload nginx-logs-dashboard.json. Confirm that all five charts map to the Logs data source, then click Finish Import.
3

View the dashboard

Filter the dashboard to ServiceName:nginx-demo for the demo dataset, or ServiceName:nginx for your own logs. Set the time range to cover the ingested records. For the demo, select Last 2 days.The following dashboard shows the demo dataset:

Troubleshooting

Collector fails to start

Check the collector’s terminal output for configuration errors. Confirm that the YAML file exists at the mounted path. If you use the OTLP exporter configuration, check that the endpoint variable and any required authentication variable are set in the terminal where you run Docker.

No logs appearing

  • Check the collector output for authentication or export errors. If you use the OTLP exporter, verify the endpoint and authorization header against your connection details.
  • Confirm Nginx is writing JSON access logs and that the collector can read them. With start_at: end, generate new requests after the collector starts.
  • Check the selected Logs source and service-name filter: ServiceName:nginx-demo for the demo dataset, or ServiceName:nginx for your own logs.
  • Set the time range to cover the logs. For the demo, confirm transform/demo_timestamps is included in the pipeline and select Last 2 days.
For your own Nginx logs, check the file on the host and inspect the collector container’s mounts. Confirm that the destination path matches the receiver configuration. Replace CONTAINER_NAME with your collector container’s name, and adjust the host path if needed:

Next steps