CtrlK
BlogDocsLog inGet started
Tessl Logo

dash0/agent-skills

Expert guidance for configuring and deploying the OpenTelemetry Collector. Use when setting up a Collector pipeline, configuring receivers, exporters, or processors, deploying a Collector to Kubernetes or Docker, or forwarding telemetry to Dash0. Triggers on requests involving collector, pipeline, OTLP receiver, exporter, or Dash0 collector setup.

100

Quality

100%

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Advisory

Suggest reviewing before use

Overview
Quality
Evals
Security
Files

resources.mdskills/otel-instrumentation/rules/

title:
Resource attributes
impact:
CRITICAL
tags:
resources, service-name, service-version, environment

Resource attributes

Resource attributes identify what system is described by the telemetry, which very often is also the system producing the telemetry (but not always, like in case of network monitoring). They are stable for the lifetime of the process and are attached to every signal (traces, metrics, and logs) automatically. Getting them right is the single highest-impact thing you can do for observability — without them, telemetry cannot be attributed to a service, environment, or instance.

For guidance on where to place attributes across telemetry levels, see attributes.

Required attributes

service.name

Every service must set service.name. Without it, all telemetry falls into unknown_service, making it impossible to attribute to a service in dashboards, alerts, or service maps.

Set it via the OTEL_SERVICE_NAME environment variable:

export OTEL_SERVICE_NAME="order-api"

[!NOTE] The value of service.name is the same in every environment and instance — set it in application code, a shared .env file, or a deployment descriptor.

Choose a name that is:

  • Stable — does not change across deployments or restarts.
  • Unique per logical service — two different services must not share the same name.
  • Human-readable — descriptive enough to identify the service at a glance (e.g., checkout-service, not svc-42).
  • Case-consistent — use the exact same case-sensitive string across all deployments and environments. Variations like checkout vs CheckOut in different environments complicate querying, especially during outages.

Pick a naming convention (kebab-case, snake_case, or camelCase) and apply it consistently across the entire service fleet.

Recommended attributes

service.namespace

Groups related services within the same application or product. Use it to scope services that belong together — for example, a checkout, payment, and inventory service might all share the namespace acme-webstore.

export OTEL_RESOURCE_ATTRIBUTES="service.namespace=acme-webstore"

Without a namespace, identically named services across different products become ambiguous.

[!NOTE] The value of service.namespace is the same in every environment and instance — set it in application code or a shared .env file, like service.name.

deployment.environment.name

Distinguish production from staging, development, and other environments. Without it, production and test telemetry are mixed together, making dashboards and alerts unreliable.

export OTEL_RESOURCE_ATTRIBUTES="deployment.environment.name=production"

[!NOTE] The value of deployment.environment.name changes per environment — inject it from the deployment pipeline (e.g., Helm values, CI/CD variable), not from application code.

See resolving configuration values for ordered lookup strategies.

service.version

Set the service version to enable deployment tracking, regression detection, and version-aware analysis. This attribute is invaluable during rollouts to compare how the new version and the old one behave.

export OTEL_RESOURCE_ATTRIBUTES="service.version=1.4.2"

[!NOTE] The value of service.version changes per release — derive it from the build pipeline (e.g., git tag, CI build number), never hardcode it in application code.

See resolving configuration values for ordered lookup strategies to find the version value.

service.instance.id

Uniquely identifies a single instance of the service. The triplet (service.namespace, service.name, service.instance.id) must be globally unique. Without it, instance-level analysis (e.g., identifying a single unhealthy pod) is not possible.

[!NOTE] The value of service.instance.id changes per instance — generate it at startup (e.g., UUID v4) or inject it from the deployment platform (e.g., Kubernetes downward API), never hardcode it in application code.

It must be stable for the lifetime of the process and should be an opaque identifier — do not expose infrastructure details like pod names or container IDs directly. See resolving configuration values for generation strategies (UUID v4, UUID v5, and common pitfalls).

Setting service.instance.id does not replace the need to also set k8s.pod.uid in Kubernetes. Both attributes serve different purposes: service.instance.id is a logical, opaque identifier, while k8s.pod.uid is used by the k8sattributes processor for Kubernetes metadata enrichment.

Kubernetes attributes

k8s.* attributes describe the infrastructure running the service, not the service itself.

[!NOTE] Set k8s.* attributes via the Kubernetes downward API in pod specs or let the k8sattributes Collector processor resolve them automatically — never set them in application code.

Follow the guidance issued in Kubernetes deployment. For configuring the k8sattributes processor in the Collector, see the processors rule in the otel-collector skill.

Setting resource attributes

Resource attributes are set via the OTEL_RESOURCE_ATTRIBUTES environment variable as a comma-separated list of key=value pairs.

export OTEL_RESOURCE_ATTRIBUTES="service.version=1.4.2,deployment.environment.name=production,service.instance.id=$(uuidgen)"

Combine this with OTEL_SERVICE_NAME (which takes precedence over service.name in OTEL_RESOURCE_ATTRIBUTES):

export OTEL_SERVICE_NAME="order-api"
export OTEL_RESOURCE_ATTRIBUTES="service.version=1.4.2,deployment.environment.name=production"

Complete .env.local example

This example is suitable for local development. Application-identity attributes are set directly; deployment-context attributes use placeholder values that the deployment pipeline would replace in production.

# Application-identity attributes (same in every environment)
OTEL_SERVICE_NAME=order-api
OTEL_RESOURCE_ATTRIBUTES=service.namespace=acme-webstore,service.version=local-dev,deployment.environment.name=development

# Exporter configuration
OTEL_TRACES_EXPORTER=otlp
OTEL_METRICS_EXPORTER=otlp
OTEL_LOGS_EXPORTER=otlp
OTEL_EXPORTER_OTLP_ENDPOINT=https://<OTLP_ENDPOINT>
OTEL_EXPORTER_OTLP_HEADERS=Authorization=Bearer YOUR_AUTH_TOKEN
NODE_OPTIONS=--import @opentelemetry/auto-instrumentations-node/register

In a production deployment descriptor (e.g., Kubernetes manifest, Docker Compose, or CI/CD pipeline), override service.version and deployment.environment.name with values derived from the build and deployment pipeline.

Anti-patterns

  • Missing service.name. Telemetry appears as unknown_service and cannot be attributed in service maps, dashboards, or alerts.
  • Inconsistent service.name casing across environments. Variations like checkout vs Checkout create duplicate entries in service maps and break cross-environment queries.
  • Same service.instance.id across multiple pods. Instance-level queries return aggregated data from all pods instead of a single instance.
  • Hardcoded service.version. Falls out of sync after the first deployment. Derive it from the build pipeline, git tags, or commit SHAs.
  • Missing deployment.environment.name. Production and staging telemetry are mixed, making dashboards and alerts unreliable.

References

  • service.instance.id semantic conventions
  • Resource semantic conventions
  • OTel SDK configuration
  • Service attributes best practices
  • Attribute placement guidance
  • Kubernetes deployment

skills

README.md

tile.json