chronos-ruby 1.1.0 → 1.2.0.pre.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 +4 -4
- data/CHANGELOG.md +18 -0
- data/README.md +6 -4
- data/docs/adr/ADR-010-opentelemetry-interoperability.md +3 -3
- data/docs/compatibility.md +10 -16
- data/docs/configuration.md +6 -2
- data/docs/modules/context.md +1 -1
- data/docs/modules/external-http.md +3 -2
- data/lib/chronos/adapters/fiber_local_context_store.rb +57 -0
- data/lib/chronos/agent.rb +7 -1
- data/lib/chronos/configuration/apm_validation.rb +2 -0
- data/lib/chronos/configuration/validation.rb +2 -2
- data/lib/chronos/configuration.rb +4 -1
- data/lib/chronos/core/trace_context.rb +38 -0
- data/lib/chronos/integrations/active_job.rb +2 -2
- data/lib/chronos/integrations/faraday.rb +76 -0
- data/lib/chronos/integrations/net_http.rb +5 -1
- data/lib/chronos/integrations/opentelemetry.rb +44 -0
- data/lib/chronos/integrations/rack/middleware.rb +8 -2
- data/lib/chronos/integrations/sidekiq.rb +1 -1
- data/lib/chronos/rails/error_reporter_subscriber.rb +39 -0
- data/lib/chronos/rails/installer.rb +13 -0
- data/lib/chronos/rails/notifications_subscriber.rb +12 -0
- data/lib/chronos/rails.rb +1 -0
- data/lib/chronos/version.rb +2 -2
- data/lib/chronos.rb +4 -0
- metadata +41 -38
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: c13c2858edcb41d4b2a0bfc83049349ee13a5a9ecee873798750b4bf9f1da48c
|
|
4
|
+
data.tar.gz: a21babcc28ce763e7d867f35064735d661214724c1ed9d256e8d174a1a04c5dc
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 81ab0672785236e1ffaeecf0fbb5ae3187f319be349a06f724eee50dd0d20963afb74a84485267e8ea5e3a7dd37dacef15ab456783fee622bef901110b98344a
|
|
7
|
+
data.tar.gz: 835ee551ddcec646a44376dcdfc09748e12c0fa360fee62365455e6776503a0597baed504a33276059853e652f5a90458ad7ae43bb582f7647303af9940a5d1f
|
data/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,24 @@ All notable changes are documented here. The project follows Semantic Versioning
|
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
|
+
## [1.2.0.pre.1] - 2026-08-11
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- fiber-aware execution context with a thread-local fallback;
|
|
12
|
+
- Sidekiq 7 and Rails 7 error reporter integration using public extension APIs;
|
|
13
|
+
- Action Cable notification spans and a dependency-free Faraday middleware;
|
|
14
|
+
- optional W3C `traceparent` propagation and an OpenTelemetry bridge that consumes the active span without installing an SDK or exporter.
|
|
15
|
+
|
|
16
|
+
### Changed
|
|
17
|
+
|
|
18
|
+
- the transitional runtime range is Ruby 2.7 through 3.4 and the default context strategy is `:fiber_local`;
|
|
19
|
+
- Active Job and Sidekiq envelopes may propagate allowlisted span ID and trace flags in addition to trace/request IDs.
|
|
20
|
+
|
|
21
|
+
### Security
|
|
22
|
+
|
|
23
|
+
- W3C identifiers are syntax-validated, all-zero IDs are rejected, and Rails error reporter context is reduced to bounded allowlisted metadata.
|
|
24
|
+
|
|
7
25
|
## [1.1.0] - 2026-08-05
|
|
8
26
|
|
|
9
27
|
### Added
|
data/README.md
CHANGED
|
@@ -24,7 +24,7 @@ A gem não varre variáveis de ambiente, sistema de arquivos ou lockfiles e não
|
|
|
24
24
|
|
|
25
25
|
## Versões Ruby e Rails suportadas
|
|
26
26
|
|
|
27
|
-
A versão 1.
|
|
27
|
+
A versão candidata 1.2.0.pre.1 inicia a linha transitional para Ruby 2.7–3.4, Rails 7.x e Sidekiq 7. Ela adiciona contexto por Fiber, Rails Error Reporter, Action Cable, Faraday, Trace Context W3C opcional e coexistência com um SDK OpenTelemetry já configurado. Use-a explicitamente em staging enquanto a matriz transitional é validada; as linhas legadas permanecem disponíveis em releases anteriores.
|
|
28
28
|
|
|
29
29
|
Rubies e frameworks antigos estão fora do suporte de segurança de seus mantenedores. A Chronos oferece compatibilidade técnica, não manutenção de segurança do runtime. Veja [Compatibilidade](docs/compatibility.md).
|
|
30
30
|
|
|
@@ -204,14 +204,16 @@ Por padrão, SQL bruto e binds não são lidos pelo pipeline de análise. A insp
|
|
|
204
204
|
|
|
205
205
|
## Sidekiq e Active Job
|
|
206
206
|
|
|
207
|
-
A
|
|
207
|
+
A integração mantém o require explícito e suporta a API pública de middleware do Sidekiq 7:
|
|
208
|
+
|
|
209
|
+
O suporte histórico começou em `0.6.0.pre.1`; aplicações em Sidekiq 4/5 devem permanecer numa release legada compatível.
|
|
208
210
|
|
|
209
211
|
```ruby
|
|
210
212
|
gem "sidekiq", "~> 5.0"
|
|
211
213
|
gem "chronos-ruby", "~> 1.1.0", :require => "chronos/sidekiq"
|
|
212
214
|
```
|
|
213
215
|
|
|
214
|
-
O envelope de contexto não altera argumentos públicos e contém somente IDs limitados de trace/request. Active Job usa um campo serializado com namespace (`chronos_context`) e hooks públicos. Erros aninhados são deduplicados e reerguidos. Veja [Sidekiq legado](docs/modules/sidekiq-legacy.md), [Active Job](docs/modules/active-job.md) e [Jobs](docs/modules/job-monitoring.md).
|
|
216
|
+
O envelope de contexto não altera argumentos públicos e contém somente IDs limitados de trace/span/request e flags. Active Job usa um campo serializado com namespace (`chronos_context`) e hooks públicos. Erros aninhados são deduplicados e reerguidos. Veja [Sidekiq legado](docs/modules/sidekiq-legacy.md), [Active Job](docs/modules/active-job.md) e [Jobs](docs/modules/job-monitoring.md).
|
|
215
217
|
|
|
216
218
|
## Deploy tracking
|
|
217
219
|
|
|
@@ -319,7 +321,7 @@ Execute suíte e lint no runtime atual:
|
|
|
319
321
|
bundle _1.17.3_ exec rake
|
|
320
322
|
```
|
|
321
323
|
|
|
322
|
-
A matriz CI cobre
|
|
324
|
+
A matriz CI cobre a linha transitional e os checks de pacote/documentação; workflows legados preservam evidência das releases anteriores.
|
|
323
325
|
|
|
324
326
|
## Contribuição
|
|
325
327
|
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
## Status
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Aceito para 1.2.
|
|
6
6
|
|
|
7
7
|
## Contexto
|
|
8
8
|
|
|
@@ -10,7 +10,7 @@ O Chronos precisa correlacionar trace/request sem duplicar SDKs ou impor depend
|
|
|
10
10
|
|
|
11
11
|
## Decisão
|
|
12
12
|
|
|
13
|
-
Manter IDs de correlação e portas independentes do fornecedor
|
|
13
|
+
Manter IDs de correlação e portas independentes do fornecedor. Na 1.2, a ponte opcional consulta somente o span atual de um SDK já carregado, traduz `trace_id`, `span_id` e flags, e nunca instala SDK, instrumentação ou exporter. IDs Chronos explícitos têm precedência; a presença de OTel deve ser usada pelas integrações para evitar spans paralelos equivalentes.
|
|
14
14
|
|
|
15
15
|
## Alternativas
|
|
16
16
|
|
|
@@ -22,4 +22,4 @@ O protocolo v1 permanece estável e aplicações legadas não recebem novas depe
|
|
|
22
22
|
|
|
23
23
|
## Consequências negativas
|
|
24
24
|
|
|
25
|
-
|
|
25
|
+
A ponte não exporta spans OTel completos nem controla exporters; consumidores que precisam desses dados continuam responsáveis pela configuração do SDK.
|
data/docs/compatibility.md
CHANGED
|
@@ -1,39 +1,33 @@
|
|
|
1
1
|
# Compatibility
|
|
2
2
|
|
|
3
|
-
Chronos Ruby 1.1 is the
|
|
3
|
+
Chronos Ruby 1.2.0.pre.1 is the first candidate of the transitional line for Rails 7 and Sidekiq 7. Combinations remain `Best effort` until their dedicated CI and real-application gates pass. Technical compatibility does not make an end-of-life Ruby, Rails, Rack, or Sidekiq release secure. Versions 1.0 and 1.1 remain the frozen legacy line.
|
|
4
4
|
|
|
5
5
|
## Core and Rack
|
|
6
6
|
|
|
7
7
|
| Ruby | Status | Evidence |
|
|
8
8
|
|---|---|---|
|
|
9
|
-
| 2.2
|
|
10
|
-
|
|
|
11
|
-
| 2.
|
|
12
|
-
| 2.5.9 | Supported | Same dedicated Docker gate |
|
|
13
|
-
| 2.6.10 | Supported | Same dedicated Docker gate |
|
|
14
|
-
| 2.7 and newer | Unsupported in 1.x legacy | Belongs to the transitional or modern lines |
|
|
9
|
+
| 2.7–3.2 | Best effort | Transitional matrix introduced in this candidate; promotion requires green CI evidence |
|
|
10
|
+
| 3.3–3.4 | Best effort | Core checks run in modern CI; Rails 8-specific behavior belongs to 2.x |
|
|
11
|
+
| Earlier than 2.7 | Unsupported in 1.2 | Use an appropriate frozen legacy release |
|
|
15
12
|
|
|
16
13
|
## Rails
|
|
17
14
|
|
|
18
15
|
| Ruby | Rails | Status | Evidence |
|
|
19
16
|
|---|---|---|---|
|
|
20
|
-
| 2.2
|
|
21
|
-
|
|
|
22
|
-
|
|
|
23
|
-
| 2.6.10 | 5.2 | Supported | Same dedicated application gate |
|
|
24
|
-
| Other Ruby/Rails pairs | — | Unsupported | No complete release gate; feature detection alone is not a support claim |
|
|
17
|
+
| 2.7–3.2 | 7.0–7.1 | Best effort | Real Rails applications and the complete integration gate are pending |
|
|
18
|
+
| 3.1–3.4 | 7.2 | Best effort | Feature and package checks; use a validated application combination before production rollout |
|
|
19
|
+
| Rails 4–6 | — | Unsupported in 1.2 | Use a matching earlier Chronos release |
|
|
25
20
|
|
|
26
21
|
## Sidekiq
|
|
27
22
|
|
|
28
23
|
| Ruby | Sidekiq | Status | Evidence |
|
|
29
24
|
|---|---|---|---|
|
|
30
|
-
| 2.
|
|
31
|
-
|
|
|
32
|
-
| Other Ruby/Sidekiq pairs | — | Unsupported | No complete release gate |
|
|
25
|
+
| 2.7–3.4 | 7.x | Best effort | Real Sidekiq 7 smoke applications are pending |
|
|
26
|
+
| Sidekiq 4–6 | — | Unsupported in 1.2 | Use a matching earlier Chronos release |
|
|
33
27
|
|
|
34
28
|
Active Job uses the public `serialize`, `deserialize`, and `perform_now` extension points with a bounded namespaced field. Support follows the validated Rails pairs above. Adapters that bypass these hooks require their own evidence.
|
|
35
29
|
|
|
36
|
-
|
|
30
|
+
Historical evidence remains in [Version 1.0 readiness](release-1.0-readiness.md) and [Version 1.1 readiness](release-1.1-readiness.md).
|
|
37
31
|
|
|
38
32
|
Status meanings:
|
|
39
33
|
|
data/docs/configuration.md
CHANGED
|
@@ -47,7 +47,7 @@
|
|
|
47
47
|
| `sampling_rate` | Optional | `1.0` | Local upper bound for event sampling |
|
|
48
48
|
| `enabled_event_types` | Optional | exception, request, query, job, cache, external_http, dependencies, deploy, metric_batch | Local allowlist for supported event envelopes |
|
|
49
49
|
| `max_remote_send_interval` | Optional | `60.0` | Local upper bound for remotely requested send spacing |
|
|
50
|
-
| `context_store` | Optional | `:
|
|
50
|
+
| `context_store` | Optional | `:fiber_local` | `:fiber_local`, `:thread_local`, or an object implementing `get`, `set`, `clear`, and `with_context` |
|
|
51
51
|
| `breadcrumb_capacity` | Optional | `20` | Positive count of newest breadcrumbs retained per execution |
|
|
52
52
|
| `breadcrumb_max_bytes` | Optional | `2048` | Maximum bytes per normalized breadcrumb; minimum `128` |
|
|
53
53
|
| `rails_enabled` | Optional | `true` | Enables automatic Rails middleware and subscribers |
|
|
@@ -75,6 +75,8 @@
|
|
|
75
75
|
| `apm_transaction_max_connections` | Optional | `100` | Maximum concurrently tracked transaction connections; range 1–500 |
|
|
76
76
|
| `external_http_enabled` | Optional | `false` | Allows explicit per-instance outbound `Net::HTTP` instrumentation |
|
|
77
77
|
| `external_http_trace_headers` | Optional | `true` | Propagates Chronos trace/request headers on instrumented requests |
|
|
78
|
+
| `w3c_trace_context` | Optional | `false` | Injects a validated W3C `traceparent` header when trace and span IDs exist |
|
|
79
|
+
| `opentelemetry_bridge` | Optional | `true` | Consumes the current OpenTelemetry span when an SDK is already active; installs nothing |
|
|
78
80
|
| `cache_key_mode` | Optional | `:none` | `:none` omits keys; `:sha256` emits a project-scoped key hash |
|
|
79
81
|
| `dependency_reporting` | Optional | `true` | Emits one bounded dependency event per configured agent |
|
|
80
82
|
| `dependency_max_items` | Optional | `100` | Loaded gem entries retained in the inventory; range 1–200 |
|
|
@@ -100,7 +102,7 @@ Chronos.configure do |config|
|
|
|
100
102
|
config.max_retries = 3
|
|
101
103
|
config.backlog_size = 100
|
|
102
104
|
config.circuit_failure_threshold = 5
|
|
103
|
-
config.context_store = :
|
|
105
|
+
config.context_store = :fiber_local
|
|
104
106
|
config.breadcrumb_capacity = 20
|
|
105
107
|
config.rails_capture_in_test = false
|
|
106
108
|
config.rails_capture_in_console = false
|
|
@@ -125,6 +127,8 @@ Chronos.configure do |config|
|
|
|
125
127
|
config.apm_transaction_max_connections = 100
|
|
126
128
|
config.external_http_enabled = false
|
|
127
129
|
config.external_http_trace_headers = true
|
|
130
|
+
config.w3c_trace_context = false
|
|
131
|
+
config.opentelemetry_bridge = true
|
|
128
132
|
config.cache_key_mode = :none
|
|
129
133
|
config.dependency_reporting = true
|
|
130
134
|
config.dependency_max_items = 100
|
data/docs/modules/context.md
CHANGED
|
@@ -6,7 +6,7 @@ O contexto relaciona uma exceção ou métrica ao request/job atual sem criar de
|
|
|
6
6
|
|
|
7
7
|
## Fluxo e classes
|
|
8
8
|
|
|
9
|
-
`Chronos::Ports::ContextStore` define `get`, `set`, `clear` e `with_context`. Na linha
|
|
9
|
+
`Chronos::Ports::ContextStore` define `get`, `set`, `clear` e `with_context`. Na linha 1.2, `Chronos::Adapters::FiberLocalContextStore` usa storage do Fiber quando disponível e volta com segurança ao adapter thread-local. A fachada combina o contexto explícito com o escopo atual; o serializer sanitiza e limita tudo antes da fila. Rack limpa o escopo em `ensure`, enquanto Sidekiq e Active Job propagam somente `trace_id`, `span_id`, `trace_flags` e `request_id`.
|
|
10
10
|
|
|
11
11
|
## Extensão, riscos e exemplo
|
|
12
12
|
|
|
@@ -10,6 +10,7 @@ Chronos.configure do |config|
|
|
|
10
10
|
# connection settings omitted
|
|
11
11
|
config.external_http_enabled = true
|
|
12
12
|
config.external_http_trace_headers = true
|
|
13
|
+
config.w3c_trace_context = true
|
|
13
14
|
end
|
|
14
15
|
|
|
15
16
|
http = Net::HTTP.new("payments.example.com", 443)
|
|
@@ -18,10 +19,10 @@ Chronos.instrument_net_http(http)
|
|
|
18
19
|
response = http.request(Net::HTTP::Get.new("/health"))
|
|
19
20
|
```
|
|
20
21
|
|
|
21
|
-
The event contains a bounded lowercase host, uppercase method, response status, monotonic duration, timeout flag, connection-error flag, and error class. A request made inside a Chronos context receives `X-Chronos-Trace-ID` and `X-Chronos-Request-ID` unless the application already set those headers. Disable propagation with `external_http_trace_headers = false`.
|
|
22
|
+
The event contains a bounded lowercase host, uppercase method, response status, monotonic duration, timeout flag, connection-error flag, and error class. A request made inside a Chronos context receives `X-Chronos-Trace-ID` and `X-Chronos-Request-ID` unless the application already set those headers. With `w3c_trace_context = true`, Net::HTTP and `Chronos::Integrations::FaradayMiddleware` also preserve an existing header or inject a validated `traceparent`. Disable all propagation with `external_http_trace_headers = false`.
|
|
22
23
|
|
|
23
24
|
The wrapper never reads or records the path, query string, Authorization, other request headers, request body, response headers/body, or exception message. The native streaming block is forwarded and the identical HTTP exception is re-raised. Telemetry failures are contained.
|
|
24
25
|
|
|
25
|
-
Successful and failed calls become bounded `external_http` APM groups keyed only by host and method. A call carrying a trace ID contributes its duration to the enclosing request's `external_http` breakdown. Faraday
|
|
26
|
+
Successful and failed calls become bounded `external_http` APM groups keyed only by host and method. A call carrying a trace ID contributes its duration to the enclosing request's `external_http` breakdown. Faraday is supported through explicit middleware installation; HTTP.rb, Excon, and RestClient remain outside this release.
|
|
26
27
|
|
|
27
28
|
Installation is idempotent per object. A `false` result means collection is disabled, the object is incompatible or already instrumented, or installation was contained after an internal error.
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
module Chronos
|
|
2
|
+
module Adapters
|
|
3
|
+
# Stores execution context on the current Fiber when Ruby exposes Fiber storage.
|
|
4
|
+
#
|
|
5
|
+
# @responsibility Isolate context between concurrent fibers and restore nested scopes.
|
|
6
|
+
# @motivation Rails 7 applications increasingly multiplex work on one thread.
|
|
7
|
+
# @limits Fiber storage is not propagated automatically to newly-created fibers.
|
|
8
|
+
# @collaborators ContextStore port and Agent composition root.
|
|
9
|
+
# @thread_safety Each fiber owns its value and may be used from concurrent threads.
|
|
10
|
+
# @compatibility Ruby 3.2+ Fiber storage; falls back to thread-local storage otherwise.
|
|
11
|
+
# @example
|
|
12
|
+
# store.with_context(:request_id => "r1") { store.get }
|
|
13
|
+
# @errors Previous context is restored even when the block raises.
|
|
14
|
+
# @performance Constant-time storage operations with a bounded hash merge.
|
|
15
|
+
class FiberLocalContextStore
|
|
16
|
+
def initialize(fallback = ThreadLocalContextStore.new)
|
|
17
|
+
@key = "chronos_context_#{object_id}".to_sym
|
|
18
|
+
@fallback = fallback
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def get
|
|
22
|
+
supported? ? (Fiber[@key] || {}) : @fallback.get
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def set(context)
|
|
26
|
+
raise ArgumentError, "context must be a Hash" unless context.is_a?(Hash)
|
|
27
|
+
|
|
28
|
+
supported? ? Fiber[@key] = context : @fallback.set(context)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def clear
|
|
32
|
+
supported? ? Fiber[@key] = nil : @fallback.clear
|
|
33
|
+
nil
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def with_context(context)
|
|
37
|
+
previous = get
|
|
38
|
+
set(previous.merge(valid_context(context)))
|
|
39
|
+
yield
|
|
40
|
+
ensure
|
|
41
|
+
previous && !previous.empty? ? set(previous) : clear
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
private
|
|
45
|
+
|
|
46
|
+
def supported?
|
|
47
|
+
Fiber.respond_to?(:[]) && Fiber.respond_to?(:[]=)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def valid_context(context)
|
|
51
|
+
raise ArgumentError, "context must be a Hash" unless context.is_a?(Hash)
|
|
52
|
+
|
|
53
|
+
context
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
data/lib/chronos/agent.rb
CHANGED
|
@@ -148,7 +148,8 @@ module Chronos
|
|
|
148
148
|
end
|
|
149
149
|
|
|
150
150
|
def external_http_integration_options
|
|
151
|
-
{:enabled => @config.external_http_enabled, :trace_headers => @config.external_http_trace_headers
|
|
151
|
+
{:enabled => @config.external_http_enabled, :trace_headers => @config.external_http_trace_headers,
|
|
152
|
+
:w3c_trace_context => @config.w3c_trace_context}
|
|
152
153
|
end
|
|
153
154
|
|
|
154
155
|
def cache_integration_options
|
|
@@ -165,6 +166,10 @@ module Chronos
|
|
|
165
166
|
"request_id" => nested["request_id"] || nested[:request_id] ||
|
|
166
167
|
request["request_id"] || request[:request_id]
|
|
167
168
|
}
|
|
169
|
+
if @config.opentelemetry_bridge
|
|
170
|
+
otel = Integrations::OpenTelemetry.current_context
|
|
171
|
+
values = otel.merge(values.delete_if { |_key, value| value.to_s.empty? })
|
|
172
|
+
end
|
|
168
173
|
values.delete_if { |_key, value| value.to_s.empty? }
|
|
169
174
|
rescue StandardError
|
|
170
175
|
{}
|
|
@@ -237,6 +242,7 @@ module Chronos
|
|
|
237
242
|
|
|
238
243
|
def build_context_store(strategy)
|
|
239
244
|
return Adapters::ThreadLocalContextStore.new if strategy == :thread_local
|
|
245
|
+
return Adapters::FiberLocalContextStore.new if strategy == :fiber_local
|
|
240
246
|
|
|
241
247
|
strategy
|
|
242
248
|
end
|
|
@@ -110,6 +110,8 @@ module Chronos
|
|
|
110
110
|
errors = []
|
|
111
111
|
errors << "external_http_enabled must be true or false" unless boolean?(external_http_enabled)
|
|
112
112
|
errors << "external_http_trace_headers must be true or false" unless boolean?(external_http_trace_headers)
|
|
113
|
+
errors << "w3c_trace_context must be true or false" unless boolean?(w3c_trace_context)
|
|
114
|
+
errors << "opentelemetry_bridge must be true or false" unless boolean?(opentelemetry_bridge)
|
|
113
115
|
errors << "cache_key_mode must be :none or :sha256" unless [:none, :sha256].include?(cache_key_mode)
|
|
114
116
|
errors << "dependency_reporting must be true or false" unless boolean?(dependency_reporting)
|
|
115
117
|
unless dependency_max_items.is_a?(Integer) && dependency_max_items >= 1 && dependency_max_items <= 200
|
|
@@ -67,8 +67,8 @@ module Chronos
|
|
|
67
67
|
|
|
68
68
|
def context_errors
|
|
69
69
|
errors = []
|
|
70
|
-
unless
|
|
71
|
-
errors << "context_store must be :thread_local or implement get, set, clear, and with_context"
|
|
70
|
+
unless [:thread_local, :fiber_local].include?(context_store) || compatible_context_store?
|
|
71
|
+
errors << "context_store must be :thread_local, :fiber_local, or implement get, set, clear, and with_context"
|
|
72
72
|
end
|
|
73
73
|
errors << "breadcrumb_capacity must be a positive integer" unless positive_integer?(breadcrumb_capacity)
|
|
74
74
|
unless breadcrumb_max_bytes.is_a?(Integer) && breadcrumb_max_bytes >= 128
|
|
@@ -54,6 +54,7 @@ module Chronos
|
|
|
54
54
|
:apm_query_inspection_min_duration_ms, :apm_query_inspection_max_queries,
|
|
55
55
|
:apm_transaction_tracking_enabled, :apm_transaction_max_connections,
|
|
56
56
|
:external_http_enabled, :external_http_trace_headers,
|
|
57
|
+
:w3c_trace_context, :opentelemetry_bridge,
|
|
57
58
|
:cache_key_mode, :dependency_reporting, :dependency_max_items
|
|
58
59
|
].freeze
|
|
59
60
|
|
|
@@ -123,7 +124,7 @@ module Chronos
|
|
|
123
124
|
@user_agent = "chronos-ruby/#{Chronos::VERSION}"
|
|
124
125
|
@max_payload_size = 1_048_576
|
|
125
126
|
@gzip = false
|
|
126
|
-
@context_store = :
|
|
127
|
+
@context_store = :fiber_local
|
|
127
128
|
@breadcrumb_capacity = 20
|
|
128
129
|
@breadcrumb_max_bytes = 2048
|
|
129
130
|
end
|
|
@@ -167,6 +168,8 @@ module Chronos
|
|
|
167
168
|
def initialize_observability_defaults
|
|
168
169
|
@external_http_enabled = false
|
|
169
170
|
@external_http_trace_headers = true
|
|
171
|
+
@w3c_trace_context = false
|
|
172
|
+
@opentelemetry_bridge = true
|
|
170
173
|
@cache_key_mode = :none
|
|
171
174
|
@dependency_reporting = true
|
|
172
175
|
@dependency_max_items = 100
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
module Chronos
|
|
2
|
+
module Core
|
|
3
|
+
# Parses and formats the W3C Trace Context headers without an OpenTelemetry dependency.
|
|
4
|
+
module TraceContext
|
|
5
|
+
TRACEPARENT = /\A([\da-f]{2})-([\da-f]{32})-([\da-f]{16})-([\da-f]{2})\z/.freeze
|
|
6
|
+
|
|
7
|
+
module_function
|
|
8
|
+
|
|
9
|
+
def parse(value)
|
|
10
|
+
match = TRACEPARENT.match(value.to_s.downcase)
|
|
11
|
+
return {} unless match && match[1] == "00"
|
|
12
|
+
return {} if match[2] == ("0" * 32) || match[3] == ("0" * 16)
|
|
13
|
+
|
|
14
|
+
{"trace_id" => match[2], "span_id" => match[3], "trace_flags" => match[4]}
|
|
15
|
+
rescue StandardError
|
|
16
|
+
{}
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def format(context)
|
|
20
|
+
trace_id = value(context, "trace_id")
|
|
21
|
+
span_id = value(context, "span_id")
|
|
22
|
+
flags = value(context, "trace_flags")
|
|
23
|
+
return nil unless trace_id =~ /\A[\da-f]{32}\z/ && span_id =~ /\A[\da-f]{16}\z/
|
|
24
|
+
return nil if trace_id == ("0" * 32) || span_id == ("0" * 16)
|
|
25
|
+
|
|
26
|
+
"00-#{trace_id}-#{span_id}-#{flags =~ /\A[\da-f]{2}\z/ ? flags : '01'}"
|
|
27
|
+
rescue StandardError
|
|
28
|
+
nil
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def value(context, key)
|
|
32
|
+
return "" unless context.is_a?(Hash)
|
|
33
|
+
|
|
34
|
+
(context[key] || context[key.to_sym]).to_s.downcase
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
@@ -40,7 +40,7 @@ module Chronos
|
|
|
40
40
|
def envelope(notifier)
|
|
41
41
|
source = notifier.respond_to?(:propagation_context) ? notifier.propagation_context : {}
|
|
42
42
|
source = {} unless source.is_a?(Hash)
|
|
43
|
-
context = %w(trace_id request_id).each_with_object({}) do |key, result|
|
|
43
|
+
context = %w(trace_id span_id trace_flags request_id).each_with_object({}) do |key, result|
|
|
44
44
|
value = source[key] || source[key.to_sym]
|
|
45
45
|
result[key] = bounded(value) unless value.to_s.empty?
|
|
46
46
|
end
|
|
@@ -57,7 +57,7 @@ module Chronos
|
|
|
57
57
|
source = value["context"] || value[:context]
|
|
58
58
|
return {} unless source.is_a?(Hash)
|
|
59
59
|
|
|
60
|
-
%w(trace_id request_id).each_with_object({}) do |key, result|
|
|
60
|
+
%w(trace_id span_id trace_flags request_id).each_with_object({}) do |key, result|
|
|
61
61
|
candidate = source[key] || source[key.to_sym]
|
|
62
62
|
result[key] = bounded(candidate) unless candidate.to_s.empty?
|
|
63
63
|
end
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
module Chronos
|
|
2
|
+
module Integrations
|
|
3
|
+
# Optional Faraday middleware for outbound timing and W3C propagation.
|
|
4
|
+
# @responsibility Instrument one explicit Faraday connection without global patches.
|
|
5
|
+
# @motivation Modern Rails applications commonly use Faraday for outbound HTTP.
|
|
6
|
+
# @limits It never reads paths, queries, headers other than trace fields, or bodies.
|
|
7
|
+
# @collaborators Faraday middleware stack, TraceContext, and Chronos facade.
|
|
8
|
+
# @thread_safety Calls retain request state in local variables.
|
|
9
|
+
# @compatibility Faraday 1.x and 2.x middleware contracts.
|
|
10
|
+
# @example builder.use Chronos::Integrations::FaradayMiddleware
|
|
11
|
+
# @errors Original client exceptions are recorded by class and re-raised.
|
|
12
|
+
# @performance Two clock reads and one bounded asynchronous event per request.
|
|
13
|
+
class FaradayMiddleware
|
|
14
|
+
def initialize(app, options = {})
|
|
15
|
+
@app = app
|
|
16
|
+
@notifier = options[:notifier] || Chronos
|
|
17
|
+
@clock = options[:clock] || proc { Process.clock_gettime(Process::CLOCK_MONOTONIC) }
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def call(environment)
|
|
21
|
+
started_at = @clock.call
|
|
22
|
+
inject_headers(environment)
|
|
23
|
+
response = @app.call(environment)
|
|
24
|
+
if response.respond_to?(:on_complete)
|
|
25
|
+
response.on_complete { |completed| record(completed, started_at, nil) }
|
|
26
|
+
else
|
|
27
|
+
record(environment, started_at, nil)
|
|
28
|
+
end
|
|
29
|
+
response
|
|
30
|
+
rescue StandardError => error
|
|
31
|
+
record(environment, started_at, error) if started_at
|
|
32
|
+
raise
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
private
|
|
36
|
+
|
|
37
|
+
def inject_headers(environment)
|
|
38
|
+
options = integration_options
|
|
39
|
+
return unless options[:trace_headers] && environment.respond_to?(:request_headers)
|
|
40
|
+
|
|
41
|
+
context = @notifier.respond_to?(:propagation_context) ? @notifier.propagation_context : {}
|
|
42
|
+
headers = environment.request_headers
|
|
43
|
+
traceparent = Core::TraceContext.format(context) if options[:w3c_trace_context]
|
|
44
|
+
headers["traceparent"] ||= traceparent if traceparent
|
|
45
|
+
headers["X-Chronos-Trace-ID"] ||= context["trace_id"] if context["trace_id"]
|
|
46
|
+
headers["X-Chronos-Request-ID"] ||= context["request_id"] if context["request_id"]
|
|
47
|
+
rescue StandardError
|
|
48
|
+
nil
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def record(environment, started_at, error)
|
|
52
|
+
url = environment.url if environment.respond_to?(:url)
|
|
53
|
+
payload = {
|
|
54
|
+
"host" => (url.host.to_s if url && url.respond_to?(:host)),
|
|
55
|
+
"method" => (environment.method.to_s.upcase if environment.respond_to?(:method)),
|
|
56
|
+
"status" => (environment.status.to_i if environment.respond_to?(:status) && environment.status),
|
|
57
|
+
"duration_ms" => ((@clock.call - started_at) * 1000.0).round(3),
|
|
58
|
+
"error_class" => (error.class.name.to_s if error)
|
|
59
|
+
}
|
|
60
|
+
payload.delete_if { |_key, value| value.nil? || value == "" }
|
|
61
|
+
@notifier.record_event("external_http", payload)
|
|
62
|
+
rescue StandardError
|
|
63
|
+
false
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def integration_options
|
|
67
|
+
return {:enabled => true, :trace_headers => true, :w3c_trace_context => false} unless
|
|
68
|
+
@notifier.respond_to?(:external_http_integration_options)
|
|
69
|
+
|
|
70
|
+
@notifier.external_http_integration_options
|
|
71
|
+
rescue StandardError
|
|
72
|
+
{:enabled => false, :trace_headers => false, :w3c_trace_context => false}
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
@@ -53,7 +53,8 @@ module Chronos
|
|
|
53
53
|
{
|
|
54
54
|
:notifier => notifier,
|
|
55
55
|
:clock => options[:clock] || proc { monotonic_time },
|
|
56
|
-
:trace_headers => configured.fetch(:trace_headers, true)
|
|
56
|
+
:trace_headers => configured.fetch(:trace_headers, true),
|
|
57
|
+
:w3c_trace_context => configured.fetch(:w3c_trace_context, false)
|
|
57
58
|
}
|
|
58
59
|
end
|
|
59
60
|
|
|
@@ -106,6 +107,9 @@ module Chronos
|
|
|
106
107
|
end
|
|
107
108
|
set_header(request, "X-Chronos-Trace-ID", context["trace_id"] || context[:trace_id])
|
|
108
109
|
set_header(request, "X-Chronos-Request-ID", context["request_id"] || context[:request_id])
|
|
110
|
+
if options[:w3c_trace_context]
|
|
111
|
+
set_header(request, "traceparent", Core::TraceContext.format(context))
|
|
112
|
+
end
|
|
109
113
|
rescue StandardError
|
|
110
114
|
nil
|
|
111
115
|
end
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
module Chronos
|
|
2
|
+
module Integrations
|
|
3
|
+
# Optional, dependency-free bridge to an already configured OpenTelemetry SDK.
|
|
4
|
+
module OpenTelemetry
|
|
5
|
+
module_function
|
|
6
|
+
|
|
7
|
+
def current_context
|
|
8
|
+
return {} unless defined?(::OpenTelemetry::Trace) && ::OpenTelemetry::Trace.respond_to?(:current_span)
|
|
9
|
+
|
|
10
|
+
span = ::OpenTelemetry::Trace.current_span
|
|
11
|
+
context = span.context if span && span.respond_to?(:context)
|
|
12
|
+
return {} unless context && (!context.respond_to?(:valid?) || context.valid?)
|
|
13
|
+
|
|
14
|
+
trace_id = hex_identifier(context, :hex_trace_id, :trace_id, 32)
|
|
15
|
+
span_id = hex_identifier(context, :hex_span_id, :span_id, 16)
|
|
16
|
+
return {} if trace_id.empty? || span_id.empty?
|
|
17
|
+
|
|
18
|
+
{"trace_id" => trace_id, "span_id" => span_id,
|
|
19
|
+
"trace_flags" => sampled?(context) ? "01" : "00", "source" => "opentelemetry"}
|
|
20
|
+
rescue StandardError
|
|
21
|
+
{}
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def active?
|
|
25
|
+
!current_context.empty?
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def hex_identifier(context, hex_method, numeric_method, width)
|
|
29
|
+
value = context.public_send(hex_method) if context.respond_to?(hex_method)
|
|
30
|
+
value ||= context.public_send(numeric_method).to_i.to_s(16) if context.respond_to?(numeric_method)
|
|
31
|
+
value.to_s.downcase.rjust(width, "0")[-width, width]
|
|
32
|
+
rescue StandardError
|
|
33
|
+
""
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def sampled?(context)
|
|
37
|
+
flags = context.trace_flags if context.respond_to?(:trace_flags)
|
|
38
|
+
flags.respond_to?(:sampled?) ? flags.sampled? : flags.to_i.odd?
|
|
39
|
+
rescue StandardError
|
|
40
|
+
false
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
@@ -62,7 +62,7 @@ module Chronos
|
|
|
62
62
|
def request_capture_context(env)
|
|
63
63
|
request = request_values(env)
|
|
64
64
|
{
|
|
65
|
-
:context =>
|
|
65
|
+
:context => trace_context(env).merge("request" => request),
|
|
66
66
|
:parameters => parameters(env),
|
|
67
67
|
:user => hash_value(env["chronos.user"])
|
|
68
68
|
}
|
|
@@ -124,7 +124,13 @@ module Chronos
|
|
|
124
124
|
end
|
|
125
125
|
|
|
126
126
|
def trace_id(env)
|
|
127
|
-
env["
|
|
127
|
+
trace_context(env)["trace_id"]
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
def trace_context(env)
|
|
131
|
+
parsed = Core::TraceContext.parse(env["HTTP_TRACEPARENT"])
|
|
132
|
+
parsed["trace_id"] = env["chronos.trace_id"] || SecureRandom.hex(16) if parsed.empty?
|
|
133
|
+
parsed
|
|
128
134
|
end
|
|
129
135
|
|
|
130
136
|
def response_size(headers)
|
|
@@ -110,7 +110,7 @@ module Chronos
|
|
|
110
110
|
source = @notifier.propagation_context
|
|
111
111
|
return {} unless source.is_a?(Hash)
|
|
112
112
|
|
|
113
|
-
%w(trace_id request_id).each_with_object({}) do |key, result|
|
|
113
|
+
%w(trace_id span_id trace_flags request_id).each_with_object({}) do |key, result|
|
|
114
114
|
value = source[key] || source[key.to_sym]
|
|
115
115
|
result[key] = value.to_s unless value.to_s.empty?
|
|
116
116
|
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
module Chronos
|
|
2
|
+
module Rails
|
|
3
|
+
# Sends exceptions observed by the Rails 7 error reporter to Chronos once.
|
|
4
|
+
# @responsibility Translate the public Rails reporter callback into one notice.
|
|
5
|
+
# @motivation Rails can report handled errors that never reach Rack middleware.
|
|
6
|
+
# @limits Only handled, severity, source, and one bounded component are retained.
|
|
7
|
+
# @collaborators ActiveSupport::ErrorReporter and Chronos facade.
|
|
8
|
+
# @thread_safety Instances contain only an immutable notifier reference.
|
|
9
|
+
# @compatibility Rails 7 public error reporter subscriber API.
|
|
10
|
+
# @example Rails.error.subscribe(ErrorReporterSubscriber.new)
|
|
11
|
+
# @errors Agent and context failures are contained and return false.
|
|
12
|
+
# @performance Allocates one small allowlisted metadata hash per report.
|
|
13
|
+
class ErrorReporterSubscriber
|
|
14
|
+
def initialize(notifier = Chronos)
|
|
15
|
+
@notifier = notifier
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def report(error, handled:, severity:, context:, source: nil)
|
|
19
|
+
details = {
|
|
20
|
+
:context => {"rails_error_reporter" => {
|
|
21
|
+
"handled" => handled == true, "severity" => severity.to_s, "source" => source.to_s
|
|
22
|
+
}}
|
|
23
|
+
}
|
|
24
|
+
details[:context]["rails_error_reporter"]["component"] = component(context)
|
|
25
|
+
@notifier.notify_once(error, details)
|
|
26
|
+
rescue StandardError
|
|
27
|
+
false
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
private
|
|
31
|
+
|
|
32
|
+
def component(context)
|
|
33
|
+
return "" unless context.is_a?(Hash)
|
|
34
|
+
|
|
35
|
+
(context[:controller] || context["controller"] || context[:job] || context["job"]).to_s[0, 128]
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -34,6 +34,7 @@ module Chronos
|
|
|
34
34
|
|
|
35
35
|
install_middleware(application, options)
|
|
36
36
|
install_active_job
|
|
37
|
+
install_error_reporter
|
|
37
38
|
@subscriber.install
|
|
38
39
|
self.class.applications[application.object_id] = true
|
|
39
40
|
end
|
|
@@ -65,6 +66,18 @@ module Chronos
|
|
|
65
66
|
Chronos::Integrations::ActiveJob.install(::ActiveJob::Base, @notifier)
|
|
66
67
|
end
|
|
67
68
|
|
|
69
|
+
def install_error_reporter
|
|
70
|
+
return false unless defined?(::Rails) && ::Rails.respond_to?(:error)
|
|
71
|
+
|
|
72
|
+
reporter = ::Rails.error
|
|
73
|
+
return false unless reporter && reporter.respond_to?(:subscribe)
|
|
74
|
+
|
|
75
|
+
reporter.subscribe(ErrorReporterSubscriber.new(@notifier))
|
|
76
|
+
true
|
|
77
|
+
rescue StandardError
|
|
78
|
+
false
|
|
79
|
+
end
|
|
80
|
+
|
|
68
81
|
def environment
|
|
69
82
|
defined?(::Rails) && ::Rails.respond_to?(:env) ? ::Rails.env.to_s : nil
|
|
70
83
|
end
|
|
@@ -17,6 +17,7 @@ module Chronos
|
|
|
17
17
|
process_action.action_controller render_template.action_view sql.active_record
|
|
18
18
|
deliver.action_mailer perform.active_job cache_read.active_support
|
|
19
19
|
cache_write.active_support cache_fetch_hit.active_support
|
|
20
|
+
perform_action.action_cable transmit.action_cable broadcast.action_cable
|
|
20
21
|
).freeze
|
|
21
22
|
|
|
22
23
|
@mutex = Mutex.new
|
|
@@ -105,6 +106,8 @@ module Chronos
|
|
|
105
106
|
when "sql.active_record" then sql(payload, duration)
|
|
106
107
|
when "deliver.action_mailer" then mailer(payload, duration)
|
|
107
108
|
when "perform.active_job" then active_job(payload, duration)
|
|
109
|
+
when "perform_action.action_cable", "transmit.action_cable", "broadcast.action_cable"
|
|
110
|
+
action_cable(name, payload, duration)
|
|
108
111
|
else cache(name, payload, duration)
|
|
109
112
|
end
|
|
110
113
|
end
|
|
@@ -345,6 +348,15 @@ module Chronos
|
|
|
345
348
|
@notifier.record_event("cache", data)
|
|
346
349
|
end
|
|
347
350
|
|
|
351
|
+
def action_cable(name, payload, duration)
|
|
352
|
+
data = {
|
|
353
|
+
"kind" => "action_cable", "operation" => name.split(".").first,
|
|
354
|
+
"channel" => safe_class_name(value(payload, :channel)),
|
|
355
|
+
"action" => value(payload, :action).to_s[0, 128], "duration_ms" => duration
|
|
356
|
+
}
|
|
357
|
+
@notifier.record_event("request", data)
|
|
358
|
+
end
|
|
359
|
+
|
|
348
360
|
def capture_controller_exception(payload)
|
|
349
361
|
exception = value(payload, :exception_object)
|
|
350
362
|
details = value(payload, :exception)
|
data/lib/chronos/rails.rb
CHANGED
data/lib/chronos/version.rb
CHANGED
data/lib/chronos.rb
CHANGED
|
@@ -16,6 +16,7 @@ require "chronos/core/sensitive_value_filter"
|
|
|
16
16
|
require "chronos/core/sanitizer"
|
|
17
17
|
require "chronos/core/safe_serializer"
|
|
18
18
|
require "chronos/core/correlation_context"
|
|
19
|
+
require "chronos/core/trace_context"
|
|
19
20
|
require "chronos/core/deploy_normalizer"
|
|
20
21
|
require "chronos/core/payload_serializer"
|
|
21
22
|
require "chronos/core/telemetry_event"
|
|
@@ -32,6 +33,7 @@ require "chronos/internal/memory_backlog"
|
|
|
32
33
|
require "chronos/internal/worker_pool"
|
|
33
34
|
require "chronos/adapters/net_http_transport"
|
|
34
35
|
require "chronos/adapters/thread_local_context_store"
|
|
36
|
+
require "chronos/adapters/fiber_local_context_store"
|
|
35
37
|
require "chronos/core/breadcrumb"
|
|
36
38
|
require "chronos/application/retry_policy"
|
|
37
39
|
require "chronos/application/circuit_breaker"
|
|
@@ -49,6 +51,8 @@ require "chronos/observability_facade"
|
|
|
49
51
|
require "chronos/integrations"
|
|
50
52
|
require "chronos/integrations/rack"
|
|
51
53
|
require "chronos/integrations/rack/middleware"
|
|
54
|
+
require "chronos/integrations/opentelemetry"
|
|
55
|
+
require "chronos/integrations/faraday"
|
|
52
56
|
|
|
53
57
|
# Framework-independent public facade for the Chronos Ruby agent.
|
|
54
58
|
#
|
metadata
CHANGED
|
@@ -1,93 +1,91 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: chronos-ruby
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.
|
|
4
|
+
version: 1.2.0.pre.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Antonio Jefferson
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-08-
|
|
11
|
+
date: 2026-08-11 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: bundler
|
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
|
16
16
|
requirements:
|
|
17
|
-
- - "
|
|
17
|
+
- - ">="
|
|
18
18
|
- !ruby/object:Gem::Version
|
|
19
|
-
version: '1
|
|
19
|
+
version: '2.1'
|
|
20
|
+
- - "<"
|
|
21
|
+
- !ruby/object:Gem::Version
|
|
22
|
+
version: '3'
|
|
20
23
|
type: :development
|
|
21
24
|
prerelease: false
|
|
22
25
|
version_requirements: !ruby/object:Gem::Requirement
|
|
23
26
|
requirements:
|
|
24
|
-
- - "
|
|
27
|
+
- - ">="
|
|
28
|
+
- !ruby/object:Gem::Version
|
|
29
|
+
version: '2.1'
|
|
30
|
+
- - "<"
|
|
25
31
|
- !ruby/object:Gem::Version
|
|
26
|
-
version: '
|
|
32
|
+
version: '3'
|
|
27
33
|
- !ruby/object:Gem::Dependency
|
|
28
34
|
name: rake
|
|
29
35
|
requirement: !ruby/object:Gem::Requirement
|
|
30
36
|
requirements:
|
|
31
|
-
- - "
|
|
37
|
+
- - ">="
|
|
32
38
|
- !ruby/object:Gem::Version
|
|
33
39
|
version: '12.3'
|
|
34
|
-
- - "
|
|
40
|
+
- - "<"
|
|
35
41
|
- !ruby/object:Gem::Version
|
|
36
|
-
version:
|
|
42
|
+
version: '14'
|
|
37
43
|
type: :development
|
|
38
44
|
prerelease: false
|
|
39
45
|
version_requirements: !ruby/object:Gem::Requirement
|
|
40
46
|
requirements:
|
|
41
|
-
- - "
|
|
47
|
+
- - ">="
|
|
42
48
|
- !ruby/object:Gem::Version
|
|
43
49
|
version: '12.3'
|
|
44
|
-
- - "
|
|
50
|
+
- - "<"
|
|
45
51
|
- !ruby/object:Gem::Version
|
|
46
|
-
version:
|
|
52
|
+
version: '14'
|
|
47
53
|
- !ruby/object:Gem::Dependency
|
|
48
54
|
name: rspec
|
|
49
55
|
requirement: !ruby/object:Gem::Requirement
|
|
50
56
|
requirements:
|
|
51
|
-
- - "
|
|
57
|
+
- - ">="
|
|
58
|
+
- !ruby/object:Gem::Version
|
|
59
|
+
version: '3.10'
|
|
60
|
+
- - "<"
|
|
52
61
|
- !ruby/object:Gem::Version
|
|
53
|
-
version: '
|
|
62
|
+
version: '4'
|
|
54
63
|
type: :development
|
|
55
64
|
prerelease: false
|
|
56
65
|
version_requirements: !ruby/object:Gem::Requirement
|
|
57
66
|
requirements:
|
|
58
|
-
- - "
|
|
67
|
+
- - ">="
|
|
59
68
|
- !ruby/object:Gem::Version
|
|
60
|
-
version: '3.
|
|
69
|
+
version: '3.10'
|
|
70
|
+
- - "<"
|
|
71
|
+
- !ruby/object:Gem::Version
|
|
72
|
+
version: '4'
|
|
61
73
|
- !ruby/object:Gem::Dependency
|
|
62
74
|
name: rubocop
|
|
63
75
|
requirement: !ruby/object:Gem::Requirement
|
|
64
76
|
requirements:
|
|
65
77
|
- - "~>"
|
|
66
78
|
- !ruby/object:Gem::Version
|
|
67
|
-
version:
|
|
79
|
+
version: 1.57.0
|
|
68
80
|
type: :development
|
|
69
81
|
prerelease: false
|
|
70
82
|
version_requirements: !ruby/object:Gem::Requirement
|
|
71
83
|
requirements:
|
|
72
84
|
- - "~>"
|
|
73
85
|
- !ruby/object:Gem::Version
|
|
74
|
-
version:
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
requirement: !ruby/object:Gem::Requirement
|
|
78
|
-
requirements:
|
|
79
|
-
- - '='
|
|
80
|
-
- !ruby/object:Gem::Version
|
|
81
|
-
version: 1.19.2
|
|
82
|
-
type: :development
|
|
83
|
-
prerelease: false
|
|
84
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
85
|
-
requirements:
|
|
86
|
-
- - '='
|
|
87
|
-
- !ruby/object:Gem::Version
|
|
88
|
-
version: 1.19.2
|
|
89
|
-
description: Base do cliente Chronos para excecoes, telemetria e observabilidade em
|
|
90
|
-
aplicacoes Ruby legadas.
|
|
86
|
+
version: 1.57.0
|
|
87
|
+
description: Cliente Chronos para excecoes, telemetria e observabilidade em aplicacoes
|
|
88
|
+
Ruby e Rails.
|
|
91
89
|
email:
|
|
92
90
|
- antoniojeferson96@gmail.com
|
|
93
91
|
executables: []
|
|
@@ -171,6 +169,7 @@ files:
|
|
|
171
169
|
- docs/troubleshooting.md
|
|
172
170
|
- lib/chronos.rb
|
|
173
171
|
- lib/chronos/adapters.rb
|
|
172
|
+
- lib/chronos/adapters/fiber_local_context_store.rb
|
|
174
173
|
- lib/chronos/adapters/net_http_transport.rb
|
|
175
174
|
- lib/chronos/adapters/thread_local_context_store.rb
|
|
176
175
|
- lib/chronos/agent.rb
|
|
@@ -210,12 +209,15 @@ files:
|
|
|
210
209
|
- lib/chronos/core/sql_normalizer.rb
|
|
211
210
|
- lib/chronos/core/sql_query_analyzer.rb
|
|
212
211
|
- lib/chronos/core/telemetry_event.rb
|
|
212
|
+
- lib/chronos/core/trace_context.rb
|
|
213
213
|
- lib/chronos/errors.rb
|
|
214
214
|
- lib/chronos/integrations.rb
|
|
215
215
|
- lib/chronos/integrations/active_job.rb
|
|
216
216
|
- lib/chronos/integrations/capistrano.rb
|
|
217
|
+
- lib/chronos/integrations/faraday.rb
|
|
217
218
|
- lib/chronos/integrations/job_payload.rb
|
|
218
219
|
- lib/chronos/integrations/net_http.rb
|
|
220
|
+
- lib/chronos/integrations/opentelemetry.rb
|
|
219
221
|
- lib/chronos/integrations/rack.rb
|
|
220
222
|
- lib/chronos/integrations/rack/middleware.rb
|
|
221
223
|
- lib/chronos/integrations/sidekiq.rb
|
|
@@ -232,6 +234,7 @@ files:
|
|
|
232
234
|
- lib/chronos/ports/transport.rb
|
|
233
235
|
- lib/chronos/rails.rb
|
|
234
236
|
- lib/chronos/rails/active_record_query_inspector.rb
|
|
237
|
+
- lib/chronos/rails/error_reporter_subscriber.rb
|
|
235
238
|
- lib/chronos/rails/installer.rb
|
|
236
239
|
- lib/chronos/rails/notifications_subscriber.rb
|
|
237
240
|
- lib/chronos/rails/railtie.rb
|
|
@@ -258,15 +261,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
258
261
|
requirements:
|
|
259
262
|
- - ">="
|
|
260
263
|
- !ruby/object:Gem::Version
|
|
261
|
-
version: 2.
|
|
264
|
+
version: '2.7'
|
|
262
265
|
- - "<"
|
|
263
266
|
- !ruby/object:Gem::Version
|
|
264
|
-
version: '
|
|
267
|
+
version: '3.5'
|
|
265
268
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
266
269
|
requirements:
|
|
267
|
-
- - "
|
|
270
|
+
- - ">"
|
|
268
271
|
- !ruby/object:Gem::Version
|
|
269
|
-
version:
|
|
272
|
+
version: 1.3.1
|
|
270
273
|
requirements: []
|
|
271
274
|
rubygems_version: 3.4.22
|
|
272
275
|
signing_key:
|