exis_ray 0.7.1 → 0.7.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 +4 -4
- data/CHANGELOG.md +6 -0
- data/README.md +52 -16
- data/lib/exis_ray/version.rb +1 -1
- data/skill/SKILL.md +74 -5
- metadata +4 -4
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 5dd52ddf30f1d4eaaaad95ed4acde4bd94c8dd4a01b20853f42ddd71887c0876
|
|
4
|
+
data.tar.gz: 329163a0bbbd0473e8da70971822c645de763f6a2c99eb4ccf1c973603cd700e
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 9eb8bb340dae5b7f423e206ed1fa708caf0b599be0bfc3dd9f1d71209485cf6f2a17a06c9805167cd4988cae20b751f684fda2253d5983efa3c3d9e456e51849
|
|
7
|
+
data.tar.gz: e18cf7eaa0962d39591072eb9241df8c950c0d1d1c1786aaff4d84ebc4acd1b6ff993b280f5bedc6175bbabd56a0a75f0e8f92a50b899051a1942d21e91888fc
|
data/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
## [0.7.2] - 2026-05-11
|
|
2
|
+
|
|
3
|
+
### Documentación
|
|
4
|
+
- **Warning sobre `ActiveSupport::TaggedLogging` con JSON logging:** `TaggedLogging` antepone tags como texto raw antes del formatter, rompiendo el JSON (`[req_id] {...}`). `JsonFormatter` ya inyecta `request_id`/`trace_id` como campos JSON — usar ambos genera salida inválida. Documentada la config correcta del logger en `production.rb` (README + SKILL FAQ).
|
|
5
|
+
- **Skill improvements (issue #4):** (1) Clarificado el criterio auto-inyectado vs manual — el formatter solo conoce contexto de ejecución (Tracer/Current), por eso `component` y `event` deben aportarse manualmente. (2) Agregados ejemplos concretos de output JSON lado-a-lado con el input KV/Hash. (3) Completada la lista de campos default de `LogSubscriber` (17 campos con tipos y condiciones, antes truncado con "etc."). (4) Documentados los 3 modos de input del formatter (KV / Hash / string libre) con ejemplos de cada uno.
|
|
6
|
+
|
|
1
7
|
## [0.7.1] - 2026-04-06
|
|
2
8
|
|
|
3
9
|
### Fixed
|
data/README.md
CHANGED
|
@@ -252,22 +252,46 @@ Con `log_format: :json`, `ExisRay::JsonFormatter` reemplaza el formatter de Rail
|
|
|
252
252
|
{"time":"2026-04-01T14:30:00Z","level":"INFO","severity_number":9,"service":"wispro_agent","service_version":"1.2.3","deployment_environment":"production","root_id":"1-65f...abc","trace_id":"Root=1-65f...;Self=...","source":"http","user_id":42,"isp_id":10,"component":"exis_ray","event":"http_request","method":"GET","path":"/api/v1/users","http_route":"/api/v1/users","http_status":200,"duration_s":0.0452,"user_agent_original":"Mozilla/5.0","server_address":"api.example.com"}
|
|
253
253
|
```
|
|
254
254
|
|
|
255
|
-
|
|
255
|
+
El formatter acepta tres tipos de mensaje. Los tres producen output JSON equivalente; elegí el que sea más legible para tu caso:
|
|
256
256
|
|
|
257
257
|
```ruby
|
|
258
|
+
# 1. String KV — one-liner rápido, valores numéricos se castean
|
|
258
259
|
Rails.logger.info "component=billing event=invoice_created invoice_id=123 total=45.50"
|
|
259
|
-
# => {"time":"...","level":"INFO","service":"...","root_id":"...","component":"billing","event":"invoice_created","invoice_id":123,"total":45.5}
|
|
260
|
-
```
|
|
261
260
|
|
|
262
|
-
|
|
261
|
+
# 2. Hash style — payloads complejos o con valores nested
|
|
262
|
+
Rails.logger.info(component: "billing", event: "invoice_created",
|
|
263
|
+
invoice: { id: 123, total: 45.50 })
|
|
263
264
|
|
|
264
|
-
|
|
265
|
+
# 3. String libre — fallback, va a la clave `body`
|
|
265
266
|
Rails.logger.info "Algo pasó sin formato KV"
|
|
266
267
|
# => {"time":"...","level":"INFO","service":"...","body":"Algo pasó sin formato KV"}
|
|
267
268
|
```
|
|
268
269
|
|
|
270
|
+
Los mensajes Hash también son la forma que usa internamente `LogSubscriber` para emitir el cierre de cada request HTTP.
|
|
271
|
+
|
|
272
|
+
> **Nota:** `component` (módulo de negocio) y `event` (qué pasó) **no** son auto-inyectados — los aporta el call site. El formatter solo conoce el contexto de **ejecución** (quién, de dónde, con qué identidad), no el contexto del **lugar del código** que loguea.
|
|
273
|
+
|
|
269
274
|
En modo `:text`, ExisRay inyecta el `trace_id` o `root_id` como tag de Rails (`config.log_tags`) y no modifica el formatter.
|
|
270
275
|
|
|
276
|
+
### Configuración del logger en producción
|
|
277
|
+
|
|
278
|
+
Para logs JSON limpios sin códigos ANSI ni texto extra, configurar el logger así:
|
|
279
|
+
|
|
280
|
+
```ruby
|
|
281
|
+
# config/environments/production.rb
|
|
282
|
+
config.colorize_logging = false
|
|
283
|
+
config.logger = ActiveSupport::Logger.new(STDOUT)
|
|
284
|
+
config.logger.formatter = ExisRay::JsonFormatter
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
**No usar `ActiveSupport::TaggedLogging`** — agrega tags como texto al inicio de cada línea antes del formatter, lo cual rompe el JSON:
|
|
288
|
+
|
|
289
|
+
```
|
|
290
|
+
[request_id] {"time":"...","level":"INFO",...} # ← texto antes del JSON (INVALIDO)
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
`ExisRay::JsonFormatter` ya inyecta los tags (`request_id`, `trace_id`, etc.) como campos JSON, así que `TaggedLogging` es redundante e incompatible.
|
|
294
|
+
|
|
271
295
|
### Campos auto-inyectados
|
|
272
296
|
|
|
273
297
|
`JsonFormatter` inyecta estos campos automáticamente en cada línea. **Nunca** los incluyas manualmente en tus logs:
|
|
@@ -290,17 +314,29 @@ En modo `:text`, ExisRay inyecta el `trace_id` o `root_id` como tag de Rails (`c
|
|
|
290
314
|
| `task` | Solo en procesos TaskMonitor |
|
|
291
315
|
| `tags` | Solo si hay Rails tagged logging activo |
|
|
292
316
|
|
|
293
|
-
`LogSubscriber` inyecta además estos campos en
|
|
294
|
-
|
|
295
|
-
| Campo |
|
|
296
|
-
|
|
297
|
-
| `
|
|
298
|
-
| `
|
|
299
|
-
| `
|
|
300
|
-
| `
|
|
301
|
-
| `
|
|
302
|
-
| `
|
|
303
|
-
| `
|
|
317
|
+
`LogSubscriber` inyecta además estos campos en cada log de cierre de request HTTP. **Nunca duplicarlos** en logs manuales:
|
|
318
|
+
|
|
319
|
+
| Campo | Tipo | Notas |
|
|
320
|
+
|:------|:-----|:------|
|
|
321
|
+
| `component` | String | Siempre `"exis_ray"` |
|
|
322
|
+
| `event` | String | Siempre `"http_request"` |
|
|
323
|
+
| `method` | String | Verbo HTTP |
|
|
324
|
+
| `path` | String | URL concreta del request |
|
|
325
|
+
| `http_route` | String | Template (ej: `/users/:id`). Baja cardinalidad para dashboards |
|
|
326
|
+
| `format` | Symbol/String | `html`, `json`, etc. |
|
|
327
|
+
| `controller` | String | Class name del controller |
|
|
328
|
+
| `action` | String | Nombre del action |
|
|
329
|
+
| `http_status` | Integer | Status HTTP final. Antes `status`, renombrado en v0.6.0 |
|
|
330
|
+
| `duration_s` | Float | Segundos (Rails reporta ms, se convierte), redondeo 4 decimales |
|
|
331
|
+
| `duration_human` | String | Legible: `"42.5ms"`, `"1.25s"`, `"2 minutes 5 seconds"` |
|
|
332
|
+
| `view_runtime_s` | Float\|nil | Solo si Rails lo reporta |
|
|
333
|
+
| `db_runtime_s` | Float\|nil | Solo si ActiveRecord lo reporta |
|
|
334
|
+
| `user_agent_original` | String | Header `User-Agent` |
|
|
335
|
+
| `server_address` | String | Hostname sin puerto del header `Host` |
|
|
336
|
+
| `error_class`, `error_message` | String | Solo en fallo (legacy) |
|
|
337
|
+
| `exception.type`, `exception.message`, `exception.stacktrace` | String | Solo en fallo (OTel; stack limitado a 20 líneas) |
|
|
338
|
+
|
|
339
|
+
Severity del log: `ERROR` si `http_status >= 500`, sino `INFO`.
|
|
304
340
|
|
|
305
341
|
### Filtrado de claves sensibles
|
|
306
342
|
|
data/lib/exis_ray/version.rb
CHANGED
data/skill/SKILL.md
CHANGED
|
@@ -71,8 +71,8 @@ ExisRay unifica trazabilidad distribuida, logging estructurado JSON, contexto de
|
|
|
71
71
|
2. `Tracer.parse_trace_id` extrae `root_id`, `self_id`, `called_from`, `total_time_so_far`
|
|
72
72
|
3. `ExisRay.sync_correlation_id` asigna `Tracer.correlation_id` a `Current.correlation_id`
|
|
73
73
|
4. Controller ejecuta `before_action` para setear `Current.user_id`, `Current.isp_id`
|
|
74
|
-
5. `JsonFormatter` intercepta cada `Rails.logger.*` e inyecta automaticamente: `time`, `level`, `severity_number`, `service`, `service_version`, `deployment_environment`, `root_id`, `trace_id`, `source`, `user_id`, `isp_id`, `correlation_id`
|
|
75
|
-
6. `LogSubscriber` emite un unico Hash al finalizar el request (method
|
|
74
|
+
5. `JsonFormatter` intercepta cada `Rails.logger.*` e inyecta automaticamente: `time`, `level`, `severity_number`, `service`, `service_version`, `deployment_environment`, `root_id`, `trace_id`, `source`, `user_id`, `isp_id`, `correlation_id`. El developer aporta `component` (modulo de negocio) y `event` (que paso); estos NO son auto-inyectados porque dependen del call site, no del contexto de ejecucion.
|
|
75
|
+
6. `LogSubscriber` emite un unico Hash al finalizar el request con campos default (`component`, `event`, `method`, `path`, `http_route`, `format`, `controller`, `action`, `http_status`, `duration_s`, `duration_human`, `view_runtime_s`, `db_runtime_s`, `user_agent_original`, `server_address`, y en error `error_class`/`error_message`/`exception.*`).
|
|
76
76
|
7. En llamadas salientes, `FaradayMiddleware`/`ActiveResourceInstrumentation` inyectan `propagation_trace_header` con `Tracer.generate_trace_header`
|
|
77
77
|
8. Al finalizar, `ActiveSupport::CurrentAttributes` hace reset automatico
|
|
78
78
|
|
|
@@ -212,6 +212,32 @@ end
|
|
|
212
212
|
|
|
213
213
|
### ExisRay::LogSubscriber
|
|
214
214
|
|
|
215
|
+
Reemplaza Lograge. Se suscribe a `process_action.action_controller` y emite un Hash por request HTTP. Severity es `ERROR` si `http_status >= 500`, sino `INFO`.
|
|
216
|
+
|
|
217
|
+
**Campos default emitidos** (mergeados al payload JSON; nunca duplicarlos manualmente):
|
|
218
|
+
|
|
219
|
+
| Campo | Tipo | Notas |
|
|
220
|
+
|:------|:-----|:------|
|
|
221
|
+
| `component` | String | Siempre `"exis_ray"` |
|
|
222
|
+
| `event` | String | Siempre `"http_request"` |
|
|
223
|
+
| `method` | String | Verbo HTTP |
|
|
224
|
+
| `path` | String | URL concreta del request |
|
|
225
|
+
| `http_route` | String | Template (ej: `/users/:id`). Baja cardinalidad para dashboards |
|
|
226
|
+
| `format` | Symbol/String | `html`, `json`, etc. |
|
|
227
|
+
| `controller` | String | Class name del controller |
|
|
228
|
+
| `action` | String | Nombre del action |
|
|
229
|
+
| `http_status` | Integer | Status HTTP final |
|
|
230
|
+
| `duration_s` | Float | Segundos (Rails reporta ms, se convierte), redondeo 4 decimales |
|
|
231
|
+
| `duration_human` | String | Legible: `"42.5ms"`, `"1.25s"`, `"2 minutes 5 seconds"` |
|
|
232
|
+
| `view_runtime_s` | Float\|nil | Solo si Rails lo reporta |
|
|
233
|
+
| `db_runtime_s` | Float\|nil | Solo si ActiveRecord lo reporta |
|
|
234
|
+
| `user_agent_original` | String | Header `User-Agent` |
|
|
235
|
+
| `server_address` | String | Hostname sin puerto (de `Host` header) |
|
|
236
|
+
| `error_class`, `error_message` | String | Solo en fallo (legacy) |
|
|
237
|
+
| `exception.type`, `exception.message`, `exception.stacktrace` | String | Solo en fallo (OTel; stack limitado a 20 lineas) |
|
|
238
|
+
|
|
239
|
+
Para inyectar campos extra, sobreescribir `extra_fields`:
|
|
240
|
+
|
|
215
241
|
```ruby
|
|
216
242
|
class MyLogSubscriber < ExisRay::LogSubscriber
|
|
217
243
|
def self.extra_fields(event)
|
|
@@ -227,12 +253,41 @@ ExisRay.configure { |c| c.log_subscriber_class = "MyLogSubscriber" }
|
|
|
227
253
|
|
|
228
254
|
Se asigna automaticamente a `Rails.logger.formatter` cuando `log_format: :json`. Acepta tres tipos de mensaje:
|
|
229
255
|
|
|
230
|
-
- **Hash**: merge directo al payload JSON
|
|
231
|
-
- **String KV** (`"event=foo bar=baz"`): parsea pares y los eleva al root del JSON
|
|
232
|
-
- **String libre**: asigna al campo `body`
|
|
256
|
+
- **Hash**: merge directo al payload JSON. Util para payloads complejos o con valores nested.
|
|
257
|
+
- **String KV** (`"event=foo bar=baz"`): parsea pares y los eleva al root del JSON. Util para one-liners rapidos.
|
|
258
|
+
- **String libre**: asigna al campo `body` (OTel log body).
|
|
233
259
|
|
|
234
260
|
Casteo automatico: integers, floats, objetos JSON (`{...}`, `[...]`). Filtra claves sensibles (`password|secret|token|api_key|auth`) a `[FILTERED]`. Fallback a JSON minimo si el formateo falla.
|
|
235
261
|
|
|
262
|
+
#### Criterio auto-inyectado vs manual
|
|
263
|
+
|
|
264
|
+
- **Auto-inyectado** (formatter conoce desde `Tracer`/`Current`): contexto de **ejecucion** — quien hace el request, de donde viene, en que servicio, con que identidad.
|
|
265
|
+
- **Manual** (lo aporta cada `Rails.logger.*`): contexto del **call site** — que modulo (`component`) y que paso (`event`). El formatter no puede saber esto sin recorrer el stack en cada log.
|
|
266
|
+
|
|
267
|
+
Por eso `component` y `event` jamas se auto-inyectan, aunque el estandar Wispro los exija.
|
|
268
|
+
|
|
269
|
+
#### Ejemplos: KV vs Hash producen output equivalente
|
|
270
|
+
|
|
271
|
+
```ruby
|
|
272
|
+
# KV string — one-liner rapido
|
|
273
|
+
Rails.logger.info("component=billing event=invoice_paid invoice_id=42 total=199.99")
|
|
274
|
+
|
|
275
|
+
# Hash style — payloads complejos / nested
|
|
276
|
+
Rails.logger.info(component: "billing", event: "invoice_paid",
|
|
277
|
+
invoice: { id: 42, total: 199.99 })
|
|
278
|
+
|
|
279
|
+
# String libre — fallback, va a `body`
|
|
280
|
+
Rails.logger.info("usuario hizo click")
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
#### Output JSON resultante (mismo para KV y Hash del ejemplo)
|
|
284
|
+
|
|
285
|
+
```json
|
|
286
|
+
{"time":"2026-05-11T09:15:00.123Z","level":"INFO","severity_number":9,"service":"box_radius_manager","service_version":"1.2.3","deployment_environment":"production","root_id":"1-abc","trace_id":"Root=1-abc;Self=...","source":"http","user_id":42,"isp_id":10,"correlation_id":"box_radius_manager;1-abc","component":"billing","event":"invoice_paid","invoice_id":42,"total":199.99}
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
Los campos hasta `correlation_id` los inyecta el formatter automaticamente. De `component` en adelante son los campos del mensaje del developer.
|
|
290
|
+
|
|
236
291
|
### Middlewares de propagacion
|
|
237
292
|
|
|
238
293
|
```ruby
|
|
@@ -290,6 +345,20 @@ Agrega `f.use ExisRay::FaradayMiddleware` al stack de Faraday. Solo inyecta head
|
|
|
290
345
|
**P: Puedo usar ExisRay sin JSON logging?**
|
|
291
346
|
Si. Con `log_format: :text` (default), ExisRay inyecta el `root_id` como tag de Rails via `config.log_tags`. El JsonFormatter y LogSubscriber no se activan.
|
|
292
347
|
|
|
348
|
+
**P: Por que no usar `ActiveSupport::TaggedLogging` con JSON logging?**
|
|
349
|
+
`TaggedLogging` agrega tags como texto plano al inicio de cada línea **antes** del formatter, lo cual rompe el JSON:
|
|
350
|
+
```
|
|
351
|
+
[request_id] {"time":"...","level":"INFO",...} # ← texto antes del JSON
|
|
352
|
+
```
|
|
353
|
+
`ExisRay::JsonFormatter` ya inyecta los tags (`request_id`, `trace_id`, etc.) como campos JSON. Usar ambos genera JSON inválido.
|
|
354
|
+
|
|
355
|
+
Configuración correcta en production.rb:
|
|
356
|
+
```ruby
|
|
357
|
+
config.colorize_logging = false
|
|
358
|
+
config.logger = ActiveSupport::Logger.new(STDOUT)
|
|
359
|
+
config.logger.formatter = ExisRay::JsonFormatter
|
|
360
|
+
```
|
|
361
|
+
|
|
293
362
|
**P: Que pasa con los logs de Sidekiq (el propio logger de Sidekiq)?**
|
|
294
363
|
Si `json_logs?` es true, el Railtie asigna `Sidekiq.logger.formatter = ExisRay::JsonFormatter.new`, asi los logs internos de Sidekiq tambien salen en JSON.
|
|
295
364
|
|
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.7.
|
|
4
|
+
version: 0.7.2
|
|
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-
|
|
11
|
+
date: 2026-05-11 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: activesupport
|
|
@@ -87,8 +87,8 @@ licenses:
|
|
|
87
87
|
metadata:
|
|
88
88
|
homepage_uri: https://github.com/gedera/exis_ray
|
|
89
89
|
source_code_uri: https://github.com/gedera/exis_ray
|
|
90
|
-
changelog_uri: https://github.com/gedera/exis_ray/blob/v0.7.
|
|
91
|
-
documentation_uri: https://github.com/gedera/exis_ray/blob/v0.7.
|
|
90
|
+
changelog_uri: https://github.com/gedera/exis_ray/blob/v0.7.2/CHANGELOG.md
|
|
91
|
+
documentation_uri: https://github.com/gedera/exis_ray/blob/v0.7.2/skill
|
|
92
92
|
post_install_message:
|
|
93
93
|
rdoc_options: []
|
|
94
94
|
require_paths:
|