Dash0 Raises $110M Series B at $1B Valuation

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.name and dash0.operation.type attributes 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.name on spans, logs, and metric data points before the data is sent to Dash0. The dash0.operation.type attribute 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.kind is 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.

TypePattern
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 TriggerCron ${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}
Backward compatibility

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.kind is SERVER, CONSUMER, or INTERNAL, the operation type is set to HEADLESS.
  • If span.kind is CLIENT or PRODUCER, dash0.operation.type is set to UNKNOWN and dash0.operation.name to Unknown 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.