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.
/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.
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.
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.
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.
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.
file_storage extension so filelog persists its read offset.Authorization: Bearer <token>, including the Bearer prefix.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.