> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/open-telemetry/opentelemetry-rust/llms.txt
> Use this file to discover all available pages before exploring further.

# Resources

> Learn how to identify and describe your services using OpenTelemetry resources, including automatic detection and manual configuration.

## 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:

```rust theme={null}
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:

```rust theme={null}
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:

1. **SdkProvidedResourceDetector** - Provides required SDK attributes
2. **TelemetryResourceDetector** - Adds telemetry SDK information
3. **EnvResourceDetector** - Reads from environment variables

```rust theme={null}
use opentelemetry_sdk::Resource;

// This includes default detectors
let resource = Resource::builder().build();
```

### Environment Variables

The `EnvResourceDetector` reads from standard OpenTelemetry environment variables:

```bash theme={null}
# Set service name
export OTEL_SERVICE_NAME="my_service"

# Set additional attributes
export OTEL_RESOURCE_ATTRIBUTES="deployment.environment=production,service.version=1.0.0"
```

```rust theme={null}
use opentelemetry_sdk::Resource;

// Automatically picks up environment variables
let resource = Resource::builder().build();
```

<Note>
  The `OTEL_SERVICE_NAME` environment variable takes priority over `service.name` in `OTEL_RESOURCE_ATTRIBUTES`.
</Note>

### Custom Detectors

You can implement custom resource detectors:

```rust theme={null}
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`](https://github.com/open-telemetry/opentelemetry-rust-contrib/tree/main/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:

1. `OTEL_SERVICE_NAME` environment variable
2. `service.name` in `OTEL_RESOURCE_ATTRIBUTES`
3. `unknown_service:<executable_name>` (fallback)

```rust theme={null}
// 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"
```

<Tip>
  Always set a meaningful service name to identify your service in observability backends.
</Tip>

## Using Resources

### With Tracer Provider

```rust theme={null}
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

```rust theme={null}
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

```rust theme={null}
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:

```rust theme={null}
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" }
```

<Warning>
  When merging, attributes from the second resource (parameter) override those from the first resource (caller).
</Warning>

## Schema URL

Resources can have an associated schema URL that defines the semantic conventions being used:

```rust theme={null}
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:

1. If both have the **same** schema URL, it's preserved
2. If both have **different** schema URLs, the result has no schema URL
3. If one has a schema URL and the other doesn't, the existing schema URL is used

```rust theme={null}
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

```rust theme={null}
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

```rust theme={null}
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:

```rust theme={null}
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

<Tip>
  **Always set a service name**: This is the most important resource attribute for identifying your service in observability backends.
</Tip>

<Tip>
  **Use environment variables in production**: Configure resources via `OTEL_SERVICE_NAME` and `OTEL_RESOURCE_ATTRIBUTES` for flexibility.
</Tip>

<Tip>
  **Include version information**: Add `service.version` to track which version of your service is running.
</Tip>

<Tip>
  **Leverage detectors**: Use resource detectors to automatically capture environmental information instead of manually configuring it.
</Tip>

## Next Steps

<CardGroup cols={2}>
  <Card title="Context Propagation" icon="arrows-rotate" href="/concepts/context-propagation">
    Learn how context flows across services
  </Card>

  <Card title="Signals" icon="signal" href="/concepts/signals">
    Understand traces, metrics, and logs
  </Card>
</CardGroup>
