traces 0.18.0 → 0.18.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b0ef616a2189f63b63abe00e1dc84c0d13b48dc0099c90b4c5aa5ea420ea92fa
4
- data.tar.gz: 310a045915e9831698ca681c61d53a6175a00a9b34e44e4d9b92ff8b6917dc51
3
+ metadata.gz: 53f12f0b9d29fc4be9a9e701a4946bdf3ad74c226e3ba6059fccab724625c02d
4
+ data.tar.gz: 02b432f57ec9f3b2ddd2c0b793d490db2e5c4be827baeb63bee26c6e1d0a19ed
5
5
  SHA512:
6
- metadata.gz: 3d5ab804b31b9440fd4cc36af5dfb9bd553d370681417f6441e86bcaeed6a41e7b02eff4f771144fac8f3fa528930bb457a7b60b902c2fe40b26e26ea901eb1e
7
- data.tar.gz: 35918ff43dfac6158cb42dea57942a491b58ed906d67a5de03bd0bfffaa3cbda7e4ade3edd2e3c0ce1774a2c9e8caede58c8cb97b5bcf5c2cd5a1d921dc4d7d9
6
+ metadata.gz: 36710faff7e4ba0a5f22318d5e74304d92ccd8f82761f89fc7c75608bbbba81e7a221996195c1eda59f37c569a3f0ed0fb6c54fd0bdd9088c01508fce0a4ab8f
7
+ data.tar.gz: ee106e0da529d689f268c4a92f8bc7dacfb2103fb13f15d55577c826c6ae07b495c85fd47ea67812179437074f82f0bac4affc1f836aa75e402c053295e6c550
checksums.yaml.gz.sig CHANGED
Binary file
@@ -0,0 +1,39 @@
1
+ # Capture
2
+
3
+ This guide explains how to use `traces` for exporting traces from your application. This can be used to document all possible traces.
4
+
5
+ ## With Test Suite
6
+
7
+ If your application defines one or more traces and emits them as part of a test suite, you can export them using the `bake traces:capture` command.
8
+
9
+ ```bash
10
+ $ cd test/traces/backend/.capture/
11
+ $ bake traces:capture run traces:capture:list output --format json
12
+ [
13
+ {
14
+ "name": "my_trace",
15
+ "attributes": {
16
+ "foo": "baz"
17
+ },
18
+ "context": {
19
+ "trace_id": "038d110379a499a8ebcfb2b77cd69e1a",
20
+ "parent_id": "bf134b25de4f4a82",
21
+ "flags": 0,
22
+ "state": null,
23
+ "remote": false
24
+ }
25
+ },
26
+ {
27
+ "name": "nested",
28
+ "attributes": {
29
+ },
30
+ "context": {
31
+ "trace_id": "038d110379a499a8ebcfb2b77cd69e1a",
32
+ "parent_id": "2dd5510eb8fffc5f",
33
+ "flags": 0,
34
+ "state": null,
35
+ "remote": false
36
+ }
37
+ }
38
+ ]
39
+ ```
@@ -0,0 +1,212 @@
1
+ # Context Propagation
2
+
3
+ This guide explains how to propagate trace context between different execution contexts within your application using `Traces.current_context` and `Traces.with_context`.
4
+
5
+ ## Overview
6
+
7
+ The `traces` library provides two complementary approaches for managing trace context:
8
+
9
+ - **Local context propagation** (`Traces.current_context` / `Traces.with_context`): For passing context between execution contexts within the same process (threads, fibers, async tasks).
10
+ - **Distributed context propagation** (`Traces.inject` / `Traces.extract`): For transmitting context across process and service boundaries via serialization (HTTP headers, message metadata, etc.).
11
+
12
+ There is a legacy interface `Traces.trace_context` and `Traces.trace_context=` but you should prefer to use the new methods outlined above.
13
+
14
+ ## Local Context Propagation
15
+
16
+ Local context propagation involves passing trace context between different execution contexts within the same process. This is essential for maintaining trace continuity when code execution moves between threads, fibers, async tasks, or other concurrent execution contexts. Unlike distributed propagation which requires serialization over network boundaries, local propagation uses Context objects directly.
17
+
18
+ ### Capturing the Current Context
19
+
20
+ Use `Traces.current_context` to capture the current trace context as a Context object:
21
+
22
+ ~~~ ruby
23
+ current_context = Traces.current_context
24
+ # Returns a Traces::Context object or nil if no active trace
25
+ ~~~
26
+
27
+ ### Using the Context
28
+
29
+ Use `Traces.with_context(context)` to execute code within a specific trace context:
30
+
31
+ ~~~ ruby
32
+ # With block (automatic restoration):
33
+ Traces.with_context(context) do
34
+ # Code runs with the specified context.
35
+ end
36
+
37
+ # Without block (permanent switch):
38
+ Traces.with_context(context)
39
+ # Context remains active.
40
+ ~~~
41
+
42
+ ### Use Cases
43
+
44
+ #### Thread-Safe Context Propagation
45
+
46
+ When spawning background threads, you often want them to inherit the current trace context:
47
+
48
+ ~~~ ruby
49
+ require 'traces'
50
+
51
+ # Main thread has active tracing
52
+ Traces.trace("main_operation") do
53
+ # Capture current context before spawning thread:
54
+ current_context = Traces.current_context
55
+
56
+ # Spawn background thread:
57
+ Thread.new do
58
+ # Restore context in the new thread:
59
+ Traces.with_context(current_context) do
60
+ # This thread now has the same trace context as main thread:
61
+ Traces.trace("background_work") do
62
+ perform_heavy_computation
63
+ end
64
+ end
65
+ end.join
66
+ end
67
+ ~~~
68
+
69
+ #### Fiber-Based Async Operations
70
+
71
+ For fiber-based concurrency (like in async frameworks), context propagation ensures trace continuity:
72
+
73
+ ~~~ ruby
74
+ require 'traces'
75
+
76
+ Traces.trace("main_operation") do
77
+ current_context = Traces.current_context
78
+
79
+ # Create fiber for async work:
80
+ fiber = Fiber.new do
81
+ Traces.with_context(current_context) do
82
+ # Fiber inherits the trace context:
83
+ Traces.trace("fiber_work") do
84
+ perform_async_operation
85
+ end
86
+ end
87
+ end
88
+
89
+ fiber.resume
90
+ end
91
+ ~~~
92
+
93
+ ### Context Propagation vs. New Spans
94
+
95
+ Remember that context propagation maintains the same trace, while `trace()` creates new spans:
96
+
97
+ ~~~ ruby
98
+ Traces.trace("parent") do
99
+ context = Traces.current_context
100
+
101
+ Thread.new do
102
+ # This maintains the same trace context:
103
+ Traces.with_context(context) do
104
+ # This creates a NEW span within the same trace:
105
+ Traces.trace("child") do
106
+ # Child span, same trace as parent
107
+ end
108
+ end
109
+ end
110
+ end
111
+ ~~~
112
+
113
+ ## Distributed Context Propagation
114
+
115
+ Distributed context propagation involves transmitting trace context across process and service boundaries. Unlike local propagation which works within a single process, distributed propagation requires serializing context data and transmitting it over network protocols.
116
+
117
+ ### Injecting Context into Headers
118
+
119
+ Use `Traces.inject(headers, context = nil)` to add W3C Trace Context headers to a headers hash for transmission over network boundaries:
120
+
121
+ ~~~ ruby
122
+ require 'traces'
123
+
124
+ # Capture current context:
125
+ context = Traces.current_context
126
+ headers = {'Content-Type' => 'application/json'}
127
+
128
+ # Inject trace headers:
129
+ Traces.inject(headers, context)
130
+ # headers now contains: {'Content-Type' => '...', 'traceparent' => '00-...'}
131
+
132
+ # Or use current context by default:
133
+ Traces.inject(headers) # Uses current trace context
134
+ ~~~
135
+
136
+ ### Extracting Context from Headers
137
+
138
+ Use `Traces.extract(headers)` to extract trace context from W3C headers received over the network:
139
+
140
+ ~~~ ruby
141
+ # Receive headers from incoming request:
142
+ incoming_headers = request.headers
143
+
144
+ # Extract context:
145
+ context = Traces.extract(incoming_headers)
146
+ # Returns a Traces::Context object or nil if no valid context
147
+
148
+ # Use the extracted context:
149
+ if context
150
+ Traces.with_context(context) do
151
+ # Process request with distributed trace context
152
+ end
153
+ end
154
+ ~~~
155
+
156
+ ### Use Cases
157
+
158
+ #### Outgoing HTTP Requests
159
+
160
+ ~~~ ruby
161
+ require 'traces'
162
+
163
+ class ApiClient
164
+ def make_request(endpoint, data)
165
+ Traces.trace("api_request", attributes: {endpoint: endpoint}) do
166
+ headers = {
167
+ 'content-type' => 'application/json'
168
+ }
169
+
170
+ # Add trace context to outgoing request:
171
+ Traces.inject(headers)
172
+
173
+ http_client.post(endpoint,
174
+ body: data.to_json,
175
+ headers: headers
176
+ )
177
+ end
178
+ end
179
+ end
180
+ ~~~
181
+
182
+ #### Incoming HTTP Requests
183
+
184
+ ~~~ ruby
185
+ require 'traces'
186
+
187
+ class WebController
188
+ def handle_request(request)
189
+ # Extract trace context from incoming headers:
190
+ context = Traces.extract(request.headers)
191
+
192
+ # Process request with inherited context:
193
+ if context
194
+ Traces.with_context(context) do
195
+ Traces.trace("web_request", attributes: {
196
+ path: request.path,
197
+ method: request.method
198
+ }) do
199
+ process_business_logic
200
+ end
201
+ end
202
+ else
203
+ Traces.trace("web_request", attributes: {
204
+ path: request.path,
205
+ method: request.method
206
+ }) do
207
+ process_business_logic
208
+ end
209
+ end
210
+ end
211
+ end
212
+ ~~~
@@ -0,0 +1,126 @@
1
+ # Getting Started
2
+
3
+ This guide explains how to use `traces` for tracing code execution.
4
+
5
+ ## Installation
6
+
7
+ Add the gem to your project:
8
+
9
+ ~~~ bash
10
+ $ bundle add traces
11
+ ~~~
12
+
13
+ ## Core Concepts
14
+
15
+ `traces` has several core concepts:
16
+
17
+ - A {ruby Traces::Provider} which implements custom logic for wrapping existing code in traces.
18
+ - A {ruby Traces::Context} which represents the current tracing environment which can include distributed tracing.
19
+ - A {ruby Traces::Backend} which connects traces to a specific backend system for processing.
20
+
21
+ ## Usage
22
+
23
+ There are two main aspects to integrating within this gem.
24
+
25
+ 1. Libraries and applications must provide traces.
26
+ 2. Those traces must be consumed or emitted somewhere.
27
+
28
+ ### Providing Traces
29
+
30
+ Adding tracing to libraries requires the use of {ruby Traces::Provider}:
31
+
32
+ ~~~ ruby
33
+ require 'traces'
34
+
35
+ class MyClass
36
+ def my_method
37
+ puts "Hello World"
38
+ end
39
+ end
40
+
41
+ # If tracing is disabled, this is a no-op.
42
+ Traces::Provider(MyClass) do
43
+ def my_method
44
+ attributes = {
45
+ 'foo' => 'bar'
46
+ }
47
+
48
+ Traces.trace('my_method', attributes: attributes) do
49
+ super
50
+ end
51
+ end
52
+ end
53
+
54
+ MyClass.new.my_method
55
+ ~~~
56
+
57
+ This code by itself will not create any traces. In order to execute it and output traces, you must set up a backend to consume them.
58
+
59
+ In addition, to trace class methods:
60
+
61
+ ~~~ ruby
62
+ require 'traces'
63
+
64
+ class MyClass
65
+ def self.my_method
66
+ puts "Hello World"
67
+ end
68
+ end
69
+
70
+ # If tracing is disabled, this is a no-op.
71
+ Traces::Provider(MyClass.singleton_class) do
72
+ def my_method
73
+ attributes = {
74
+ 'foo' => 'bar'
75
+ }
76
+
77
+ Traces.trace('my_method', attributes: attributes) do
78
+ super
79
+ end
80
+ end
81
+ end
82
+
83
+ MyClass.my_method
84
+ ~~~
85
+
86
+ ### Consuming Traces
87
+
88
+ Consuming traces means proving a backend implementation which can emit those traces to some log or service. There are several options, but two backends are included by default:
89
+
90
+ - `traces/backend/test` does not emit any traces, but validates the usage of the tracing interface.
91
+ - `traces/backend/console` emits traces using the [`console`](https://github.com/socketry/console) gem.
92
+
93
+ In order to use a specific backend, set the `TRACES_BACKEND` environment variable, e.g.
94
+
95
+ ~~~ shell
96
+ $ TRACES_BACKEND=traces/backend/console ./my_script.rb
97
+ ~~~
98
+
99
+ Separate implementations are provided for specific APMs:
100
+
101
+ - [OpenTelemetry](https://github.com/socketry/traces-backend-open_telemetry)
102
+ - [Datadog](https://github.com/socketry/traces-backend-datadog)
103
+ - [New Relic](https://github.com/newrelic/traces-backend-newrelic)
104
+
105
+ ### Configuration
106
+
107
+ By default, you may not have many traces available, as they are typically opt-in. To enable more traces, create a `config/traces.rb` file in your project root and require the providers you want to use:
108
+
109
+ ```ruby
110
+ # config/traces.rb
111
+ def prepare
112
+ require "traces/provider/async"
113
+ require "traces/provider/async/pool"
114
+ end
115
+ ```
116
+
117
+ To get a list of all available providers, you can use the `bake` command:
118
+
119
+ ~~~ shell
120
+ $ bundle exec bake traces:provider:list
121
+ {"async" => ["traces/provider/async/barrier.rb", "traces/provider/async/task.rb", "traces/provider/async.rb"],
122
+ "async-pool" => ["traces/provider/async/pool/controller.rb"],
123
+ "protocol-http2" => ["traces/provider/protocol/http2/framer.rb", "traces/provider/protocol/http2.rb"]}
124
+ ~~~
125
+
126
+ You can then add the providers you want to use to your `config/traces.rb` file.
@@ -0,0 +1,23 @@
1
+ # Automatically generated context index for Utopia::Project guides.
2
+ # Do not edit then files in this directory directly, instead edit the guides and then run `bake utopia:project:agent:context:update`.
3
+ ---
4
+ description: Application instrumentation and tracing.
5
+ metadata:
6
+ documentation_uri: https://socketry.github.io/traces/
7
+ source_code_uri: https://github.com/socketry/traces.git
8
+ files:
9
+ - path: getting-started.md
10
+ title: Getting Started
11
+ description: This guide explains how to use `traces` for tracing code execution.
12
+ - path: context-propagation.md
13
+ title: Context Propagation
14
+ description: This guide explains how to propagate trace context between different
15
+ execution contexts within your application using `Traces.current_context` and
16
+ `Traces.with_context`.
17
+ - path: testing.md
18
+ title: Testing
19
+ description: This guide explains how to test traces in your code.
20
+ - path: capture.md
21
+ title: Capture
22
+ description: This guide explains how to use `traces` for exporting traces from your
23
+ application. This can be used to document all possible traces.
@@ -0,0 +1,32 @@
1
+ # Testing
2
+
3
+ This guide explains how to test traces in your code.
4
+
5
+ ## Expectations
6
+
7
+ One approach to testing traces are emitted, is by using mocks to verify that methods are called with the expected arguments.
8
+
9
+ ```ruby
10
+ it "should trace the operation" do
11
+ expect(Traces).to receive(:trace).with("my_controller.do_something")
12
+
13
+ my_controller.do_something
14
+ end
15
+ ```
16
+
17
+ This is generally a good appoach for testing that specific traces are emitted.
18
+
19
+ ## Validation
20
+
21
+ The traces gem supports a variety of backends, and each backend may have different requirements for the data that is submitted. The test backend is designed to be used for testing that the data submitted is valid.
22
+
23
+ ```ruby
24
+ ENV['TRACES_BACKEND'] = 'traces/backend/test'
25
+
26
+ require 'traces'
27
+
28
+ Traces.trace(5) do
29
+ puts "Hello"
30
+ end
31
+ # => lib/traces/backend/test.rb:52:in `trace': Invalid name (must be String): 5! (ArgumentError)
32
+ ```
@@ -36,8 +36,6 @@ module Traces
36
36
 
37
37
  return provider
38
38
  end
39
-
40
- Config::DEFAULT.prepare
41
39
  else
42
40
  def self.Provider(klass, &block)
43
41
  # Tracing disabled.
@@ -4,5 +4,5 @@
4
4
  # Copyright, 2021-2025, by Samuel Williams.
5
5
 
6
6
  module Traces
7
- VERSION = "0.18.0"
7
+ VERSION = "0.18.2"
8
8
  end
data/lib/traces.rb CHANGED
@@ -5,8 +5,10 @@
5
5
 
6
6
  require_relative "traces/version"
7
7
  require_relative "traces/provider"
8
- require_relative "traces/context"
9
8
 
10
9
  # @namespace
11
10
  module Traces
11
+ if self.enabled?
12
+ Config::DEFAULT.prepare
13
+ end
12
14
  end
data/readme.md CHANGED
@@ -25,6 +25,10 @@ Please see the [project documentation](https://socketry.github.io/traces/) for m
25
25
 
26
26
  Please see the [project releases](https://socketry.github.io/traces/releases/index) for all releases.
27
27
 
28
+ ### v0.18.1
29
+
30
+ - Don't call `prepare` in `traces/provider.rb`. It can cause circular loading warnings.
31
+
28
32
  ### v0.18.0
29
33
 
30
34
  - **W3C Baggage Support** - Full support for W3C Baggage specification for application-specific context propagation.
data/releases.md CHANGED
@@ -1,5 +1,9 @@
1
1
  # Releases
2
2
 
3
+ ## v0.18.1
4
+
5
+ - Don't call `prepare` in `traces/provider.rb`. It can cause circular loading warnings.
6
+
3
7
  ## v0.18.0
4
8
 
5
9
  - **W3C Baggage Support** - Full support for W3C Baggage specification for application-specific context propagation.
data.tar.gz.sig CHANGED
Binary file
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: traces
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.18.0
4
+ version: 0.18.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Samuel Williams
@@ -46,6 +46,11 @@ extra_rdoc_files: []
46
46
  files:
47
47
  - bake/traces/capture.rb
48
48
  - bake/traces/provider.rb
49
+ - context/capture.md
50
+ - context/context-propagation.md
51
+ - context/getting-started.md
52
+ - context/index.yaml
53
+ - context/testing.md
49
54
  - lib/traces.rb
50
55
  - lib/traces/backend.rb
51
56
  - lib/traces/backend/capture.rb
metadata.gz.sig CHANGED
Binary file