OpenTelemetry Go implementation providing APIs for distributed tracing, metrics, and logging to instrument applications and send telemetry data to observability platforms
The OpenTelemetry Go SDK resource package provides functionality for detecting and creating resources that describe the entity producing telemetry data.
import "go.opentelemetry.io/otel/sdk/resource"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.
type Resource struct {
// Has unexported fields
}// 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) *ResourceExample:
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)
}
}// 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() stringOptions for creating resources.
type Option interface {
// Has unexported methods
}Add attributes to the resource.
func WithAttributes(attributes ...attribute.KeyValue) OptionExample:
res, err := resource.New(ctx,
resource.WithAttributes(
semconv.ServiceName("my-service"),
semconv.ServiceVersion("1.0.0"),
semconv.ServiceInstanceID("instance-1"),
semconv.DeploymentEnvironment("production"),
),
)Associate a schema URL with the resource.
func WithSchemaURL(schemaURL string) OptionExample:
res, err := resource.New(ctx,
resource.WithSchemaURL(semconv.SchemaURL),
resource.WithAttributes(/*...*/),
)The SDK provides several built-in resource detectors.
Detect process information (PID, executable name, command, owner, runtime).
func WithProcess() OptionDetected Attributes:
process.pidprocess.executable.nameprocess.executable.pathprocess.command_argsprocess.ownerprocess.runtime.nameprocess.runtime.versionprocess.runtime.descriptionExample:
res, err := resource.New(ctx,
resource.WithProcess(),
)Detect host information (hostname, ID, name, type, architecture).
func WithHost() OptionDetected Attributes:
host.namehost.idhost.archhost.typeExample:
res, err := resource.New(ctx,
resource.WithHost(),
)Detect operating system information (type, description).
func WithOS() OptionDetected Attributes:
os.typeos.descriptionos.nameos.versionExample:
res, err := resource.New(ctx,
resource.WithOS(),
)Detect container information (ID, name, image).
func WithContainer() OptionDetected Attributes:
container.idcontainer.namecontainer.image.namecontainer.image.tagExample:
res, err := resource.New(ctx,
resource.WithContainer(),
)Detect resource attributes from environment variables.
func WithFromEnv() OptionReads attributes from OTEL_RESOURCE_ATTRIBUTES environment variable.
Example:
export OTEL_RESOURCE_ATTRIBUTES="key1=value1,key2=value2"res, err := resource.New(ctx,
resource.WithFromEnv(),
)Use custom detectors.
func WithDetectors(d ...Detector) OptionExample:
// 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{}),
)For fine-grained control, you can use individual attribute detectors instead of the composite ones.
// 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() OptionExample:
// Add only specific process attributes
res, err := resource.New(ctx,
resource.WithProcessPID(),
resource.WithProcessExecutableName(),
resource.WithProcessRuntimeName(),
resource.WithProcessRuntimeVersion(),
)// WithHostID adds host ID information
func WithHostID() OptionExample:
res, err := resource.New(ctx,
resource.WithHostID(),
resource.WithAttributes(
semconv.HostName("my-host"),
),
)// 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() OptionExample:
res, err := resource.New(ctx,
resource.WithOSType(),
resource.WithOSDescription(),
)// 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() OptionExample:
res, err := resource.New(ctx,
resource.WithContainerID(),
)// StringDetector creates a custom detector for a single string attribute
func StringDetector(schemaURL string, k attribute.Key, f func() (string, error)) DetectorExample:
// 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),
)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"
}Get the default resource.
// Default returns the default resource
func Default() *Resource
// Empty returns an empty resource
func Empty() *ResourceExample:
// Get default resource (includes service.name from OTEL_SERVICE_NAME)
res := resource.Default()
// Get empty resource
res := resource.Empty()Merge multiple resources together.
// Merge creates a new Resource by merging a and b
func Merge(a, b *Resource) (*Resource, error)Merge Rules:
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)
}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.0package 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)
}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(),
)
}// 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// 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(),
)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# Set via environment for flexibility
export OTEL_SERVICE_NAME=my-service
export OTEL_RESOURCE_ATTRIBUTES=deployment.environment=prod,k8s.cluster.name=productionres, err := resource.New(ctx,
resource.WithFromEnv(),
resource.WithProcess(),
)Install with Tessl CLI
npx tessl i tessl/golang-go-opentelemetry-io--otel