@spree/docs 0.1.158 → 0.1.159
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.
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Telemetry
|
|
3
|
+
description: Distributed tracing with OpenTelemetry — one gem, standard OTEL_* environment variables, and every checkout becomes a trace from HTTP request to gateway call to webhook delivery.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Spree supports [OpenTelemetry](https://opentelemetry.io), the open standard for
|
|
7
|
+
distributed tracing. Install the optional `spree_opentelemetry` gem, point it
|
|
8
|
+
at your collector with the same environment variables every other
|
|
9
|
+
OpenTelemetry service uses, and Spree exports traces — no code changes, no
|
|
10
|
+
vendor lock-in. Traces flow to any OpenTelemetry-compatible backend: Grafana
|
|
11
|
+
Tempo, Jaeger, Datadog, Honeycomb, New Relic, Dynatrace, and others.
|
|
12
|
+
|
|
13
|
+
## Setup
|
|
14
|
+
|
|
15
|
+
Add the gem to your application's Gemfile:
|
|
16
|
+
|
|
17
|
+
```ruby
|
|
18
|
+
gem 'spree_opentelemetry'
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Then configure the exporter through the standard OpenTelemetry environment
|
|
22
|
+
variables:
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
OTEL_SERVICE_NAME=spree
|
|
26
|
+
OTEL_EXPORTER_OTLP_ENDPOINT=http://collector:4318
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
That is the entire setup. Without an exporter configured, the gem stays
|
|
30
|
+
dormant and adds no overhead. `OTEL_SDK_DISABLED=true` turns telemetry off
|
|
31
|
+
regardless of any other setting.
|
|
32
|
+
|
|
33
|
+
Other standard variables work as documented in the
|
|
34
|
+
[OpenTelemetry SDK configuration reference](https://opentelemetry.io/docs/languages/sdk-configuration/),
|
|
35
|
+
including sampling:
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
# Sample 10% of traces (children follow their parent's decision)
|
|
39
|
+
OTEL_TRACES_SAMPLER=parentbased_traceidratio
|
|
40
|
+
OTEL_TRACES_SAMPLER_ARG=0.1
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## What gets traced
|
|
44
|
+
|
|
45
|
+
Two layers combine into one trace per request or job.
|
|
46
|
+
|
|
47
|
+
**Framework spans** come from the official Rails auto-instrumentation: HTTP
|
|
48
|
+
requests, controller actions, database queries, background job enqueues and
|
|
49
|
+
executions, mail deliveries, and outbound HTTP calls. Trace context carries
|
|
50
|
+
across the job boundary, so work that happens in a background job stays
|
|
51
|
+
connected to the request that caused it.
|
|
52
|
+
|
|
53
|
+
**Commerce spans** come from Spree itself:
|
|
54
|
+
|
|
55
|
+
| Span | Kind | What it covers |
|
|
56
|
+
|---|---|---|
|
|
57
|
+
| `carts.complete` (any workflow key) | internal | One span per workflow run, with its outcome |
|
|
58
|
+
| `carts.complete process_payments` (any step) | internal / client | One span per workflow step; steps declared as external I/O become client spans |
|
|
59
|
+
| `carts.add_item hooks validate` | internal | Extension hook dispatch, only when handlers are registered |
|
|
60
|
+
| `order.placed dispatch` | internal | Event delivery to each subscriber, showing whether it ran inline or was enqueued |
|
|
61
|
+
| `spree.webhook.deliver order.placed` | client | Each webhook POST, with the destination host and response code |
|
|
62
|
+
| `spree.gateway.purchase` (any gateway action) | client | Each payment gateway call — authorize, purchase, capture, void, credit, and payment session operations |
|
|
63
|
+
|
|
64
|
+
A completed checkout, for example, produces one trace containing the HTTP
|
|
65
|
+
request, the `carts.complete` workflow and its steps, the payment gateway
|
|
66
|
+
call, the database work, and — linked from it — the background jobs and
|
|
67
|
+
webhook deliveries the order triggered.
|
|
68
|
+
|
|
69
|
+
Spree also propagates
|
|
70
|
+
[W3C Trace Context](https://www.w3.org/TR/trace-context/) headers on outbound
|
|
71
|
+
webhooks, so a system receiving your webhooks can join its own spans to the
|
|
72
|
+
trace that produced the event.
|
|
73
|
+
|
|
74
|
+
## Span attributes and personal data
|
|
75
|
+
|
|
76
|
+
Span attributes never contain personal or sensitive data. They are limited to
|
|
77
|
+
workflow and step names, gateway action names, payment method class names,
|
|
78
|
+
event names, webhook destination hosts, and HTTP status codes. Order contents,
|
|
79
|
+
customer emails, addresses, payment details, and webhook payloads are never
|
|
80
|
+
attached to spans.
|
|
81
|
+
|
|
82
|
+
## Metrics
|
|
83
|
+
|
|
84
|
+
Spree exports the trace signal. Request rates, error rates, and latency
|
|
85
|
+
percentiles per endpoint, workflow, or gateway are derived from spans in the
|
|
86
|
+
OpenTelemetry Collector with the
|
|
87
|
+
[span metrics connector](https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/connector/spanmetricsconnector):
|
|
88
|
+
|
|
89
|
+
```yaml
|
|
90
|
+
# otel-collector config
|
|
91
|
+
connectors:
|
|
92
|
+
spanmetrics:
|
|
93
|
+
dimensions:
|
|
94
|
+
- name: spree.workflow
|
|
95
|
+
- name: spree.gateway.action
|
|
96
|
+
|
|
97
|
+
service:
|
|
98
|
+
pipelines:
|
|
99
|
+
traces:
|
|
100
|
+
receivers: [otlp]
|
|
101
|
+
exporters: [spanmetrics, otlp]
|
|
102
|
+
metrics:
|
|
103
|
+
receivers: [spanmetrics]
|
|
104
|
+
exporters: [prometheusremotewrite]
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
## Using with Sentry
|
|
108
|
+
|
|
109
|
+
Sentry and OpenTelemetry are complementary — Sentry's error capture works
|
|
110
|
+
independently of tracing, so having both installed (as spree-starter does)
|
|
111
|
+
requires no special setup. For traces there are three arrangements:
|
|
112
|
+
|
|
113
|
+
**Sentry for errors, OpenTelemetry for traces (default).** Nothing to
|
|
114
|
+
configure. Just don't *also* enable Sentry's own performance tracing
|
|
115
|
+
(`traces_sample_rate`) — that would instrument every request twice and
|
|
116
|
+
produce two disconnected trace systems.
|
|
117
|
+
|
|
118
|
+
**Sentry as the trace backend.** Sentry ingests OpenTelemetry spans directly
|
|
119
|
+
through its [OTLP integration](https://docs.sentry.io/platforms/ruby/guides/rails/integrations/otlp/).
|
|
120
|
+
Order matters here: Sentry registers its span processor inside `Sentry.init`,
|
|
121
|
+
which only works if the OpenTelemetry SDK is already installed — so install
|
|
122
|
+
Spree's telemetry explicitly at the top of the same initializer:
|
|
123
|
+
|
|
124
|
+
```ruby
|
|
125
|
+
# Gemfile
|
|
126
|
+
gem 'sentry-opentelemetry'
|
|
127
|
+
|
|
128
|
+
# config/initializers/sentry.rb
|
|
129
|
+
SpreeOpenTelemetry.configure { |config| config.enabled = true }
|
|
130
|
+
SpreeOpenTelemetry.install!
|
|
131
|
+
|
|
132
|
+
Sentry.init do |config|
|
|
133
|
+
config.dsn = ENV['SENTRY_DSN']
|
|
134
|
+
config.otlp.enabled = true
|
|
135
|
+
# Do not set traces_sample_rate or instrumenter — OpenTelemetry owns tracing.
|
|
136
|
+
end
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
```bash
|
|
140
|
+
# Sentry provides the exporter (derived from the DSN) — tell the SDK not to
|
|
141
|
+
# wire its own default OTLP exporter alongside it.
|
|
142
|
+
OTEL_TRACES_EXPORTER=none
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
A DSN alone does **not** enable tracing; `config.otlp.enabled` is the
|
|
146
|
+
explicit opt-in (Sentry bills for ingested spans, so error capture never
|
|
147
|
+
silently becomes span ingestion).
|
|
148
|
+
|
|
149
|
+
Spree's commerce spans — workflows, gateway calls, webhook deliveries — show
|
|
150
|
+
up in Sentry's trace view, and Sentry errors are linked automatically to the
|
|
151
|
+
span that was active when they were captured.
|
|
152
|
+
|
|
153
|
+
**Both, via the collector.** Point Spree at an OpenTelemetry Collector and
|
|
154
|
+
fan out from there — one pipeline exporting to your tracing backend and
|
|
155
|
+
another to Sentry's OTLP endpoint. This is the most flexible arrangement for
|
|
156
|
+
teams that want Grafana/Jaeger for latency work and Sentry for error triage
|
|
157
|
+
over the same traces.
|
|
158
|
+
|
|
159
|
+
## Correlating logs
|
|
160
|
+
|
|
161
|
+
To connect log lines to traces, tag your Rails logs with the current trace:
|
|
162
|
+
|
|
163
|
+
```ruby
|
|
164
|
+
# config/environments/production.rb
|
|
165
|
+
config.log_tags = [
|
|
166
|
+
->(_request) { "trace_id=#{OpenTelemetry::Trace.current_span.context.hex_trace_id}" }
|
|
167
|
+
]
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
## Trying it locally
|
|
171
|
+
|
|
172
|
+
Run Jaeger with an OTLP receiver and point Spree at it:
|
|
173
|
+
|
|
174
|
+
```bash
|
|
175
|
+
docker run --rm -p 16686:16686 -p 4318:4318 jaegertracing/jaeger:latest
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
```bash
|
|
179
|
+
OTEL_SERVICE_NAME=spree \
|
|
180
|
+
OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318 \
|
|
181
|
+
bin/rails server
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
Place a test order and open [http://localhost:16686](http://localhost:16686)
|
|
185
|
+
to see the trace.
|
|
186
|
+
|
|
187
|
+
## Code-level configuration
|
|
188
|
+
|
|
189
|
+
Everything routine is controlled by environment variables. A
|
|
190
|
+
`SpreeOpenTelemetry.configure` block exists for the rest — adding
|
|
191
|
+
instrumentation for libraries your app uses, removing a default, or advanced
|
|
192
|
+
SDK tuning:
|
|
193
|
+
|
|
194
|
+
```ruby
|
|
195
|
+
# config/initializers/opentelemetry.rb
|
|
196
|
+
SpreeOpenTelemetry.configure do |config|
|
|
197
|
+
config.use 'OpenTelemetry::Instrumentation::Redis' # add an instrumentation
|
|
198
|
+
config.skip 'OpenTelemetry::Instrumentation::ActionMailer' # remove a default
|
|
199
|
+
config.with_sdk { |otel| otel.add_span_processor(my_processor) }
|
|
200
|
+
end
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
## Instrumenting your own code
|
|
204
|
+
|
|
205
|
+
Spree's spans are built on `ActiveSupport::Notifications`, and yours can be
|
|
206
|
+
too — or use the OpenTelemetry API directly:
|
|
207
|
+
|
|
208
|
+
```ruby
|
|
209
|
+
tracer = OpenTelemetry.tracer_provider.tracer('my_app')
|
|
210
|
+
|
|
211
|
+
tracer.in_span('loyalty.award_points', attributes: { 'loyalty.points' => 50 }) do
|
|
212
|
+
# your code
|
|
213
|
+
end
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
Custom workflows get traced automatically: every `Spree::Workflow` run, step,
|
|
217
|
+
and hook dispatch is instrumented by the framework, including workflows your
|
|
218
|
+
application or extensions define.
|