Skip to main content
Version: v1.1.4 (latest)

Telemetry (Tracing & Metrics)

Ratatosk emits OpenTelemetry-compatible tracing and metrics from every connector operation. Each connector has its own ActivitySource and Meter — traces and metrics are available out of the box without any manual instrumentation.

Signals emitted​

Tracing (Activity)​

OperationSpan nameActivitySource
SendMessageAsync{connector} sendRatatosk.Connector.{type}
ReceiveMessagesAsync{connector} receiveRatatosk.Connector.{type}
SendBatchAsync{connector} batch_sendRatatosk.Connector.{type}
InitializeAsync{connector} initializeRatatosk.Connector.{type}
GetStatusAsync{connector} status_queryRatatosk.Connector.{type}
GetMessageStatusAsync{connector} status_queryRatatosk.Connector.{type}
ReceiveMessageStatusAsync{connector} receive_statusRatatosk.Connector.{type}
GetHealthAsync{connector} health_checkRatatosk.Connector.{type}

Each span carries semantic convention attributes:

AttributeExample value
messaging.systemratatosk
messaging.operationsend, receive, status_query
messaging.destinationChannel name
messaging.message.idMessage ID
ratatosk.connector.typetwilio_sms
ratatosk.connector.nameConnector instance name
error.typeError code (on failure)

Metrics (Meter)​

Each connector exposes a Meter named Ratatosk.Connector.{type} with the following instruments:

Metric nameTypeUnitDescription
ratatosk.messages.sentCounter{message}Total messages sent
ratatosk.messages.send_failedCounter{message}Messages that failed to send
ratatosk.messages.receivedCounter{message}Total messages received
ratatosk.messages.receive_failedCounter{message}Messages that failed to receive
ratatosk.messages.send.durationHistogrammsSend operation latency
ratatosk.messages.receive.durationHistogrammsReceive operation latency
ratatosk.messages.send.payload_sizeHistogramByPayload size in bytes
ratatosk.connector.state_changesCounter{change}Connector state transitions

The IMessagingClient facade also emits its own telemetry under Ratatosk.Client:

Metric nameTypeUnit
ratatosk.client.messages.sentCounter{message}
ratatosk.client.messages.send_failedCounter{message}
ratatosk.client.messages.send.durationHistogramms

Wiring with OpenTelemetry SDK​

Add the Ratatosk.Extensions.OpenTelemetry package to register all sources:

dotnet add package Ratatosk.Extensions.OpenTelemetry
using Ratatosk;

builder.Services
.AddMessaging()
.AddTwilioSmsConnector(options => { /* ... */ })
.WithOpenTelemetry();

.WithOpenTelemetry() internally calls AddOpenTelemetry().WithTracing().WithMetrics(), registers both the connector (Ratatosk.Connector.*) and client (Ratatosk.Client) sources, and manages the TracerProvider/MeterProvider lifecycle through the host.

Option 2 — Manual on TracerProviderBuilder / MeterProviderBuilder​

When you already have an OpenTelemetry setup and want to add Ratatosk sources:

using OpenTelemetry.Metrics;
using OpenTelemetry.Trace;
using Ratatosk;

builder.Services.AddOpenTelemetry()
.WithTracing(t => t
.AddRatatoskInstrumentation()
.AddConsoleExporter() // or any exporter
)
.WithMetrics(m => m
.AddRatatoskInstrumentation()
.AddConsoleExporter()
);

AddRatatoskInstrumentation() adds:

  • Ratatosk.Client — client-level ActivitySource and Meter
  • Ratatosk.Connector.* — all connector ActivitySources and Meters (wildcard matching, new connectors are picked up automatically)

Configuration​

Telemetry can be configured per connector without modifying its provider-specific options.

Via the connector builder​

services.AddMessaging()
.AddConnector<TwilioSmsConnector>("sms", cfg => cfg
.WithSettings("Twilio")
.WithTelemetry(t =>
{
t.EnableTracing = true;
t.EnableMetrics = true;
t.EnablePayloadSizeMetrics = false; // off by default
}));

Via ConnectionSettings​

var settings = new ConnectionSettings()
.SetParameter("Telemetry.EnableTracing", false)
.SetParameter("Telemetry.EnablePayloadSizeMetrics", true);

var connector = new TwilioSmsConnector(schema, settings);

TelemetryOptions reference​

PropertyDefaultDescription
EnableTracingtrueEmit Activity spans for connector operations
EnableMetricstrueRecord metric counters and histograms
EnablePayloadSizeMetricsfalseSerialize message to measure payload size (may impact throughput)

Client-level telemetry​

The IMessagingClient facade reads its telemetry configuration from MessagingClientOptions:

services.AddMessaging()
.AddClient(options =>
{
options.Telemetry.EnableTracing = true;
options.Telemetry.EnableMetrics = true;
});

ConnectionSettings keys​

All telemetry settings keys are available as constants in TelemetrySettingsKeys:

KeyConstantExpected value
Telemetry.EnableTracing.EnableTracingbool
Telemetry.EnableMetrics.EnableMetricsbool
Telemetry.EnablePayloadSizeMetrics.EnablePayloadSizeMetricsbool

Performance considerations​

  • Payload size metrics require serialising the message to JSON to measure byte count — this adds CPU and memory overhead per send. Disabled by default.
  • When telemetry is fully enabled, the overhead is limited to creating Activity objects and recording metric observations, both designed for high-throughput scenarios.
  • Each connector has its own ActivitySource and Meter — if no OpenTelemetry SDK is configured (no listeners attached), HasListeners() returns false and the activity creation is skipped entirely with negligible cost.

Viewing telemetry​

Once wired, traces and metrics flow to any OpenTelemetry-compatible backend:

# Console output during development
dotnet add package OpenTelemetry.Exporter.Console

builder.Services.AddOpenTelemetry()
.WithTracing(t => t
.AddRatatoskInstrumentation()
.AddConsoleExporter())
.WithMetrics(m => m
.AddRatatoskInstrumentation()
.AddConsoleExporter());

For production, configure an OTLP exporter:

dotnet add package OpenTelemetry.Exporter.OpenTelemetryProtocol
builder.Services.AddOpenTelemetry()
.WithTracing(t => t
.AddRatatoskInstrumentation()
.AddOtlpExporter())
.WithMetrics(m => m
.AddRatatoskInstrumentation()
.AddOtlpExporter());

Example: tracing a send operation​

Service A Twilio Connector
│ │
│ SendAsync(channel, message) │
│─────────────────────────────────▶ │
│ Span: "twilio_sms send" │
│ tags: │
│ messaging.system=ratatosk │
│ messaging.operation=send │
│ messaging.message.id=... │
│ ratatosk.connector.type= │
│ twilio_sms │
│ │
│ SendMessageCoreAsync() │
│ ─────────────────────────▶ │
│ ◀──────────────────────── │
│ │
│ counter: sent +1 │
│ histogram: send.duration │
│ │
│◀───────────────────────────────── │

Structured Logging​

ChannelConnectorBase automatically creates structured logging scopes:

// These scopes are active inside any connector method:
// Connector: {Provider}/{Type} → "Connector: Twilio/SMS"
// Message: {message.Id} → "Message: sms-123"

// Logging inside a connector:
Logger.LogInformation("Sending to {Receiver}", message.Receiver?.Address);

// Output with structured loggers (e.g., Serilog, Application Insights):
// [Connector: Twilio/SMS] [Message: sms-123] Sending to +15550002222

See also​