Skip to content

Commit 9205185

Browse files
feat(ruby): Add queues, caches and requests modules (#10245)
* feat(ruby): Add queues, caches and requests modules * Update docs/platforms/ruby/common/performance/instrumentation/custom-instrumentation/caches-module.mdx Co-authored-by: Anton Pirker <anton.pirker@sentry.io> --------- Co-authored-by: Anton Pirker <anton.pirker@sentry.io>
1 parent 47b1413 commit 9205185

File tree

9 files changed

+240
-12
lines changed

9 files changed

+240
-12
lines changed
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
---
2+
title: Instrument Caches
3+
sidebar_order: 1000
4+
description: "Learn how to manually instrument your code to use Sentry's Caches module. "
5+
---
6+
A cache can be used to speed up data retrieval, thereby improving application performance. Because instead of getting data from a potentially slow data layer, your application will be getting data from memory (in a best case scenario). Caching can speed up read-heavy workloads for applications like Q&A portals, gaming, media sharing, and social networking.
7+
8+
Sentry offers a [cache-monitoring dashboard](https://sentry.io/orgredirect/organizations/:orgslug/insights/caches/) for getting an overview of your application's caches.
9+
10+
To make it possible for Sentry to give you an overview of your cache performance, you'll need to create two spans - one indicating that something is being put into the cache, and a second one indicating that something is being fetched from the cache.
11+
12+
Make sure that there's a transaction running when you create the spans. If you're using a web framework like Rails those transactions will be created for you automatically. See <PlatformLink to='/performance/'>Performance Monitoring</PlatformLink> for more information.
13+
14+
For detailed information about which data can be set, see the [Cache Module Developer Specification](https://develop.sentry.dev/sdk/performance/modules/caches/).
15+
16+
## Manual Instrumentation
17+
18+
Follow the steps below to make sure your Cache related spans end up in Sentry correctly.
19+
20+
### Add Span When Putting Data Into the Cache
21+
22+
1. Set the cache value with whatever cache library you happen to be using.
23+
2. Wrap the part of your application that uses the cached value with `Sentry.with_child_span { |span| ... }`
24+
3. Set `op` to `cache.put`.
25+
4. Set `cache.item_size` to an integer representing the size of the cached item.
26+
27+
(The steps described above are documented in the snippet.)
28+
29+
```ruby
30+
key = 'myCacheKey123'
31+
value = 'The value I want to cache.'
32+
33+
Sentry.with_child_span(op: 'cache.put') do |span|
34+
# Set a key in your cache using your custom caching solution
35+
my_cache.set(key, value)
36+
37+
# Describe the cache server you are accessing
38+
span.set_data('network.peer.address', 'cache.example.com/supercache')
39+
span.set_data('network.peer.port', 9000)
40+
41+
# Add the key you want to set
42+
span.set_data('cache.key', key)
43+
44+
# Add the size of the value you stored in the cache
45+
span.set_data('cache.item_size', value.size) # Warning: if value is very big this could use lots of memory
46+
end
47+
```
48+
49+
50+
### Add Span When Retrieving Data From the Cache
51+
52+
1. Fetch the cached value from whatever cache library you happen to be using.
53+
2. Wrap the part of your application that uses the cached value with `Sentry.with_child_span { |span| ... }`
54+
3. Set `op` to `cache.get`.
55+
4. Set `cache.hit` to a boolean value representing whether the value was successfully fetched from the cache or not.
56+
5. Set `cache.item_size` to an integer representing the size of the cached item.
57+
58+
(The steps described above are documented in the snippet.)
59+
60+
```ruby
61+
key = 'myCacheKey123'
62+
value = nil
63+
64+
Sentry.with_child_span(op: 'cache.get') do |span|
65+
# Get a key from your caching solution
66+
value = my_cache.get(key)
67+
68+
# Describe the cache server you are accessing
69+
span.set_data('network.peer.address', 'cache.example.com/supercache')
70+
span.set_data('network.peer.port', 9000)
71+
72+
# Add the key you just retrieved from the cache
73+
span.set_data('cache.key', key)
74+
75+
if value
76+
# If you retrieved a value, the cache was hit
77+
span.set_data('cache.hit', True)
78+
79+
# Optionally also add the size of the value you retrieved
80+
span.set_data('cache.item_size', value.size)
81+
else
82+
# If you could not retrieve a value, it was a miss
83+
span.set_data('cache.hit', False)
84+
end
85+
end
86+
```
87+
88+
You should now have the right spans in place. Head over to the [Cache dashboard](https://sentry.io/orgredirect/organizations/:orgslug/performance/caches/) to see how your cache is performing.
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
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 `Sentry.with_child_span` 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+
Make sure that there's a transaction running when you create the spans. If you're using a web framework like Rails those transactions will be created for you automatically. See <PlatformLink to='/performance/'>Performance Monitoring</PlatformLink> for more information.
19+
20+
You must also include the trace propagation headers (`sentry-trace` and `baggage`) using the `Sentry.get_trace_propagation_headers` helper in your message so that your consumers can continue your trace once your message is picked up.
21+
22+
```ruby
23+
connection = my_custom_queue.connect
24+
25+
# The message you want to send to the queue
26+
queue = 'messages'
27+
message = 'Hello World!'
28+
message_id = 'abc123'
29+
30+
Sentry.with_child_span(op: 'queue.publish', description: 'queue_producer') do |span|
31+
# Set span data
32+
span.set_data('messaging.message.id', message_id)
33+
span.set_data('messaging.destination.name', queue)
34+
span.set_data('messaging.message.body.size', message.size)
35+
36+
# Publish the message to the queue (including trace information and current timestamp)
37+
connection.publish(
38+
queue: queue,
39+
body: message,
40+
timestamp: Time.now.utc,
41+
headers: Sentry.get_trace_propagation_headers
42+
)
43+
end
44+
```
45+
46+
## Consumer Instrumentation
47+
48+
To start capturing performance metrics, use the `Sentry.with_child_span` 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:
49+
50+
| Data Attribute | Type | Description |
51+
|:--|:--|:--|
52+
| `messaging.message.id ` | string | The message identifier |
53+
| `messaging.destination.name` | string | The queue or topic name |
54+
| `messaging.message.body.size` | number | Size of the message body in bytes |
55+
| `messaging.message.retry.count ` | number | The number of times a message was attempted to be processed |
56+
| `messaging.message.receive.latency ` | number | The time in milliseconds that a message awaited processing in queue |
57+
58+
Use `Sentry.continue_trace(trace_propagation_headers)` to start a transaction and connect your consumer spans to their associated producer spans, and `span.set_status` to mark the trace of your message as success or failed.
59+
60+
```ruby
61+
connection = my_custom_queue.connect
62+
63+
# Pick up message from queues
64+
queue = 'messages'
65+
message = connection.consume(queue: queue)
66+
67+
# Calculate latency (optional, but valuable)
68+
now = Time.now.utc
69+
message_time = Time.new(message[:timestamp])
70+
latency = now - message_time
71+
72+
# Continue the trace started in the producer and start a transaction
73+
transaction = sentry_sdk.continue_trace(message[:headers], op: 'function', name: 'queue_consumer_transaction')
74+
Sentry.start_transaction(transaction)
75+
Sentry.get_current_scope.set_span(transaction)
76+
77+
# Start the queue.process span
78+
Sentry.with_child_span(op: 'queue.process', description: 'queue_consumer') do |span|
79+
# Set span data
80+
span.set_data('messaging.message.id', message[:message_id])
81+
span.set_data('messaging.destination.name', queue)
82+
span.set_data('messaging.message.body.size', message[:body].size)
83+
span.set_data('messaging.message.receive.latency', latency)
84+
span.set_data('messaging.message.retry.count', 0)
85+
86+
process_message(message)
87+
rescue
88+
# In case of an error set the status to 'internal_error'
89+
span.set_status('internal_error')
90+
end
91+
```
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
---
2+
title: Instrument HTTP Requests
3+
sidebar_order: 2000
4+
description: "Learn how to manually instrument your code to use Sentry's Requests module."
5+
---
6+
7+
As a prerequisite to setting up [Requests](/product/performance/requests/), you’ll need to first <PlatformLink to='/performance/'>set up performance monitoring</PlatformLink>. Once this is done, the Ruby SDK will automatically instrument outgoing HTTP requests made via `Net::HTTP`. If that doesn't fit your use case, you can set up using [custom instrumentation](#custom-instrumentation).
8+
9+
## Custom Instrumentation
10+
11+
For detailed information about which data can be set, see the [Requests Module developer specifications](https://develop.sentry.dev/sdk/performance/modules/requests/).
12+
13+
### Wrap HTTP Requests in a Span
14+
15+
NOTE: Refer to [HTTP Span Data Conventions](https://develop.sentry.dev/sdk/performance/span-data-conventions/#http) for a full list of the span data attributes.
16+
17+
Here is an example of an instrumented function that makes HTTP requests:
18+
19+
```ruby
20+
require 'uri'
21+
22+
def make_request(method, url)
23+
Sentry.with_child_span(op: 'http.client', description: "#{method} #{url}") do |span|
24+
span.set_data('http.request.method', method)
25+
26+
parsed_url = URI.parse(url)
27+
span.set_data('url', url)
28+
span.set_data('server.address', parsed_url.hostname)
29+
span.set_data('server.port', parsed_url.port)
30+
31+
# make your custom HTTP request
32+
response = do_request(method: method, url: url)
33+
34+
span.set_data('http.response.status_code', response.status_code)
35+
span.set_data('http.response_content_length', response.headers['content-length'])
36+
37+
response
38+
end
39+
end
40+
```

docs/product/performance/caches/index.mdx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,5 +37,10 @@ If available, custom instrumentation is documented on an environment-by-environm
3737

3838
- [Python SDK](/platforms/python/performance/instrumentation/custom-instrumentation/caches-module/)
3939
- [JavaScript SDKs](/platforms/javascript/guides/node/performance/instrumentation/custom-instrumentation/caches-module/)
40+
- [Laravel SDK](/platforms/php/guides/laravel/performance/instrumentation/custom-instrumentation/)
41+
- [Java SDK](/platforms/java/performance/instrumentation/custom-instrumentation/)
42+
- [Ruby SDK](/platforms/ruby/performance/instrumentation/custom-instrumentation/caches-module/)
43+
- [.NET SDK](/platforms/dotnet/performance/instrumentation/custom-instrumentation/)
44+
- [Symfony SDK](/platforms/php/guides/symfony/performance/instrumentation/custom-instrumentation/)
4045

4146
To see what cache data can be set on spans, see the [Cache Module Developer Specification](https://develop.sentry.dev/sdk/performance/modules/caches/).

docs/product/performance/queue-monitoring/index.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,6 @@ Instructions for custom instrumentation in various languages are linked to below
3737
- [JavaScript SDK](/platforms/javascript/guides/node/performance/instrumentation/custom-instrumentation/queues-module/)
3838
- [Laravel SDK](/platforms/php/guides/laravel/performance/instrumentation/custom-instrumentation/)
3939
- [Java SDK](/platforms/java/distributed-tracing/custom-instrumentation/)
40-
- [Ruby SDK](/platforms/ruby/)
40+
- [Ruby SDK](/platforms/ruby/performance/instrumentation/custom-instrumentation/queues-module/)
4141
- [.NET SDK](/platforms/dotnet/distributed-tracing/custom-instrumentation/)
4242
- [Symfony SDK](/platforms/php/guides/symfony/distributed-tracing/custom-instrumentation/)

platform-includes/performance/add-spans-example/ruby.mdx

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,23 @@
11
## Add More Spans to the Transaction
22

3-
The next example contains the implementation of the hypothetical `process_item` function called from the code snippet in the previous section. Our SDK can determine if there is currently an open transaction and add all newly created spans as child operations to that transaction. Keep in mind that each individual span also needs to be manually finished; otherwise, spans will not show up in the transaction. When using spans and transactions as context managers, they are automatically finished at the end of the `with` block.
4-
5-
You can choose the values of `op` and `description`.
3+
The next example contains the implementation of the hypothetical `process_item` function called from the code snippet in the previous section. Our SDK can determine if there is currently an open transaction and add all newly created spans as child operations to that transaction. You can choose the values of `op` and `description`.
64

75
```ruby
86
class OrdersController < ApplicationController
97
def create
108
order = Order.new
119

12-
Sentry.with_child_span(op: :process_items, description: "") do |span|
13-
span.set_data(:key, "value")
10+
Sentry.with_child_span(op: :process_items, description: 'processing items') do |span|
11+
span.set_data(:key, 'value')
1412

1513
order.process_items(params)
1614
end
17-
end
15+
end # the child span ends with the block
1816
end
1917
```
2018

2119
Your new span will be nested under whichever span is currently
22-
running, otherwise it will be at the root of the transaction event.
20+
running on the scope, otherwise it will be at the root of the transaction event.
2321

2422
Alternatively, you can manually grab the current transaction and use
2523
its `with_child_span` method to always create a top-level span.
@@ -29,8 +27,9 @@ class OrdersController < ApplicationController
2927
def create
3028
order = Order.new
3129
transaction = Sentry.get_current_scope.get_transaction
32-
transaction.with_child_span(op: :process_items, description: "process order's items") do |span|
33-
span.set_data(:key, "value")
30+
31+
transaction.with_child_span(op: :process_items, description: 'processing items') do |span|
32+
span.set_data(:key, 'value')
3433
order.process_items(params)
3534
end # the child span ends with the block
3635
end

platform-includes/performance/enable-manual-instrumentation/ruby.mdx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,13 @@ The following example creates a transaction for a scope that contains an expensi
66
# start a transaction
77
transaction = Sentry.start_transaction(op: "process_item")
88

9+
# set the transaction on the scope so children span are attached to this transaction
10+
Sentry.get_current_scope.set_span(transaction)
11+
912
# perform the operation
1013
process_item(args)
1114

15+
1216
# finish the transaction, which will send it to Sentry automatically
1317
transaction.finish
1418
```

platform-includes/performance/retrieve-transaction/ruby.mdx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,11 @@
33
In cases where you want to attach Spans to an already ongoing Transaction you can use `Sentry.get_current_scope.get_transaction`. This property will return a `Transaction` in case there is a running Transaction otherwise it returns `nil`.
44

55
```ruby
6-
transaction = Sentry.get_current_scope.get_transaction || Sentry.start_transaction(name: "task")
6+
transaction = Sentry.get_current_scope.get_transaction || Sentry.start_transaction(name: 'task')
77

8-
span = transaction.start_child(op: "operation")
8+
span = transaction.start_child(op: 'operation')
99
# perform the operation
10+
span.finish
1011
```
1112

1213
## Retrieve the Current Span

0 commit comments

Comments
 (0)