exis_ray 0.5.5 → 0.5.7
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 +4 -4
- data/CHANGELOG.md +12 -0
- data/README.md +49 -0
- data/lib/exis_ray/bug_bunny/consumer_tracing.rb +63 -0
- data/lib/exis_ray/bug_bunny/publisher_tracing.rb +39 -0
- data/lib/exis_ray/http_middleware.rb +6 -12
- data/lib/exis_ray/json_formatter.rb +3 -2
- data/lib/exis_ray/sidekiq/server_middleware.rb +4 -5
- data/lib/exis_ray/tracer.rb +14 -0
- data/lib/exis_ray/version.rb +1 -1
- data/lib/exis_ray.rb +18 -0
- metadata +4 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: fa3229011d1a59fbd0d65ec137d7a5223f70bd3c3f69add47c27bc965a3e62f1
|
|
4
|
+
data.tar.gz: f08f78169685640fc2c6f1dbfb51c5e64826e4e776c4c1b66ee5d4196592697d
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: cc5941334d4f7a7241ba6629d5e27f08ac93ce6e704aaa31b90868a5353ff92143795b3b21cb6426d6b47172fa457de3e834899212b9b8ef1a8b28c4a1d81895
|
|
7
|
+
data.tar.gz: 3d9113cc7e2ed5790723290ff9c635b15bb8d4ec6b649c55cf3aab406a8e12d3598dff59d2f2c12d310d256a3f535fda4f816ee66d196e752c5ffb9e8d9d33e3
|
data/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,15 @@
|
|
|
1
|
+
## [0.5.7] - 2026-03-27
|
|
2
|
+
|
|
3
|
+
### Fixed
|
|
4
|
+
- **JSON HTML Escaping:** `JsonFormatter` now uses `JSON.generate` with `ascii_only: false` instead of `.to_json`, preventing `>` from being escaped as `\u003e` in log output.
|
|
5
|
+
- **BugBunny Header Standardization:** `PublisherTracing` and `ConsumerTracing` now use `ExisRay.configuration.propagation_trace_header` instead of the hardcoded `'x-trace-id'` constant, aligning with the same pattern used by `FaradayMiddleware` and `ActiveResourceInstrumentation`. The header is now fully configurable and consistent across all outgoing transports.
|
|
6
|
+
|
|
7
|
+
## [0.5.6] - 2026-03-26
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
- **BugBunny Integration:** Added `ExisRay::BugBunny::PublisherTracing` middleware for `BugBunny::Client` and `BugBunny::Resource`. Injects the active trace context into the `x-trace-id` AMQP header on every published message.
|
|
11
|
+
- **BugBunny Integration:** Added `ExisRay::BugBunny::ConsumerTracing` concern for `BugBunny::Controller`. Restores the ExisRay trace context from `x-trace-id` header via `around_action`, enabling end-to-end distributed tracing across RabbitMQ message boundaries.
|
|
12
|
+
|
|
1
13
|
## [0.5.5] - 2026-03-24
|
|
2
14
|
|
|
3
15
|
### Added
|
data/README.md
CHANGED
|
@@ -14,6 +14,7 @@ It acts as the backbone of your architecture, ensuring that every request, backg
|
|
|
14
14
|
* **Sidekiq Integration:** Automatic context propagation (User/ISP/Trace) and log formatting between the Enqueuer and the Worker.
|
|
15
15
|
* **Task Monitor:** A specialized monitor for Rake/Cron tasks to initialize traces and format logs where no HTTP request exists.
|
|
16
16
|
* **HTTP Clients:** Automatically patches `ActiveResource` and provides middleware for `Faraday`.
|
|
17
|
+
* **BugBunny Integration:** Propagates the trace context across RabbitMQ message boundaries via a publisher middleware and a consumer concern.
|
|
17
18
|
|
|
18
19
|
---
|
|
19
20
|
|
|
@@ -200,6 +201,54 @@ conn = Faraday.new(url: "[https://api.internal](https://api.internal)") do |f|
|
|
|
200
201
|
end
|
|
201
202
|
```
|
|
202
203
|
|
|
204
|
+
### E. BugBunny (RabbitMQ)
|
|
205
|
+
|
|
206
|
+
If your app publishes messages via [BugBunny](https://github.com/gedera/bug_bunny), ExisRay can propagate the active trace context through the `x-trace-id` AMQP header, and restore it on the consumer side so every log line during message processing shares the same `root_id` as the original HTTP request.
|
|
207
|
+
|
|
208
|
+
#### Publisher — inject the trace header
|
|
209
|
+
|
|
210
|
+
Add `ExisRay::BugBunny::PublisherTracing` to your publisher middleware stack.
|
|
211
|
+
|
|
212
|
+
**Using `BugBunny::Client` directly:**
|
|
213
|
+
|
|
214
|
+
```ruby
|
|
215
|
+
client = BugBunny::Client.new(pool: connection_pool) do |stack|
|
|
216
|
+
stack.use ExisRay::BugBunny::PublisherTracing
|
|
217
|
+
stack.use BugBunny::Middleware::JsonResponse
|
|
218
|
+
end
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
**Using `BugBunny::Resource`** (via `client_middleware`):
|
|
222
|
+
|
|
223
|
+
```ruby
|
|
224
|
+
class ApplicationResource < BugBunny::Resource
|
|
225
|
+
client_middleware do |stack|
|
|
226
|
+
stack.use ExisRay::BugBunny::PublisherTracing
|
|
227
|
+
end
|
|
228
|
+
end
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
Defining it once in a base `ApplicationResource` is enough — all subclasses inherit the middleware stack automatically.
|
|
232
|
+
|
|
233
|
+
If no trace context is active (e.g. a standalone script), the middleware does nothing.
|
|
234
|
+
|
|
235
|
+
#### Consumer — restore the trace context
|
|
236
|
+
|
|
237
|
+
Include `ExisRay::BugBunny::ConsumerTracing` in your base controller. It registers an `around_action` that reads `x-trace-id` from the message headers and hydrates `ExisRay::Tracer` before your action runs. The context is always reset in `ensure`, preventing leaks between messages.
|
|
238
|
+
|
|
239
|
+
```ruby
|
|
240
|
+
class ApplicationController < BugBunny::Controller
|
|
241
|
+
include ExisRay::BugBunny::ConsumerTracing
|
|
242
|
+
end
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
**How it works end-to-end:**
|
|
246
|
+
1. **Publish:** The publisher middleware injects `x-trace-id` into the AMQP headers of every outgoing message.
|
|
247
|
+
2. **Consume:** The consumer concern reads that header, restores the trace context, and sets `source=system`.
|
|
248
|
+
3. **Logs:** Every log line emitted during the controller action carries the original `root_id` and `correlation_id` from the upstream HTTP request.
|
|
249
|
+
|
|
250
|
+
If a message arrives without `x-trace-id` (published without ExisRay), the concern is a no-op.
|
|
251
|
+
|
|
203
252
|
---
|
|
204
253
|
|
|
205
254
|
## 📋 Advanced Logging Guide
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'active_support/concern'
|
|
4
|
+
|
|
5
|
+
module ExisRay
|
|
6
|
+
module BugBunny
|
|
7
|
+
# Concern para BugBunny::Controller que restaura el trace context de ExisRay
|
|
8
|
+
# a partir del header configurado en `ExisRay.configuration.propagation_trace_header`
|
|
9
|
+
# (por defecto `'X-Amzn-Trace-Id'`) inyectado por el publicador.
|
|
10
|
+
#
|
|
11
|
+
# Permite que todos los logs emitidos durante el procesamiento de un mensaje
|
|
12
|
+
# incluyan el mismo root_id y correlation_id que el request HTTP original,
|
|
13
|
+
# logrando trazabilidad distribuida de punta a punta.
|
|
14
|
+
#
|
|
15
|
+
# El contexto se limpia siempre en `ensure`, garantizando que un error en el
|
|
16
|
+
# controller no contamine el procesamiento del siguiente mensaje.
|
|
17
|
+
#
|
|
18
|
+
# @example Incluir en el ApplicationController de BugBunny
|
|
19
|
+
# class ApplicationController < BugBunny::Controller
|
|
20
|
+
# include ExisRay::BugBunny::ConsumerTracing
|
|
21
|
+
# end
|
|
22
|
+
module ConsumerTracing
|
|
23
|
+
extend ActiveSupport::Concern
|
|
24
|
+
|
|
25
|
+
# Header AMQP desde el cual se lee el trace context propagado.
|
|
26
|
+
# Debe coincidir con `propagation_trace_header` usado por el publisher.
|
|
27
|
+
def self.trace_header
|
|
28
|
+
ExisRay.configuration.propagation_trace_header
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
included do
|
|
32
|
+
around_action :exis_ray_trace_context
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
private
|
|
36
|
+
|
|
37
|
+
# Restaura el contexto de trazabilidad y lo limpia al finalizar,
|
|
38
|
+
# independientemente de si el controller levantó una excepción.
|
|
39
|
+
#
|
|
40
|
+
# @yieldreturn [void]
|
|
41
|
+
def exis_ray_trace_context
|
|
42
|
+
setup_exis_ray_context
|
|
43
|
+
yield
|
|
44
|
+
ensure
|
|
45
|
+
ExisRay::Tracer.reset rescue nil
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# Hidrata el Tracer con el header de traza recibido en el mensaje.
|
|
49
|
+
# Si el header no está presente (mensaje sin trace context), no hace nada.
|
|
50
|
+
#
|
|
51
|
+
# @return [void]
|
|
52
|
+
def setup_exis_ray_context
|
|
53
|
+
trace_header = headers[self.class.trace_header]
|
|
54
|
+
return unless trace_header.present?
|
|
55
|
+
|
|
56
|
+
ExisRay::Tracer.hydrate(trace_id: trace_header, source: 'system')
|
|
57
|
+
ExisRay.sync_correlation_id
|
|
58
|
+
rescue StandardError
|
|
59
|
+
# El tracing nunca debe interrumpir el procesamiento del mensaje.
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ExisRay
|
|
4
|
+
module BugBunny
|
|
5
|
+
# Middleware de publicación para BugBunny::Client.
|
|
6
|
+
#
|
|
7
|
+
# Inyecta el header de trazabilidad de ExisRay en cada mensaje publicado,
|
|
8
|
+
# permitiendo la propagación del trace context a los servicios consumidores.
|
|
9
|
+
# Esto hace posible correlacionar un request HTTP original con todos los mensajes
|
|
10
|
+
# y logs que genera en el ecosistema de microservicios.
|
|
11
|
+
#
|
|
12
|
+
# @example Configuración en el cliente
|
|
13
|
+
# client = BugBunny::Client.new(pool: pool) do |stack|
|
|
14
|
+
# stack.use ExisRay::BugBunny::PublisherTracing
|
|
15
|
+
# end
|
|
16
|
+
#
|
|
17
|
+
# @example Configuración en un BugBunny::Resource
|
|
18
|
+
# class UserResource < BugBunny::Resource
|
|
19
|
+
# middleware do |stack|
|
|
20
|
+
# stack.use ExisRay::BugBunny::PublisherTracing
|
|
21
|
+
# end
|
|
22
|
+
# end
|
|
23
|
+
class PublisherTracing < ::BugBunny::Middleware::Base
|
|
24
|
+
# Inyecta el header de traza antes de publicar el mensaje.
|
|
25
|
+
# Solo actúa si hay un trace context activo (root_id presente).
|
|
26
|
+
# Usa `propagation_trace_header` de la configuración, igual que FaradayMiddleware.
|
|
27
|
+
#
|
|
28
|
+
# @param env [BugBunny::Request] El objeto request del mensaje saliente.
|
|
29
|
+
# @return [void]
|
|
30
|
+
def on_request(env)
|
|
31
|
+
return unless ExisRay::Tracer.root_id.present?
|
|
32
|
+
|
|
33
|
+
env.headers[ExisRay.configuration.propagation_trace_header] = ExisRay::Tracer.generate_trace_header
|
|
34
|
+
rescue StandardError
|
|
35
|
+
# La propagación de tracing nunca debe interrumpir la publicación de mensajes.
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -8,20 +8,14 @@ module ExisRay
|
|
|
8
8
|
|
|
9
9
|
def call(env)
|
|
10
10
|
# 1. Hidratar Infraestructura
|
|
11
|
-
ExisRay::Tracer.
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
ExisRay::Tracer.trace_id = env[trace_header_key]
|
|
17
|
-
ExisRay::Tracer.request_id = env['action_dispatch.request_id']
|
|
18
|
-
ExisRay::Tracer.parse_trace_id
|
|
11
|
+
ExisRay::Tracer.hydrate(
|
|
12
|
+
trace_id: env[ExisRay.configuration.trace_header],
|
|
13
|
+
source: "http"
|
|
14
|
+
)
|
|
15
|
+
ExisRay::Tracer.request_id = env['action_dispatch.request_id']
|
|
19
16
|
|
|
20
17
|
# 2. Hidratar Negocio
|
|
21
|
-
|
|
22
|
-
if (curr = ExisRay.current_class) && curr.respond_to?(:correlation_id=) && ExisRay::Tracer.root_id.present?
|
|
23
|
-
curr.correlation_id = ExisRay::Tracer.correlation_id
|
|
24
|
-
end
|
|
18
|
+
ExisRay.sync_correlation_id
|
|
25
19
|
|
|
26
20
|
@app.call(env)
|
|
27
21
|
end
|
|
@@ -47,8 +47,9 @@ module ExisRay
|
|
|
47
47
|
inject_current_tags(payload)
|
|
48
48
|
process_message(payload, msg)
|
|
49
49
|
|
|
50
|
-
# Compactamos para eliminar claves con valores nulos (nil) y generamos el JSON
|
|
51
|
-
|
|
50
|
+
# Compactamos para eliminar claves con valores nulos (nil) y generamos el JSON.
|
|
51
|
+
# Usamos JSON.generate con unsafe_chars para evitar el escape HTML de > como \u003e.
|
|
52
|
+
"#{JSON.generate(payload.compact, { ascii_only: false })}\n"
|
|
52
53
|
end
|
|
53
54
|
|
|
54
55
|
private
|
|
@@ -46,17 +46,16 @@ module ExisRay
|
|
|
46
46
|
# @param job [Hash] Payload de Sidekiq.
|
|
47
47
|
# @return [void]
|
|
48
48
|
def hydrate_tracer(worker, job)
|
|
49
|
-
ExisRay::Tracer.created_at = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
50
49
|
ExisRay::Tracer.sidekiq_job = worker.class.name
|
|
51
|
-
ExisRay::Tracer.source = "sidekiq"
|
|
52
50
|
|
|
53
51
|
if job["exis_ray_trace"]
|
|
54
52
|
# Continuidad: Usamos la traza propagada desde el cliente (Web/Cron)
|
|
55
|
-
ExisRay::Tracer.trace_id
|
|
56
|
-
ExisRay::Tracer.parse_trace_id
|
|
53
|
+
ExisRay::Tracer.hydrate(trace_id: job["exis_ray_trace"], source: "sidekiq")
|
|
57
54
|
else
|
|
58
55
|
# Origen: El job nació directamente aquí sin contexto previo
|
|
59
|
-
ExisRay::Tracer.
|
|
56
|
+
ExisRay::Tracer.created_at = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
57
|
+
ExisRay::Tracer.source = "sidekiq"
|
|
58
|
+
ExisRay::Tracer.root_id = ExisRay::Tracer.send(:generate_new_root)
|
|
60
59
|
end
|
|
61
60
|
end
|
|
62
61
|
|
data/lib/exis_ray/tracer.rb
CHANGED
|
@@ -61,6 +61,20 @@ module ExisRay
|
|
|
61
61
|
(current_duration_s * 1000).round
|
|
62
62
|
end
|
|
63
63
|
|
|
64
|
+
# Hidrata el Tracer con un trace header entrante y registra el inicio del contexto.
|
|
65
|
+
# Centraliza la inicialización de contexto de trazabilidad para todos los entrypoints
|
|
66
|
+
# (HTTP, Sidekiq, BugBunny, etc.), eliminando duplicación entre middlewares.
|
|
67
|
+
#
|
|
68
|
+
# @param trace_id [String] El header de traza entrante (formato AWS X-Ray).
|
|
69
|
+
# @param source [String] El entrypoint de ejecución ('http', 'sidekiq', 'task', 'system').
|
|
70
|
+
# @return [void]
|
|
71
|
+
def self.hydrate(trace_id:, source:)
|
|
72
|
+
self.created_at = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
73
|
+
self.source = source
|
|
74
|
+
self.trace_id = trace_id
|
|
75
|
+
parse_trace_id
|
|
76
|
+
end
|
|
77
|
+
|
|
64
78
|
# Calcula el tiempo transcurrido en segundos desde el inicio de la request.
|
|
65
79
|
# Cumple con el estándar Wispro-Observability-Spec (v1).
|
|
66
80
|
#
|
data/lib/exis_ray/version.rb
CHANGED
data/lib/exis_ray.rb
CHANGED
|
@@ -24,6 +24,13 @@ require "exis_ray/faraday_middleware" if defined?(Faraday)
|
|
|
24
24
|
# Solo cargamos la instrumentación si ActiveResource está presente.
|
|
25
25
|
require "exis_ray/active_resource_instrumentation" if defined?(ActiveResource::Base)
|
|
26
26
|
|
|
27
|
+
# Integraciones BugBunny: publisher middleware y consumer concern.
|
|
28
|
+
# Solo se cargan si la gema BugBunny está presente.
|
|
29
|
+
if defined?(::BugBunny)
|
|
30
|
+
require "exis_ray/bug_bunny/publisher_tracing"
|
|
31
|
+
require "exis_ray/bug_bunny/consumer_tracing"
|
|
32
|
+
end
|
|
33
|
+
|
|
27
34
|
# Integración automática con Rails
|
|
28
35
|
# Solo cargamos el Railtie si la constante Rails está definida.
|
|
29
36
|
require "exis_ray/railtie" if defined?(Rails)
|
|
@@ -96,6 +103,17 @@ module ExisRay
|
|
|
96
103
|
end
|
|
97
104
|
end
|
|
98
105
|
|
|
106
|
+
# Sincroniza el correlation_id del Tracer en la clase Current configurada.
|
|
107
|
+
# Debe llamarse después de hidratar el Tracer (post `hydrate` o `parse_trace_id`).
|
|
108
|
+
#
|
|
109
|
+
# @return [void]
|
|
110
|
+
def sync_correlation_id
|
|
111
|
+
curr = current_class
|
|
112
|
+
return unless curr&.respond_to?(:correlation_id=) && Tracer.root_id.present?
|
|
113
|
+
|
|
114
|
+
curr.correlation_id = Tracer.correlation_id
|
|
115
|
+
end
|
|
116
|
+
|
|
99
117
|
private
|
|
100
118
|
|
|
101
119
|
def resolve_class(klass_name)
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: exis_ray
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.5.
|
|
4
|
+
version: 0.5.7
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Gabriel Edera
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-03-
|
|
11
|
+
date: 2026-03-27 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: activesupport
|
|
@@ -54,6 +54,8 @@ files:
|
|
|
54
54
|
- Rakefile
|
|
55
55
|
- lib/exis_ray.rb
|
|
56
56
|
- lib/exis_ray/active_resource_instrumentation.rb
|
|
57
|
+
- lib/exis_ray/bug_bunny/consumer_tracing.rb
|
|
58
|
+
- lib/exis_ray/bug_bunny/publisher_tracing.rb
|
|
57
59
|
- lib/exis_ray/configuration.rb
|
|
58
60
|
- lib/exis_ray/current.rb
|
|
59
61
|
- lib/exis_ray/faraday_middleware.rb
|