Last updated: April 16, 2026
Understand Resource Equality
In practice, the same application or infrastructure component often emits telemetry from multiple sources: an OpenTelemetry SDK inside a container, a log agent on the host, a metrics exporter like kube-state-metrics. Each source describes the same logical resource, but with different sets of resource attributes.
Why Resource Equality Matters
Without intervention, an observability backend treats each unique attribute dictionary as a separate resource. The result is resource fragmentation: your pod's spans appear on one resource, its logs on another, and its metrics on a third. You lose the unified view you need to troubleshoot effectively.
Resource equality is Dash0's solution to this problem. It is not a built-in OpenTelemetry mechanism. It's a set of 30+ rules Dash0 applies at ingestion time to determine when different attribute dictionaries describe the same logical resource, so their telemetry can be correlated automatically.
A Quick Example: Amazon EKS Pod Logs
When using Fluent Bit or Fluentd to collect Amazon EKS pod logs, the log agent accesses the host's /var/log/pods/<namespace>_<pod_name>_<pod_id>/<container_name>/ path. Without special configuration, it can only set:
k8s.namespace.namek8s.pod.namek8s.pod.uidcontainer.name
Meanwhile, the OpenTelemetry SDK inside the same pod reports a much richer set of attributes: service name, deployment metadata, node information, and more. Despite describing the same pod, these two attribute sets would produce two separate resources without resource equality.
Dash0's Kubernetes workload equality rules recognize that both sources share k8s.pod.uid and merge them into a single coalesced resource.
For more scenarios like this, see Recognize common resource fragmentation scenarios.
How the Rules Work
Resource equality uses a hierarchy of rules, evaluated in order of precedence:
- SemConv-based equalities: Technology-specific rules using subsets of resource attributes based on OpenTelemetry semantic conventions
- Identity: Exact attribute dictionary match (same keys, same typed values)
When two resources are matched by any rule, Dash0 merges them into a single coalesced resource. The system adds several attributes to track the equality process:
dash0.resource.id: The unique identifier for the coalesced resource, computed from the matching equality ruledash0.resource.name: Human-readable name derived from resource attributesdash0.resource.type: Resource type classification (e.g.,k8s.pod,aws.lambda.function)
SemConv-based Equalities
Two resources are considered the same if the attribute subsets specified by the same rule match. Rules are evaluated in descending order of precedence: the first matching rule determines the resource identity (dash0.resource.id).
Kubernetes Workload Equality
For applications running in pods:
By Pod UID:
k8s.pod.uid(unique across clusters)
This is the highest-priority Kubernetes rule. When k8s.pod.uid is present, it uniquely identifies the pod regardless of other attributes.
By Pod Name + Workload UID:
k8s.pod.nameAND one of:k8s.namespace.uid,k8s.deployment.uid,k8s.daemonset.uid,k8s.replicaset.uid,k8s.statefulset.uid,k8s.cronjob.uid,k8s.job.uid
By Pod Name + Workload Name + Namespace:
k8s.pod.nameAND one of:k8s.deployment.name,k8s.daemonset.name,k8s.replicaset.name,k8s.statefulset.name,k8s.cronjob.name,k8s.job.nameANDk8s.namespace.name
Kubernetes Resource Equality
For aggregate metrics and events about Kubernetes resources (not pods):
Workload Schedulers:
k8s.daemonset.uidORk8s.deployment.uidORk8s.replicaset.uidORk8s.statefulset.uidORk8s.cronjob.uidORk8s.job.uid
Namespaces:
k8s.namespace.uidORk8s.namespace.name
Clusters:
k8s.cluster.uidORk8s.cluster.nameORaws.eks.cluster.arn
Kubernetes Node Equality
When k8s.node.name or k8s.node.id is set AND no pod/workload attributes are present:
By Node ID:
k8s.node.idORk8s.node.name
AWS Service Equality
AWS Lambda:
cloud.provider == "aws"+faas.instance(the unique invocation ID)
Each Lambda invocation is treated as a distinct resource. Use faas.name for the function name and cloud.region for the region in queries.
Amazon ECS:
- ECS tasks:
aws.ecs.task.arn(unique per task execution) - ECS clusters:
aws.ecs.cluster.arn
Amazon SQS:
cloud.provider == "aws"+messaging.destination.namewithmessaging.system == "aws_sqs"
Amazon SNS:
cloud.provider == "aws"+messaging.destination.namewithmessaging.system == "aws_sns"
AWS API Gateway:
cloud.provider == "aws"+faas.trigger == "http"+cloud.region+ API identifier fromurl.full(or legacyhttp.url) orfaas.name
These rules extract the API Gateway ID using regular expressions from URLs like https://<api-id>.execute-api.<region>.amazonaws.com/.
GCP Service Equality
Google Cloud Run:
cloud.provider == "gcp"+faas.instance(the unique instance ID)
Cloud Run instances are identified by their instance ID, with faas.name providing the service name and cloud.region the region.
Google Cloud Pub/Sub:
cloud.provider == "gcp"+messaging.destination.namewithmessaging.system == "gcp_pubsub"
Google Cloud Storage:
cloud.provider == "gcp"+gcp.gcs.bucket.name
Each GCS bucket is treated as a distinct resource.
Container Equality
For containers not running on Kubernetes (e.g., Docker Desktop):
By Container ID:
container.idORcontainer.name
Host Equality
By Host ID:
host.idORhost.name
Heroku Equality
By App and Dyno:
heroku.app.id+service.instance.id
Each Heroku dyno (identified by service.instance.id) within an app is a distinct resource.
CI/CD Pipeline Equality
By Pipeline Run:
cicd.pipeline.name+cicd.pipeline.run.id
Each pipeline execution is treated as a distinct resource.
Vercel Equality
When cloud.provider == "Vercel":
By Function and Region:
cloud.region+faas.name
Vercel serverless functions are identified by their name and deployment region.
Browser/RUM Equality
Special handling for web applications:
Real User Monitoring (RUM) telemetry from browser applications receives special treatment:
- When
telemetry.sdk.language == "webjs"orprocess.runtime.name == "browser", the resource is identified by the service triplet - Important: For browser resources, each unique combination of browser attributes creates a distinct resource
- This prevents browser sessions with different configurations (user agents, screen sizes, etc.) from being incorrectly merged
Service Equality
As a fallback, resources can be identified by the service triplet:
By Service Identity:
service.namespace+service.name+service.instance.id
To use service-based resource equality, set these environment variables:
12OTEL_SERVICE_NAME=my-serviceOTEL_RESOURCE_ATTRIBUTES="service.instance.id=instance-123"
Service equality has the lowest priority to avoid overriding more specific technology-based equalities.
Identity
Two resources are identical if their attribute dictionaries have equivalent sets of attribute keys (case-sensitive, order-insensitive) and, for each key, the associated values have the same type and are equivalent.
Coalesced Resources
When viewing resources in the Map or Resource pages, telemetry from multiple sources is correlated using the equality rules above. The result of merging equal resources is a coalesced resource.
Handling Attribute Conflicts
When merging resources, attribute conflicts are handled as follows:
| Scenario | Resource 1 | Resource 2 | Coalesced Result |
|---|---|---|---|
| Attribute missing in both | unset | unset | unset |
| Present only in first | value | unset | value |
| Present only in second | unset | value | value |
| Same value in both | value | value | value |
| Different values | value1 | value2 | value1 OR value2 |
When querying coalesced resources:
- Attribute existence: Matches if any underlying resource has the attribute
- Attribute value: Matches if any underlying resource has that specific value
For details, see Common Resource Attribute Conflict Issues.
Practical Examples
Finding resources that changed teams: Query for team = A AND team = B to find resources where the team attribute changed during the time range.
Multi-team ownership: A Kubernetes pod with a service mesh sidecar may have attributes from both the platform team (sidecar) and application team (main container). Both teams can find "their" resources using their respective attribute queries.
Querying Lambda functions by region: Use dash0.resource.type == "aws.lambda.function" AND cloud.region == "us-east-1" to find all Lambda invocations in a specific region.
Finding Cloud Run instances: Query dash0.resource.type == "gcp.cloud_run.service" AND faas.name == "my-service" to see all instances of a specific Cloud Run service.
Best Practices
- Use consistent resource attributes across all telemetry sources for the same logical resource
- Leverage resource detectors in OpenTelemetry SDKs to automatically populate standard attributes
- Configure log agents to include Kubernetes metadata when collecting pod logs
- Use the K8sAttributes processor in the OpenTelemetry Collector to enrich telemetry with Kubernetes metadata
- Set
service.instance.idexplicitly when service-based equality is needed - For cloud services, ensure
cloud.providerand service-specific attributes are set correctly - For AWS services, use the AWS resource detectors to automatically populate ARNs and IDs
- For GCP services, use the GCP resource detectors to populate project, region, and service information