or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

attributes.mdbridges.mdcontext-propagation.mdexporters-other.mdexporters-otlp.mdindex.mdlogging.mdmetrics.mdsdk-log.mdsdk-metric.mdsdk-resource.mdsdk-trace.mdsemantic-conventions.mdtracing.md
tile.json

sdk-resource.mddocs/

SDK Resource Detection

The OpenTelemetry Go SDK resource package provides functionality for detecting and creating resources that describe the entity producing telemetry data.

Package Import

import "go.opentelemetry.io/otel/sdk/resource"

Overview

A Resource is an immutable set of attributes that describe the entity producing telemetry. Resources typically include information about the service, host, container, process, and runtime environment.

Resource Type

type Resource struct {
	// Has unexported fields
}

Creating Resources

// New creates a Resource from detectors and options
func New(ctx context.Context, opts ...Option) (*Resource, error)

// NewWithAttributes creates a Resource from attributes and associates it with a schema URL
func NewWithAttributes(schemaURL string, attrs ...attribute.KeyValue) *Resource

// NewSchemaless creates a Resource from attributes without a schema URL
func NewSchemaless(attrs ...attribute.KeyValue) *Resource

Example:

package main

import (
	"context"
	"log"

	"go.opentelemetry.io/otel/sdk/resource"
	semconv "go.opentelemetry.io/otel/semconv/v1.37.0"
)

func main() {
	ctx := context.Background()

	// Create resource with attributes
	res, err := resource.New(ctx,
		resource.WithAttributes(
			semconv.ServiceName("my-service"),
			semconv.ServiceVersion("1.0.0"),
			semconv.DeploymentEnvironment("production"),
		),
	)
	if err != nil {
		log.Fatal(err)
	}

	// Create resource with built-in detectors
	res, err = resource.New(ctx,
		resource.WithAttributes(
			semconv.ServiceName("my-service"),
		),
		resource.WithProcess(),
		resource.WithHost(),
		resource.WithOS(),
		resource.WithContainer(),
	)
	if err != nil {
		log.Fatal(err)
	}
}

Resource Methods

// Attributes returns a copy of attributes from the resource
func (r *Resource) Attributes() []attribute.KeyValue

// SchemaURL returns the schema URL associated with the Resource
func (r *Resource) SchemaURL() string

// Iter returns an iterator of the Resource attributes
func (r *Resource) Iter() attribute.Iterator

// Equal reports whether r and o represent the same resource
func (r *Resource) Equal(o *Resource) bool

// Equivalent returns an attribute.Distinct that uniquely identifies the Resource
func (r *Resource) Equivalent() attribute.Distinct

// MarshalLog returns logging data about the Resource
func (r *Resource) MarshalLog() any

// String returns a human-readable form of the resource
func (r *Resource) String() string

Resource Options

Options for creating resources.

type Option interface {
	// Has unexported methods
}

WithAttributes

Add attributes to the resource.

func WithAttributes(attributes ...attribute.KeyValue) Option

Example:

res, err := resource.New(ctx,
	resource.WithAttributes(
		semconv.ServiceName("my-service"),
		semconv.ServiceVersion("1.0.0"),
		semconv.ServiceInstanceID("instance-1"),
		semconv.DeploymentEnvironment("production"),
	),
)

WithSchemaURL

Associate a schema URL with the resource.

func WithSchemaURL(schemaURL string) Option

Example:

res, err := resource.New(ctx,
	resource.WithSchemaURL(semconv.SchemaURL),
	resource.WithAttributes(/*...*/),
)

Built-in Detectors

The SDK provides several built-in resource detectors.

WithProcess

Detect process information (PID, executable name, command, owner, runtime).

func WithProcess() Option

Detected Attributes:

  • process.pid
  • process.executable.name
  • process.executable.path
  • process.command_args
  • process.owner
  • process.runtime.name
  • process.runtime.version
  • process.runtime.description

Example:

res, err := resource.New(ctx,
	resource.WithProcess(),
)

WithHost

Detect host information (hostname, ID, name, type, architecture).

func WithHost() Option

Detected Attributes:

  • host.name
  • host.id
  • host.arch
  • host.type

Example:

res, err := resource.New(ctx,
	resource.WithHost(),
)

WithOS

Detect operating system information (type, description).

func WithOS() Option

Detected Attributes:

  • os.type
  • os.description
  • os.name
  • os.version

Example:

res, err := resource.New(ctx,
	resource.WithOS(),
)

WithContainer

Detect container information (ID, name, image).

func WithContainer() Option

Detected Attributes:

  • container.id
  • container.name
  • container.image.name
  • container.image.tag

Example:

res, err := resource.New(ctx,
	resource.WithContainer(),
)

WithFromEnv

Detect resource attributes from environment variables.

func WithFromEnv() Option

Reads attributes from OTEL_RESOURCE_ATTRIBUTES environment variable.

Example:

export OTEL_RESOURCE_ATTRIBUTES="key1=value1,key2=value2"
res, err := resource.New(ctx,
	resource.WithFromEnv(),
)

WithDetectors

Use custom detectors.

func WithDetectors(d ...Detector) Option

Example:

// Custom detector
type customDetector struct{}

func (d customDetector) Detect(ctx context.Context) (*resource.Resource, error) {
	return resource.NewSchemaless(
		attribute.String("custom.key", "custom.value"),
	), nil
}

res, err := resource.New(ctx,
	resource.WithDetectors(customDetector{}),
)

Individual Attribute Detectors

For fine-grained control, you can use individual attribute detectors instead of the composite ones.

Process Attribute Detectors

// WithProcessPID adds the process identifier (PID)
func WithProcessPID() Option

// WithProcessExecutableName adds the process executable name
func WithProcessExecutableName() Option

// WithProcessExecutablePath adds the full path to the process executable
func WithProcessExecutablePath() Option

// WithProcessCommandArgs adds all command arguments (including the executable)
// Warning: May contain sensitive information
func WithProcessCommandArgs() Option

// WithProcessOwner adds the username of the user that owns the process
func WithProcessOwner() Option

// WithProcessRuntimeName adds the name of the runtime (e.g., "go")
func WithProcessRuntimeName() Option

// WithProcessRuntimeVersion adds the version of the runtime
func WithProcessRuntimeVersion() Option

// WithProcessRuntimeDescription adds additional runtime description
func WithProcessRuntimeDescription() Option

Example:

// Add only specific process attributes
res, err := resource.New(ctx,
	resource.WithProcessPID(),
	resource.WithProcessExecutableName(),
	resource.WithProcessRuntimeName(),
	resource.WithProcessRuntimeVersion(),
)

Host Attribute Detectors

// WithHostID adds host ID information
func WithHostID() Option

Example:

res, err := resource.New(ctx,
	resource.WithHostID(),
	resource.WithAttributes(
		semconv.HostName("my-host"),
	),
)

OS Attribute Detectors

// WithOSType adds the operating system type (e.g., "linux", "darwin", "windows")
func WithOSType() Option

// WithOSDescription adds the operating system description
// Equivalent to the output of `uname -snrvm`
func WithOSDescription() Option

Example:

res, err := resource.New(ctx,
	resource.WithOSType(),
	resource.WithOSDescription(),
)

Container Attribute Detectors

// WithContainerID adds the container ID
// Note: Will not extract correct container ID in ECS environments
// Use the ECS resource detector instead for ECS
func WithContainerID() Option

Example:

res, err := resource.New(ctx,
	resource.WithContainerID(),
)

Utility Detectors

// StringDetector creates a custom detector for a single string attribute
func StringDetector(schemaURL string, k attribute.Key, f func() (string, error)) Detector

Example:

// Create a custom detector for a deployment ID
deploymentDetector := resource.StringDetector(
	semconv.SchemaURL,
	semconv.DeploymentEnvironmentKey,
	func() (string, error) {
		// Read from environment or configuration
		return os.Getenv("DEPLOYMENT_ENV"), nil
	},
)

res, err := resource.New(ctx,
	resource.WithDetectors(deploymentDetector),
)

Detector Interface

Custom detectors implement the Detector interface.

type Detector interface {
	// Detect returns a Resource describing the detected entity
	Detect(ctx context.Context) (*Resource, error)
}

Example:

type cloudProviderDetector struct{}

func (d cloudProviderDetector) Detect(ctx context.Context) (*resource.Resource, error) {
	// Detect cloud provider metadata
	provider := detectCloudProvider()
	if provider == "" {
		return resource.Empty(), nil
	}

	return resource.NewSchemaless(
		semconv.CloudProvider(provider),
		semconv.CloudAccountID("123456"),
		semconv.CloudRegion("us-east-1"),
	), nil
}

func detectCloudProvider() string {
	// Detection logic
	return "aws"
}

Default Resource

Get the default resource.

// Default returns the default resource
func Default() *Resource

// Empty returns an empty resource
func Empty() *Resource

Example:

// Get default resource (includes service.name from OTEL_SERVICE_NAME)
res := resource.Default()

// Get empty resource
res := resource.Empty()

Merging Resources

Merge multiple resources together.

// Merge creates a new Resource by merging a and b
func Merge(a, b *Resource) (*Resource, error)

Merge Rules:

  • If there are common keys, the value from b overwrites the value from a
  • Schema URLs are merged according to OpenTelemetry specification rules
  • Returns error containing ErrSchemaURLConflict if schema URLs conflict

Example:

// Create base resource
base, _ := resource.New(ctx,
	resource.WithAttributes(
		semconv.ServiceName("my-service"),
		semconv.ServiceVersion("1.0.0"),
	),
)

// Create additional resource
additional, _ := resource.New(ctx,
	resource.WithAttributes(
		semconv.DeploymentEnvironment("production"),
		semconv.ServiceInstanceID("instance-1"),
	),
)

// Merge resources
merged, err := resource.Merge(base, additional)
if err != nil {
	log.Printf("Error merging resources: %v", err)
}

Environment Variables

The SDK respects the following environment variables:

# Service name
OTEL_SERVICE_NAME=my-service

# Resource attributes as comma-separated key=value pairs
OTEL_RESOURCE_ATTRIBUTES=deployment.environment=production,service.version=1.0.0

Complete Example

Full Resource Setup

package main

import (
	"context"
	"log"

	"go.opentelemetry.io/otel"
	"go.opentelemetry.io/otel/attribute"
	"go.opentelemetry.io/otel/sdk/resource"
	semconv "go.opentelemetry.io/otel/semconv/v1.37.0"
)

func createResource(ctx context.Context) (*resource.Resource, error) {
	// Create resource with all recommended detectors
	return resource.New(ctx,
		// Static attributes
		resource.WithAttributes(
			semconv.ServiceName("my-service"),
			semconv.ServiceVersion("1.0.0"),
			semconv.DeploymentEnvironment("production"),
		),
		// Built-in detectors
		resource.WithProcess(),      // Process information
		resource.WithHost(),          // Host information
		resource.WithOS(),            // OS information
		resource.WithContainer(),     // Container information (if running in container)
		resource.WithFromEnv(),       // From OTEL_RESOURCE_ATTRIBUTES
		// Custom detector
		resource.WithDetectors(&customDetector{}),
	)
}

type customDetector struct{}

func (d *customDetector) Detect(ctx context.Context) (*resource.Resource, error) {
	// Detect custom attributes
	return resource.NewSchemaless(
		attribute.String("custom.region", "us-east-1"),
		attribute.String("custom.availability_zone", "us-east-1a"),
	), nil
}

func main() {
	ctx := context.Background()

	// Create resource
	res, err := createResource(ctx)
	if err != nil {
		log.Fatalf("Failed to create resource: %v", err)
	}

	// Log resource attributes
	log.Println("Resource attributes:")
	iter := res.Iter()
	for iter.Next() {
		attr := iter.Attribute()
		log.Printf("  %s: %v", attr.Key, attr.Value.AsInterface())
	}

	// Use resource with tracer provider
	// tp := sdktrace.NewTracerProvider(
	// 	sdktrace.WithResource(res),
	// )
	// otel.SetTracerProvider(tp)
}

Kubernetes Resource Detection

import (
	"context"
	"os"
	"go.opentelemetry.io/otel/sdk/resource"
	semconv "go.opentelemetry.io/otel/semconv/v1.37.0"
)

type k8sDetector struct{}

func (d k8sDetector) Detect(ctx context.Context) (*resource.Resource, error) {
	// Detect Kubernetes attributes from environment
	var attrs []attribute.KeyValue

	if podName := os.Getenv("K8S_POD_NAME"); podName != "" {
		attrs = append(attrs, semconv.K8SPodName(podName))
	}

	if namespace := os.Getenv("K8S_NAMESPACE_NAME"); namespace != "" {
		attrs = append(attrs, semconv.K8SNamespaceName(namespace))
	}

	if nodeName := os.Getenv("K8S_NODE_NAME"); nodeName != "" {
		attrs = append(attrs, semconv.K8SNodeName(nodeName))
	}

	if deployment := os.Getenv("K8S_DEPLOYMENT_NAME"); deployment != "" {
		attrs = append(attrs, semconv.K8SDeploymentName(deployment))
	}

	if len(attrs) == 0 {
		return resource.Empty(), nil
	}

	return resource.NewSchemaless(attrs...), nil
}

func createK8sResource(ctx context.Context) (*resource.Resource, error) {
	return resource.New(ctx,
		resource.WithAttributes(
			semconv.ServiceName("my-service"),
		),
		resource.WithDetectors(k8sDetector{}),
		resource.WithHost(),
		resource.WithProcess(),
	)
}

Best Practices

1. Always Set Service Name

// Good: Always set service name
res, err := resource.New(ctx,
	resource.WithAttributes(
		semconv.ServiceName("my-service"),
		semconv.ServiceVersion("1.0.0"),
	),
)

// Bad: Missing service name
res, err := resource.New(ctx) // Will use default

2. Use Built-in Detectors

// Good: Use built-in detectors for common attributes
res, err := resource.New(ctx,
	resource.WithAttributes(semconv.ServiceName("my-service")),
	resource.WithProcess(),
	resource.WithHost(),
	resource.WithOS(),
)

3. Handle Detection Errors

res, err := resource.New(ctx,
	resource.WithAttributes(/*...*/),
	resource.WithProcess(),
)
if err != nil {
	// Log error but continue with partial resource
	log.Printf("Failed to detect some resource attributes: %v", err)
}
// res may be partial but still usable

4. Use Environment Variables for Configuration

# Set via environment for flexibility
export OTEL_SERVICE_NAME=my-service
export OTEL_RESOURCE_ATTRIBUTES=deployment.environment=prod,k8s.cluster.name=production
res, err := resource.New(ctx,
	resource.WithFromEnv(),
	resource.WithProcess(),
)

Related Documentation

  • SDK Trace: Using resources with TracerProvider
  • SDK Metric: Using resources with MeterProvider
  • SDK Log: Using resources with LoggerProvider
  • Semantic Conventions: Standard resource attributes