Overview
A Resource is an immutable representation of the entity producing telemetry. It captures information about your application, service, or infrastructure component as a set of attributes.
For example, a process running in a Kubernetes pod might have these resource attributes:
service.name - The name of your service
service.version - The version of your service
deployment.environment - The environment (production, staging, etc.)
k8s.pod.name - The Kubernetes pod name
k8s.namespace.name - The Kubernetes namespace
Creating Resources
Using the Builder
The recommended way to create a resource is using the builder pattern:
use opentelemetry_sdk :: Resource ;
use opentelemetry :: KeyValue ;
let resource = Resource :: builder ()
. with_service_name ( "my_service" )
. with_attribute ( KeyValue :: new ( "service.version" , "1.0.0" ))
. with_attribute ( KeyValue :: new ( "deployment.environment" , "production" ))
. build ();
Empty Resources
You can also start with an empty resource:
let resource = Resource :: builder_empty ()
. with_attributes ([
KeyValue :: new ( "service.name" , "my_service" ),
KeyValue :: new ( "custom.attribute" , "value" ),
])
. build ();
Resource Detectors
Resource detectors automatically discover information about your runtime environment. OpenTelemetry provides several built-in detectors:
Default Detectors
When you call Resource::builder(), these detectors are automatically included:
SdkProvidedResourceDetector - Provides required SDK attributes
TelemetryResourceDetector - Adds telemetry SDK information
EnvResourceDetector - Reads from environment variables
use opentelemetry_sdk :: Resource ;
// This includes default detectors
let resource = Resource :: builder () . build ();
Environment Variables
The EnvResourceDetector reads from standard OpenTelemetry environment variables:
# Set service name
export OTEL_SERVICE_NAME = "my_service"
# Set additional attributes
export OTEL_RESOURCE_ATTRIBUTES = "deployment.environment=production,service.version=1.0.0"
use opentelemetry_sdk :: Resource ;
// Automatically picks up environment variables
let resource = Resource :: builder () . build ();
The OTEL_SERVICE_NAME environment variable takes priority over service.name in OTEL_RESOURCE_ATTRIBUTES.
Custom Detectors
You can implement custom resource detectors:
use opentelemetry_sdk :: resource :: { ResourceDetector , Resource };
use opentelemetry :: KeyValue ;
struct CustomDetector ;
impl ResourceDetector for CustomDetector {
fn detect ( & self ) -> Resource {
Resource :: builder_empty ()
. with_attributes ([
KeyValue :: new ( "custom.attribute" , "detected_value" ),
KeyValue :: new ( "host.name" , std :: env :: var ( "HOSTNAME" ) . unwrap_or_default ()),
])
. build ()
}
}
// Use the custom detector
let resource = Resource :: builder ()
. with_detector ( Box :: new ( CustomDetector ))
. build ();
Additional Detectors
The opentelemetry-resource-detectors crate provides detectors for:
Operating System - OS type, version, and architecture
Process - Process ID, executable name, command line args
Host - Hostname and other host information
Service Name
The service.name attribute is required by the OpenTelemetry specification. The SDK determines it using this priority:
OTEL_SERVICE_NAME environment variable
service.name in OTEL_RESOURCE_ATTRIBUTES
unknown_service:<executable_name> (fallback)
// Priority 1: OTEL_SERVICE_NAME (highest)
export OTEL_SERVICE_NAME = "my_service"
// Priority 2: OTEL_RESOURCE_ATTRIBUTES
export OTEL_RESOURCE_ATTRIBUTES = "service.name=my_service"
// Priority 3: Automatic fallback
// Results in "unknown_service:my_binary"
Always set a meaningful service name to identify your service in observability backends.
Using Resources
With Tracer Provider
use opentelemetry_sdk :: trace :: SdkTracerProvider ;
use opentelemetry_sdk :: Resource ;
let resource = Resource :: builder ()
. with_service_name ( "my_service" )
. with_attribute ( KeyValue :: new ( "service.version" , "1.0.0" ))
. build ();
let provider = SdkTracerProvider :: builder ()
. with_resource ( resource )
. with_simple_exporter ( exporter )
. build ();
With Meter Provider
use opentelemetry_sdk :: metrics :: SdkMeterProvider ;
use opentelemetry_sdk :: Resource ;
let resource = Resource :: builder ()
. with_service_name ( "my_service" )
. build ();
let provider = SdkMeterProvider :: builder ()
. with_resource ( resource )
. with_periodic_exporter ( exporter )
. build ();
With Logger Provider
use opentelemetry_sdk :: logs :: SdkLoggerProvider ;
use opentelemetry_sdk :: Resource ;
let resource = Resource :: builder ()
. with_service_name ( "my_service" )
. build ();
let provider = SdkLoggerProvider :: builder ()
. with_resource ( resource )
. with_simple_exporter ( exporter )
. build ();
Merging Resources
Resources can be merged to combine attributes from multiple sources:
use opentelemetry_sdk :: Resource ;
use opentelemetry :: KeyValue ;
let resource_a = Resource :: builder_empty ()
. with_attributes ([
KeyValue :: new ( "service.name" , "my_service" ),
KeyValue :: new ( "a" , "value_a" ),
])
. build ();
let resource_b = Resource :: builder_empty ()
. with_attributes ([
KeyValue :: new ( "b" , "value_b" ),
KeyValue :: new ( "a" , "value_a_override" ), // This will override
])
. build ();
let merged = resource_a . merge ( & resource_b );
// Result: { service.name: "my_service", a: "value_a_override", b: "value_b" }
When merging, attributes from the second resource (parameter) override those from the first resource (caller).
Schema URL
Resources can have an associated schema URL that defines the semantic conventions being used:
use opentelemetry_sdk :: Resource ;
use opentelemetry :: KeyValue ;
let resource = Resource :: builder_empty ()
. with_schema_url (
vec! [ KeyValue :: new ( "service.name" , "my_service" )],
"https://opentelemetry.io/schemas/1.17.0"
)
. build ();
Schema URL Merging Rules
When merging resources with schema URLs:
If both have the same schema URL, it’s preserved
If both have different schema URLs, the result has no schema URL
If one has a schema URL and the other doesn’t, the existing schema URL is used
let r1 = Resource :: from_schema_url (
[ KeyValue :: new ( "a" , "1" )],
"https://opentelemetry.io/schemas/1.17.0"
);
let r2 = Resource :: from_schema_url (
[ KeyValue :: new ( "b" , "2" )],
"https://opentelemetry.io/schemas/1.17.0"
);
let merged = r1 . merge ( & r2 );
// Schema URL: https://opentelemetry.io/schemas/1.17.0 (same)
let r3 = Resource :: from_schema_url (
[ KeyValue :: new ( "c" , "3" )],
"https://opentelemetry.io/schemas/1.18.0"
);
let merged = r1 . merge ( & r3 );
// Schema URL: None (different)
Accessing Resource Attributes
use opentelemetry :: Key ;
let resource = Resource :: builder ()
. with_service_name ( "my_service" )
. build ();
// Get a single attribute
if let Some ( service_name ) = resource . get ( & Key :: new ( "service.name" )) {
println! ( "Service: {}" , service_name );
}
// Iterate over all attributes
for ( key , value ) in resource . iter () {
println! ( "{}: {:?}" , key , value );
}
// Check if resource is empty
if resource . is_empty () {
println! ( "No resource attributes" );
}
// Get number of attributes
let count = resource . len ();
Standard Resource Attributes
OpenTelemetry defines semantic conventions for common resource attributes:
Service Attributes
service.name - Logical name of the service (required)
service.version - Version of the service
service.namespace - Namespace for service grouping
service.instance.id - Unique identifier for the service instance
Deployment Attributes
deployment.environment - Environment (production, staging, development)
deployment.name - Name of the deployment
Telemetry SDK Attributes
telemetry.sdk.name - Name of the SDK (automatically set)
telemetry.sdk.language - Language of the SDK (automatically set to “rust”)
telemetry.sdk.version - Version of the SDK (automatically set)
Example
use opentelemetry_sdk :: Resource ;
use opentelemetry :: KeyValue ;
let resource = Resource :: builder ()
. with_service_name ( "payment-service" )
. with_attributes ([
KeyValue :: new ( "service.version" , "2.1.0" ),
KeyValue :: new ( "service.namespace" , "ecommerce" ),
KeyValue :: new ( "deployment.environment" , "production" ),
KeyValue :: new ( "cloud.provider" , "aws" ),
KeyValue :: new ( "cloud.region" , "us-east-1" ),
])
. build ();
Complete Example
Here’s a complete example showing resource configuration:
use opentelemetry :: {global, KeyValue };
use opentelemetry_sdk :: {
Resource ,
trace :: SdkTracerProvider ,
};
fn main () {
// Create a resource with multiple sources
let resource = Resource :: builder ()
// Sets service.name
. with_service_name ( "my_service" )
// Add custom attributes
. with_attributes ([
KeyValue :: new ( "service.version" , env! ( "CARGO_PKG_VERSION" )),
KeyValue :: new ( "deployment.environment" , "production" ),
])
// Add custom detector
. with_detector ( Box :: new ( CustomDetector ))
. build ();
// Use the resource with a provider
let provider = SdkTracerProvider :: builder ()
. with_resource ( resource )
. with_simple_exporter ( exporter )
. build ();
global :: set_tracer_provider ( provider . clone ());
// All telemetry will include the resource attributes
let tracer = global :: tracer ( "my_component" );
tracer . in_span ( "operation" , | cx | {
// This span will have the resource attributes attached
});
provider . shutdown () . unwrap ();
}
Best Practices
Always set a service name : This is the most important resource attribute for identifying your service in observability backends.
Use environment variables in production : Configure resources via OTEL_SERVICE_NAME and OTEL_RESOURCE_ATTRIBUTES for flexibility.
Include version information : Add service.version to track which version of your service is running.
Leverage detectors : Use resource detectors to automatically capture environmental information instead of manually configuring it.
Next Steps
Context Propagation Learn how context flows across services
Signals Understand traces, metrics, and logs