Last updated: April 16, 2026
Operations
In Dash0, operations provide a structured way to categorize and analyze application behaviors across various APIs and services.
OpenTelemetry provides a broad set of semantic conventions for telemetry data, but it lacks a consistent and unified way to represent operations across different telemetry types. This inconsistency can lead to high-cardinality span names and fragmented observability data, making it difficult to analyze and troubleshoot issues effectively.
Dash0 fills this gap through the concept of an operation. Whether dealing with HTTP requests, messaging systems, databases, or cloud services, Dash0 assigns each span a meaningful operation name and type. Operations help you detect performance issues, set alerts, and improve observability by reducing high-cardinality attributes like span names into more generalized, consistent values.
Key Takeaways
- Standardized categorization: Dash0 automatically assigns
dash0.operation.nameanddash0.operation.typeattributes to spans, logs, and metric data points through rules defined on the basis of OpenTelemetry semantic conventions. - Override support: You can override operation names by setting
dash0.operation.nameon spans, logs, and metric data points before the data is sent to Dash0. Thedash0.operation.typeattribute cannot currently be overridden. - Reduced cardinality: By grouping spans into meaningful operations, Dash0 avoids excessive cardinality that can make analysis more difficult.
- Cross-service consistency: The same operation names are assigned to telemetry with comparable attributes, ensuring consistency across your data.
How Operations Are Assigned
During telemetry ingestion, Dash0 automatically assigns operations following a structured set of rules. These attributes are added only if dash0.operation.name is not already present in the incoming telemetry, so you can override them when necessary.
If you specify dash0.operation.name, Dash0 will still calculate a value for dash0.operation.type. Unlike dash0.operation.name, any dash0.operation.type value you send will be ignored, as Dash0 requires it to be one of a fixed set of supported values.
The rules are split into three groups depending on span.kind and whether the span is a root span:
- Span categories based on OpenTelemetry conventions:
span.kindis SERVER or CONSUMER, and the span is not a root span. - Root spans (spans with no parent): Any root span, regardless of
span.kind. - Fallback: Where none of the rules above apply.
1. Span categories based on OpenTelemetry conventions
Spans are categorized using predefined rules, evaluated from top to bottom. The first matching rule determines the operation name. This categorization applies only to non-root spans of kind SERVER or CONSUMER.
Each rule defines a pattern that constructs dash0.operation.name from span attributes (e.g., ${http.request.method} ${http.route}). The pattern applies only if all required attributes are present.
| Type | Pattern |
|---|---|
| GraphQL | ${graphql.operation.type} ${graphql.operation.name} |
| Object Storage (AWS S3) | ${rpc.method} ${aws.s3.bucket} |
| FaaS: Database Trigger | ${faas.document.collection} ${faas.document.operation} ${faas.document.name} |
| FaaS: Timer Trigger | Cron ${faas.cron} |
| FaaS: FaaS Name | ${faas.name} |
| Databases: AWS DynamoDB | ${rpc.method} ${aws.dynamodb.table_names} |
| Database: Namespace and Query | ${db.namespace} ${db.query.text} |
| Database: Query | ${db.query.text} |
| Database: Namespace, Operation, and Collection | ${db.namespace} ${db.operation.name} ${db.collection.name} |
| Database: Operation and Collection | ${db.operation.name} ${db.collection.name} |
| Messaging: Operation Type, Operation Name, and Destination | ${messaging.operation.type} ${messaging.operation.name | messaging.operation} ${messaging.destination.template | messaging.destination.name | messaging.destination_publish.name} |
| Messaging: Operation Type and Destination | ${messaging.operation.type} ${messaging.destination.template | messaging.destination.name | messaging.destination_publish.name} |
| Messaging: Operation and Destination | ${messaging.operation.name | messaging.operation} ${messaging.destination.template | messaging.destination.name | messaging.destination_publish.name} |
| Messaging: Type and Name | ${messaging.operation.type} ${messaging.operation.name | messaging.operation} |
| RPC: Service and Method | ${rpc.service} ${rpc.method} |
| RPC: System | ${rpc.system} |
| HTTP: Route | ${http.request.method | http.method} ${http.route} |
| HTTP: URL | ${http.request.method | http.method} ${url.path | http.target | http.url | url.full} |
Some patterns above include deprecated attribute names as fallbacks (e.g., http.method, messaging.operation). These fallbacks exist to ensure operation names are assigned correctly for instrumentation libraries that have not yet migrated to the stable OpenTelemetry HTTP and messaging semantic conventions introduced in v1.23.0. The current attribute name is always listed first and takes precedence when present.
2. Root spans (spans with no parent)
- If none of the rules above apply and
span.kindis SERVER, CONSUMER, or INTERNAL, the operation type is set to HEADLESS. - If
span.kindis CLIENT or PRODUCER,dash0.operation.typeis set to UNKNOWN anddash0.operation.nametoUnknown operation, because these outgoing operations lack the parent context that would explain what triggered them.
3. Fallback
If none of the rules above apply, the span name or metric name itself is used as dash0.operation.name.
FAQs
Can I override operation names?
Yes. If an incoming span already has dash0.operation.name, Dash0 will not override it, allowing you to define your own naming scheme when necessary.
Can I override operation types?
Operation types are determined automatically and cannot be overridden. This keeps them aligned with OpenTelemetry conventions and ensures consistency across your data.
Why does my operation have the type Unknown?
An Unknown operation occurs when a root span has span.kind CLIENT or PRODUCER. These span kinds cannot represent an API invoked on the system; instead, they indicate the trace is malformed and missing the parent span that should describe what API was actually called. This typically happens with scheduled tasks or background workers that lack proper instrumentation, or when trace context propagation fails between services.