← Back to blog
Guide 4 min read 炬鲸团队

Connect in 10 Minutes: Ship Logs, Metrics, and Traces to OBSERVE with the OpenTelemetry Collector

A copy-paste guide to installing the OpenTelemetry Collector and shipping file logs, metrics, and traces to OBSERVE with a single config — plus verification steps and common failure fixes.

Getting logs, metrics, and traces into OBSERVE doesn't require touching your application code. The OpenTelemetry Collector acts as a single ingestion layer: point it at your log files, have your SDKs send to it, and one config ships all three signals to OBSERVE. This guide gets you from zero to flowing data in about ten minutes.

Prerequisites

  • A Linux server (x86_64 or ARM64) that can reach OBSERVE.
  • An OBSERVE tenant with an ingestion token (console → Integration → generate token).
  • An application that already writes file logs, e.g. /var/log/app/*.log.

For metrics and traces, your app needs the OpenTelemetry SDK or auto-instrumentation. Logs come straight from the files, with zero code changes.

Install the Collector

Use the contrib distribution, which bundles the filelog receiver:

wget https://github.com/open-telemetry/opentelemetry-collector-releases/releases/download/v0.105.0/otelcol-contrib_0.105.0_linux_amd64.tar.gz
tar -xzf otelcol-contrib_0.105.0_linux_amd64.tar.gz
sudo install otelcol-contrib /usr/local/bin/

On ARM64, swap amd64 for arm64 in the filename. The contrib build is the one you want — the plain build omits the filelog receiver and several other useful components.

Write the config

Create /etc/otelcol/config.yaml:

receivers:
  filelog:
    include: [/var/log/app/*.log]
    start_at: end
    operators:
      - type: json_parser
  otlp:
    protocols:
      grpc: { endpoint: 0.0.0.0:4317 }
      http: { endpoint: 0.0.0.0:4318 }

processors:
  batch:
    timeout: 5s
    send_batch_size: 1024

exporters:
  otlphttp:
    endpoint: https://ob.jjhub.cn/otel
    headers:
      Authorization: "Bearer <your-token>"

service:
  pipelines:
    logs:
      receivers: [filelog]
      processors: [batch]
      exporters: [otlphttp]
    traces:
      receivers: [otlp]
      processors: [batch]
      exporters: [otlphttp]
    metrics:
      receivers: [otlp]
      processors: [batch]
      exporters: [otlphttp]

Three pipelines — logs, traces, metrics — each route to the same otlphttp exporter pointed at OBSERVE. The filelog receiver watches your log files; the otlp receiver listens on 4317 (gRPC) and 4318 (HTTP) for your SDKs.

Start and verify

sudo otelcol-contrib --config /etc/otelcol/config.yaml

Check the Integration page in the console: logs appear within seconds, metrics within a minute. For traces, make sure your SDK is actually exporting — for Java, attach the agent with -javaagent:path/to/opentelemetry-javaagent.jar; for Go, wire up the otel sdk and exporter.

Wiring up your application

For logs, you're already done — the collector reads the files. For metrics and traces, your app needs to export OTLP to the collector. In Java, the fastest path is the auto-instrumentation agent, which requires no code changes:

java -javaagent:/opt/opentelemetry-javaagent.jar   -Dotel.exporter.otlp.endpoint=http://localhost:4317   -Dotel.resource.attributes=service.name=order-service   -jar order-service.jar

The service.name resource attribute matters: OBSERVE uses it as the service field in queries and as the grouping key in dashboards, so set it consistently across every instance of the same service. In Go, use the otel sdk with the otlptracegrpc and otlpmetricgrpc exporters and set the same service.name. The app and the collector can run on different hosts — just make sure the app can reach port 4317/4318.

The batch processor in our config is worth understanding: it holds spans and metrics for a few seconds and sends them in bulk, trading a little latency for a large drop in HTTP request count. That tradeoff matters a lot at scale.

Common problems

  1. Logs arrive but no traces or metrics: check the app is exporting OTLP and the endpoint points at the Collector's 4317/4318, not OBSERVE directly. (That also works, but then the Collector pipeline is bypassed.)
  2. Logs duplicate after a restart: add the file_storage extension so filelog persists its read offset.
  3. 401 on the exporter: make sure the header is exactly Authorization: Bearer <token>, including the Bearer prefix.
  4. Spans arrive but traces look incomplete: check that parent/child context is propagated through async hops (thread pools, queues) in your service — a span without its parent lands as a separate, disconnected trace.

Production hardening

Before you roll this out, add three things: the file_storage extension for offset persistence, a disk-backed sending queue so the exporter buffers during network blips, and a systemd unit with Restart=always. The disk-backed queue is a small addition to the exporter:

extensions:
  file_storage:
    directory: /var/lib/otelcol

exporters:
  otlphttp:
    endpoint: https://ob.jjhub.cn/otel
    headers: { Authorization: "Bearer <token>" }
    sending_queue:
      storage: file_storage
      queue_size: 10000

Pin the collector version, and in production run at least two instances behind a load balancer so a single node failure doesn't stop ingestion. The collector is stateless apart from the file offsets, so scaling it horizontally is straightforward — just make sure each instance has its own file_storage directory.