diff --git a/CHANGELOG.md b/CHANGELOG.md index a4f9c5425ed..807c3671b4e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -133,6 +133,28 @@ release. - Rename `http.retry_count` to `http.resend_count` and clarify its meaning. ([#2743](/~https://github.com/open-telemetry/opentelemetry-specification/pull/2743)) +- BREAKING: rename `messaging.consumer_id` to `messaging.consumer.id`, + `messaging.destination` to `messaging.destination.name`, + `messaging.temp_destination` to `messaging.destination.temporary`, + `messaging.destination_kind` to `messaging.destination.kind`, + `messaging.message_id` to `messaging.message.id`, + `messaging.protocol` to `net.app.protocol.name`, + `messaging.protocol_version`, `net.app.protocol.version`, + `messaging.conversation_id` to `messaging.message.conversation_id`, + `messaging.message_payload_size_bytes` to `messaging.message.payload_size_bytes`, + `messaging.message_payload_compressed_size_bytes` to `messaging.message.payload_compressed_size_bytes`, + `messaging.rabbitmq.routing_key`: `messaging.rabbitmq.destination.routing_key`, + `messaging.kafka.message_key` to `messaging.kafka.message.key`, + `messaging.kafka.consumer_group` to `messaging.kafka.consumer.group`, + `messaging.kafka.partition` to `messaging.kafka.destination.partition`, + `messaging.kafka.tombstone` to `messaging.kafka.message.tombstone`, + `messaging.rocketmq.message_type` to `messaging.rocketmq.message.type`, + `messaging.rocketmq.message_tag` to `messaging.rocketmq.message.tag`, + `messaging.rocketmq.message_keys` to `messaging.rocketmq.message.keys`; + Removed `messaging.url`; + Renamed `send` operation to `publish`; + Split `destination` and `source` namespaces and clarify per-message attributes in batching scenarios. + ([#2763](/~https://github.com/open-telemetry/opentelemetry-specification/pull/2763)). ### Metrics diff --git a/schemas/1.17.0 b/schemas/1.17.0 new file mode 100644 index 00000000000..46e3180f912 --- /dev/null +++ b/schemas/1.17.0 @@ -0,0 +1,59 @@ +file_format: 1.1.0 +schema_url: https://opentelemetry.io/schemas/1.17.0 +versions: + 1.17.0: + spans: + changes: + # /~https://github.com/open-telemetry/opentelemetry-specification/pull/2763 + - rename_attributes: + attribute_map: + messaging.consumer_id: messaging.consumer.id + messaging.protocol: net.app.protocol.name + messaging.protocol_version: net.app.protocol.version + messaging.destination: messaging.destination.name + messaging.temp_destination: messaging.destination.temporary + messaging.destination_kind: messaging.destination.kind + messaging.message_id: messaging.message.id + messaging.conversation_id: messaging.message.conversation_id + messaging.message_payload_size_bytes: messaging.message.payload_size_bytes + messaging.message_payload_compressed_size_bytes: messaging.message.payload_compressed_size_bytes + messaging.rabbitmq.routing_key: messaging.rabbitmq.destination.routing_key + messaging.kafka.message_key: messaging.kafka.message.key + messaging.kafka.partition: messaging.kafka.destination.partition + messaging.kafka.tombstone: messaging.kafka.message.tombstone + messaging.rocketmq.message_type: messaging.rocketmq.message.type + messaging.rocketmq.message_tag: messaging.rocketmq.message.tag + messaging.rocketmq.message_keys: messaging.rocketmq.message.keys + messaging.kafka.consumer_group: messaging.kafka.consumer.group + 1.16.0: + 1.15.0: + spans: + changes: + # /~https://github.com/open-telemetry/opentelemetry-specification/pull/2743 + - rename_attributes: + attribute_map: + http.retry_count: http.resend_count + 1.14.0: + 1.13.0: + spans: + changes: + # /~https://github.com/open-telemetry/opentelemetry-specification/pull/2614 + - rename_attributes: + attribute_map: + net.peer.ip: net.sock.peer.addr + net.host.ip: net.sock.host.addr + 1.12.0: + 1.11.0: + 1.10.0: + 1.9.0: + 1.8.0: + spans: + changes: + - rename_attributes: + attribute_map: + db.cassandra.keyspace: db.name + db.hbase.namespace: db.name + 1.7.0: + 1.6.1: + 1.5.0: + 1.4.0: diff --git a/semantic_conventions/trace/messaging.yaml b/semantic_conventions/trace/messaging.yaml index ff917a05091..83b049f4561 100644 --- a/semantic_conventions/trace/messaging.yaml +++ b/semantic_conventions/trace/messaging.yaml @@ -1,24 +1,47 @@ groups: - - id: messaging + - id: messaging.message prefix: messaging + # todo (/~https://github.com/open-telemetry/build-tools/issues/123) type: span - brief: > - This document defines the attributes used in - messaging systems. + brief: 'Semantic convention describing per-message attributes populated on messaging spans or links.' attributes: - - id: system + - ref: messaging.destination.name + - ref: messaging.source.name + - id: message.id type: string - requirement_level: required - brief: 'A string identifying the messaging system.' - examples: ['kafka', 'rabbitmq', 'rocketmq', 'activemq', 'AmazonSQS'] - - id: destination + brief: 'A value used by the messaging system as an identifier for the message, represented as a string.' + examples: '452a7c7c7c7048c2f887f61572b18fc2' + - id: message.conversation_id type: string - requirement_level: required brief: > - The message destination name. This might be equal to the span name - but is required nevertheless. + The [conversation ID](#conversations) identifying the conversation to which the message belongs, + represented as a string. Sometimes called "Correlation ID". + examples: 'MyConversationId' + - id: message.payload_size_bytes + type: int + brief: > + The (uncompressed) size of the message payload in bytes. + Also use this attribute if it is unknown whether the compressed or uncompressed payload size is reported. + examples: 2738 + - id: message.payload_compressed_size_bytes + type: int + brief: 'The compressed size of the message payload in bytes.' + examples: 2048 + + - id: messaging.destination + prefix: messaging.destination + # todo (/~https://github.com/open-telemetry/build-tools/issues/123) + type: span + brief: 'Semantic convention for attributes that describe messaging destination on broker' + attributes: + - id: name + type: string + brief: 'The message destination name' + note: | + Destination name SHOULD uniquely identify a specific queue, topic or other entity within the broker. If + the broker does not have such notion, the destination name SHOULD uniquely identify the broker. examples: ['MyQueue', 'MyTopic'] - - id: destination_kind + - id: kind type: allow_custom_values: false members: @@ -28,46 +51,114 @@ groups: - id: topic value: "topic" brief: "A message sent to a topic" - requirement_level: - conditionally_required: If the message destination is either a `queue` or `topic`. brief: 'The kind of message destination' - - id: temp_destination - type: boolean - requirement_level: - conditionally_required: If value is `true`. When missing, the value is assumed to be `false`. - brief: 'A boolean that is true if the message destination is temporary.' - - id: protocol + - id: template type: string - brief: 'The name of the transport protocol.' - examples: ['AMQP', 'MQTT'] - - id: protocol_version - type: string - brief: 'The version of the transport protocol.' - examples: '0.9.1' - - id: url + brief: Low cardinality representation of the messaging destination name + note: > + Destination names could be constructed from templates. + An example would be a destination name involving a user name or product id. + Although the destination name in this case is of high cardinality, + the underlying template is of low cardinality and can be effectively + used for grouping and aggregation. + examples: ['/customers/{customerId}'] + - id: temporary + type: boolean + brief: 'A boolean that is true if the message destination is temporary and might not exist anymore after messages are processed.' + - id: anonymous + type: boolean + brief: 'A boolean that is true if the message destination is anonymous (could be unnamed or have auto-generated name).' + + - id: messaging.source + prefix: messaging.source + # todo (/~https://github.com/open-telemetry/build-tools/issues/123) + type: span + brief: 'Semantic convention for attributes that describe messaging source on broker' + attributes: + - id: name type: string - brief: 'Connection string.' - examples: ['tibjmsnaming://localhost:7222', 'https://queue.amazonaws.com/80398EXAMPLE/MyQueue'] - - id: message_id + brief: 'The message source name' + note: | + Source name SHOULD uniquely identify a specific queue, topic, or other entity within the broker. If + the broker does not have such notion, the source name SHOULD uniquely identify the broker. + examples: ['MyQueue', 'MyTopic'] + - id: kind + type: + allow_custom_values: true + members: + - id: queue + value: "queue" + brief: "A message received from a queue" + - id: topic + value: "topic" + brief: "A message received from a topic" + brief: 'The kind of message source' + - id: template type: string - brief: 'A value used by the messaging system as an identifier for the message, represented as a string.' - examples: '452a7c7c7c7048c2f887f61572b18fc2' - - id: conversation_id + brief: 'Low cardinality representation of the messaging source name' + examples: ['/customers/{customerId}'] + note: > + Source names could be constructed from templates. + An example would be a source name involving a user name or product id. + Although the source name in this case is of high cardinality, + the underlying template is of low cardinality and can be effectively + used for grouping and aggregation. + - id: temporary + type: boolean + brief: 'A boolean that is true if the message source is temporary and might not exist anymore after messages are processed.' + - id: anonymous + type: boolean + brief: 'A boolean that is true if the message source is anonymous (could be unnamed or have auto-generated name).' + + - id: messaging + prefix: messaging + type: span + brief: > + This document defines general attributes used in + messaging systems. + attributes: + - id: system type: string + requirement_level: required + brief: 'A string identifying the messaging system.' + examples: ['kafka', 'rabbitmq', 'rocketmq', 'activemq', 'AmazonSQS'] + - id: operation + type: + allow_custom_values: true + members: + - id: publish + value: "publish" + - id: receive + value: "receive" + - id: process + value: "process" + requirement_level: required brief: > - The [conversation ID](#conversations) identifying the conversation to which the message belongs, - represented as a string. Sometimes called "Correlation ID". - examples: 'MyConversationId' - - id: message_payload_size_bytes - type: int - brief: > - The (uncompressed) size of the message payload in bytes. - Also use this attribute if it is unknown whether the compressed or uncompressed payload size is reported. - examples: 2738 - - id: message_payload_compressed_size_bytes + A string identifying the kind of messaging operation as defined in the + [Operation names](#operation-names) section above. + note: If a custom value is used, it MUST be of low cardinality. + - id: batch.message_count type: int - brief: 'The compressed size of the message payload in bytes.' - examples: 2048 + brief: The number of messages sent, received, or processed in the scope of the batching operation. + requirement_level: + conditionally_required: If the span describes an operation on a batch of messages. + note: > + Instrumentations SHOULD NOT set `messaging.batch.message_count` on spans that operate with a single message. + When a messaging client library supports both batch and single-message API for the same operation, instrumentations SHOULD + use `messaging.batch.message_count` for batching APIs and SHOULD NOT use it for single-message APIs. + examples: [0, 1, 2] + - ref: messaging.message.id + requirement_level: + recommended: Only for spans that represent an operation on a single message. + - ref: messaging.message.conversation_id + requirement_level: + recommended: Only if span represents operation on a single message. + - ref: messaging.message.payload_size_bytes + requirement_level: + recommended: Only if span represents operation on a single message. + - ref: messaging.message.payload_compressed_size_bytes + requirement_level: + recommended: Only if span represents operation on a single message. - ref: net.peer.name note: > This should be the IP/hostname of the broker (or other network-level peer) this specific message is sent to/received from. @@ -83,7 +174,9 @@ groups: tag: connection-level requirement_level: recommended: If different than `net.peer.name` and if `net.sock.peer.addr` is set. - + - ref: net.app.protocol.name + examples: ['amqp', 'mqtt'] + - ref: net.app.protocol.version constraints: - include: network @@ -93,6 +186,24 @@ groups: extends: messaging span_kind: producer brief: 'Semantic convention for producers of messages sent to a messaging systems.' + attributes: + - ref: messaging.destination.name + requirement_level: + conditionally_required: If one message is being published or if the value applies to all messages in the batch. + - ref: messaging.destination.kind + requirement_level: + conditionally_required: If the message destination is either a `queue` or a `topic`. + - ref: messaging.destination.template + requirement_level: + conditionally_required: > + If available. Instrumentations MUST NOT use `messaging.destination.name` as template + unless low-cardinality of destination name is guaranteed. + - ref: messaging.destination.temporary + requirement_level: + conditionally_required: If value is `true`. When missing, the value is assumed to be `false`. + - ref: messaging.destination.anonymous + requirement_level: + conditionally_required: If value is `true`. When missing, the value is assumed to be `false`. - id: messaging.producer.synchronous prefix: messaging @@ -110,27 +221,43 @@ groups: span_kind: consumer brief: 'Semantic convention for a consumer of messages received from a messaging system' attributes: - - id: operation - type: - allow_custom_values: false - members: - - id: receive - value: "receive" - - id: process - value: "process" - brief: > - A string identifying the kind of message consumption as defined in the - [Operation names](#operation-names) section above. - If the operation is "send", this attribute MUST NOT be set, since the - operation can be inferred from the span kind in that case. - - id: consumer_id + - id: consumer.id type: string brief: > The identifier for the consumer receiving a message. For Kafka, set it to - `{messaging.kafka.consumer_group} - {messaging.kafka.client_id}`, if both are present, or only - `messaging.kafka.consumer_group`. For brokers, such as RabbitMQ and Artemis, set it to the `client_id` + `{messaging.kafka.consumer.group} - {messaging.kafka.client_id}`, if both are present, or only + `messaging.kafka.consumer.group`. For brokers, such as RabbitMQ and Artemis, set it to the `client_id` of the client consuming the message. examples: 'mygroup - client-6' + - ref: messaging.source.name + requirement_level: + conditionally_required: If the value applies to all messages in the batch. + - ref: messaging.source.kind + requirement_level: + conditionally_required: If the message source is either a `queue` or `topic`. + - ref: messaging.source.template + requirement_level: + conditionally_required: > + If available. Instrumentations MUST NOT use `messaging.source.name` as template + unless low-cardinality of source name is guaranteed. + - ref: messaging.source.temporary + requirement_level: + recommended: When supported by messaging system and only if the source is temporary. When missing, the value is assumed to be `false`. + - ref: messaging.source.anonymous + requirement_level: + recommended: When supported by messaging system and only if the source is anonymous. When missing, the value is assumed to be `false`. + - ref: messaging.destination.name + requirement_level: + recommended: If known on consumer + - ref: messaging.destination.kind + requirement_level: + recommended: If known on consumer + - ref: messaging.destination.temporary + requirement_level: + recommended: If known on consumer + - ref: messaging.destination.anonymous + requirement_level: + recommended: If known on consumer - id: messaging.consumer.synchronous prefix: messaging @@ -148,7 +275,7 @@ groups: brief: > Attributes for RabbitMQ attributes: - - id: routing_key + - id: destination.routing_key type: string requirement_level: conditionally_required: If not empty. @@ -163,17 +290,17 @@ groups: brief: > Attributes for Apache Kafka attributes: - - id: message_key + - id: message.key type: string brief: > Message keys in Kafka are used for grouping alike messages to ensure they're processed on the same partition. - They differ from `messaging.message_id` in that they're not unique. + They differ from `messaging.message.id` in that they're not unique. If the key is `null`, the attribute MUST NOT be set. note: > If the key type is not string, it's string representation has to be supplied for the attribute. If the key has no unambiguous, canonical string form, don't include its value. examples: 'myKey' - - id: consumer_group + - id: consumer.group type: string brief: > Name of the Kafka Consumer Group that is handling the message. @@ -184,17 +311,22 @@ groups: brief: > Client Id for the Consumer or Producer that is handling the message. examples: 'client-5' - - id: partition + - id: destination.partition type: int brief: > Partition the message is sent to. examples: 2 + - id: source.partition + type: int + brief: > + Partition the message is received from. + examples: 2 - id: message.offset type: int brief: > The offset of a record in the corresponding Kafka partition. examples: 42 - - id: tombstone + - id: message.tombstone type: boolean requirement_level: conditionally_required: If value is `true`. When missing, the value is assumed to be `false`. @@ -225,28 +357,28 @@ groups: brief: > The unique identifier for each client. examples: 'myhost@8742@s8083jm' - - id: delivery_timestamp + - id: message.delivery_timestamp type: int requirement_level: conditionally_required: If the message type is delay and delay time level is not specified. brief: > The timestamp in milliseconds that the delay message is expected to be delivered to consumer. examples: 1665987217045 - - id: delay_time_level + - id: message.delay_time_level type: int requirement_level: conditionally_required: If the message type is delay and delivery timestamp is not specified. brief: > The delay time level for delay message, which determines the message delay time. examples: 3 - - id: message_group + - id: message.group type: string requirement_level: conditionally_required: If the message type is FIFO. brief: > It is essential for FIFO message. Messages that belong to the same message group are always processed one by one within the same consumer group. examples: 'myMessageGroup' - - id: message_type + - id: message.type type: allow_custom_values: false members: @@ -264,12 +396,12 @@ groups: brief: 'Transaction message' brief: > Type of message. - - id: message_tag + - id: message.tag type: string brief: > The secondary classifier of message besides topic. examples: tagA - - id: message_keys + - id: message.keys type: string[] brief: > Key(s) of message, another way to mark message besides message id. diff --git a/specification/trace/semantic_conventions/instrumentation/aws-lambda.md b/specification/trace/semantic_conventions/instrumentation/aws-lambda.md index dc4ad1e47d1..c35c23d27b2 100644 --- a/specification/trace/semantic_conventions/instrumentation/aws-lambda.md +++ b/specification/trace/semantic_conventions/instrumentation/aws-lambda.md @@ -123,7 +123,7 @@ added as a link to the span. This means the span may have as many links as messa - [`faas.trigger`][faas]] MUST be set to `pubsub`. - [`messaging.operation`](../messaging.md) MUST be set to `process`. - [`messaging.system`](../messaging.md) MUST be set to `AmazonSQS`. -- [`messaging.destination_kind`](../messaging.md#messaging-attributes) MUST be set to `queue`. +- [`messaging.destination.kind` or `messaging.source.kind`](../messaging.md#messaging-attributes) MUST be set to `queue`. ### SQS Message @@ -136,7 +136,7 @@ added as a link to the span. - [`faas.trigger`][faas] MUST be set to `pubsub`. - [`messaging.operation`](../messaging.md#messaging-attributes) MUST be set to `process`. - [`messaging.system`](../messaging.md#messaging-attributes) MUST be set to `AmazonSQS`. -- [`messaging.destination_kind`](../messaging.md#messaging-attributes) MUST be set to `queue`. +- [`messaging.destination.kind` or `messaging.source.kind`](../messaging.md#messaging-attributes) MUST be set to `queue`. Other [Messaging attributes](../messaging.md#messaging-attributes) SHOULD be set based on the available information in the SQS message event. @@ -219,13 +219,15 @@ Function F: | Span ProcBatch | | SpanKind | `PRODUCER` | `PRODUCER` | `CONSUMER` | `CONSUMER` | `CONSUMER` | | Status | `Ok` | `Ok` | `Ok` | `Ok` | `Ok` | | `messaging.system` | `AmazonSQS` | `AmazonSQS` | `AmazonSQS` | `AmazonSQS` | `AmazonSQS` | -| `messaging.destination` | `Q` | `Q` | `Q` | `Q` | `Q` | -| `messaging.destination_kind` | `queue` | `queue` | `queue` | `queue` | `queue` | +| `messaging.destination.name` | `Q` | `Q` | | | | +| `messaging.source.name` | | | `Q` | `Q` | `Q` | +| `messaging.destination.kind` | `queue` | `queue` | | | | +| `messaging.source.kind` | | | `queue` | `queue` | `queue` | | `messaging.operation` | | | `process` | `process` | `process` | -| `messaging.message_id` | | | | `"a1"` | `"a2"` | +| `messaging.message.id` | | | | `"a1"` | `"a2"` | Note that if Span Prod1 and Span Prod2 were sent to different queues, Span ProcBatch would not have -`messaging.destination` set as it would correspond to multiple destinations. +`messaging.source.name` set as it would correspond to multiple sources. The above requires user code change to create `Span Proc1` and `Span Proc2`. In Java, the user would inherit from [TracingSqsMessageHandler][] instead of Lambda's standard `RequestHandler` to enable them. Otherwise these two spans diff --git a/specification/trace/semantic_conventions/messaging.md b/specification/trace/semantic_conventions/messaging.md index faecbe03658..9b23b62a3f0 100644 --- a/specification/trace/semantic_conventions/messaging.md +++ b/specification/trace/semantic_conventions/messaging.md @@ -11,16 +11,20 @@ * [Producer](#producer) * [Consumer](#consumer) * [Intermediary](#intermediary) - * [Destinations](#destinations) + * [Destinations and sources](#destinations-and-sources) * [Message consumption](#message-consumption) * [Conversations](#conversations) - * [Temporary destinations](#temporary-destinations) + * [Temporary and anonymous destinations](#temporary-and-anonymous-destinations) - [Conventions](#conventions) * [Context propagation](#context-propagation) * [Span name](#span-name) * [Span kind](#span-kind) * [Operation names](#operation-names) - [Messaging attributes](#messaging-attributes) + * [Attribute namespaces](#attribute-namespaces) + * [Producer attributes](#producer-attributes) + * [Consumer attributes](#consumer-attributes) + * [Per-message attributes](#per-message-attributes) * [Attributes specific to certain messaging systems](#attributes-specific-to-certain-messaging-systems) + [RabbitMQ](#rabbitmq) + [Apache Kafka](#apache-kafka) @@ -71,12 +75,16 @@ process of notifying an intermediary that a message was processed successfully. An "intermediary" receives a message to forward it to the next receiver, which might be another intermediary or a consumer. -### Destinations +### Destinations and sources -A destination is usually identified by some name unique within the messaging system instance, which might look like a URL or a simple one-word identifier. +A destination is usually uniquely identified by name within the messaging system instance. Examples of a destination name would be a URL or a simple one-word identifier. Traditional messaging, such as JMS, involves two kinds of destinations: *topic*s and *queue*s. + A message that is sent (the send-operation is often called "*publish*" in this context) to a *topic* is broadcasted to all consumers that have *subscribed* to the topic. -A message submitted to a queue is processed by a message *consumer* (usually exactly once although some message systems support a more performant at-least-once mode for messages with [idempotent][] processing). + +A message that is sent to a *queue* is processed by a message *consumer* (usually exactly once although some message systems support a more performant at-least-once mode for messages with [idempotent][] processing). + +A source represents an entity within messaging system messages are consumed from. Source and destination for specific message may be the same. However, if message is routed within one or multiple brokers, source and destination can be different. In a messaging system such as Apache Kafka, all destinations are *topic*s. Each record, or message, is sent to a single consumer per consumer group. @@ -99,10 +107,10 @@ In some messaging systems, a message can receive one or more reply messages that The grouping usually happens through some sort of "In-Reply-To:" meta information or an explicit *conversation ID* (sometimes called *correlation ID*). Sometimes a conversation can span multiple message destinations (e.g. initiated via a topic, continued on a temporary one-to-one queue). -### Temporary destinations +### Temporary and anonymous destinations Some messaging systems support the concept of *temporary destination* (often only temporary queues) that are established just for a particular set of communication partners (often one to one) or conversation. -Often such destinations are unnamed or have an auto-generated name. +Often such destinations are also unnamed (anonymous) or have an auto-generated name. ## Conventions @@ -152,20 +160,20 @@ The destination name SHOULD only be used for the span name if it is known to be This can be assumed if it is statically derived from application code or configuration. Wherever possible, the real destination names after resolving logical or aliased names SHOULD be used. If the destination name is dynamic, such as a [conversation ID](#conversations) or a value obtained from a `Reply-To` header, it SHOULD NOT be used for the span name. -In these cases, an artificial destination name that best expresses the destination, or a generic, static fallback like `"(temporary)"` for [temporary destinations](#temporary-destinations) SHOULD be used instead. +In these cases, an artificial destination name that best expresses the destination, or a generic, static fallback like `"(anonymous)"` for [anonymous destinations](#temporary-and-anonymous-destinations) SHOULD be used instead. The values allowed for `` are defined in the section [Operation names](#operation-names) below. If the format above is used, the operation name MUST match the `messaging.operation` attribute defined for message consumer spans below. Examples: -* `shop.orders send` +* `shop.orders publish` * `shop.orders receive` * `shop.orders process` -* `print_jobs send` +* `print_jobs publish` * `topic with spaces process` * `AuthenticationRequest-Conversations process` -* `(temporary) send` (`(temporary)` being a stable identifier for randomly generated, temporary destination names) +* `(anonymous) publish` (`(anonymous)` being a stable identifier for an unnamed destination) ### Span kind @@ -179,7 +187,7 @@ The following operations related to messages are defined for these semantic conv | Operation name | Description | | -------------- | ----------- | -| `send` | A message is sent to a destination by a message producer/client. | +| `publish` | A message is sent to a destination by a message producer/client. | | `receive` | A message is received from a destination by a message consumer/server. | | `process` | A message that was previously received from a destination is processed by a message consumer/server. | @@ -189,64 +197,141 @@ The following operations related to messages are defined for these semantic conv | Attribute | Type | Description | Examples | Requirement Level | |---|---|---|---|---| | `messaging.system` | string | A string identifying the messaging system. | `kafka`; `rabbitmq`; `rocketmq`; `activemq`; `AmazonSQS` | Required | -| `messaging.destination` | string | The message destination name. This might be equal to the span name but is required nevertheless. | `MyQueue`; `MyTopic` | Required | -| `messaging.destination_kind` | string | The kind of message destination | `queue` | Conditionally Required: [1] | -| `messaging.temp_destination` | boolean | A boolean that is true if the message destination is temporary. | | Conditionally Required: [2] | -| `messaging.protocol` | string | The name of the transport protocol. | `AMQP`; `MQTT` | Recommended | -| `messaging.protocol_version` | string | The version of the transport protocol. | `0.9.1` | Recommended | -| `messaging.url` | string | Connection string. | `tibjmsnaming://localhost:7222`; `https://queue.amazonaws.com/80398EXAMPLE/MyQueue` | Recommended | -| `messaging.message_id` | string | A value used by the messaging system as an identifier for the message, represented as a string. | `452a7c7c7c7048c2f887f61572b18fc2` | Recommended | -| `messaging.conversation_id` | string | The [conversation ID](#conversations) identifying the conversation to which the message belongs, represented as a string. Sometimes called "Correlation ID". | `MyConversationId` | Recommended | -| `messaging.message_payload_size_bytes` | int | The (uncompressed) size of the message payload in bytes. Also use this attribute if it is unknown whether the compressed or uncompressed payload size is reported. | `2738` | Recommended | -| `messaging.message_payload_compressed_size_bytes` | int | The compressed size of the message payload in bytes. | `2048` | Recommended | -| [`net.peer.name`](span-general.md) | string | Logical remote hostname, see note below. [3] | `example.com` | Conditionally Required: If available. | -| [`net.sock.family`](span-general.md) | string | Protocol [address family](https://man7.org/linux/man-pages/man7/address_families.7.html) which is used for communication. | `inet6`; `bluetooth` | Conditionally Required: [4] | +| `messaging.operation` | string | A string identifying the kind of messaging operation as defined in the [Operation names](#operation-names) section above. [1] | `publish` | Required | +| `messaging.batch.message_count` | int | The number of messages sent, received, or processed in the scope of the batching operation. [2] | `0`; `1`; `2` | Conditionally Required: [3] | +| `messaging.message.conversation_id` | string | The [conversation ID](#conversations) identifying the conversation to which the message belongs, represented as a string. Sometimes called "Correlation ID". | `MyConversationId` | Recommended: [4] | +| `messaging.message.id` | string | A value used by the messaging system as an identifier for the message, represented as a string. | `452a7c7c7c7048c2f887f61572b18fc2` | Recommended: [5] | +| `messaging.message.payload_compressed_size_bytes` | int | The compressed size of the message payload in bytes. | `2048` | Recommended: [6] | +| `messaging.message.payload_size_bytes` | int | The (uncompressed) size of the message payload in bytes. Also use this attribute if it is unknown whether the compressed or uncompressed payload size is reported. | `2738` | Recommended: [7] | +| [`net.app.protocol.name`](span-general.md) | string | Application layer protocol used. The value SHOULD be normalized to lowercase. | `amqp`; `mqtt` | Recommended | +| [`net.app.protocol.version`](span-general.md) | string | Version of the application layer protocol used. See note below. [8] | `3.1.1` | Recommended | +| [`net.peer.name`](span-general.md) | string | Logical remote hostname, see note below. [9] | `example.com` | Conditionally Required: If available. | +| [`net.sock.family`](span-general.md) | string | Protocol [address family](https://man7.org/linux/man-pages/man7/address_families.7.html) which is used for communication. | `inet6`; `bluetooth` | Conditionally Required: [10] | | [`net.sock.peer.addr`](span-general.md) | string | Remote socket peer address: IPv4 or IPv6 for internet protocols, path for local communication, [etc](https://man7.org/linux/man-pages/man7/address_families.7.html). | `127.0.0.1`; `/tmp/mysql.sock` | Recommended | -| [`net.sock.peer.name`](span-general.md) | string | Remote socket peer name. | `proxy.example.com` | Recommended: [5] | -| [`net.sock.peer.port`](span-general.md) | int | Remote socket peer port. | `16456` | Recommended: [6] | +| [`net.sock.peer.name`](span-general.md) | string | Remote socket peer name. | `proxy.example.com` | Recommended: [11] | +| [`net.sock.peer.port`](span-general.md) | int | Remote socket peer port. | `16456` | Recommended: [12] | -**[1]:** If the message destination is either a `queue` or `topic`. +**[1]:** If a custom value is used, it MUST be of low cardinality. -**[2]:** If value is `true`. When missing, the value is assumed to be `false`. +**[2]:** Instrumentations SHOULD NOT set `messaging.batch.message_count` on spans that operate with a single message. When a messaging client library supports both batch and single-message API for the same operation, instrumentations SHOULD use `messaging.batch.message_count` for batching APIs and SHOULD NOT use it for single-message APIs. + +**[3]:** If the span describes an operation on a batch of messages. + +**[4]:** Only if span represents operation on a single message. -**[3]:** This should be the IP/hostname of the broker (or other network-level peer) this specific message is sent to/received from. +**[5]:** Only for spans that represent an operation on a single message. -**[4]:** If different than `inet` and if any of `net.sock.peer.addr` or `net.sock.host.addr` are set. Consumers of telemetry SHOULD accept both IPv4 and IPv6 formats for the address in `net.sock.peer.addr` if `net.sock.family` is not set. This is to support instrumentations that follow previous versions of this document. +**[6]:** Only if span represents operation on a single message. -**[5]:** If different than `net.peer.name` and if `net.sock.peer.addr` is set. +**[7]:** Only if span represents operation on a single message. -**[6]:** If defined for the address family and if different than `net.peer.port` and if `net.sock.peer.addr` is set. +**[8]:** `net.app.protocol.version` refers to the version of the protocol used and might be different from the protocol client's version. If the HTTP client used has a version of `0.27.2`, but sends HTTP version `1.1`, this attribute should be set to `1.1`. -`messaging.destination_kind` MUST be one of the following: +**[9]:** This should be the IP/hostname of the broker (or other network-level peer) this specific message is sent to/received from. + +**[10]:** If different than `inet` and if any of `net.sock.peer.addr` or `net.sock.host.addr` are set. Consumers of telemetry SHOULD accept both IPv4 and IPv6 formats for the address in `net.sock.peer.addr` if `net.sock.family` is not set. This is to support instrumentations that follow previous versions of this document. + +**[11]:** If different than `net.peer.name` and if `net.sock.peer.addr` is set. + +**[12]:** If defined for the address family and if different than `net.peer.port` and if `net.sock.peer.addr` is set. + +`messaging.operation` has the following list of well-known values. If one of them applies, then the respective value MUST be used, otherwise a custom value MAY be used. | Value | Description | |---|---| -| `queue` | A message sent to a queue | -| `topic` | A message sent to a topic | +| `publish` | publish | +| `receive` | receive | +| `process` | process | Additionally `net.peer.port` from the [network attributes][] is recommended. Furthermore, it is strongly recommended to add the [`net.transport`][] attribute and follow its guidelines, especially for in-process queueing systems (like [Hangfire][], for example). These attributes should be set to the broker to which the message is sent/from which it is received. +### Attribute namespaces + +- `messaging.message`: Contains attributes that describe individual messages +- `messaging.destination`: Contains attributes that describe the logical entity messages are published to. + See [Destinations and sources](#destinations-and-sources) for more details +- `messaging.source`: Contains attributes that describe the logical entity messages are received from +- `messaging.batch`: Contains attributes that describe batch operations +- `messaging.consumer`: Contains attributes that describe application instance that consumes a message. See [consumer](#consumer) for more details + +Communication with broker is described with general [network attributes]. + +Messaging system-specific attributes MUST be defined in the corresponding `messaging.{system}` namespace +as described in [Attributes specific to certain messaging systems](#attributes-specific-to-certain-messaging-systems). + [network attributes]: span-general.md#general-network-connection-attributes [`net.transport`]: span-general.md#network-transport-attributes [Hangfire]: https://www.hangfire.io/ -For message consumers, the following additional attributes may be set: +### Producer attributes + +The following additional attributes describe message producer operations. + + +| Attribute | Type | Description | Examples | Requirement Level | +|---|---|---|---|---| +| `messaging.destination.anonymous` | boolean | A boolean that is true if the message destination is anonymous (could be unnamed or have auto-generated name). | | Conditionally Required: [1] | +| `messaging.destination.kind` | string | The kind of message destination | `queue` | Conditionally Required: [2] | +| `messaging.destination.name` | string | The message destination name [3] | `MyQueue`; `MyTopic` | Conditionally Required: [4] | +| `messaging.destination.template` | string | Low cardinality representation of the messaging destination name [5] | `/customers/{customerId}` | Conditionally Required: [6] | +| `messaging.destination.temporary` | boolean | A boolean that is true if the message destination is temporary and might not exist anymore after messages are processed. | | Conditionally Required: [7] | + +**[1]:** If value is `true`. When missing, the value is assumed to be `false`. + +**[2]:** If the message destination is either a `queue` or a `topic`. + +**[3]:** Destination name SHOULD uniquely identify a specific queue, topic or other entity within the broker. If +the broker does not have such notion, the destination name SHOULD uniquely identify the broker. + +**[4]:** If one message is being published or if the value applies to all messages in the batch. + +**[5]:** Destination names could be constructed from templates. An example would be a destination name involving a user name or product id. Although the destination name in this case is of high cardinality, the underlying template is of low cardinality and can be effectively used for grouping and aggregation. + +**[6]:** If available. Instrumentations MUST NOT use `messaging.destination.name` as template unless low-cardinality of destination name is guaranteed. + +**[7]:** If value is `true`. When missing, the value is assumed to be `false`. + + +### Consumer attributes + +The following additional attributes describe message consumer operations. + +> Note: Consumer spans can have attributes describing source and destination. Since messages could be routed by brokers, source and destination don't always match. If original destination information is available on the consumer, consumer instrumentations SHOULD populate corresponding `messaging.destination` attributes. | Attribute | Type | Description | Examples | Requirement Level | |---|---|---|---|---| -| `messaging.operation` | string | A string identifying the kind of message consumption as defined in the [Operation names](#operation-names) section above. If the operation is "send", this attribute MUST NOT be set, since the operation can be inferred from the span kind in that case. | `receive` | Recommended | -| `messaging.consumer_id` | string | The identifier for the consumer receiving a message. For Kafka, set it to `{messaging.kafka.consumer_group} - {messaging.kafka.client_id}`, if both are present, or only `messaging.kafka.consumer_group`. For brokers, such as RabbitMQ and Artemis, set it to the `client_id` of the client consuming the message. | `mygroup - client-6` | Recommended | +| `messaging.consumer.id` | string | The identifier for the consumer receiving a message. For Kafka, set it to `{messaging.kafka.consumer.group} - {messaging.kafka.client_id}`, if both are present, or only `messaging.kafka.consumer.group`. For brokers, such as RabbitMQ and Artemis, set it to the `client_id` of the client consuming the message. | `mygroup - client-6` | Recommended | +| `messaging.destination.anonymous` | boolean | A boolean that is true if the message destination is anonymous (could be unnamed or have auto-generated name). | | Recommended: If known on consumer | +| `messaging.destination.kind` | string | The kind of message destination | `queue` | Recommended: If known on consumer | +| `messaging.destination.name` | string | The message destination name [1] | `MyQueue`; `MyTopic` | Recommended: If known on consumer | +| `messaging.destination.temporary` | boolean | A boolean that is true if the message destination is temporary and might not exist anymore after messages are processed. | | Recommended: If known on consumer | +| `messaging.source.anonymous` | boolean | A boolean that is true if the message source is anonymous (could be unnamed or have auto-generated name). | | Recommended: [2] | +| `messaging.source.kind` | string | The kind of message source | `queue` | Conditionally Required: [3] | +| `messaging.source.name` | string | The message source name [4] | `MyQueue`; `MyTopic` | Conditionally Required: [5] | +| `messaging.source.template` | string | Low cardinality representation of the messaging source name [6] | `/customers/{customerId}` | Conditionally Required: [7] | +| `messaging.source.temporary` | boolean | A boolean that is true if the message source is temporary and might not exist anymore after messages are processed. | | Recommended: [8] | -`messaging.operation` MUST be one of the following: +**[1]:** Destination name SHOULD uniquely identify a specific queue, topic or other entity within the broker. If +the broker does not have such notion, the destination name SHOULD uniquely identify the broker. -| Value | Description | -|---|---| -| `receive` | receive | -| `process` | process | +**[2]:** When supported by messaging system and only if the source is anonymous. When missing, the value is assumed to be `false`. + +**[3]:** If the message source is either a `queue` or `topic`. + +**[4]:** Source name SHOULD uniquely identify a specific queue, topic, or other entity within the broker. If +the broker does not have such notion, the source name SHOULD uniquely identify the broker. + +**[5]:** If the value applies to all messages in the batch. + +**[6]:** Source names could be constructed from templates. An example would be a source name involving a user name or product id. Although the source name in this case is of high cardinality, the underlying template is of low cardinality and can be effectively used for grouping and aggregation. + +**[7]:** If available. Instrumentations MUST NOT use `messaging.source.name` as template unless low-cardinality of source name is guaranteed. + +**[8]:** When supported by messaging system and only if the source is temporary. When missing, the value is assumed to be `false`. The *receive* span is be used to track the time used for receiving the message(s), whereas the *process* span(s) track the time for processing the message(s). @@ -256,17 +341,34 @@ For batch receiving and processing (see the [Batch receiving](#batch-receiving) Even though in that case one might think that the processing span's kind should be `INTERNAL`, that kind MUST NOT be used. Instead span kind should be set to either `CONSUMER` or `SERVER` according to the rules defined above. +### Per-message attributes + +All messaging operations (`publish`, `receive`, `process`, or others not covered by this specification) can describe both single and/or batch of messages. +Attributes in the `messaging.message` or `messaging.{system}.message` namespace describe individual messages. For single-message operations they SHOULD be set on corresponding span. + +For batch operations, per-message attributes are usually different and cannot be set on the corresponding span. In such cases the attributes MAY be set on links. See [Batch Receiving](#batch-receiving) and [Batch Processing](#batch-processing) for more information on correlation using links. + +Some messaging systems (e.g., Kafka, Azure EventGrid) allow publishing a single batch of messages to different topics. In such cases, the attributes in `messaging.destination` and `messaging.source` MAY be +set on links. Instrumentations MAY set source and destination attributes on the span if all messages in the batch share the same destination or source. + ### Attributes specific to certain messaging systems +All attributes that are specific for a messaging system SHOULD be populated in `messaging.{system}` namespace. Attributes that describe a message, a destination, a source, a consumer or a batch of messages SHOULD be populated under the corresponding namespace: + +* `messaging.{system}.message`: Describes attributes for individual messages +* `messaging.{system}.destination` and `messaging.{system}.source`: Describe the destination and source a message (or a batch) are published to and received from respectively. The combination of attributes in these namespaces should uniquely identify the entity and include properties significant for this messaging system. For example, Kafka instrumentations should include partition identifier. +* `messaging.{system}.consumer`: Describes message consumer properties +* `messaging.{system}.batch`: Describes message batch properties + #### RabbitMQ In RabbitMQ, the destination is defined by an *exchange* and a *routing key*. -`messaging.destination` MUST be set to the name of the exchange. This will be an empty string if the default exchange is used. +`messaging.destination.name` MUST be set to the name of the exchange. This will be an empty string if the default exchange is used. | Attribute | Type | Description | Examples | Requirement Level | |---|---|---|---|---| -| `messaging.rabbitmq.routing_key` | string | RabbitMQ message routing key. | `myKey` | Conditionally Required: If not empty. | +| `messaging.rabbitmq.destination.routing_key` | string | RabbitMQ message routing key. | `myKey` | Conditionally Required: If not empty. | #### Apache Kafka @@ -276,12 +378,13 @@ For Apache Kafka, the following additional attributes are defined: | Attribute | Type | Description | Examples | Requirement Level | |---|---|---|---|---| -| `messaging.kafka.message_key` | string | Message keys in Kafka are used for grouping alike messages to ensure they're processed on the same partition. They differ from `messaging.message_id` in that they're not unique. If the key is `null`, the attribute MUST NOT be set. [1] | `myKey` | Recommended | -| `messaging.kafka.consumer_group` | string | Name of the Kafka Consumer Group that is handling the message. Only applies to consumers, not producers. | `my-group` | Recommended | +| `messaging.kafka.message.key` | string | Message keys in Kafka are used for grouping alike messages to ensure they're processed on the same partition. They differ from `messaging.message.id` in that they're not unique. If the key is `null`, the attribute MUST NOT be set. [1] | `myKey` | Recommended | +| `messaging.kafka.consumer.group` | string | Name of the Kafka Consumer Group that is handling the message. Only applies to consumers, not producers. | `my-group` | Recommended | | `messaging.kafka.client_id` | string | Client Id for the Consumer or Producer that is handling the message. | `client-5` | Recommended | -| `messaging.kafka.partition` | int | Partition the message is sent to. | `2` | Recommended | +| `messaging.kafka.destination.partition` | int | Partition the message is sent to. | `2` | Recommended | +| `messaging.kafka.source.partition` | int | Partition the message is received from. | `2` | Recommended | | `messaging.kafka.message.offset` | int | The offset of a record in the corresponding Kafka partition. | `42` | Recommended | -| `messaging.kafka.tombstone` | boolean | A boolean that is true if the message is a tombstone. | | Conditionally Required: [2] | +| `messaging.kafka.message.tombstone` | boolean | A boolean that is true if the message is a tombstone. | | Conditionally Required: [2] | **[1]:** If the key type is not string, it's string representation has to be supplied for the attribute. If the key has no unambiguous, canonical string form, don't include its value. @@ -302,19 +405,19 @@ Specific attributes for Apache RocketMQ are defined below. | `messaging.rocketmq.namespace` | string | Namespace of RocketMQ resources, resources in different namespaces are individual. | `myNamespace` | Required | | `messaging.rocketmq.client_group` | string | Name of the RocketMQ producer/consumer group that is handling the message. The client type is identified by the SpanKind. | `myConsumerGroup` | Required | | `messaging.rocketmq.client_id` | string | The unique identifier for each client. | `myhost@8742@s8083jm` | Required | -| `messaging.rocketmq.delivery_timestamp` | int | The timestamp in milliseconds that the delay message is expected to be delivered to consumer. | `1665987217045` | Conditionally Required: [1] | -| `messaging.rocketmq.delay_time_level` | int | The delay time level for delay message, which determines the message delay time. | `3` | Conditionally Required: [2] | -| `messaging.rocketmq.message_group` | string | It is essential for FIFO message. Messages that belong to the same message group are always processed one by one within the same consumer group. | `myMessageGroup` | Conditionally Required: If the message type is FIFO. | -| `messaging.rocketmq.message_type` | string | Type of message. | `normal` | Recommended | -| `messaging.rocketmq.message_tag` | string | The secondary classifier of message besides topic. | `tagA` | Recommended | -| `messaging.rocketmq.message_keys` | string[] | Key(s) of message, another way to mark message besides message id. | `[keyA, keyB]` | Recommended | +| `messaging.rocketmq.message.delivery_timestamp` | int | The timestamp in milliseconds that the delay message is expected to be delivered to consumer. | `1665987217045` | Conditionally Required: [1] | +| `messaging.rocketmq.message.delay_time_level` | int | The delay time level for delay message, which determines the message delay time. | `3` | Conditionally Required: [2] | +| `messaging.rocketmq.message.group` | string | It is essential for FIFO message. Messages that belong to the same message group are always processed one by one within the same consumer group. | `myMessageGroup` | Conditionally Required: If the message type is FIFO. | +| `messaging.rocketmq.message.type` | string | Type of message. | `normal` | Recommended | +| `messaging.rocketmq.message.tag` | string | The secondary classifier of message besides topic. | `tagA` | Recommended | +| `messaging.rocketmq.message.keys` | string[] | Key(s) of message, another way to mark message besides message id. | `[keyA, keyB]` | Recommended | | `messaging.rocketmq.consumption_model` | string | Model of message consumption. This only applies to consumer spans. | `clustering` | Recommended | **[1]:** If the message type is delay and delay time level is not specified. **[2]:** If the message type is delay and delivery timestamp is not specified. -`messaging.rocketmq.message_type` MUST be one of the following: +`messaging.rocketmq.message.type` MUST be one of the following: | Value | Description | |---|---| @@ -347,7 +450,7 @@ Process CB: | Span CB1 | | Field or Attribute | Span Prod1 | Span CA1 | Span CB1 | |-|-|-|-| -| Span name | `"T send"` | `"T process"` | `"T process"` | +| Span name | `"T publish"` | `"T process"` | `"T process"` | | Parent | | Span Prod1 | Span Prod1 | | Links | | | | | SpanKind | `PRODUCER` | `CONSUMER` | `CONSUMER` | @@ -355,10 +458,12 @@ Process CB: | Span CB1 | | `net.peer.name` | `"ms"` | `"ms"` | `"ms"` | | `net.peer.port` | `1234` | `1234` | `1234` | | `messaging.system` | `"rabbitmq"` | `"rabbitmq"` | `"rabbitmq"` | -| `messaging.destination` | `"T"` | `"T"` | `"T"` | -| `messaging.destination_kind` | `"topic"` | `"topic"` | `"topic"` | +| `messaging.destination.name` | `"T"` | | | +| `messaging.destination.kind` | `"topic"` | | | +| `messaging.source.name` | | `"T"` | `"T"` | +| `messaging.source.kind` | | `"topic"` | `"topic"` | | `messaging.operation` | | `"process"` | `"process"` | -| `messaging.message_id` | `"a1"` | `"a1"`| `"a1"` | +| `messaging.message.id` | `"a1"` | `"a1"`| `"a1"` | ### Apache Kafka with Quarkus or Spring Boot Example @@ -382,7 +487,7 @@ Process CB: | Span Rcv2 | | Field or Attribute | Span Prod1 | Span Rcv1 | Span Proc1 | Span Prod2 | Span Rcv2 |-|-|-|-|-|-| -| Span name | `"T1 send"` | `"T1 receive"` | `"T1 process"` | `"T2 send"` | `"T2 receive`" | +| Span name | `"T1 publish"` | `"T1 receive"` | `"T1 process"` | `"T2 publish"` | `"T2 receive`" | | Parent | | Span Prod1 | Span Rcv1 | Span Rcv1 | Span Prod2 | | Links | | | | | | | SpanKind | `PRODUCER` | `CONSUMER` | `CONSUMER` | `PRODUCER` | `CONSUMER` | @@ -390,18 +495,20 @@ Process CB: | Span Rcv2 | | `peer.service` | `"myKafka"` | | | `"myKafka"` | | | `service.name` | | `"myConsumer1"` | `"myConsumer1"` | | `"myConsumer2"` | | `messaging.system` | `"kafka"` | `"kafka"` | `"kafka"` | `"kafka"` | `"kafka"` | -| `messaging.destination` | `"T1"` | `"T1"` | `"T1"` | `"T2"` | `"T2"` | -| `messaging.destination_kind` | `"topic"` | `"topic"` | `"topic"` | `"topic"` | `"topic"` | +| `messaging.destination.name` | `"T1"` | | | | | +| `messaging.destination.kind` | `"topic"` | | | | | +| `messaging.source.name` | | `"T1"` | `"T1"` | `"T2"` | `"T2"` | +| `messaging.source.kind` | | `"topic"` | `"topic"` | `"topic"` | `"topic"` | | `messaging.operation` | | | `"process"` | | `"receive"` | -| `messaging.kafka.message_key` | `"myKey"` | `"myKey"` | `"myKey"` | `"anotherKey"` | `"anotherKey"` | -| `messaging.kafka.consumer_group` | | `"my-group"` | `"my-group"` | | `"another-group"` | +| `messaging.kafka.message.key` | `"myKey"` | `"myKey"` | `"myKey"` | `"anotherKey"` | `"anotherKey"` | +| `messaging.kafka.consumer.group` | | `"my-group"` | `"my-group"` | | `"another-group"` | | `messaging.kafka.client_id` | | `"5"` | `"5"` | `"5"` | `"8"` | | `messaging.kafka.partition` | `"1"` | `"1"` | `"1"` | `"3"` | `"3"` | | `messaging.kafka.message.offset` | `"12"` | `"12"` | `"12"` | `"32"` | `"32"` | ### Batch receiving -Given is a process P, that sends two messages to a queue Q on messaging system MS, and a process C, which receives both of them in one batch (Span Recv1) and processes each message separately (Spans Proc1 and Proc2). +Given is a process P, that publishes two messages to a queue Q on messaging system MS, and a process C, which receives both of them in one batch (Span Recv1) and processes each message separately (Spans Proc1 and Proc2). Since a span can only have one parent and the propagated trace and span IDs are not known when the receiving span is started, the receiving span will have no parent and the processing spans are correlated with the producing spans using links. @@ -415,7 +522,7 @@ Process C: | Span Recv1 | | Field or Attribute | Span Prod1 | Span Prod2 | Span Recv1 | Span Proc1 | Span Proc2 | |-|-|-|-|-|-| -| Span name | `"Q send"` | `"Q send"` | `"Q receive"` | `"Q process"` | `"Q process"` | +| Span name | `"Q publish"` | `"Q publish"` | `"Q receive"` | `"Q process"` | `"Q process"` | | Parent | | | | Span Recv1 | Span Recv1 | | Links | | | | Span Prod1 | Span Prod2 | | SpanKind | `PRODUCER` | `PRODUCER` | `CONSUMER` | `CONSUMER` | `CONSUMER` | @@ -423,17 +530,19 @@ Process C: | Span Recv1 | | `net.peer.name` | `"ms"` | `"ms"` | `"ms"` | `"ms"` | `"ms"` | | `net.peer.port` | `1234` | `1234` | `1234` | `1234` | `1234` | | `messaging.system` | `"rabbitmq"` | `"rabbitmq"` | `"rabbitmq"` | `"rabbitmq"` | `"rabbitmq"` | -| `messaging.destination` | `"Q"` | `"Q"` | `"Q"` | `"Q"` | `"Q"` | -| `messaging.destination_kind` | `"queue"` | `"queue"` | `"queue"` | `"queue"` | `"queue"` | +| `messaging.destination.name` | `"Q"` | `"Q"` | | | | +| `messaging.destination.kind` | `"queue"` | `"queue"` | | | | +| `messaging.source.name` | | | `"Q"` | `"Q"` | `"Q"` | +| `messaging.source.kind` | | | `"queue"` | `"queue"` | `"queue"` | | `messaging.operation` | | | `"receive"` | `"process"` | `"process"` | -| `messaging.message_id` | `"a1"` | `"a2"` | | `"a1"` | `"a2"` | +| `messaging.message.id` | `"a1"` | `"a2"` | | `"a1"` | `"a2"` | +| `messaging.batch.message_count` | | | 2 | | | ### Batch processing -Given is a process P, that sends two messages to a queue Q on messaging system MS, and a process C, which receives both of them separately (Span Recv1 and Recv2) and processes both messages in one batch (Span Proc1). +Given is a process P, that publishes two messages to a queue Q on messaging system MS, and a process C, which receives them separately in two different operations (Span Recv1 and Recv2) and processes both messages in one batch (Span Proc1). Since each span can only have one parent, C3 should not choose a random parent out of C1 and C2, but rather rely on the implicitly selected parent as defined by the [tracing API spec](../api.md). -Similarly, only one value can be set as `message_id`, so C3 cannot report both `a1` and `a2` and therefore attribute is left out. Depending on the implementation, the producing spans might still be available in the meta data of the messages and should be added to C3 as links. The client library or application could also add the receiver span's SpanContext to the data structure it returns for each message. In this case, C3 could also add links to the receiver spans C1 and C2. @@ -448,15 +557,20 @@ Process C: | Span Recv1 | Span Recv2 | | Field or Attribute | Span Prod1 | Span Prod2 | Span Recv1 | Span Recv2 | Span Proc1 | |-|-|-|-|-|-| -| Span name | `"Q send"` | `"Q send"` | `"Q receive"` | `"Q receive"` | `"Q process"` | +| Span name | `"Q publish"` | `"Q publish"` | `"Q receive"` | `"Q receive"` | `"Q process"` | | Parent | | | Span Prod1 | Span Prod2 | | -| Links | | | | | Span Prod1 + Prod2 | +| Links | | | | | [Span Prod1, Span Prod2 ] | +| Link attributes | | | | | Span Prod1: `messaging.message.id`: `"a1"` | +| | | | | | Span Prod2: `messaging.message.id`: `"a2"` | | SpanKind | `PRODUCER` | `PRODUCER` | `CONSUMER` | `CONSUMER` | `CONSUMER` | | Status | `Ok` | `Ok` | `Ok` | `Ok` | `Ok` | | `net.peer.name` | `"ms"` | `"ms"` | `"ms"` | `"ms"` | `"ms"` | | `net.peer.port` | `1234` | `1234` | `1234` | `1234` | `1234` | | `messaging.system` | `"rabbitmq"` | `"rabbitmq"` | `"rabbitmq"` | `"rabbitmq"` | `"rabbitmq"` | -| `messaging.destination` | `"Q"` | `"Q"` | `"Q"` | `"Q"` | `"Q"` | -| `messaging.destination_kind` | `"queue"` | `"queue"` | `"queue"` | `"queue"` | `"queue"` | +| `messaging.destination.name` | `"Q"` | `"Q"` | | | | +| `messaging.destination.kind` | `"queue"` | `"queue"` | | | | +| `messaging.source.name` | | | `"Q"` | `"Q"` | `"Q"` | +| `messaging.source.kind` | | | `"queue"` | `"queue"` | `"queue"` | | `messaging.operation` | | | `"receive"` | `"receive"` | `"process"` | -| `messaging.message_id` | `"a1"` | `"a2"` | `"a1"` | `"a2"` | | +| `messaging.message.id` | `"a1"` | `"a2"` | `"a1"` | `"a2"` | | +| `messaging.batch.message_count` | | | 1 | 1 | 2 |