exis_ray 0.5.4 → 0.5.6

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: 13877001eee2022a6c6de0d2709ef5080b0cc2e43459d5e81ea99d9f28f9b216
4
- data.tar.gz: c6b551a316813a3671ae980a0fc8061b32fc1b585bc39b49a5c761a73c3af145
3
+ metadata.gz: d66d71924fff9cf19c12e42d411963948739da61e6b223db1444c16633a3158e
4
+ data.tar.gz: 26c599899ecf1f87388c73e1b4a183370e0902893c09e40c24c7796c973c0d96
5
5
  SHA512:
6
- metadata.gz: e41a2bc99ab67896aac64e6eb8becca74fd03217807fa16e24ed434477109b053f9d9580b206a2c4f4123fefa6beca5f580b934e22c468175d20fa808179a7eb
7
- data.tar.gz: 80bc6a49ea2b9ed2e4b45aa3f4e501752edb2d5873a8871cce6ba3b4e1bf4f925fb793a3ba5ab1a0f9c717d4ee63c9411bc1d738ab7d9a742ed48585071664fd
6
+ metadata.gz: 60c34361234b638c3758b3b51d38933efcbf5db19fb8e1a9365f53f1e21bcfc42e680ceb37755c792663e7146826af2453d862b7ae526481870f65518a84b311
7
+ data.tar.gz: e3cb2ffc12e45d5bdd6f3c1d1a864bc9884b7709c531fa2780923834f0ca4d4766c75148c6afd15aac4d6a6dbf716a151042620474127b544b779fa86ec9c62b
@@ -0,0 +1,32 @@
1
+ # OpenTelemetry Implementation Guidelines
2
+
3
+ This document provides expert guidance for aligning code and logs with OpenTelemetry (OTel) standards. Follow these rules for all new instrumentation.
4
+
5
+ ## 1. Log Data Model
6
+ - **Body:** Use `body` for the primary log message.
7
+ - **Attributes:** Metadata must be flat Key-Value pairs.
8
+ - **Severity:** `level` maps to `severity_text`.
9
+
10
+ ## 2. Semantic Conventions
11
+ When adding attributes, check the official OTel [Semantic Conventions](https://opentelemetry.io/docs/specs/semconv/).
12
+
13
+ ### HTTP Attributes
14
+ - `http.request.method`: GET, POST, etc.
15
+ - `http.response.status_code`: 200, 404, etc.
16
+ - `url.path`: The request path.
17
+ - `user_agent.original`: The raw User-Agent string.
18
+
19
+ ### Database Attributes
20
+ - `db.system`: postgresql, redis, etc.
21
+ - `db.operation`: select, update, etc.
22
+ - `db.collection.name`: table or collection name.
23
+
24
+ ## 3. Metrics & Units
25
+ - Always use the lowest common denominator for units (seconds, bytes).
26
+ - Use `_s` suffix for time duration.
27
+ - Avoid compound strings like `"10ms"`. Use `duration_s=0.01`.
28
+
29
+ ## 4. Distributed Tracing
30
+ - **TraceID:** 16-byte array, represented as a 32-char lowercase hex string.
31
+ - **SpanID:** 8-byte array, represented as a 16-char lowercase hex string.
32
+ - **Context Propagation:** Follow W3C Trace Context (traceparent) when possible, or maintain AWS X-Ray compatibility as per project requirements.
data/CHANGELOG.md CHANGED
@@ -1,3 +1,16 @@
1
+ ## [0.5.6] - 2026-03-26
2
+
3
+ ### Added
4
+ - **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.
5
+ - **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.
6
+
7
+ ## [0.5.5] - 2026-03-24
8
+
9
+ ### Added
10
+ - **Deep Security Filtering:** The `JsonFormatter` now recursively filters sensitive data within `Array` and nested `Hash` structures.
11
+ - **OTel Semantic Mapping:** Added formal mapping of ExisRay fields to OpenTelemetry Semantic Conventions in `MANIFEST.md`.
12
+ - **Test Hardening:** Expanded test suite to cover deep filtering and ensure correct numeric type-casting in logs.
13
+
1
14
  ## [0.5.4] - 2026-03-24
2
15
 
3
16
  ### Changed
data/CLAUDE.md CHANGED
@@ -32,6 +32,7 @@
32
32
  ## Execution Rules
33
33
  - **No Lograge:** Do not suggest or re-add the Lograge dependency.
34
34
  - **Pure Data Logging:** Internal logs use KV strings (`component=exis_ray event=...`).
35
+ - **OTel Compliance:** Always follow the guidelines in `.gemini/docs/TELEMETRY_GUIDELINES.md` and alignment in `MANIFEST.md`. Use OTel Semantic Conventions for new attributes.
35
36
  - **Resilience:** All logging operations must be wrapped in `rescue StandardError`.
36
37
  - **Automatic Fields:** NEVER manually log `time`, `level`, `service`, `source`, `root_id`, `correlation_id`, `sidekiq_job` or `task`. These are handled by the library.
37
38
  - **Source Values:** Valid values for `source` field: `http`, `sidekiq`, `task`, `system`.
data/MANIFEST.md CHANGED
@@ -26,10 +26,24 @@ Cada línea de log debe llevar los metadatos necesarios para identificar su orig
26
26
  * `source`: El punto de entrada de la ejecución (`http`, `sidekiq`, `task`, `system`).
27
27
 
28
28
  ### 3. Convenciones de Naming & Tipos
29
- - **Naming:** Las llaves (keys) deben usar siempre `snake_case`.
29
+ - **Naming:** Las llaves (keys) deben usar siempre `snake_case`. Para campos estándar, se prefiere seguir las **OpenTelemetry Semantic Conventions**.
30
30
  - **Valores Numéricos:** Deben emitirse como números reales (sin sufijos de texto) para permitir que el motor de logs realice el casting automático.
31
31
  - **Formato:** Pares `key=value` en una sola línea estructurada.
32
32
 
33
+ ## 🔭 Alineación con OpenTelemetry
34
+
35
+ Para garantizar la interoperabilidad, `exis_ray` sigue el **OpenTelemetry Log Data Model**. Siempre que sea posible, los campos deben mapearse a las convenciones semánticas oficiales:
36
+
37
+ | Campo ExisRay | OTel Semantic Convention | Descripción |
38
+ | :--- | :--- | :--- |
39
+ | `body` | `body` | El contenido principal del log. |
40
+ | `level` | `severity_text` | Nivel de importancia. |
41
+ | `duration_s` | `duration` (en segundos) | Tiempo de ejecución. |
42
+ | `method` | `http.request.method` | Método HTTP. |
43
+ | `status` | `http.response.status_code` | Código de respuesta. |
44
+ | `path` | `url.path` | Ruta del request. |
45
+ | `user_id` | `user.id` | Identificador del usuario. |
46
+
33
47
  ## 🏗 Infraestructura de Datos (Automática)
34
48
 
35
49
  Para evitar logs redundantes y pesados, **NUNCA** incluyas manualmente las siguientes llaves en tus mensajes de log. La capa de infraestructura (`exis_ray`) las inyecta automáticamente en el nivel raíz del JSON:
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,40 @@ 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 client middleware stack. Works with both `BugBunny::Client` and `BugBunny::Resource`.
211
+
212
+ ```ruby
213
+ client = BugBunny::Client.new(pool: connection_pool) do |stack|
214
+ stack.use ExisRay::BugBunny::PublisherTracing
215
+ stack.use BugBunny::Middleware::JsonResponse
216
+ end
217
+ ```
218
+
219
+ If no trace context is active (e.g. a standalone script), the middleware does nothing.
220
+
221
+ #### Consumer — restore the trace context
222
+
223
+ 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.
224
+
225
+ ```ruby
226
+ class ApplicationController < BugBunny::Controller
227
+ include ExisRay::BugBunny::ConsumerTracing
228
+ end
229
+ ```
230
+
231
+ **How it works end-to-end:**
232
+ 1. **Publish:** The publisher middleware injects `x-trace-id` into the AMQP headers of every outgoing message.
233
+ 2. **Consume:** The consumer concern reads that header, restores the trace context, and sets `source=system`.
234
+ 3. **Logs:** Every log line emitted during the controller action carries the original `root_id` and `correlation_id` from the upstream HTTP request.
235
+
236
+ If a message arrives without `x-trace-id` (published without ExisRay), the concern is a no-op.
237
+
203
238
  ---
204
239
 
205
240
  ## 📋 Advanced Logging Guide
@@ -0,0 +1,59 @@
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 'x-trace-id' inyectado por el publicador.
9
+ #
10
+ # Permite que todos los logs emitidos durante el procesamiento de un mensaje
11
+ # incluyan el mismo root_id y correlation_id que el request HTTP original,
12
+ # logrando trazabilidad distribuida de punta a punta.
13
+ #
14
+ # El contexto se limpia siempre en `ensure`, garantizando que un error en el
15
+ # controller no contamine el procesamiento del siguiente mensaje.
16
+ #
17
+ # @example Incluir en el ApplicationController de BugBunny
18
+ # class ApplicationController < BugBunny::Controller
19
+ # include ExisRay::BugBunny::ConsumerTracing
20
+ # end
21
+ module ConsumerTracing
22
+ extend ActiveSupport::Concern
23
+
24
+ # Header AMQP desde el cual se lee el trace context propagado.
25
+ TRACE_HEADER = 'x-trace-id'
26
+
27
+ included do
28
+ around_action :exis_ray_trace_context
29
+ end
30
+
31
+ private
32
+
33
+ # Restaura el contexto de trazabilidad y lo limpia al finalizar,
34
+ # independientemente de si el controller levantó una excepción.
35
+ #
36
+ # @yieldreturn [void]
37
+ def exis_ray_trace_context
38
+ setup_exis_ray_context
39
+ yield
40
+ ensure
41
+ ExisRay::Tracer.reset rescue nil
42
+ end
43
+
44
+ # Hidrata el Tracer con el header de traza recibido en el mensaje.
45
+ # Si el header no está presente (mensaje sin trace context), no hace nada.
46
+ #
47
+ # @return [void]
48
+ def setup_exis_ray_context
49
+ trace_header = headers[TRACE_HEADER]
50
+ return unless trace_header.present?
51
+
52
+ ExisRay::Tracer.hydrate(trace_id: trace_header, source: 'system')
53
+ ExisRay.sync_correlation_id
54
+ rescue StandardError
55
+ # El tracing nunca debe interrumpir el procesamiento del mensaje.
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,41 @@
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
+ # Header AMQP personalizado para propagar el trace context entre servicios.
25
+ TRACE_HEADER = 'x-trace-id'
26
+
27
+ # Inyecta el header de traza antes de publicar el mensaje.
28
+ # Solo actúa si hay un trace context activo (root_id presente).
29
+ #
30
+ # @param env [BugBunny::Request] El objeto request del mensaje saliente.
31
+ # @return [void]
32
+ def on_request(env)
33
+ return unless ExisRay::Tracer.root_id.present?
34
+
35
+ env.headers[TRACE_HEADER] = ExisRay::Tracer.generate_trace_header
36
+ rescue StandardError
37
+ # La propagación de tracing nunca debe interrumpir la publicación de mensajes.
38
+ end
39
+ end
40
+ end
41
+ end
@@ -8,20 +8,14 @@ module ExisRay
8
8
 
9
9
  def call(env)
10
10
  # 1. Hidratar Infraestructura
11
- ExisRay::Tracer.created_at = Process.clock_gettime(Process::CLOCK_MONOTONIC)
12
- ExisRay::Tracer.source = "http"
13
-
14
- trace_header_key = ExisRay.configuration.trace_header
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
- # Usamos el helper centralizado para obtener la clase Current
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
@@ -163,17 +163,34 @@ module ExisRay
163
163
  end
164
164
 
165
165
  # Filtra recursivamente un Hash que contenga claves sensibles.
166
+ # Maneja valores anidados de tipo Hash o Array.
166
167
  #
167
168
  # @param hash [Hash]
168
169
  # @return [Hash]
169
170
  def filter_sensitive_hash(hash)
170
171
  hash.each_with_object({}) do |(k, v), result|
171
- result[k] = if v.is_a?(Hash)
172
- filter_sensitive_hash(v)
173
- else
174
- cast_value(k, v)
172
+ result[k] = case v
173
+ when Hash then filter_sensitive_hash(v)
174
+ when Array then filter_sensitive_array(k, v)
175
+ else cast_value(k, v)
175
176
  end
176
177
  end
177
178
  end
179
+
180
+ # Filtra recursivamente los elementos de un Array, propagando la clave padre
181
+ # para que el filtrado de claves sensibles se aplique a hashes anidados.
182
+ #
183
+ # @param key [String, Symbol] Clave padre (para filtrado si el array no contiene hashes).
184
+ # @param array [Array]
185
+ # @return [Array]
186
+ def filter_sensitive_array(key, array)
187
+ array.map do |element|
188
+ case element
189
+ when Hash then filter_sensitive_hash(element)
190
+ when Array then filter_sensitive_array(key, element)
191
+ else cast_value(key, element)
192
+ end
193
+ end
194
+ end
178
195
  end
179
196
  end
@@ -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 = job["exis_ray_trace"]
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.root_id = ExisRay::Tracer.send(:generate_new_root)
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
 
@@ -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
  #
@@ -2,5 +2,5 @@
2
2
 
3
3
  module ExisRay
4
4
  # Versión actual de la gema.
5
- VERSION = "0.5.4"
5
+ VERSION = "0.5.6"
6
6
  end
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)
@@ -92,11 +92,10 @@ RSpec.describe ExisRay::JsonFormatter do
92
92
  expect(result).to include(
93
93
  "component" => "orders",
94
94
  "event" => "invoice_generated",
95
- "duration_ms" => "42.5",
96
- "retries" => "0"
95
+ "duration_ms" => 42.5,
96
+ "retries" => 0
97
97
  )
98
98
  end
99
- end
100
99
 
101
100
  it "cae a body si el string parece kv pero no produce ningún par" do
102
101
  result = call("key=")
@@ -156,10 +155,10 @@ RSpec.describe ExisRay::JsonFormatter do
156
155
  end
157
156
 
158
157
  describe "#parse_kv_string (privado)" do
159
- it "retorna un hash con claves symbol" do
158
+ it "retorna un hash con claves symbol y valores casteados" do
160
159
  result = formatter.send(:parse_kv_string, "a=1 b=2")
161
160
 
162
- expect(result).to eq({ a: "1", b: "2" })
161
+ expect(result).to eq({ a: 1, b: 2 })
163
162
  end
164
163
 
165
164
  it "desenvuelve las comillas dobles de los valores" do
@@ -168,4 +167,44 @@ RSpec.describe ExisRay::JsonFormatter do
168
167
  expect(result).to eq({ msg: "hello world" })
169
168
  end
170
169
  end
170
+
171
+ describe "#filter_sensitive_hash (privado)" do
172
+ it "filtra claves sensibles en el nivel raíz" do
173
+ result = formatter.send(:filter_sensitive_hash, { user: "gabriel", password: "secret" })
174
+
175
+ expect(result[:user]).to eq("gabriel")
176
+ expect(result[:password]).to eq("[FILTERED]")
177
+ end
178
+
179
+ it "filtra claves sensibles en hashes anidados" do
180
+ result = formatter.send(:filter_sensitive_hash, {
181
+ db: { host: "localhost", token: "abc123" }
182
+ })
183
+
184
+ expect(result[:db][:host]).to eq("localhost")
185
+ expect(result[:db][:token]).to eq("[FILTERED]")
186
+ end
187
+
188
+ it "filtra claves sensibles dentro de arrays de hashes" do
189
+ result = formatter.send(:filter_sensitive_hash, {
190
+ users: [{ name: "gabriel", password: "secret" }, { name: "ana", password: "other" }]
191
+ })
192
+
193
+ expect(result[:users][0][:name]).to eq("gabriel")
194
+ expect(result[:users][0][:password]).to eq("[FILTERED]")
195
+ expect(result[:users][1][:password]).to eq("[FILTERED]")
196
+ end
197
+
198
+ it "filtra claves sensibles en arrays primitivos cuando la clave padre es sensible" do
199
+ result = formatter.send(:filter_sensitive_hash, { tokens: ["abc", "def"] })
200
+
201
+ expect(result[:tokens]).to eq(["[FILTERED]", "[FILTERED]"])
202
+ end
203
+
204
+ it "no altera valores no sensibles en arrays" do
205
+ result = formatter.send(:filter_sensitive_hash, { tags: ["admin", "active"] })
206
+
207
+ expect(result[:tags]).to eq(["admin", "active"])
208
+ end
209
+ end
171
210
  end
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
4
+ version: 0.5.6
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-24 00:00:00.000000000 Z
11
+ date: 2026-03-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -45,6 +45,7 @@ executables: []
45
45
  extensions: []
46
46
  extra_rdoc_files: []
47
47
  files:
48
+ - ".gemini/docs/TELEMETRY_GUIDELINES.md"
48
49
  - CHANGELOG.md
49
50
  - CLAUDE.md
50
51
  - LICENSE.txt
@@ -53,6 +54,8 @@ files:
53
54
  - Rakefile
54
55
  - lib/exis_ray.rb
55
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
56
59
  - lib/exis_ray/configuration.rb
57
60
  - lib/exis_ray/current.rb
58
61
  - lib/exis_ray/faraday_middleware.rb