exis_ray 0.4.2 → 0.5.1

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: ad3239a79f3c1393bc7138ed81a149afbc8564817687906e1dd06931a231a03f
4
- data.tar.gz: 5ff151e3ca3035d9d962622ea9a5b3231078fe913be160d1acb1e8f1c892f05e
3
+ metadata.gz: de4cf609747379030a7d49bf06aea93efbe9d60490eb3d9bfe4af3fec0fe1bd4
4
+ data.tar.gz: 0f3cbba6bf49ffec549c1cc7a306b9c018c12196f4a60afd62769268c5f964bf
5
5
  SHA512:
6
- metadata.gz: 333e04eb54ce9df129976069e99bd349d4c56902e0f1c2e39baa56fc15bcdfacea9b977bb4e03f35bad36d0cf3ad149aa232c8de90385f267d035b24af666fc4
7
- data.tar.gz: 1cb26ee1550c63524352ecce48ce2fcc761076cf9f6957757ce0e14b9ab6ced7aadc09e45ac0a954f8c2dc1018555f446ed1aa0fc9f2d3e44d6e7722c8d5e3a9
6
+ metadata.gz: 5e9532985f27d6ccb4efe76be22b3ff580eb60169e7f7c4a6a9db4ae19ac05a41489d43635f754deb6effd7732c97203ab0e28c19ae845f41f1a284ed79231ec
7
+ data.tar.gz: 40796e0043612a9636e212ae4ced8e096a984144e35f4d1e4baa9a1216514f8916ad9f3b2c054852861157015b4d37e9987da5e6b335a34254d0e5b5b8327468
data/CHANGELOG.md CHANGED
@@ -1,3 +1,18 @@
1
+ ## [0.5.1] - 2026-03-24
2
+
3
+ ### Fixed
4
+ - **Type-Aware KV Parser:** The `JsonFormatter` now automatically casts numeric strings to `Integer` or `Float` when parsing KV messages. This ensures compliance with the Wispro standard where `duration_s` and `count` must be numeric types in the final JSON, not strings.
5
+
6
+ ## [0.5.0] - 2026-03-23
7
+
8
+ ### Changed
9
+ - **Wispro-Observability-Spec (v1) Compliance:** Refactored telemetry across all execution layers (`TaskMonitor` and HTTP `LogSubscriber`).
10
+ - **Unit Standard:** Duration metrics now use `_s` suffix (Float) as the source of truth (e.g., `duration_s`, `view_runtime_s`, `db_runtime_s`).
11
+ - **Human Readability:** Added `duration_human` to both HTTP requests and Background Tasks.
12
+ - **Task Lifecycle:** The closing log now always uses `event=task_finished` with `status`, `duration_s`, and `duration_human` fields.
13
+ - **Error Consistency:** Failed tasks now include `error_class` and `error_message` fields in the JSON log.
14
+ - **Tracer Accuracy:** Improved `Tracer` with `current_duration_s` using monotonic clock precision.
15
+
1
16
  ## [0.4.2] - 2026-03-23
2
17
 
3
18
  ### Added
data/CLAUDE.md ADDED
@@ -0,0 +1,27 @@
1
+ # ExisRay Project Memory
2
+
3
+ ## Architecture & Components
4
+ - `ExisRay::Tracer`: Distributed tracing (AWS X-Ray). Uses `CurrentAttributes` for thread-safety.
5
+ - `ExisRay::Current`: Business context (User, ISP). Abstract base class for host app subclassing.
6
+ - `ExisRay::Reporter`: Sentry wrapper. Abstract base class for host app subclassing.
7
+ - `ExisRay::JsonFormatter`: Core engine. Handles Hash, KV strings, and free-text with automatic masking.
8
+ - `ExisRay::LogSubscriber`: Native HTTP logger since v0.4.0. Replaces Lograge.
9
+
10
+ ## Technical Knowledge & Compatibility
11
+
12
+ ### Rails Compatibility (6, 7, 8)
13
+ - **Reloading:** Use `cache_classes?` helper (checks `respond_to?(:enable_reloading)`) to avoid deprecation warnings in Rails 7.1+.
14
+ - **Notifications:** Rails 7.1+ uses `all_listeners_for`, while 6/7.0 uses `listeners_for`. Always use `respond_to?` guards when manipulating subscribers.
15
+
16
+ ### Distributed Tracing (AWS X-Ray)
17
+ - **Propagation:** Use `propagation_trace_header` (standard HTTP format) for outgoing requests.
18
+ - **Parsing:** `trace_header` (Rack format) is ONLY for incoming request parsing.
19
+
20
+ ### Security & Privacy
21
+ - **Sentry Context:** Default `sentry_user_context` and `sentry_isp_context` to `{ id: }` only. Never send full objects to avoid leaking sensitive fields (PII/Tokens).
22
+ - **Masking:** `JsonFormatter` automatically filters `password`, `token`, `api_key`, `auth`, `secret`.
23
+
24
+ ## Execution Rules
25
+ - **No Lograge:** Do not suggest or re-add the Lograge dependency.
26
+ - **Pure Data Logging:** Gem internal logs must use KV strings (`component=exis_ray event=...`).
27
+ - **Resilience:** All logging operations must be wrapped in `rescue StandardError` to ensure the host application never crashes due to a telemetry failure.
@@ -127,6 +127,7 @@ module ExisRay
127
127
 
128
128
  # Parsea un string con formato key=value y retorna un Hash.
129
129
  # Soporta valores con espacios si están entre comillas dobles (ej: message="algo salió mal").
130
+ # Intenta convertir valores numéricos a Float o Integer automáticamente.
130
131
  #
131
132
  # @param str [String]
132
133
  # @return [Hash]
@@ -134,18 +135,25 @@ module ExisRay
134
135
  result = {}
135
136
  str.scan(KV_PARSE_RE) do |key, value|
136
137
  val = value.start_with?('"') ? (value[1..-2] || "").gsub('\\"', '"') : value
137
- result[key.to_sym] = filter_sensitive_value(key, val)
138
+ result[key.to_sym] = cast_value(key, val)
138
139
  end
139
140
  result
140
141
  end
141
142
 
142
143
  # Filtra un valor si la clave se considera sensible.
144
+ # Si no es sensible, intenta castear el valor a número si corresponde.
143
145
  #
144
146
  # @param key [String, Symbol]
145
147
  # @param value [Object]
146
148
  # @return [Object]
147
- def filter_sensitive_value(key, value)
148
- key.to_s.match?(SENSITIVE_KEYS) ? "[FILTERED]" : value
149
+ def cast_value(key, value)
150
+ return "[FILTERED]" if key.to_s.match?(SENSITIVE_KEYS)
151
+
152
+ case value
153
+ when /\A\d+\z/ then value.to_i
154
+ when /\A\d+\.\d+\z/ then value.to_f
155
+ else value
156
+ end
149
157
  end
150
158
 
151
159
  # Filtra recursivamente un Hash que contenga claves sensibles.
@@ -69,18 +69,24 @@ module ExisRay
69
69
  payload = event.payload
70
70
  status = payload[:status] || exception_status(payload[:exception])
71
71
 
72
+ # Convertimos milisegundos (Rails default) a segundos (Estandar Wispro)
73
+ duration_s = (event.duration / 1000.0).round(4)
74
+ view_s = payload[:view_runtime] ? (payload[:view_runtime] / 1000.0).round(4) : nil
75
+ db_s = payload[:db_runtime] ? (payload[:db_runtime] / 1000.0).round(4) : nil
76
+
72
77
  data = {
73
- component: "exis_ray",
74
- event: "http_request",
75
- method: payload[:method],
76
- path: payload[:path],
77
- format: payload[:format],
78
- controller: payload[:controller],
79
- action: payload[:action],
80
- status: status,
81
- duration: event.duration.round(2),
82
- view: payload[:view_runtime]&.round(2),
83
- db: payload[:db_runtime]&.round(2)
78
+ component: "exis_ray",
79
+ event: "http_request",
80
+ method: payload[:method],
81
+ path: payload[:path],
82
+ format: payload[:format],
83
+ controller: payload[:controller],
84
+ action: payload[:action],
85
+ status: status,
86
+ duration_s: duration_s,
87
+ duration_human: ActiveSupport::Duration.build(duration_s).inspect,
88
+ view_runtime_s: view_s,
89
+ db_runtime_s: db_s
84
90
  }
85
91
 
86
92
  data.merge!(self.class.extra_fields(event))
@@ -34,9 +34,15 @@ module ExisRay
34
34
  # Bloque de ejecución con o sin tags dependiendo de la configuración
35
35
  execute_with_optional_tags { yield }
36
36
 
37
- log_event(:info, "component=exis_ray event=task_finished task=#{task_name} status=success")
37
+ duration_s = ExisRay::Tracer.current_duration_s
38
+ human_time = ActiveSupport::Duration.build(duration_s).inspect
39
+
40
+ log_event(:info, "component=exis_ray event=task_finished task=#{task_name} status=success duration_s=#{duration_s} duration_human=\"#{human_time}\"")
38
41
  rescue StandardError => e
39
- log_event(:error, "component=exis_ray event=task_failed task=#{task_name} status=failed error=#{e.message.inspect}")
42
+ duration_s = ExisRay::Tracer.current_duration_s
43
+ human_time = ActiveSupport::Duration.build(duration_s).inspect
44
+
45
+ log_event(:error, "component=exis_ray event=task_finished task=#{task_name} status=failed duration_s=#{duration_s} duration_human=\"#{human_time}\" error_class=#{e.class} error_message=#{e.message.inspect}")
40
46
  raise e
41
47
  ensure
42
48
  # Limpieza centralizada obligatoria para evitar filtraciones de memoria o contexto
@@ -58,8 +58,16 @@ module ExisRay
58
58
  #
59
59
  # @return [Integer] Duración en ms.
60
60
  def self.current_duration_ms
61
- return 0 unless created_at
62
- ((Process.clock_gettime(Process::CLOCK_MONOTONIC) - created_at) * 1000).round
61
+ (current_duration_s * 1000).round
62
+ end
63
+
64
+ # Calcula el tiempo transcurrido en segundos desde el inicio de la request.
65
+ # Cumple con el estándar Wispro-Observability-Spec (v1).
66
+ #
67
+ # @return [Float] Duración en segundos.
68
+ def self.current_duration_s
69
+ return 0.0 unless created_at
70
+ (Process.clock_gettime(Process::CLOCK_MONOTONIC) - created_at).round(4)
63
71
  end
64
72
 
65
73
  # Construye el header de trazabilidad para enviar al siguiente servicio.
@@ -2,5 +2,5 @@
2
2
 
3
3
  module ExisRay
4
4
  # Versión actual de la gema.
5
- VERSION = "0.4.2"
5
+ VERSION = "0.5.1"
6
6
  end
data/lib/exis_ray.rb CHANGED
@@ -1,10 +1,12 @@
1
1
  require "exis_ray/version"
2
2
 
3
3
  # Dependencias externas
4
- # Necesario para 'safe_constantize', 'present?', y 'CurrentAttributes'
4
+ # Necesario para 'safe_constantize', 'present?', 'CurrentAttributes' y 'Duration'
5
5
  require "active_support"
6
6
  require "active_support/core_ext/string/inflections" # Para safe_constantize
7
7
  require "active_support/current_attributes"
8
+ require "active_support/duration"
9
+ require "active_support/core_ext/numeric/time" # Para .seconds, .minutes, etc.
8
10
 
9
11
  # Componentes internos del Core
10
12
  require "exis_ray/configuration"
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.4.2
4
+ version: 0.5.1
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-23 00:00:00.000000000 Z
11
+ date: 2026-03-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -46,6 +46,7 @@ extensions: []
46
46
  extra_rdoc_files: []
47
47
  files:
48
48
  - CHANGELOG.md
49
+ - CLAUDE.md
49
50
  - LICENSE.txt
50
51
  - README.md
51
52
  - Rakefile