exis_ray 0.5.7 → 0.5.8
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 +13 -0
- data/MANIFEST.md +167 -57
- data/lib/exis_ray/bug_bunny/consumer_tracing_middleware.rb +56 -0
- data/lib/exis_ray/railtie.rb +25 -0
- data/lib/exis_ray/version.rb +1 -1
- data/lib/exis_ray.rb +0 -7
- metadata +3 -3
- data/lib/exis_ray/bug_bunny/consumer_tracing.rb +0 -63
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 327a3ed9c5558bba99acba81d3a3b328a271c16f4725c88a435f08ea8b1526a8
|
|
4
|
+
data.tar.gz: 661cf580101b617b50b565ec342f8a09d8da5a4b8c4d8c11163ea5000236a64e
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: d23f08bf5951c9efa611c09a2ba3654ae8763b5bff0e4706ae68f540f52f3668b0c8b6f9bb4c076ba9ad6aff05df50de40f3d0c2e1b69ebd0aaafed6dcdafce2
|
|
7
|
+
data.tar.gz: 9514884ededf873b309345eee8d6e217c6b16b49ba194b55d68825f8a544d907da6d6d624a620223653249da21c12a91de1efe235bb4e39ea5f97c95be15d11d
|
data/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,16 @@
|
|
|
1
|
+
## [0.5.8] - 2026-03-31
|
|
2
|
+
|
|
3
|
+
### Added
|
|
4
|
+
- **`ExisRay::BugBunny::ConsumerTracingMiddleware`:** Nuevo middleware para el consumer stack de BugBunny. Corre antes de que la gema procese cada mensaje (antes de `consumer.message_received`), garantizando que todos los logs internos de BugBunny — `consumer.message_received`, `consumer.route_matched`, `consumer.rpc_reply`, `consumer.message_processed` — incluyan `root_id`, `trace_id` y `source`. Si el mensaje no trae header de traza, genera un `root_id` nuevo automáticamente.
|
|
5
|
+
- **Propagación RPC bidireccional:** El `Railtie` registra automáticamente dos callbacks en BugBunny: `rpc_reply_headers` inyecta el trace header actualizado (`Self`, `TotalTimeSoFar`, `CalledFrom`) en el reply del consumer; `on_rpc_reply` hidrata el tracer en el thread del publisher al recibir la respuesta, permitiendo que `producer.rpc_response_received` y `request_complete` reflejen el viaje completo por el ecosistema de microservicios.
|
|
6
|
+
|
|
7
|
+
### Changed
|
|
8
|
+
- **BugBunny auto-instrumentado:** La integración BugBunny se mueve al `after_initialize` del `Railtie`, resolviendo el problema de orden de carga. Con ambas gemas en el `Gemfile`, todo se configura automáticamente sin intervención del desarrollador.
|
|
9
|
+
- **MANIFEST.md:** Documentación completa del estándar de observabilidad: semántica de niveles de log, block form obligatorio para DEBUG, medición de duraciones con reloj monotónico, filtrado de claves sensibles, resiliencia del logger, y tabla completa de campos auto-inyectados con condiciones de activación.
|
|
10
|
+
|
|
11
|
+
### Removed
|
|
12
|
+
- **`ExisRay::BugBunny::ConsumerTracing`:** Concern eliminado. Reemplazado por `ConsumerTracingMiddleware` que cubre el ciclo completo del mensaje, no solo el action del controller.
|
|
13
|
+
|
|
1
14
|
## [0.5.7] - 2026-03-27
|
|
2
15
|
|
|
3
16
|
### Fixed
|
data/MANIFEST.md
CHANGED
|
@@ -5,81 +5,185 @@ Este documento define el estándar obligatorio de telemetría y logging estructu
|
|
|
5
5
|
## Objetivo
|
|
6
6
|
Transformar el logging tradicional en un **flujo de eventos de datos**. Esto permite que herramientas de análisis puedan generar dashboards de rendimiento, alertas inteligentes y rastreo de errores sin necesidad de procesamiento manual de texto o transformaciones complejas.
|
|
7
7
|
|
|
8
|
+
---
|
|
9
|
+
|
|
8
10
|
## Reglas Fundamentales
|
|
9
11
|
|
|
10
|
-
### 1.
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
12
|
+
### 1. Formato de Mensaje
|
|
13
|
+
|
|
14
|
+
Todo log debe emitirse como una línea de pares `key=value` en el siguiente orden:
|
|
15
|
+
|
|
16
|
+
```
|
|
17
|
+
component=x event=y [campos adicionales]
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
- `component`: nombre de la gema, librería o módulo responsable (ej: `exis_ray`, `storage_engine`). Siempre en `snake_case`.
|
|
21
|
+
- `event`: nombre puntual de la acción o hito (ej: `http_request`, `sync_complete`). Siempre en `snake_case`.
|
|
22
|
+
- Los campos adicionales van a continuación, en cualquier orden.
|
|
23
|
+
|
|
24
|
+
Valores con espacios deben ir entre comillas dobles: `error_message="Server reset connection"`.
|
|
25
|
+
|
|
26
|
+
### 2. Niveles de Log
|
|
27
|
+
|
|
28
|
+
Cada nivel tiene una semántica estricta. Usar el nivel incorrecto es un error.
|
|
29
|
+
|
|
30
|
+
| Nivel | Cuándo usarlo |
|
|
31
|
+
| :------ | :------------ |
|
|
32
|
+
| `ERROR` | Se lanzó una excepción o el sistema no pudo completar una operación crítica. |
|
|
33
|
+
| `WARN` | Ocurrió algo inesperado pero la ejecución continuó. |
|
|
34
|
+
| `INFO` | Flujo normal del sistema. Eventos relevantes para el negocio u operaciones. |
|
|
35
|
+
| `DEBUG` | Detalle técnico interno. Solo útil durante desarrollo o diagnóstico. |
|
|
36
|
+
|
|
37
|
+
**Regla de DEBUG:** Siempre usar block form para evitar interpolación innecesaria:
|
|
38
|
+
```ruby
|
|
39
|
+
# Correcto
|
|
40
|
+
logger.debug { "component=cache event=miss key=#{key}" }
|
|
41
|
+
|
|
42
|
+
# Incorrecto — evalúa la interpolación aunque DEBUG esté desactivado
|
|
43
|
+
logger.debug "component=cache event=miss key=#{key}"
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
**Prohibido:** Nunca usar `Kernel#warn` ni escribir directamente a `$stderr`. Todo output debe ir por el logger configurado.
|
|
47
|
+
|
|
48
|
+
### 3. Unidad en la Key, Número en el Valor (Data First)
|
|
49
|
+
|
|
50
|
+
La regla de oro para que las métricas sean operables es separar la unidad del dato numérico. **Nunca** incluir unidades dentro de los valores.
|
|
51
|
+
|
|
52
|
+
```
|
|
53
|
+
# Incorrecto
|
|
54
|
+
duration="0.5s" memory="128MB"
|
|
55
|
+
|
|
56
|
+
# Correcto
|
|
57
|
+
duration_s=0.5 memory_mb=128
|
|
58
|
+
```
|
|
14
59
|
|
|
15
|
-
**Sufijos de unidad
|
|
16
|
-
- `_s`: Segundos (Float). Estándar para duraciones y latencias
|
|
60
|
+
**Sufijos de unidad:**
|
|
61
|
+
- `_s`: Segundos (Float). Estándar para duraciones y latencias.
|
|
17
62
|
- `_ms`: Milisegundos (Integer). Para precisión técnica interna de alta frecuencia.
|
|
18
63
|
- `_count`: Cantidades o volúmenes (Integer). Ej: `record_count`, `retry_count`.
|
|
19
64
|
- `_bytes` / `_kb` / `_mb`: Unidades de almacenamiento o memoria.
|
|
20
|
-
- `_human`: (Opcional) Texto
|
|
65
|
+
- `_human`: (Opcional) Texto legible para humanos. Ej: `duration_human="2 minutes 5 seconds"`.
|
|
66
|
+
|
|
67
|
+
### 4. Medición de Duraciones
|
|
68
|
+
|
|
69
|
+
Las duraciones **siempre** deben medirse con reloj monotónico. Nunca con `Time.now` (susceptible a saltos de reloj del sistema).
|
|
70
|
+
|
|
71
|
+
```ruby
|
|
72
|
+
# Correcto
|
|
73
|
+
start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
74
|
+
# ... operación ...
|
|
75
|
+
duration_s = Process.clock_gettime(Process::CLOCK_MONOTONIC) - start
|
|
76
|
+
|
|
77
|
+
# Incorrecto
|
|
78
|
+
start = Time.now
|
|
79
|
+
duration_s = Time.now - start
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### 5. Source: Entrypoint de Ejecución
|
|
21
83
|
|
|
22
|
-
|
|
23
|
-
Cada línea de log debe llevar los metadatos necesarios para identificar su origen técnico de forma inmediata:
|
|
24
|
-
* `component`: Nombre de la gema, librería o módulo responsable (ej: `exis_ray`, `storage_engine`).
|
|
25
|
-
* `event`: Nombre de la acción puntual o hito alcanzado (ej: `http_request`, `engine.complete`).
|
|
26
|
-
* `source`: El punto de entrada de la ejecución (`http`, `sidekiq`, `task`, `system`).
|
|
84
|
+
El campo `source` identifica el punto de entrada del proceso. Es obligatorio y solo acepta estos valores:
|
|
27
85
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
86
|
+
| Valor | Cuándo usarlo |
|
|
87
|
+
| :--------- | :------------ |
|
|
88
|
+
| `http` | Request HTTP entrante (procesado por Rack/Rails). |
|
|
89
|
+
| `sidekiq` | Job procesado por Sidekiq. |
|
|
90
|
+
| `task` | Tarea programada o proceso de larga duración (Rake, Cron, TaskMonitor). |
|
|
91
|
+
| `system` | Ejecución iniciada por otro sistema interno (ej: consumidor RabbitMQ/BugBunny). |
|
|
92
|
+
|
|
93
|
+
`source` es inyectado automáticamente por el middleware correspondiente. **No lo incluyas manualmente.**
|
|
94
|
+
|
|
95
|
+
### 6. Seguridad y Privacidad
|
|
96
|
+
|
|
97
|
+
**Filtrado de claves sensibles:** Cualquier campo cuya key coincida con el patrón `password|pass|passwd|secret|token|api_key|auth` debe reemplazar su valor por `[FILTERED]`. Esto es aplicado automáticamente por `ExisRay::JsonFormatter` en todos los logs.
|
|
98
|
+
|
|
99
|
+
**Sin PII:** Nunca loguear datos crudos de usuarios. Solo se permiten identificadores: `user_id`, `isp_id`.
|
|
100
|
+
|
|
101
|
+
```
|
|
102
|
+
# Incorrecto
|
|
103
|
+
component=auth event=login email=user@example.com password=abc123
|
|
104
|
+
|
|
105
|
+
# Correcto
|
|
106
|
+
component=auth event=login user_id=42 password=[FILTERED]
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### 7. Resiliencia del Logger
|
|
110
|
+
|
|
111
|
+
Un fallo en el logging nunca debe interrumpir el flujo principal de la aplicación. Toda operación de logging debe estar protegida:
|
|
112
|
+
|
|
113
|
+
```ruby
|
|
114
|
+
# Correcto
|
|
115
|
+
begin
|
|
116
|
+
logger.info "component=sync event=complete duration_s=#{duration_s}"
|
|
117
|
+
rescue StandardError
|
|
118
|
+
# silenciar — el log es accesorio, no crítico
|
|
119
|
+
end
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### 8. Convenciones de Naming
|
|
123
|
+
|
|
124
|
+
- Keys siempre en `snake_case`.
|
|
125
|
+
- Valores numéricos emitidos como números reales (sin comillas) para que el motor de logs realice casting automático.
|
|
126
|
+
- Para campos estándar, seguir las **OpenTelemetry Semantic Conventions** donde sea posible.
|
|
127
|
+
|
|
128
|
+
---
|
|
32
129
|
|
|
33
130
|
## 🔭 Alineación con OpenTelemetry
|
|
34
131
|
|
|
35
|
-
|
|
132
|
+
`exis_ray` sigue el **OpenTelemetry Log Data Model**. Los campos se mapean a las convenciones semánticas oficiales:
|
|
36
133
|
|
|
37
|
-
| Campo ExisRay
|
|
38
|
-
|
|
|
39
|
-
| `body`
|
|
40
|
-
| `level`
|
|
41
|
-
| `duration_s`
|
|
42
|
-
| `method`
|
|
43
|
-
| `status`
|
|
44
|
-
| `path`
|
|
45
|
-
| `user_id`
|
|
134
|
+
| Campo ExisRay | OTel Semantic Convention | Descripción |
|
|
135
|
+
| :------------- | :-------------------------- | :----------------------- |
|
|
136
|
+
| `body` | `body` | Contenido principal del log (texto libre). |
|
|
137
|
+
| `level` | `severity_text` | Nivel de importancia. |
|
|
138
|
+
| `duration_s` | `duration` (en segundos) | Tiempo de ejecución. |
|
|
139
|
+
| `method` | `http.request.method` | Método HTTP. |
|
|
140
|
+
| `status` | `http.response.status_code` | Código de respuesta HTTP.|
|
|
141
|
+
| `path` | `url.path` | Ruta del request. |
|
|
142
|
+
| `user_id` | `user.id` | Identificador del usuario.|
|
|
46
143
|
|
|
47
|
-
|
|
144
|
+
---
|
|
48
145
|
|
|
49
|
-
|
|
146
|
+
## 🏗 Campos Auto-Inyectados por ExisRay
|
|
50
147
|
|
|
51
|
-
|
|
52
|
-
| :--- | :--- | :--- |
|
|
53
|
-
| `time` | Timestamp ISO8601 | Lo añade el Logger base. |
|
|
54
|
-
| `level` | INFO, ERROR, etc. | Lo añade el Logger base. |
|
|
55
|
-
| `service` | Nombre de la App | Se obtiene de la configuración global. |
|
|
56
|
-
| `source` | Entrypoint (http, task) | Lo inyecta el middleware/monitor correspondiente. |
|
|
57
|
-
| `root_id` | Trace ID (AWS X-Ray) | Se gestiona a nivel de hilo/petición. |
|
|
58
|
-
| `correlation_id`| ID de rastreo cruzado | Se genera automáticamente al inicio de la ejecución. |
|
|
59
|
-
| `user_id` / `isp_id`| Contexto de negocio | Se extrae del estado global de la petición. |
|
|
60
|
-
| `sidekiq_job` | Clase del Worker | Inyectado automáticamente en procesos Sidekiq. |
|
|
61
|
-
| `task` | Nombre de la tarea | Inyectado automáticamente por el TaskMonitor. |
|
|
148
|
+
**NUNCA** incluyas manualmente los siguientes campos. `ExisRay::JsonFormatter` los inyecta automáticamente en cada línea de log:
|
|
62
149
|
|
|
63
|
-
|
|
150
|
+
| Campo | Descripción | Condición |
|
|
151
|
+
| :--------------- | :--------------------------------- | :--------------------------------------------- |
|
|
152
|
+
| `time` | Timestamp ISO8601 UTC | Siempre |
|
|
153
|
+
| `level` | Nivel de severidad | Siempre |
|
|
154
|
+
| `service` | Nombre de la aplicación | Siempre |
|
|
155
|
+
| `root_id` | Trace ID raíz (AWS X-Ray) | Cuando hay trace context activo |
|
|
156
|
+
| `trace_id` | Trace ID completo (formato X-Ray) | Cuando hay trace context activo |
|
|
157
|
+
| `source` | Entrypoint de ejecución | Cuando hay trace context activo |
|
|
158
|
+
| `correlation_id` | ID de rastreo cruzado | Cuando `Current.correlation_id` está presente |
|
|
159
|
+
| `user_id` | ID del usuario autenticado | Cuando `Current.user_id` está presente |
|
|
160
|
+
| `isp_id` | ID del ISP | Cuando `Current.isp_id` está presente |
|
|
161
|
+
| `sidekiq_job` | Clase del Worker Sidekiq | Solo en procesos Sidekiq |
|
|
162
|
+
| `task` | Nombre de la tarea | Solo en procesos TaskMonitor |
|
|
163
|
+
| `tags` | Tags de Rails TaggedLogging | Solo si hay tags activos en el hilo |
|
|
164
|
+
|
|
165
|
+
> **Regla de Oro:** Tu log manual solo debe contener datos de **tu lógica de negocio**. La infraestructura ya sabe quién eres, de dónde venís y cuál es tu ID de traza.
|
|
64
166
|
|
|
65
167
|
---
|
|
66
168
|
|
|
67
169
|
## 🛰 Ciclo de Vida del Evento
|
|
68
170
|
|
|
69
|
-
## Ciclo de Vida del Evento
|
|
70
|
-
|
|
71
171
|
### Procesos, Trabajos y Tareas (Jobs/Tasks)
|
|
172
|
+
|
|
72
173
|
Todo proceso aislado debe reportar su inicio y su finalización con una estructura consistente:
|
|
174
|
+
|
|
73
175
|
- `event`: Identificador de estado (ej: `task_started`, `task_finished`).
|
|
74
|
-
- `status`: Resultado final
|
|
75
|
-
- `duration_s`: Tiempo total de ejecución (
|
|
176
|
+
- `status`: Resultado final (`success`, `failed`, `aborted`). Siempre string semántico, nunca código HTTP.
|
|
177
|
+
- `duration_s`: Tiempo total de ejecución (reloj monotónico).
|
|
76
178
|
- `error_class` / `error_message`: Obligatorios solo en caso de fallo.
|
|
77
179
|
|
|
78
|
-
### Peticiones
|
|
79
|
-
|
|
80
|
-
|
|
180
|
+
### Peticiones HTTP
|
|
181
|
+
|
|
182
|
+
Los logs de cierre de petición deben estandarizar el reporte de rendimiento:
|
|
183
|
+
|
|
184
|
+
- `status`: Código HTTP (Integer). Ej: `200`, `404`, `500`.
|
|
81
185
|
- `duration_s`: Tiempo total de respuesta del servidor.
|
|
82
|
-
- `[subsystem]_runtime_s`: Desglose opcional
|
|
186
|
+
- `[subsystem]_runtime_s`: Desglose opcional por capa (ej: `db_runtime_s`, `view_runtime_s`).
|
|
83
187
|
|
|
84
188
|
---
|
|
85
189
|
|
|
@@ -87,26 +191,32 @@ Los logs de cierre de peticiones deben estandarizar el reporte de rendimiento pa
|
|
|
87
191
|
|
|
88
192
|
**En el código fuente:**
|
|
89
193
|
```ruby
|
|
90
|
-
|
|
91
|
-
|
|
194
|
+
start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
195
|
+
# ... operación ...
|
|
196
|
+
duration_s = Process.clock_gettime(Process::CLOCK_MONOTONIC) - start
|
|
92
197
|
|
|
93
|
-
|
|
94
|
-
|
|
198
|
+
logger.info "component=data_processor event=sync_complete status=success duration_s=#{duration_s} record_count=500"
|
|
199
|
+
|
|
200
|
+
# En caso de error:
|
|
201
|
+
rescue => e
|
|
202
|
+
logger.error "component=data_processor event=sync_complete status=failed error_class=#{e.class} error_message=\"#{e.message}\""
|
|
203
|
+
end
|
|
95
204
|
```
|
|
96
205
|
|
|
97
|
-
**Resultado JSON unificado:**
|
|
206
|
+
**Resultado JSON unificado (emitido por ExisRay):**
|
|
98
207
|
```json
|
|
99
208
|
{
|
|
100
209
|
"time": "2026-03-24T14:00:00Z",
|
|
101
210
|
"level": "INFO",
|
|
102
211
|
"service": "my_application",
|
|
212
|
+
"root_id": "1-abc123",
|
|
213
|
+
"trace_id": "Root=1-abc123",
|
|
214
|
+
"source": "task",
|
|
215
|
+
"correlation_id": "my_application;1-abc123",
|
|
103
216
|
"component": "data_processor",
|
|
104
217
|
"event": "sync_complete",
|
|
105
218
|
"status": "success",
|
|
106
219
|
"duration_s": 1.25,
|
|
107
|
-
"record_count": 500
|
|
108
|
-
"source": "task",
|
|
109
|
-
"root_id": "Root=1-...",
|
|
110
|
-
"correlation_id": "my_application;Root=..."
|
|
220
|
+
"record_count": 500
|
|
111
221
|
}
|
|
112
222
|
```
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ExisRay
|
|
4
|
+
module BugBunny
|
|
5
|
+
# Consumer middleware para BugBunny que establece el trace context de ExisRay
|
|
6
|
+
# antes de que la gema empiece a procesar el mensaje.
|
|
7
|
+
#
|
|
8
|
+
# Al correr en el consumer middleware stack (antes de `consumer.message_received`),
|
|
9
|
+
# garantiza que **todos** los logs internos de BugBunny y del controller action
|
|
10
|
+
# incluyan `root_id`, `trace_id` y `source`.
|
|
11
|
+
#
|
|
12
|
+
# Se registra automáticamente al cargar ExisRay con BugBunny presente.
|
|
13
|
+
# El usuario final no necesita configuración adicional.
|
|
14
|
+
#
|
|
15
|
+
# @example Registro automático (ocurre en Railtie#after_initialize)
|
|
16
|
+
# BugBunny.consumer_middlewares.use ExisRay::BugBunny::ConsumerTracingMiddleware
|
|
17
|
+
class ConsumerTracingMiddleware < ::BugBunny::ConsumerMiddleware::Base
|
|
18
|
+
# Inyecta el trace context antes de delegar al siguiente middleware.
|
|
19
|
+
# Limpia el contexto en `ensure` para no contaminar el próximo mensaje.
|
|
20
|
+
#
|
|
21
|
+
# @param delivery_info [Bunny::DeliveryInfo]
|
|
22
|
+
# @param properties [Bunny::MessageProperties]
|
|
23
|
+
# @param body [String]
|
|
24
|
+
def call(delivery_info, properties, body)
|
|
25
|
+
setup_trace_context(properties)
|
|
26
|
+
@app.call(delivery_info, properties, body)
|
|
27
|
+
ensure
|
|
28
|
+
ExisRay::Tracer.reset rescue nil
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
private
|
|
32
|
+
|
|
33
|
+
# Hidrata el Tracer con el header de traza del mensaje entrante.
|
|
34
|
+
# Si no hay header (mensaje publicado sin trace context), genera un root_id nuevo
|
|
35
|
+
# para que los logs siempre tengan contexto de trazabilidad.
|
|
36
|
+
#
|
|
37
|
+
# @param properties [Bunny::MessageProperties]
|
|
38
|
+
# @return [void]
|
|
39
|
+
def setup_trace_context(properties)
|
|
40
|
+
trace_header = properties.headers&.[](ExisRay.configuration.propagation_trace_header)
|
|
41
|
+
|
|
42
|
+
if trace_header.present?
|
|
43
|
+
ExisRay::Tracer.hydrate(trace_id: trace_header, source: 'system')
|
|
44
|
+
else
|
|
45
|
+
ExisRay::Tracer.created_at = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
46
|
+
ExisRay::Tracer.source = 'system'
|
|
47
|
+
ExisRay::Tracer.root_id = ExisRay::Tracer.send(:generate_new_root)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
ExisRay.sync_correlation_id
|
|
51
|
+
rescue StandardError
|
|
52
|
+
# El tracing nunca debe interrumpir el procesamiento del mensaje.
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
data/lib/exis_ray/railtie.rb
CHANGED
|
@@ -44,6 +44,31 @@ module ExisRay
|
|
|
44
44
|
log_boot("component=exis_ray event=json_logging_enabled")
|
|
45
45
|
end
|
|
46
46
|
|
|
47
|
+
# --- Integración BugBunny ---
|
|
48
|
+
if defined?(::BugBunny)
|
|
49
|
+
require "exis_ray/bug_bunny/publisher_tracing"
|
|
50
|
+
require "exis_ray/bug_bunny/consumer_tracing_middleware"
|
|
51
|
+
::BugBunny.consumer_middlewares.use ExisRay::BugBunny::ConsumerTracingMiddleware
|
|
52
|
+
::BugBunny.configuration.rpc_reply_headers = lambda {
|
|
53
|
+
next {} unless ExisRay::Tracer.root_id.present?
|
|
54
|
+
|
|
55
|
+
{ ExisRay.configuration.propagation_trace_header => ExisRay::Tracer.generate_trace_header }
|
|
56
|
+
}
|
|
57
|
+
::BugBunny.configuration.on_rpc_reply = lambda { |headers|
|
|
58
|
+
begin
|
|
59
|
+
trace_header = headers&.[](ExisRay.configuration.propagation_trace_header)
|
|
60
|
+
next unless trace_header.present?
|
|
61
|
+
|
|
62
|
+
# Solo actualizamos trace_id — no tocamos created_at ni source del publisher.
|
|
63
|
+
ExisRay::Tracer.trace_id = trace_header
|
|
64
|
+
ExisRay::Tracer.parse_trace_id
|
|
65
|
+
ExisRay.sync_correlation_id
|
|
66
|
+
rescue StandardError
|
|
67
|
+
end
|
|
68
|
+
}
|
|
69
|
+
log_boot("component=exis_ray event=bug_bunny_instrumented")
|
|
70
|
+
end
|
|
71
|
+
|
|
47
72
|
# --- Instrumentación de ActiveResource ---
|
|
48
73
|
if defined?(ActiveResource::Base)
|
|
49
74
|
require "exis_ray/active_resource_instrumentation"
|
data/lib/exis_ray/version.rb
CHANGED
data/lib/exis_ray.rb
CHANGED
|
@@ -24,13 +24,6 @@ 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
|
-
|
|
34
27
|
# Integración automática con Rails
|
|
35
28
|
# Solo cargamos el Railtie si la constante Rails está definida.
|
|
36
29
|
require "exis_ray/railtie" if defined?(Rails)
|
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.8
|
|
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-31 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: activesupport
|
|
@@ -54,7 +54,7 @@ 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/
|
|
57
|
+
- lib/exis_ray/bug_bunny/consumer_tracing_middleware.rb
|
|
58
58
|
- lib/exis_ray/bug_bunny/publisher_tracing.rb
|
|
59
59
|
- lib/exis_ray/configuration.rb
|
|
60
60
|
- lib/exis_ray/current.rb
|
|
@@ -1,63 +0,0 @@
|
|
|
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
|