Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -102,3 +102,6 @@ pkg/internal/java/.gradle
internal/test/integration/components/java_tls/netty_tls/target
internal/test/integration/components/java_tls/sync_async_tls/target
internal/test/integration/components/java_tls/jdk8/target

# Ignore the generated OpenTelemetry Collector configuration files for development.
examples/otel-collector/otelcol-dev/*
1 change: 1 addition & 0 deletions examples/otel-collector/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ RUN go build -o otelcol-dev .
# Final stage
FROM alpine:3.19@sha256:6baf43584bcb78f2e5847d1de515f23499913ac9f12bdf834811a3145eb11ca1
RUN apk add --no-cache ca-certificates
# Note: libc6-compat is not needed since the binary is statically linked

WORKDIR /
COPY --from=builder /app/examples/otel-collector/otelcol-dev/otelcol-dev /otelcol
Expand Down
261 changes: 180 additions & 81 deletions examples/otel-collector/README.md
Original file line number Diff line number Diff line change
@@ -1,101 +1,200 @@
# OBI As otel collector receiver
# OBI As OpenTelemetry Collector Receiver Example

We can follow the guide from opentelemetry.io on [Running and debugging the receiver](https://opentelemetry.io/docs/collector/extend/custom-component/receiver/#running-and-debugging-the-receiver)
This example demonstrates how to build and run the OpenTelemetry Collector with OBI as a receiver component for zero-code eBPF instrumentation.

1. First we need to [download the otel collector builder](https://opentelemetry.io/docs/collector/extend/ocb/#step-1---install-the-builder)
2. Generate the collector distribution with the OBI receiver:
## Prerequisites

```bash
./ocb --config ./builder-config.yaml
```
- Go 1.25 or later
- [OTel Collector Builder (`ocb`)](https://opentelemetry.io/docs/collector/extend/ocb/) installed
- Docker (for generating eBPF files) or a C compiler, clang, and eBPF headers
- Linux system with elevated privileges (sudo) to run the collector

## Quick Start

1. Generate eBPF files (required for OBI):

```bash
cd ../..
make docker-generate
# or if you have build tools installed locally:
# make generate
cd examples/otel-collector
```

2. Generate the collector distribution with the OBI receiver using OCB:

```bash
ocb --config ./builder-config.yaml
```

This creates a custom collector binary in `./otelcol-dev/otelcol-dev`.

3. Run the collector with elevated privileges:

```bash
pushd otelcol-dev
sudo go run . --config ../config.yaml
popd
```

The collector requires `sudo` to attach eBPF probes to processes.

## Testing the Collector

Once the collector is running, you can generate some test traces:

1. In a new terminal, start a simple HTTP server:

```bash
python3 -m http.server 8000
```

2. Make an HTTP request to generate tracing data:

```bash
curl http://localhost:8000
```

3. Check the collector logs for received traces. The debug exporter will print traces to the logs:

```
2026-01-05T23:18:08.379+0200 info ResourceSpans #0
Resource SchemaURL:
Resource attributes:
-> service.name: Str(python3.12)
-> telemetry.sdk.language: Str(python)
-> telemetry.sdk.name: Str(opentelemetry-ebpf-instrumentation)
-> telemetry.sdk.version: Str(unset)
-> host.name: Str(lima-coralogix-vm-24)
-> host.id: Str(a998876e9a2642d8a1a9b8a0030c786e)
-> os.type: Str(linux)
-> service.instance.id: Str(lima-coralogix-vm-24:295419)
-> otel.scope.name: Str(go.opentelemetry.io/obi)
ScopeSpans #0
ScopeSpans SchemaURL:
InstrumentationScope
Span #0
Trace ID : 8c28f3b6817dfc2e629612dc39952fef
Parent ID : 9adcce7d3501ea15
ID : 511fc600e31636db
Name : in queue
Kind : Internal
Start time : 2026-01-05 21:17:58.465955692 +0000 UTC
End time : 2026-01-05 21:17:58.468910267 +0000 UTC
Status code : Unset
Status message :
DroppedAttributesCount: 0
DroppedEventsCount: 0
DroppedLinksCount: 0
Span #1
Trace ID : 8c28f3b6817dfc2e629612dc39952fef
Parent ID : 9adcce7d3501ea15
ID : 302aa18decfd48f3
Name : processing
Kind : Internal
Start time : 2026-01-05 21:17:58.468910267 +0000 UTC
End time : 2026-01-05 21:17:58.496701454 +0000 UTC
Status code : Unset
Status message :
DroppedAttributesCount: 0
DroppedEventsCount: 0
DroppedLinksCount: 0
Span #2
Trace ID : 8c28f3b6817dfc2e629612dc39952fef
Parent ID :
ID : 9adcce7d3501ea15
Name : GET /
Kind : Server
Start time : 2026-01-05 21:17:58.465955692 +0000 UTC
End time : 2026-01-05 21:17:58.496701454 +0000 UTC
Status code : Unset
Status message :
DroppedAttributesCount: 0
DroppedEventsCount: 0
DroppedLinksCount: 0
Attributes:
-> http.request.method: Str(GET)
-> http.response.status_code: Int(200)
-> url.path: Str(/)
-> client.address: Str(127.0.0.1)
-> server.address: Str(python3.12)
-> server.port: Int(8000)
-> http.request.body.size: Int(77)
-> http.response.body.size: Int(11187)
-> http.route: Str(/)
{"resource": {"service.instance.id": "7e92d7ee-5866-4d53-8025-75c0d250e8cf", "service.name": "otelcol-dev", "service.version": ""}, "otelcol.component.id": "debug", "otelcol.component.kind": "exporter", "otelcol.signal": "traces"}

```

1. Run the collector with the generated distribution:
## Configuration

The `config.yaml` file defines:

- **OBI receiver**: Listens on port 8000 for HTTP traffic and automatically instruments services
- **OTLP receiver**: Accepts spans from manually instrumented applications
- **Batch processor**: Groups spans for efficient export
- **Debug exporter**: Prints spans to logs (useful for debugging)
- **OTLP exporter**: Sends spans to a Jaeger backend (requires Jaeger to be running)

You can modify `config.yaml` to:

- Add more exporters for different backends
- Configure service discovery filters
- Enable additional OBI features (metrics, logs)

## Troubleshooting

### Error: "Required system capabilities not present"

The collector requires elevated privileges to attach eBPF probes. You have two options:

#### Option 1: Run with sudo (simplest)

```bash
pushd otelcol-dev
sudo go run . --config ../config.yaml
popd
```

1. Setup a test server on port 8000
#### Option 2: Grant capabilities to the binary (more secure)

Set capabilities on the compiled binary to allow it to run without sudo:

```bash
python3 -m http.server 8000
# After building with OCB
sudo setcap cap_sys_admin,cap_sys_ptrace,cap_dac_read_search,cap_net_raw,cap_perfmon,cap_bpf,cap_checkpoint_restore=ep ./otelcol-dev/otelcol-dev

# Then run without sudo
./otelcol-dev/otelcol-dev --config ../config.yaml
```

1. Perform an HTTP request to generate some tracing data
Verify the capabilities were set:

```bash
curl http://localhost:8000
getcap ./otelcol-dev/otelcol-dev
```

1. Check the collector logs to see the received traces
### Error: "cannot unmarshal the configuration"

```
2026-01-05T23:18:08.379+0200 info ResourceSpans #0
Resource SchemaURL:
Resource attributes:
-> service.name: Str(python3.12)
-> telemetry.sdk.language: Str(python)
-> telemetry.sdk.name: Str(opentelemetry-ebpf-instrumentation)
-> telemetry.sdk.version: Str(unset)
-> host.name: Str(lima-coralogix-vm-24)
-> host.id: Str(a998876e9a2642d8a1a9b8a0030c786e)
-> os.type: Str(linux)
-> service.instance.id: Str(lima-coralogix-vm-24:295419)
-> otel.scope.name: Str(go.opentelemetry.io/obi)
ScopeSpans #0
ScopeSpans SchemaURL:
InstrumentationScope
Span #0
Trace ID : 8c28f3b6817dfc2e629612dc39952fef
Parent ID : 9adcce7d3501ea15
ID : 511fc600e31636db
Name : in queue
Kind : Internal
Start time : 2026-01-05 21:17:58.465955692 +0000 UTC
End time : 2026-01-05 21:17:58.468910267 +0000 UTC
Status code : Unset
Status message :
DroppedAttributesCount: 0
DroppedEventsCount: 0
DroppedLinksCount: 0
Span #1
Trace ID : 8c28f3b6817dfc2e629612dc39952fef
Parent ID : 9adcce7d3501ea15
ID : 302aa18decfd48f3
Name : processing
Kind : Internal
Start time : 2026-01-05 21:17:58.468910267 +0000 UTC
End time : 2026-01-05 21:17:58.496701454 +0000 UTC
Status code : Unset
Status message :
DroppedAttributesCount: 0
DroppedEventsCount: 0
DroppedLinksCount: 0
Span #2
Trace ID : 8c28f3b6817dfc2e629612dc39952fef
Parent ID :
ID : 9adcce7d3501ea15
Name : GET /
Kind : Server
Start time : 2026-01-05 21:17:58.465955692 +0000 UTC
End time : 2026-01-05 21:17:58.496701454 +0000 UTC
Status code : Unset
Status message :
DroppedAttributesCount: 0
DroppedEventsCount: 0
DroppedLinksCount: 0
Attributes:
-> http.request.method: Str(GET)
-> http.response.status_code: Int(200)
-> url.path: Str(/)
-> client.address: Str(127.0.0.1)
-> server.address: Str(python3.12)
-> server.port: Int(8000)
-> http.request.body.size: Int(77)
-> http.response.body.size: Int(11187)
-> http.route: Str(/)
{"resource": {"service.instance.id": "7e92d7ee-5866-4d53-8025-75c0d250e8cf", "service.name": "otelcol-dev", "service.version": ""}, "otelcol.component.id": "debug", "otelcol.component.kind": "exporter", "otelcol.signal": "traces"}
Your `config.yaml` may have YAML syntax errors or reference processors/exporters that aren't in the builder config. Ensure all referenced components are defined in `builder-config.yaml`.

### No traces appearing in logs

1. Verify the collector started successfully (check for startup messages)
2. Confirm your test application is actually making HTTP requests
3. Check that the OBI receiver configuration matches your port (`8000` in this example)

## Building a Docker Image

Once you have a working collector locally, you'll likely want to deploy it to your infrastructure. Containerizing the collector makes it easy to deploy across multiple nodes or into Kubernetes clusters.

The included `Dockerfile` builds the collector from source within the container. To build and push the image to your registry:

```bash
cd ../..
make docker-generate # Generate eBPF files first
cd examples/otel-collector

docker build -t my-registry/otelcol-obi:v0.5.0 .
docker push my-registry/otelcol-obi:v0.5.0
```

This image can then be deployed as a DaemonSet in Kubernetes, or used in any container orchestration platform.
26 changes: 14 additions & 12 deletions examples/otel-collector/builder-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,27 @@ dist:
description: Basic OTel Collector distribution for Developers
output_path: ./otelcol-dev

replaces:
- go.opentelemetry.io/obi => ../../..

exporters:
- gomod:
go.opentelemetry.io/collector/exporter/debugexporter v0.142.0
go.opentelemetry.io/collector/exporter/debugexporter v0.145.0
- gomod:
go.opentelemetry.io/collector/exporter/otlpexporter v0.142.0
go.opentelemetry.io/collector/exporter/otlpexporter v0.145.0

processors:
- gomod:
go.opentelemetry.io/collector/processor/batchprocessor v0.142.0
go.opentelemetry.io/collector/processor/batchprocessor v0.145.0

receivers:
- gomod:
go.opentelemetry.io/collector/receiver/otlpreceiver v0.142.0
# TODO when we push a version of obi receiver, change to that
# go.opentelemetry.io/obi/collector v0.3.0
- gomod: go.opentelemetry.io/collector/receiver/otlpreceiver v0.145.0
- gomod: go.opentelemetry.io/obi v0.5.0
import: go.opentelemetry.io/obi/collector

providers:
- gomod: go.opentelemetry.io/collector/confmap/provider/envprovider v1.18.0
- gomod: go.opentelemetry.io/collector/confmap/provider/fileprovider v1.18.0
- gomod: go.opentelemetry.io/collector/confmap/provider/httpprovider v1.18.0
- gomod: go.opentelemetry.io/collector/confmap/provider/httpsprovider v1.18.0
- gomod: go.opentelemetry.io/collector/confmap/provider/yamlprovider v1.18.0
- gomod: go.opentelemetry.io/collector/confmap/provider/envprovider v1.51.0
- gomod: go.opentelemetry.io/collector/confmap/provider/fileprovider v1.51.0
- gomod: go.opentelemetry.io/collector/confmap/provider/httpprovider v1.51.0
- gomod: go.opentelemetry.io/collector/confmap/provider/httpsprovider v1.51.0
- gomod: go.opentelemetry.io/collector/confmap/provider/yamlprovider v1.51.0
16 changes: 9 additions & 7 deletions examples/otel-collector/config.yaml
Original file line number Diff line number Diff line change
@@ -1,30 +1,32 @@
receivers:
obi:
open_port: "8000"
# discovery:
# services:
# - k8s_namespace: .
# exclude_services:
# - exe_path: ".*obi.*|.*otelcol.*"
# Uncomment to enable service discovery
# discovery:
# poll_interval: 30s
otlp:
protocols:
grpc:
endpoint: 0.0.0.0:4317

processors:
batch:
timeout: 1s
send_batch_size: 1024

exporters:
debug:
verbosity: detailed
otlp/jaeger:
endpoint: localhost:14317
tls:
insecure: true
sending_queue:
batch:

service:
pipelines:
traces:
receivers: [otlp, obi]
processors: [batch]
exporters: [otlp/jaeger, debug]
telemetry:
logs:
Expand Down
Loading