Resource attributes: who emitted this span?

2 min read

Short answer

A resource describes the entity that produces telemetry, such as a service, process, host or container, as resource attributes. They're set once per SDK and apply to every span it exports. service.name is the one that matters most: without it, backends show unknown_service. Anything that differs from span to span belongs on the span instead.

On this page

Set OTEL_SERVICE_NAME=payments-worker, restart, and your spans can still say treasury-agent. The variable is fine. A setup like the one in the quickstart never reads it.

Resource attributes such as service.name are set once and shared by every span, while agent identity such as gen_ai.agent.name differs from span to span.

Resource or span?

A resource describes whoever emits the telemetry (OpenTelemetry resources). It’s set once and attached to every span from that SDK.

Resource attribute Span attribute
Describes The process, service, host One operation
Set Once, at SDK setup Per span
Examples service.name, deployment.environment.name, telemetry.sdk.language blockchain.tx.hash, gen_ai.agent.id
Changes between spans? No Yes

Why is the variable ignored?

Because with sdk-trace-node 2.x, a resource you pass in replaces the default one, and environment variables are read by a detector you have to add. Here are three setups, each run with and without OTEL_SERVICE_NAME=payments-worker OTEL_RESOURCE_ATTRIBUTES=deployment.environment.name=staging:

Setup service.name Env vars used? telemetry.sdk.*
No resource option unknown_service:/…/bin/node No Yes
resourceFromAttributes({...}) treasury-agent No No
Default + yours + envDetector payments-worker Yes Yes

The third one does what most people expect:

import { NodeTracerProvider } from '@opentelemetry/sdk-trace-node';
import { SimpleSpanProcessor } from '@opentelemetry/sdk-trace-base';
import { defaultResource, detectResources, envDetector, resourceFromAttributes } from '@opentelemetry/resources';
const resource = defaultResource()
.merge(resourceFromAttributes({ 'service.name': 'treasury-agent' }))
.merge(detectResources({ detectors: [envDetector] })); // env vars win
new NodeTracerProvider({ resource, spanProcessors: [new SimpleSpanProcessor(exporter)] }).register();

The later merge wins, so the environment can override what the code sets. NodeSDK from @opentelemetry/sdk-node reads both variables on its own, but there a serviceName passed in code wins over OTEL_SERVICE_NAME.

Is the agent a resource?

Sometimes. If a service runs exactly one agent, service.name can be the agent’s name, and that’s what the hashspan demo does. But one service often runs many agents or many runs of one. A resource can’t tell them apart, because it’s the same for every span.

FAQ

How do I set OTEL_RESOURCE_ATTRIBUTES?

As comma-separated key=value pairs, for example OTEL_RESOURCE_ATTRIBUTES=deployment.environment.name=production. In Node.js with sdk-trace-node 2.x, it only takes effect if your setup runs the environment resource detector.

What is service.name in OpenTelemetry?

The logical name of the service, a resource attribute. Backends use it to group spans, for example as the service list in Jaeger. If you don't set it, the SDK reports unknown_service.

Should the agent's name be service.name?

Only if one service runs one agent. If a service runs several agents, or many runs of one, identify the agent on the spans with gen_ai.agent.name and gen_ai.agent.id.

Go further

Type to search the docs, Learn topics and the blog.