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.

SignalUnit of dataWhat it capturesExample from a build
TracesSpans in a parent and child treeOne operation, with a start time, a duration, and attributesA workflow run as a root span, with a child span per job and per step
MetricsMeasurements aggregated over timeA number sampled or counted repeatedlyCPU utilization on the machine, sampled every 10 seconds
LogsTimestamped recordsA message plus structured attributesSystem 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.

PieceRole
APIThe interfaces application code calls to start a span or record a measurement
SDKThe implementation behind the API: sampling, batching, and export
Instrumentation librariesPrebuilt hooks for HTTP clients, databases, and language runtimes
OTLPThe wire protocol that carries the data to a receiver
CollectorA standalone process that receives, processes, and forwards telemetry
Semantic conventionsAgreed attribute names so two systems describe the same fact identically
Context propagationThe 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.

VariablePurposeTypical value
OTEL_SERVICE_NAMENames the service the data belongs togithub-actions-runner
OTEL_EXPORTER_OTLP_ENDPOINTBase URL of the collector or backendhttps://otlp.example.internal:4318
OTEL_EXPORTER_OTLP_PROTOCOLWire format for exporthttp/protobuf
OTEL_EXPORTER_OTLP_HEADERSHeaders added to every export request, usually authauthorization=Bearer ...
OTEL_RESOURCE_ATTRIBUTESKey and value pairs attached to every record from this processcicd.pipeline.run.id=1234
OTEL_METRIC_EXPORT_INTERVALMilliseconds between metric exports10000

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 5

The 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.

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.