Skip to main content
 
 
Splunk Lantern

Getting Docker log data into Splunk Cloud Platform with OpenTelemetry

 

In this article, we’ll review a few of the ways we can get logs into Splunk Cloud Platform and demonstrate the recommended way to get Docker logs into Splunk Cloud Platform.

This article uses the Astronomy Shop OpenTelemetry Demo example configured in Setting up the OpenTelemetry Demo in Docker. If you don't have an OpenTelemetry Demo application set up in your environment, use that article first to set one up.

The Splunk Distribution of the OpenTelemetry Collector includes a number of receivers that we can use to ingest log data:

  1. Filelog receiver. This receiver tails and parses log files.
  2. Fluent Forward receiver. This receiver accepts log events using the Fluent Forward protocol.

We’ll explore both of these options below, starting with File Log Receiver, which is recommended in most environments as it’s more performant and less resource intensive.

Option 1: Use the Filelog receiver

The Filelog Receiver is a popular receiver in the OpenTelemetry community. With this option, we’ll configure the Filelog receiver to read and parse Docker log files. The logs will be processed by the various processors configured in the collector pipeline before being exported to Splunk Cloud Platform via the HEC endpoint.

This option expects Docker log files to be stored in a folder named /var/lib/docker/containers. You’ll need to adjust the configuration if your environment uses a different location for its Docker log files.

Configure the JSON log driver

Let’s start by updating the log driver settings in our docker-compose.yml file to add the container name, image name, and short id to the logs, separated by pipes. We’ll use the pipes in a subsequent step to regex extract the values in the logging pipeline.

version: '3.9'
x-default-logging: &logging
 driver: "json-file"
 options:
   max-size: "5m"
   max-file: "2"
   tag: "{{.Name}}|{{.ImageName}}|{{.ID}}"

Update the OpenTelemetry Collector service configuration

Next, let’s update the OpenTelemetry Collector service configuration in docker-compose.yml with the following changes:

  • Ensure that the container runs as “root”, so it’s able to read the /var/lib/docker/containers volume mount from the host machine
  • Update the command and volumes used to launch the container, to ensure the appropriate collector configuration file is used
  • Add a read-only volume, so the collector can see the docker logs from the host in the /var/lib/docker/containers directory

The resulting configuration looks like this.

otelcol:
 image: quay.io/signalfx/splunk-otel-collector:latest
 container_name: otel-col
 user: 0:0
 deploy:
   resources:
     limits:
       memory: 125M
 restart: unless-stopped
 command: ["--config=/etc/otelcol-config.yml"]
 volumes:
   - ./splunk/otelcol-config-filelog.yml:/etc/otelcol-config.yml
   - ./logs:/logs
   - ./checkpoint:/checkpoint
   - /var/lib/docker/containers:/var/lib/docker/containers:ro
 ports:
   - "4317" # OTLP over gRPC receiver
   - "4318" # OTLP over HTTP receiver
   - "9464"
   - "8888"
   - "13133"
   - "14250"
   - "14268"
   - "6060"
   - "9080"
   - "9411"
   - "9943"
 depends_on:
   - jaeger
 logging: *logging
 environment:
   - ENVOY_PORT
   - SPLUNK_ACCESS_TOKEN=${SPLUNK_ACCESS_TOKEN}
   - SPLUNK_REALM=${SPLUNK_REALM}
   - SPLUNK_HEC_TOKEN=${SPLUNK_HEC_TOKEN}
   - SPLUNK_HEC_URL=${SPLUNK_HEC_URL}
   - SPLUNK_MEMORY_TOTAL_MIB=${SPLUNK_MEMORY_TOTAL_MIB}

The collector will utilize the configuration file stored at ./splunk/otelcol-config-filelog.yml

Review the OpenTelemetry Collector configuration

Next, let's review the changes that have already been applied to the OpenTelemetry Collector configuration file (located at ./splunk/otelcol-config-filelog.yml) to add the filelog receiver.

receivers:
 filelog:
   include:
     - /var/lib/docker/containers/*/*-json.log
   encoding: utf-8
   fingerprint_size: 1kb
   force_flush_period: "0"
   include_file_name: false
   include_file_path: true
   max_concurrent_files: 1024
   max_log_size: 1MiB
   operators:
     - id: parser-docker
       timestamp:
         layout: '%Y-%m-%dT%H:%M:%S.%LZ'
         parse_from: attributes.time
       type: json_parser
     - id: extract_metadata_from_docker_tag
       parse_from: attributes.attrs.tag
       regex: ^(?P<name>[^\|]+)\|(?P<image_name>[^\|]+)\|(?P<id>[^$]+)$
       type: regex_parser
       if: 'attributes?.attrs?.tag != nil'
     - from: attributes.name
       to: resource["com.splunk.sourcetype"]
       type: copy
       if: 'attributes?.name != nil'
     - from: attributes.name
       to: resource["docker.container.name"]
       type: move
       if: 'attributes?.name != nil'
     - from: attributes.image_name
       to: resource["docker.image.name"]
       type: move
       if: 'attributes?.image_name != nil'
     - from: attributes.id
       to: resource["docker.container.id"]
       type: move
       if: 'attributes?.id != nil'
     - from: attributes.stream
       to: resource["log.io.stream"]
       type: move
     - field: attributes.attrs.tag
       type: remove
       if: 'attributes?.attrs?.tag != nil'
     - from: attributes.log
       to: body
       type: move
   poll_interval: 200ms
   start_at: beginning

The filelog receiver was also added to the collector pipeline.

pipelines:
 traces:
   receivers: [jaeger, otlp, sapm, zipkin]
   processors: [batch, resourcedetection]
   exporters: [ sapm, signalfx ]
 metrics:
   receivers: [otlp, signalfx, prometheus, hostmetrics]
   processors: [batch, resourcedetection]
   exporters: [signalfx]
 logs:
   receivers: [otlp, signalfx, filelog]
   processors: [batch, resourcedetection]
   exporters: [splunk_hec]

Verify log data is flowing

Restart the demo application by stopping docker compose and then running the following command:

docker compose up --no-build

You should now see log data coming in from all of the services in the application:

clipboard_eeea8aa8a4f111084aad1eac4117a18a0.png

We can also run a count by sourcetype, to ensure that we capture logs from all services in the demo application.

clipboard_e45952487554a51314ae9422ae56a1a41.png

Option 2: Using the Fluent Forward receiver

The next option is the Fluent Forward receiver, which leverages Docker’s fluentd logging driver.

Configure the Fluent Forward Receiver

We’ll begin by adding the Fluent Forward receiver to our OpenTelemetry Collector configuration.

These changes have already been applied to ./splunk/otelcol-config-fluentd.yml

Add the following code to the receivers section of the configuration file. This tells the receiver to listen on port 24224 for events using the Fluent Forward protocol.

receivers:
 fluentforward:
   endpoint: 0.0.0.0:24224

We also need to modify the pipelines section of our collector configuration to ensure that the fluentforward receiver is included in the pipeline.

pipelines:
…
 logs:
   receivers: [otlp, signalfx, fluentforward]
   processors: [batch]
   exporters: [splunk_hec]

Configure the Fluentd logging driver

Next, let’s update the docker-compose.yml to instruct Docker to use the fluentd logging driver for our demo application. This is done by replacing the existing logging configuration with the following. This directs the output to our Fluentd instance running on port 24224.

version: '3.9'
x-default-logging: &logging
 driver: "fluentd"
 options:
   fluentd-address: "localhost:24224"
   fluentd-async: "true"
   fluentd-retry-wait: 1s
   fluentd-max-retries: 10

Update the OpenTelemetry Collector service configuration

Next, let’s update the OpenTelemetry Collector service configuration in docker-compose.yml with the following changes:

  • Update the command and volumes used to launch the container, to ensure the appropriate collector configuration file is used
  • Expose the required ports for the collector, including port 24224 for the Fluent Forward receiver

The resulting configuration looks like this.

otelcol:
 image: quay.io/signalfx/splunk-otel-collector:latest
 container_name: otel-col
 deploy:
   resources:
     limits:
       memory: 125M
 restart: unless-stopped
 command: ["--config=/etc/otelcol-config.yml"]
 volumes:
   - ./splunk/otelcol-config-fluentd.yml:/etc/otelcol-config.yml
   - ./logs:/logs
   - ./checkpoint:/checkpoint
 ports:
   - "4317" # OTLP over gRPC receiver
   - "4318" # OTLP over HTTP receiver
   - "9464"
   - "8888"
   - "13133"
   - "14250"
   - "14268"
   - "6060"
   - "9080"
   - "9411"
   - "9943"
   - "24224:24224"   # Fluentforward receiver
 depends_on:
   - jaeger
 logging: *logging
 environment:
   - ENVOY_PORT
   - SPLUNK_ACCESS_TOKEN=${SPLUNK_ACCESS_TOKEN}
   - SPLUNK_REALM=${SPLUNK_REALM}
   - SPLUNK_HEC_TOKEN=${SPLUNK_HEC_TOKEN}
   - SPLUNK_HEC_URL=${SPLUNK_HEC_URL}
   - SPLUNK_MEMORY_TOTAL_MIB=${SPLUNK_MEMORY_TOTAL_MIB}

The collector will utilize the configuration file stored at ./splunk/otelcol-config-fluentd.yml

Verify log data is flowing

Restart the application by stopping docker compose and then running the following command.

docker compose up --no-build

You should now see log data coming in from all of the services in the application.

clipboard_efa036bfb3f1843fae608e21e6434527b.png

Cleanup

If you want to, you can clean up the application deployment by stopping the docker compose process using Ctrl+C. If you see that containers are still running, you can stop all the containers with the following command:

docker compose stop  

Next steps

In this article, we showed how both the Filelog and Fluent Forward receivers can be used to bring Docker logs into Splunk Cloud Platform. You might also be interested in how to do this in Kubernetes. If so, see: Getting Kubernetes log data Into Splunk Cloud Platform with OpenTelemetry.

You might also be interested in configuring Splunk Log Observer Connect to bring the logs into Splunk Observability Cloud, and then using correlated log, trace, and metric data in Splunk Observability Cloud to rapidly troubleshoot application issues.

Finally, the following resources might also help you set up this process from Docker: