OpenTelemetry
OpenTelemetry is an open standard and a set of libraries for emitting traces, metrics, and logs in one vendor-neutral format. Signals, OTLP, and an example.
OpenTelemetry is an open standard and a set of libraries for emitting traces, metrics, and logs in one vendor-neutral format. Any process that speaks it can send telemetry to any backend that accepts it, so the instrumentation in your code stops being tied to the tool that stores the data (What is OpenTelemetry, checked on 2026-08-13).
That portability is the whole point of the project. Before it existed, adding a second monitoring tool meant a second agent, a second SDK, and a second set of attribute names for the same facts.
Definition
OpenTelemetry, usually shortened to OTel, is a specification plus the APIs, SDKs, and tools that implement it. It is a Cloud Native Computing Foundation project, formed in 2019 by merging the OpenTracing and OpenCensus efforts into one standard, and it is maintained in the open at github.com/open-telemetry.
The standard covers how telemetry is produced and moved. Storage, indexing, querying, dashboards, and alerting stay with whatever backend receives the data. Changing that backend becomes an endpoint change in configuration rather than a rewrite of application code.
The three signals
OpenTelemetry organizes telemetry into signals. Three are stable and widely implemented, and each answers a different kind of question.
| Signal | Unit of data | What it captures | Example from a build |
|---|---|---|---|
| Traces | Spans in a parent and child tree | One operation, with a start time, a duration, and attributes | A workflow run as a root span, with a child span per job and per step |
| Metrics | Measurements aggregated over time | A number sampled or counted repeatedly | CPU utilization on the machine, sampled every 10 seconds |
| Logs | Timestamped records | A message plus structured attributes | System log lines written while the job was running |
A fourth signal for continuous profiling is newer and moves through the specification process separately, so check the specification index before depending on it.
The pieces you actually install
The word OpenTelemetry covers several components that are easy to confuse, and knowing which one you are configuring saves a lot of guessing.
| Piece | Role |
|---|---|
| API | The interfaces application code calls to start a span or record a measurement |
| SDK | The implementation behind the API: sampling, batching, and export |
| Instrumentation libraries | Prebuilt hooks for HTTP clients, databases, and language runtimes |
| OTLP | The wire protocol that carries the data to a receiver |
| Collector | A standalone process that receives, processes, and forwards telemetry |
| Semantic conventions | Agreed attribute names so two systems describe the same fact identically |
| Context propagation | The W3C Trace Context headers that stitch spans together across process boundaries |
The OpenTelemetry Protocol is the piece most configuration touches. It runs over gRPC on port 4317 by default, or over HTTP on port 4318, where each signal has its own path: /v1/traces, /v1/metrics, and /v1/logs.
The Collector is worth calling out because it removes work from the application. It receives data, batches it, drops or renames attributes, and forwards the result to one or more destinations. A fleet of machines can therefore point at one endpoint and have routing decided centrally.
Configuration is environment variables
SDKs and collectors read a common set of environment variables, which is why the same instrumentation moves between a laptop, a container, and a build machine untouched. The names are fixed by the SDK environment variable specification, checked on 2026-08-13.
| Variable | Purpose | Typical value |
|---|---|---|
OTEL_SERVICE_NAME | Names the service the data belongs to | github-actions-runner |
OTEL_EXPORTER_OTLP_ENDPOINT | Base URL of the collector or backend | https://otlp.example.internal:4318 |
OTEL_EXPORTER_OTLP_PROTOCOL | Wire format for export | http/protobuf |
OTEL_EXPORTER_OTLP_HEADERS | Headers added to every export request, usually auth | authorization=Bearer ... |
OTEL_RESOURCE_ATTRIBUTES | Key and value pairs attached to every record from this process | cicd.pipeline.run.id=1234 |
OTEL_METRIC_EXPORT_INTERVAL | Milliseconds between metric exports | 10000 |
Resource attributes are what make telemetry from different sources join up. Two records that carry the same run id can be shown side by side even though one came from a metrics scraper and the other from a log shipper. The attribute names for build pipelines live in the cicd group of the semantic conventions, one of the newer additions, so read the registry page before standardizing on names across repositories.
Example
A GitHub Actions job is an ordinary process tree on an ordinary machine, so a collector can run alongside it. The workflow below starts a collector on the runner, builds the project, and stops the collector at the end. The collector scrapes host metrics and exports them over OTLP with attributes naming the repository, workflow, run, and job.
name: build
on:
push:
branches: [main]
jobs:
build:
runs-on: ubuntu-latest
env:
OTEL_EXPORTER_OTLP_ENDPOINT: https://otlp.example.internal:4318
OTEL_EXPORTER_OTLP_PROTOCOL: http/protobuf
OTEL_SERVICE_NAME: github-actions-runner
OTEL_RESOURCE_ATTRIBUTES: >-
cicd.pipeline.name=${{ github.workflow }},
cicd.pipeline.run.id=${{ github.run_id }},
cicd.pipeline.task.name=${{ github.job }},
vcs.repository.name=${{ github.repository }}
steps:
- uses: actions/checkout@v4
- name: Start the metrics agent
run: |
./bin/otelcol-contrib --config=.github/otel/collector.yaml &
echo $! > /tmp/otelcol.pid
- name: Build
run: make build
- name: Stop the metrics agent
if: always()
run: |
kill "$(cat /tmp/otelcol.pid)"
sleep 5The collector configuration reads the same environment and turns machine counters into OTLP metrics:
receivers:
hostmetrics:
collection_interval: 10s
scrapers:
cpu:
memory:
disk:
filesystem:
network:
processors:
batch:
exporters:
otlp:
endpoint: ${env:OTEL_EXPORTER_OTLP_ENDPOINT}
service:
pipelines:
metrics:
receivers: [hostmetrics]
processors: [batch]
exporters: [otlp]Three details decide whether this produces anything useful.
if: always() keeps the shutdown step running after a failed build. A build that fails is the one whose CPU and memory curves you want, and a job that exits without stopping the agent loses the last export window.
The sleep 5 gives the collector time to flush its final batch before the machine is torn down. Batching is what keeps export cheap, and the cost of batching is that the last few seconds of data need a moment to leave.
The resource attributes are what put the metrics next to the job logs. A backend that indexes cicd.pipeline.run.id can answer a single query with the memory series from the collector and the log records shipped from the same job, so a step that failed at minute seven can be lined up against the machine's memory curve at minute seven.
A trace pipeline is the same shape with a different receiver. A step that records one span per build phase, exported through the same endpoint, gives a waterfall of the run to sit above those metrics.
Related Terms
- Send OpenTelemetry metrics from GitHub Actions jobs: the collector setup, attribute naming, and the queries worth building once the data lands.
- GitHub Actions observability and per-job runner metrics: CPU, memory, disk, and queue time per job, and how to read them together.
- Runner utilization: the share of a machine's CPU and memory a job actually consumes, and how it is measured.
- WarpBuild observability documentation: the metrics and system logs collected from runners, and how collection is configured.
- WarpBuild pricing: per minute rates by runner type.
FAQ
What is OpenTelemetry in one sentence?
OpenTelemetry is an open standard, together with the APIs, SDKs, and tools that implement it, for generating and exporting traces, metrics, and logs in a single vendor-neutral format that any compatible backend can read.
What is the difference between OpenTelemetry and a monitoring backend?
OpenTelemetry covers production and transport: how a process records a span or a measurement, what the attributes are called, and how the data reaches a receiver over OTLP. Storage, indexing, querying, dashboards, and alerting belong to whichever backend accepts the data, and swapping that backend is an endpoint change rather than a reinstrumentation project.
Can GitHub Actions jobs emit OpenTelemetry data?
Yes. A job is a normal process tree on a machine, so anything that can run on the runner can export OpenTelemetry data: a collector scraping host metrics, an SDK inside a test harness emitting spans, or a step that ships the run structure after the job finishes. The usual pattern is to attach the repository, workflow, run id, and job name as resource attributes so every record can be traced back to one run.
Start with $10 in free credits
Change the runner label in your workflow and keep the rest of your GitHub Actions setup. Runner time is billed per minute.