I’m adding instrumentation code to my app. To set it up, I have to create a Resource. What does that mean? What can I do with it?
Ah, I too have wondered about this.
TL;DR: The Resource says what program is sending these spans and where it’s running. You can skip it if you define OTEL_SERVICE_NAME in the environment.
When I’m setting up tracing (for instance, in a Node.js app), I have to create a Resource object in order to set up the OpenTelemetry SDK:
const sdk = new NodeSDK({ resource: new Resource({ [SemanticResourceAttributes.SERVICE_NAME]: "curdling-service", }), traceExporter: sendToHoneycomb, instrumentations: [new HttpInstrumentation(), new ExpressInstrumentation()], });
If I don’t define that resource
parameter, then tracing will still work. But my spans will show up with aservice.name
of unknown_service:node
. That isn’t right!
The important service.name
attribute is defined for all spans in the single Resource passed to the SDK at initialization. Why?
The Resource defines “who is sending this telemetry?” That includes fields like service.name
. Optionally, you can setservice.instance.id
andservice.version
. If you don’t provide a Resource, then the SDK is obligated to set service.name
to unknown_service
with a language suffix.
Really, you can put any attribute in the Resource object; it is a key-value store. The OpenTelemetry Protocol (OTLP) format groups all spans emitted by a program under one Resource. Honeycomb expands each attribute to all spans underneath. Every attribute in the resource will appear on every span emitted by my program.
But don’t put just anything in there! The resource is about who and where this telemetry is coming from. The SDK will add fields for me, like process.pid=34566
and process.command_line=”/usr/bin/node /Users/jessicakerr/code/index.js”
. Some agents will add fields like the hostname and operating system or the Kubernetes pod and deployment.
If you’re also emitting metrics, standard Resource attributes connect your trace spans with metrics from the pod or container or server your service runs on. The term Resource comes from the metrics side, where it referred originally to a physical component. OpenTelemetry emphasizes compatibility between telemetry streams, so it standardizes Resource fields.
The constants for these field names are defined in the semantic layer of OpenTelemetry
rather than the implementation or API. That is why I say [SemanticResourceAttributes.SERVICE_NAME]
in order to provide the service name.
This leads to an unpleasant number of imports. Just for this Resource, I include two packages:
const { Resource } = require("@opentelemetry/resources"); const { SemanticResourceAttributes } = require("@opentelemetry/semantic-conventions");
So much work. Here’s a trick: You can skip providing a Resource to the SDK if you define an OTEL_SERVICE_NAME environment variable.
The Resource plays an important role in saying what program, running where, is sending this telemetry. The name is confusing to me, but adopting it is part of compatibility between different forms of telemetry (metrics and traces). I appreciate the care that OpenTelemetry contributors have put into standardizing this.
And I appreciate the shortcut of setting service.name in OTEL_SERVICE_NAME instead.
What else in OpenTelemetry confuses you? Ask Miss O11y!