Skip to content

Commit 3613059

Browse files
feat(performance): Adds queues instrumentation for more platforms (#10242)
Adds custom queues instrumentation docs for java, go, and dotnet Co-authored-by: Alexander Dinauer <adinauer@users.noreply.github.com>
1 parent 01d8bfd commit 3613059

File tree

6 files changed

+368
-0
lines changed

6 files changed

+368
-0
lines changed
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
---
2+
title: Instrument Queues
3+
sidebar_order: 3000
4+
description: "Learn how to manually instrument your code to use Sentry's Queues module. "
5+
---
6+
Sentry comes with automatic instrumentation for the most common messaging queue systems. In case yours isn't supported, you can still instrument custom spans and transactions around your queue producers and consumers to ensure that you have performance data about your messaging queues.
7+
8+
## Producer Instrumentation
9+
10+
To start capturing performance metrics, use the `transaction.StartChild()` function to wrap your queue producer events. Your span `op` must be set to `queue.publish`. Include the following span data to enrich your producer spans with queue metrics:
11+
12+
| Data Attribute | Type | Description |
13+
|:--|:--|:--|
14+
| `messaging.message.id ` | string | The message identifier |
15+
| `messaging.destination.name` | string | The queue or topic name |
16+
| `messaging.message.body.size` | int | Size of the message body in bytes |
17+
18+
Your `queue.publish` span must exist inside a transaction in order to be recognized as a producer span. If you are using a supported framework, the transaction is created by the integration. If you are using plain Go, you can start a new one using `SentrySdk.StartTransaction()`.
19+
20+
You must also include trace headers in your message so that your consumers can continue your trace once your message is picked up.
21+
22+
23+
```csharp
24+
var connection = MyCustomQueue.Connect();
25+
26+
// The message you want to send to the queue
27+
var queue = "messages";
28+
var message = "Hello World!";
29+
var messageId = "abc123";
30+
var sentryTrace = SentrySdk.getTraceHeader()?.ToString();
31+
var baggage = SentrySdk.getBaggage()?.ToString();
32+
33+
// Create transaction
34+
var transaction = SentrySdk.StartTransaction(
35+
"queue_producer_transaction",
36+
"function"
37+
);
38+
39+
// Create the span
40+
var span = transaction.StartChild(
41+
"queue.publish",
42+
"queue_producer"
43+
);
44+
45+
// Set span data
46+
span.SetExtra("messaging.message.id", messageId);
47+
span.SetExtra("messaging.destination.name", queue);
48+
span.SetExtra("messaging.message.body.size", Encoding.UTF8.GetByteCount(message));
49+
50+
// Publish the message to the queue (including current time stamp)
51+
var now = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
52+
connection.Publish(
53+
queue,
54+
message,
55+
now,
56+
sentryTrace,
57+
baggage
58+
);
59+
60+
span.Finish();
61+
transaction.Finish();
62+
```
63+
64+
65+
## Consumer Instrumentation
66+
67+
To start capturing performance metrics, use the `transaction.StartChild()` function to wrap your queue consumers. Your span `op` must be set to `queue.process`. Include the following span data to enrich your consumer spans with queue metrics:
68+
69+
| Data Attribute | Type | Description |
70+
|:--|:--|:--|
71+
| `messaging.message.id ` | string | The message identifier |
72+
| `messaging.destination.name` | string | The queue or topic name |
73+
| `messaging.message.body.size` | number | Size of the message body in bytes |
74+
| `messaging.message.retry.count ` | number | The number of times a message was attempted to be processed |
75+
| `messaging.message.receive.latency ` | number | The time in milliseconds that a message awaited processing in queue |
76+
77+
Your `queue.process` span must exist inside a transaction in order to be recognized as a consumer span. If you are using a <PlatformLink to="/integrations/#web-frameworks">supported web framework</PlatformLink>, the transaction is created by the integration. If you use plain Python, you can start a new one using `SentrySdk.StartTransaction()`.
78+
79+
Use `SentrySdk.ContinueTrace()` to connect your consumer spans to their associated producer spans, and `span.SetExtra()` to mark the trace of your message as success or failed.
80+
81+
82+
```csharp
83+
var connection = MyCustomQueue.Connect();
84+
85+
// Pick up message from queues
86+
var queue = "messages";
87+
var message = connection.Consume(queue);
88+
89+
// Calculate latency (optional, but valuable)
90+
var now = DateTimeOffset.UtcNow;
91+
var messageTime = DateTimeOffset.FromUnixTimeSeconds(message["timestamp"]);
92+
var latency = now - messageTime;
93+
94+
var sentryTraceHeader = message["sentry-trace"];
95+
var sentryBaggageHeader = message["baggage"];
96+
97+
// Create transaction
98+
var transactionContext = SentrySdk.ContinueTrace(sentryTraceHeader, sentryBaggageHeader);
99+
var transaction = SentrySdk.StartTransaction(
100+
transactionContext,
101+
"queue_consumer_transaction",
102+
"function"
103+
);
104+
105+
// Create the span
106+
var span = transaction.StartChild(
107+
"queue.process",
108+
"queue_consumer"
109+
);
110+
111+
// Set span data
112+
span.SetExtra("messaging.message.id", message["message_id"]);
113+
span.SetExtra("messaging.destination.name", queue);
114+
span.SetExtra("messaging.message.body.size", Encoding.UTF8.GetByteCount(message["body"]));
115+
span.SetExtra("messaging.message.receive.latency", latency.TotalMilliseconds);
116+
span.SetExtra("messaging.message.retry.count", 0);
117+
118+
try
119+
{
120+
// Process the message
121+
ProcessMessage(message);
122+
}
123+
catch (Exception)
124+
{
125+
// In case of an error set the status to "internal_error"
126+
span.Status = SpanStatus.InternalError;
127+
}
128+
129+
span.Finish();
130+
transaction.Finish();
131+
```
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
---
2+
title: Instrument Queues
3+
sidebar_order: 3000
4+
description: "Learn how to manually instrument your code to use Sentry's Queues module. "
5+
---
6+
Sentry comes with automatic instrumentation for the most common messaging queue systems. In case yours isn't supported, you can still instrument custom spans and transactions around your queue producers and consumers to ensure that you have performance data about your messaging queues.
7+
8+
## Producer Instrumentation
9+
10+
To start capturing performance metrics, use the `StartSpan()` function to wrap your queue producer events. Your span `op` must be set to `queue.publish`. Include the following span data to enrich your producer spans with queue metrics:
11+
12+
| Data Attribute | Type | Description |
13+
|:--|:--|:--|
14+
| `messaging.message.id ` | string | The message identifier |
15+
| `messaging.destination.name` | string | The queue or topic name |
16+
| `messaging.message.body.size` | int | Size of the message body in bytes |
17+
18+
Your `queue.publish` span must exist inside a transaction in order to be recognized as a producer span. If you are using a supported framework, the transaction is created by the integration. If you are using plain Go, you can start a new one using `sentry.StartTransaction()`.
19+
20+
You must also include trace headers in your message so that your consumers can continue your trace once your message is picked up.
21+
22+
23+
```go
24+
connection := my_custom_queue.Connect()
25+
26+
// The message you want to send to the queue
27+
queue := "messages"
28+
message := "Hello World!"
29+
messageId := "abc123"
30+
31+
// Create transaction
32+
transaction := sentry.StartTransaction(
33+
ctx,
34+
"queue_producer_transaction,
35+
options...,
36+
)
37+
defer transaction.Finish()
38+
39+
// Create the span
40+
span := transaction.StartSpan(ctx, "queue.publish")
41+
span.Description = "queue_producer";
42+
defer span.Finish()
43+
44+
// Set span data
45+
span.SetData("messaging.message.id", messageId)
46+
span.SetData("messaging.destination.name", queue)
47+
span.SetData("messaging.message.body.size", utf8.RuneCountInString(message))
48+
49+
// Publish the message to the queue (including current time stamp)
50+
now := time.Now().Unix()
51+
connection.Publish(queue, message, now)
52+
```
53+
54+
55+
## Consumer Instrumentation
56+
57+
To start capturing performance metrics, use the `startChild()` function to wrap your queue consumers. Your span `op` must be set to `queue.process`. Include the following span data to enrich your consumer spans with queue metrics:
58+
59+
| Data Attribute | Type | Description |
60+
|:--|:--|:--|
61+
| `messaging.message.id ` | string | The message identifier |
62+
| `messaging.destination.name` | string | The queue or topic name |
63+
| `messaging.message.body.size` | number | Size of the message body in bytes |
64+
| `messaging.message.retry.count ` | number | The number of times a message was attempted to be processed |
65+
| `messaging.message.receive.latency ` | number | The time in milliseconds that a message awaited processing in queue |
66+
67+
Your `queue.process` span must exist inside a transaction in order to be recognized as a consumer span. If you are using a supported framework, the transaction is created by the integration. If you are using plain Go, you can start a new one using `sentry.StartTransaction()`.
68+
69+
Use `Sentry.StartTransaction()` to connect your consumer spans to their associated producer spans, and set the span `Status` to mark the trace of your message as success or failed.
70+
71+
72+
```go
73+
connection := my_custom_queue.Connect()
74+
75+
// Pick up message from queues
76+
queue := "messages"
77+
message := connection.Consume(queue)
78+
79+
// Calculate latency (optional, but valuable)
80+
now := time.Now()
81+
messageTime := time.Unix(message["timestamp"].(int64), 0)
82+
latency := now.Sub(messageTime)
83+
84+
// Create transaction
85+
transaction := sentry.StartTransaction(
86+
ctx, // Continue the trace from the message
87+
"queue_consumer_transaction",
88+
options...,
89+
)
90+
defer transaction.Finish()
91+
92+
// Create the span
93+
span := transaction.StartSpan(ctx, "queue.process")
94+
span.Description = "queue_consumer";
95+
defer span.Finish()
96+
97+
// Set span data
98+
span.SetData("messaging.message.id", message["message_id"])
99+
span.SetData("messaging.destination.name", queue)
100+
span.SetData("messaging.message.body.size", len(message["body"].(string)))
101+
span.SetData("messaging.message.receive.latency", latency)
102+
span.SetData("messaging.message.retry.count", 0)
103+
104+
// Process the message
105+
err = processMessage(message)
106+
if err != nil {
107+
// In case of an error set the status to "internal_error"
108+
span.Status = sentry.SpanStatusInternalError
109+
}
110+
```
Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
---
2+
title: Instrument Queues
3+
sidebar_order: 3000
4+
description: "Learn how to manually instrument your code to use Sentry's Queues module. "
5+
---
6+
Sentry comes with automatic instrumentation for the most common messaging queue systems. In case yours isn't supported, you can still instrument custom spans and transactions around your queue producers and consumers to ensure that you have performance data about your messaging queues.
7+
8+
## Producer Instrumentation
9+
10+
To start capturing performance metrics, use the `startChild()` function to wrap your queue producer events. Your span `op` must be set to `queue.publish`. Include the following span data to enrich your producer spans with queue metrics:
11+
12+
| Data Attribute | Type | Description |
13+
|:--|:--|:--|
14+
| `messaging.message.id ` | string | The message identifier |
15+
| `messaging.destination.name` | string | The queue or topic name |
16+
| `messaging.message.body.size` | int | Size of the message body in bytes |
17+
18+
Your `queue.publish` span must exist inside a transaction in order to be recognized as a producer span. If you are using a supported framework, the transaction is created by the integration. If you are using plain Java, you can start a new one using `Sentry.startTransaction()`.
19+
20+
You must also include trace headers in your message so that your consumers can continue your trace once your message is picked up.
21+
22+
23+
```java
24+
MyCustomQueue connection = MyCustomQueue.connect();
25+
26+
// The message you want to send to the queue
27+
String queue = "messages";
28+
String message = "Hello World!";
29+
String messageId = "abc123";
30+
31+
// Create transaction
32+
ITransaction transaction = Sentry.startTransaction("queue_producer_transaction", "function");
33+
34+
try {
35+
final SentryTraceHeader traceparent = Sentry.getTraceparent();
36+
final BaggageHeader baggage = Sentry.getBaggage();
37+
38+
ISpan span = transaction.startChild("queue.publish", "queue_producer");
39+
try {
40+
// Set span data
41+
span.setData("messaging.message.id", messageId);
42+
span.setData("messaging.destination.name", queue);
43+
span.setData("messaging.message.body.size", message.getBytes(StandardCharsets.UTF_8).length);
44+
45+
// Publish the message to the queue (including current time stamp)
46+
long now = Instant.now().getEpochSecond();
47+
48+
connection.publish(queue, message, now, traceparent, baggage);
49+
} catch (Exception e) {
50+
span.setThrowable(e);
51+
span.setStatus(SpanStatus.INTERNAL_ERROR);
52+
throw e;
53+
} finally {
54+
span.finish();
55+
}
56+
} catch (Exception e) {
57+
transaction.setThrowable(e);
58+
transaction.setStatus(SpanStatus.INTERNAL_ERROR);
59+
throw e;
60+
} finally {
61+
transaction.finish();
62+
}
63+
```
64+
65+
66+
## Consumer Instrumentation
67+
68+
To start capturing performance metrics, use the `startChild()` function to wrap your queue consumers. Your span `op` must be set to `queue.process`. Include the following span data to enrich your consumer spans with queue metrics:
69+
70+
| Data Attribute | Type | Description |
71+
|:--|:--|:--|
72+
| `messaging.message.id ` | string | The message identifier |
73+
| `messaging.destination.name` | string | The queue or topic name |
74+
| `messaging.message.body.size` | number | Size of the message body in bytes |
75+
| `messaging.message.retry.count ` | number | The number of times a message was attempted to be processed |
76+
| `messaging.message.receive.latency ` | number | The time in milliseconds that a message awaited processing in queue |
77+
78+
Your `queue.process` span must exist inside a transaction in order to be recognized as a consumer span. If you are using a supported framework, the transaction is created by the integration. If you are using plain Java, you can start a new one using `Sentry.startTransaction()`.
79+
80+
Use `Sentry.continueTrace()` to connect your consumer spans to their associated producer spans, and `setStatus()` to mark the trace of your message as success or failed.
81+
82+
83+
```java
84+
MyCustomQueue connection = MyCustomQueue.connect();
85+
86+
// Pick up message from queues
87+
String queue = "messages";
88+
Message message = connection.consume(queue);
89+
90+
// Calculate latency (optional, but valuable)
91+
Instant now = Instant.now();
92+
Instant messageTime = Instant.ofEpochSecond(message.getTimestamp());
93+
Duration latency = Duration.between(messageTime, now);
94+
95+
// Create transaction
96+
final TransactionContext transactionContext = Sentry.continueTrace(sentryTraceHeader, baggageHeader);
97+
ITransaction transaction = Sentry.startTransaction(transactionContext, "queue_consumer_transaction", "function");
98+
99+
try {
100+
ISpan span = transaction.startChild("queue.process", "queue_consumer")
101+
102+
try {
103+
// Set span data
104+
span.setData("messaging.message.id", message.getMessageId());
105+
span.setData("messaging.destination.name", queue);
106+
//
107+
span.setData("messaging.message.body.size", message.getBody().getBytes(StandardCharsets.UTF_8).length);
108+
span.setData("messaging.message.receive.latency", latency.toMillis());
109+
span.setData("messaging.message.retry.count", 0);
110+
111+
// Process the message
112+
processMessage(message);
113+
} catch (Exception e) {
114+
span.setThrowable(e);
115+
span.setStatus(SpanStatus.INTERNAL_ERROR);
116+
throw e;
117+
} finally {
118+
span.finish();
119+
}
120+
} catch (Exception e) {
121+
transaction.setThrowable(e);
122+
transaction.setStatus(SpanStatus.INTERNAL_ERROR);
123+
throw e;
124+
} finally {
125+
transaction.finish();
126+
}
127+
```

0 commit comments

Comments
 (0)