diff --git a/readme.md b/readme.md index 4a3d869..1abd0a3 100644 --- a/readme.md +++ b/readme.md @@ -404,6 +404,28 @@ this repository: ![](https://raw.githubusercontent.com/devlooped/WhatsApp/main/assets/img/aspire.png) +The spans/activites created by the `OpenTelemetryHandler` follow the [OpenTelemetry Semantic Conventions for Messaging Spans](https://opentelemetry.io/docs/specs/semconv/messaging/messaging-spans/). +Specifically, it uses a [consumer span](https://opentelemetry.io/docs/specs/semconv/messaging/messaging-spans/#consumer-spans) +named "process whatsapp" to track the processing of incoming WhatsApp messages. + +| Attribute/Tag | Value | Description | OTEL Convention | +|-----------|-------|-------------|-----------------| +| `messaging.system` | `whatsapp` | Identifies the messaging system being used. | [messaging.system](https://opentelemetry.io/docs/specs/semconv/registry/attributes/messaging/) | +| `messaging.operation.name` | `process` | The name of the operation performed on the message, indicating processing of incoming messages. | [messaging.operation.name](https://opentelemetry.io/docs/specs/semconv/registry/attributes/messaging/) | +| `messaging.destination.name` | Service ID (e.g., WhatsApp Business Account phone number) | The name of the destination to which the message is sent. In this context, it's the service identifier for the WhatsApp endpoint. | [messaging.destination.name](https://opentelemetry.io/docs/specs/semconv/registry/attributes/messaging/) | +| `messaging.client.id` | User phone number | The identifier of the client that sent the message. | [messaging.client.id](https://opentelemetry.io/docs/specs/semconv/registry/attributes/messaging/) | +| `messaging.message.id` | Message ID | The unique identifier of the message being processed. | [messaging.message.id](https://opentelemetry.io/docs/specs/semconv/registry/attributes/messaging/) | +| `messaging.message.conversation_id` | Conversation ID (if available) | The identifier of the conversation the message belongs to, if applicable. | [messaging.message.conversation_id](https://opentelemetry.io/docs/specs/semconv/registry/attributes/messaging/) | + +These attributes provide detailed context for tracing message processing flows in distributed systems. + +In addition to spans, the handler emits metrics: +- `messaging.process.duration` (histogram): Duration of WhatsApp message processing in seconds. See [OTEL convention](https://opentelemetry.io/docs/specs/semconv/messaging/messaging-metrics/#metric-messagingprocessduration) +- `messaging.client.consumed.messages` (counter): Number of WhatsApp messages processed. See [OTEL convention](https://opentelemetry.io/docs/specs/semconv/messaging/messaging-metrics/#metric-messagingclientconsumedmessages) + +These metrics also carry the same tags as the spans for correlation. + + ## Scalability and Performance diff --git a/src/WhatsApp/OpenTelemetryExtensions.cs b/src/WhatsApp/OpenTelemetryExtensions.cs index 338e0f9..7685363 100644 --- a/src/WhatsApp/OpenTelemetryExtensions.cs +++ b/src/WhatsApp/OpenTelemetryExtensions.cs @@ -22,7 +22,7 @@ static class OpenTelemetryExtensions activity.AddTag("error.type", e.GetType().FullName); activity.SetStatus(ActivityStatusCode.Error, e.Message); - activity.AddEvent(new ActivityEvent("exception", tags: new(tags))); + activity.AddEvent(new ActivityEvent("exception", tags: [.. tags])); return tags; } diff --git a/src/WhatsApp/OpenTelemetryHandler.cs b/src/WhatsApp/OpenTelemetryHandler.cs index 4e840b1..1114fa9 100644 --- a/src/WhatsApp/OpenTelemetryHandler.cs +++ b/src/WhatsApp/OpenTelemetryHandler.cs @@ -78,14 +78,14 @@ public override IAsyncEnumerable HandleAsync(IEnumerable mes } else { - using var span = activitySource.StartActivity("whatsapp process", ActivityKind.Consumer); + using var span = activitySource.StartActivity("process whatsapp", ActivityKind.Consumer); if (span != null) { span.SetTag("messaging.system", "whatsapp"); - span.SetTag("messaging.destination", "whatsapp"); - span.SetTag("messaging.operation", "process"); + span.SetTag("messaging.operation.name", "process"); + span.SetTag("messaging.destination.name", message.ServiceId); + span.SetTag("messaging.client.id", message.UserNumber); span.SetTag("messaging.message.id", message.Id); - span.SetTag("messaging.client.id", message.ServiceId); if (message.ConversationId is string conversationId) span.SetTag("messaging.message.conversation_id", conversationId); } @@ -94,8 +94,9 @@ public override IAsyncEnumerable HandleAsync(IEnumerable mes var tags = new TagList { { "messaging.system", "whatsapp" }, - { "messaging.operation", "process" }, - { "messaging.client.id", message.ServiceId }, + { "messaging.operation.name", "process" }, + { "messaging.destination.name", message.ServiceId }, + { "messaging.client.id", message.UserNumber }, }; return base.HandleAsync(messages, cancellation).WithErrorHandlingAsync(