chronos-ruby 0.1.0.pre.2 → 0.3.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.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +56 -0
  3. data/README.md +51 -21
  4. data/docs/adr/ADR-005-sanitize-before-backlog.md +2 -2
  5. data/docs/adr/ADR-011-bounded-resilience-and-remote-control.md +27 -0
  6. data/docs/architecture.md +5 -4
  7. data/docs/compatibility.md +6 -6
  8. data/docs/configuration.md +27 -1
  9. data/docs/data-collected.md +10 -7
  10. data/docs/examples/plain-ruby.md +14 -0
  11. data/docs/modules/async-queue.md +6 -2
  12. data/docs/modules/notice-pipeline.md +6 -3
  13. data/docs/modules/remote-configuration.md +54 -0
  14. data/docs/modules/retry-backlog.md +60 -0
  15. data/docs/modules/sanitization.md +19 -0
  16. data/docs/modules/serialization.md +9 -0
  17. data/docs/modules/transport.md +5 -3
  18. data/docs/performance.md +39 -2
  19. data/docs/privacy-lgpd.md +80 -10
  20. data/docs/troubleshooting.md +2 -2
  21. data/lib/chronos/adapters/net_http_transport.rb +21 -3
  22. data/lib/chronos/agent.rb +16 -8
  23. data/lib/chronos/application/capture_exception.rb +20 -14
  24. data/lib/chronos/application/circuit_breaker.rb +70 -0
  25. data/lib/chronos/application/delivery_pipeline.rb +248 -0
  26. data/lib/chronos/application/remote_configuration.rb +173 -0
  27. data/lib/chronos/application/retry_policy.rb +57 -0
  28. data/lib/chronos/configuration.rb +178 -21
  29. data/lib/chronos/core/notice.rb +1 -1
  30. data/lib/chronos/core/payload_serializer.rb +39 -89
  31. data/lib/chronos/core/runtime_info.rb +1 -1
  32. data/lib/chronos/core/safe_serializer.rb +119 -0
  33. data/lib/chronos/core/sanitizer.rb +161 -0
  34. data/lib/chronos/core/sensitive_value_filter.rb +118 -0
  35. data/lib/chronos/internal/bounded_queue.rb +1 -1
  36. data/lib/chronos/internal/memory_backlog.rb +65 -0
  37. data/lib/chronos/internal/worker_pool.rb +5 -6
  38. data/lib/chronos/ports/transport.rb +4 -3
  39. data/lib/chronos/version.rb +1 -1
  40. data/lib/chronos.rb +9 -1
  41. metadata +30 -11
@@ -0,0 +1,161 @@
1
+ require "digest"
2
+
3
+ module Chronos
4
+ module Core
5
+ # Removes secrets and personal data from event values before serialization.
6
+ #
7
+ # @responsibility Recursively redact configured keys and recognized sensitive strings.
8
+ # @motivation Make privacy protection the default before transport or future persistence.
9
+ # @limits Detection is conservative and cannot replace an application data-governance review.
10
+ # @collaborators Configuration::Snapshot and application-provided filters.
11
+ # @thread_safety Instances are immutable; configured filters must be thread-safe.
12
+ # @compatibility Ruby 2.2.10 through Ruby 2.6; independent of frameworks.
13
+ # @example
14
+ # sanitizer.call("password" => "secret") #=> {"password"=>"[FILTERED]"}
15
+ # @errors Unsafe values and failing custom filters become redacted placeholders.
16
+ # @performance Work is linear in the structurally bounded event tree.
17
+ class Sanitizer
18
+ FILTERED = SensitiveValueFilter::FILTERED
19
+ MAX_DEPTH = 10
20
+ MAX_KEYS = 100
21
+ MAX_ITEMS = 100
22
+ MAX_NODES = 2_000
23
+
24
+ def initialize(config)
25
+ @blocklist_names, @blocklist_patterns = compile_matchers(config.blocklist_keys)
26
+ @allowlist_names, @allowlist_patterns = compile_matchers(config.allowlist_keys)
27
+ @hash_names, @hash_patterns = compile_matchers(config.hash_keys)
28
+ @filters = config.filters
29
+ @sensitive_value_filter = SensitiveValueFilter.new(config.anonymize_ip)
30
+ @hash_scope = config.project_id.to_s
31
+ freeze
32
+ end
33
+
34
+ def call(value)
35
+ sanitize_value(value, nil, true, 0, :nodes => 0, :seen => {})
36
+ rescue StandardError
37
+ FILTERED
38
+ end
39
+
40
+ private
41
+
42
+ def sanitize_value(value, key, run_filters, depth, state)
43
+ state[:nodes] += 1
44
+ return "<node limit reached>" if state[:nodes] > MAX_NODES
45
+ return "<maximum depth reached>" if depth >= MAX_DEPTH
46
+
47
+ result = sanitize_type(value, depth, state)
48
+ run_filters && key && !@filters.empty? ? filter_value(key, result, depth, state) : result
49
+ rescue StandardError
50
+ FILTERED
51
+ end
52
+
53
+ def sanitize_type(value, depth, state)
54
+ return sanitize_hash(value, depth, state) if value.is_a?(Hash)
55
+ return sanitize_array(value, depth, state) if value.is_a?(Array)
56
+ return @sensitive_value_filter.call(value) if value.is_a?(String)
57
+
58
+ value
59
+ end
60
+
61
+ def sanitize_hash(value, depth, state)
62
+ return "<circular reference>" if state[:seen][value.object_id]
63
+
64
+ state[:seen][value.object_id] = true
65
+ result = {}
66
+ value.to_a.first(MAX_KEYS).each do |key, child|
67
+ result[key] = sanitize_hash_value(key, child, depth, state)
68
+ end
69
+ state[:seen].delete(value.object_id)
70
+ result
71
+ end
72
+
73
+ def sanitize_hash_value(key, value, depth, state)
74
+ return FILTERED if blocked_key?(key) && !allowed_key?(key)
75
+ return hash_value(value) if hashed_key?(key)
76
+
77
+ sanitize_value(value, key, true, depth + 1, state)
78
+ end
79
+
80
+ def sanitize_array(value, depth, state)
81
+ return "<circular reference>" if state[:seen][value.object_id]
82
+
83
+ state[:seen][value.object_id] = true
84
+ result = value.first(MAX_ITEMS).map do |child|
85
+ sanitize_value(child, nil, true, depth + 1, state)
86
+ end
87
+ state[:seen].delete(value.object_id)
88
+ result
89
+ end
90
+
91
+ def blocked_key?(key)
92
+ matches_any?(@blocklist_names, @blocklist_patterns, key, true)
93
+ end
94
+
95
+ def allowed_key?(key)
96
+ matches_any?(@allowlist_names, @allowlist_patterns, key, false)
97
+ end
98
+
99
+ def hashed_key?(key)
100
+ matches_any?(@hash_names, @hash_patterns, key, false)
101
+ end
102
+
103
+ def compile_matchers(matchers)
104
+ names = []
105
+ patterns = []
106
+ matchers.each do |matcher|
107
+ matcher.is_a?(Regexp) ? patterns << matcher : names << normalize_key(matcher)
108
+ end
109
+ [names.freeze, patterns.freeze]
110
+ end
111
+
112
+ def matches_any?(names, patterns, key, fallback)
113
+ candidate = safe_key(key)
114
+ key_name = normalize_key(candidate)
115
+ name_match = names.any? { |name| key_name == name || key_name.end_with?("_#{name}") }
116
+ name_match || patterns.any? { |pattern| pattern =~ candidate }
117
+ rescue StandardError
118
+ fallback
119
+ end
120
+
121
+ def normalize_key(value)
122
+ value.to_s.downcase.gsub(/[^a-z0-9]+/, "_").sub(/\A_+/, "").sub(/_+\z/, "")
123
+ end
124
+
125
+ def safe_key(value)
126
+ return value if value.is_a?(String)
127
+ return value.to_s if value.is_a?(Symbol) || value.is_a?(Numeric)
128
+
129
+ "<#{safe_class_name(value)}>"
130
+ rescue StandardError
131
+ "<unreadable key>"
132
+ end
133
+
134
+ def hash_value(value)
135
+ scalar = case value
136
+ when String, Symbol, Numeric
137
+ value.to_s
138
+ else
139
+ return FILTERED
140
+ end
141
+ digest = Digest::SHA256.hexdigest("chronos:#{@hash_scope}:#{scalar}")
142
+ "[HASHED_SHA256:#{digest}]"
143
+ rescue StandardError
144
+ FILTERED
145
+ end
146
+
147
+ def filter_value(key, value, depth, state)
148
+ filtered = @filters.inject(value) { |current, filter| filter.call(key, current) }
149
+ sanitize_value(filtered, nil, false, depth, state)
150
+ rescue StandardError
151
+ FILTERED
152
+ end
153
+
154
+ def safe_class_name(value)
155
+ value.class.name.to_s
156
+ rescue StandardError
157
+ "Object"
158
+ end
159
+ end
160
+ end
161
+ end
@@ -0,0 +1,118 @@
1
+ module Chronos
2
+ module Core
3
+ # Redacts recognized secret and personal-data patterns inside strings.
4
+ #
5
+ # @responsibility Detect bounded sensitive value formats independently of hash-key policy.
6
+ # @motivation Protect exception messages and allowlisted fields where no sensitive key exists.
7
+ # @limits Detection is conservative, validates documents and cards, and does not cover every format.
8
+ # @collaborators Sanitizer.
9
+ # @thread_safety Immutable after construction and safe to share between capture calls.
10
+ # @compatibility Ruby 2.2.10 through Ruby 2.6.
11
+ # @example
12
+ # filter.call("person@example.com") #=> "[FILTERED_EMAIL]"
13
+ # @errors Invalid encodings become a filtered placeholder.
14
+ # @performance Applies a fixed set of regular expressions to each bounded string.
15
+ class SensitiveValueFilter
16
+ FILTERED = "[FILTERED]".freeze
17
+ FILTERED_EMAIL = "[FILTERED_EMAIL]".freeze
18
+ FILTERED_DOCUMENT = "[FILTERED_DOCUMENT]".freeze
19
+ FILTERED_CARD = "[FILTERED_CARD]".freeze
20
+ FILTERED_JWT = "[FILTERED_JWT]".freeze
21
+
22
+ EMAIL_PATTERN = /\b[A-Z0-9._%+\-]+@[A-Z0-9.\-]+\.[A-Z]{2,}\b/i
23
+ JWT_PATTERN = /\b[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\b/
24
+ BEARER_PATTERN = /\bBearer\s+[^\s,;]+/i
25
+ CPF_PATTERN = /\b\d{3}\.?\d{3}\.?\d{3}-?\d{2}\b/
26
+ CNPJ_PATTERN = %r{\b\d{2}\.?\d{3}\.?\d{3}/?\d{4}-?\d{2}\b}
27
+ IPV4_PATTERN = /\b(?:\d{1,3}\.){3}\d{1,3}\b/
28
+ CARD_PATTERN = /\b(?:\d[ -]?){12,18}\d\b/
29
+
30
+ def initialize(anonymize_ip)
31
+ @anonymize_ip = anonymize_ip
32
+ freeze
33
+ end
34
+
35
+ def call(value)
36
+ result = safe_string(value)
37
+ result = result.gsub(BEARER_PATTERN, "Bearer #{FILTERED}") if result =~ BEARER_PATTERN
38
+ result = result.gsub(JWT_PATTERN, FILTERED_JWT) if result.count(".") >= 2
39
+ result = result.gsub(EMAIL_PATTERN, FILTERED_EMAIL) if result.include?("@")
40
+ result = redact_numeric_values(result) if result.count("0-9") >= 11
41
+ @anonymize_ip && result.count(".") >= 3 ? anonymize_ipv4(result) : result
42
+ rescue StandardError
43
+ FILTERED
44
+ end
45
+
46
+ private
47
+
48
+ def redact_numeric_values(value)
49
+ result = redact_documents(value)
50
+ value.count("0-9") >= 13 ? redact_cards(result) : result
51
+ end
52
+
53
+ def redact_cards(value)
54
+ value.gsub(CARD_PATTERN) do |candidate|
55
+ luhn_valid?(candidate) ? FILTERED_CARD : candidate
56
+ end
57
+ end
58
+
59
+ def redact_documents(value)
60
+ result = value.gsub(CNPJ_PATTERN) do |candidate|
61
+ valid_cnpj?(candidate) ? FILTERED_DOCUMENT : candidate
62
+ end
63
+ result.gsub(CPF_PATTERN) do |candidate|
64
+ valid_cpf?(candidate) ? FILTERED_DOCUMENT : candidate
65
+ end
66
+ end
67
+
68
+ def valid_cpf?(candidate)
69
+ digits = candidate.gsub(/\D/, "").chars.map(&:to_i)
70
+ return false if digits.uniq.size == 1
71
+
72
+ digits[9] == document_digit(digits.first(9), (2..10).to_a.reverse) &&
73
+ digits[10] == document_digit(digits.first(10), (2..11).to_a.reverse)
74
+ end
75
+
76
+ def valid_cnpj?(candidate)
77
+ digits = candidate.gsub(/\D/, "").chars.map(&:to_i)
78
+ return false if digits.uniq.size == 1
79
+
80
+ first_weights = [5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2]
81
+ second_weights = [6] + first_weights
82
+ digits[12] == document_digit(digits.first(12), first_weights) &&
83
+ digits[13] == document_digit(digits.first(13), second_weights)
84
+ end
85
+
86
+ def document_digit(digits, weights)
87
+ remainder = digits.each_with_index.inject(0) do |sum, (digit, index)|
88
+ sum + (digit * weights[index])
89
+ end % 11
90
+ remainder < 2 ? 0 : 11 - remainder
91
+ end
92
+
93
+ def luhn_valid?(candidate)
94
+ digits = candidate.gsub(/\D/, "").chars.map(&:to_i)
95
+ return false unless digits.length.between?(13, 19)
96
+
97
+ sum = digits.reverse.each_with_index.inject(0) do |total, (digit, index)|
98
+ doubled = index.odd? ? digit * 2 : digit
99
+ total + (doubled > 9 ? doubled - 9 : doubled)
100
+ end
101
+ (sum % 10).zero?
102
+ end
103
+
104
+ def anonymize_ipv4(value)
105
+ value.gsub(IPV4_PATTERN) do |candidate|
106
+ octets = candidate.split(".").map(&:to_i)
107
+ octets.all? { |octet| octet.between?(0, 255) } ? "#{octets[0, 3].join('.')}.0" : candidate
108
+ end
109
+ end
110
+
111
+ def safe_string(value)
112
+ value.encode("UTF-8", :invalid => :replace, :undef => :replace, :replace => "�")
113
+ rescue StandardError
114
+ FILTERED
115
+ end
116
+ end
117
+ end
118
+ end
@@ -4,7 +4,7 @@ module Chronos
4
4
  #
5
5
  # @responsibility Accept events up to a limit and count accepted and dropped items.
6
6
  # @motivation Prevent telemetry bursts from growing application memory indefinitely.
7
- # @limits Version 0.1 drops the newest item when full and does not persist to disk.
7
+ # @limits Version 0.3 drops the newest item when full and does not persist to disk.
8
8
  # @collaborators WorkerPool.
9
9
  # @thread_safety Mutex and condition variable protect all mutable state.
10
10
  # @compatibility Ruby 2.2.10 through Ruby 2.6 and fork-aware callers.
@@ -0,0 +1,65 @@
1
+ module Chronos
2
+ module Internal
3
+ # Fixed-capacity retry storage for sanitized serialized events.
4
+ #
5
+ # @responsibility Retain failed deliveries in memory without unbounded growth.
6
+ # @motivation Allow later recovery while preserving the host application's memory limit.
7
+ # @limits It never writes to disk and accepts only SerializedEvent instances.
8
+ # @collaborators DeliveryPipeline and SerializedEvent.
9
+ # @thread_safety A mutex protects storage and counters.
10
+ # @compatibility Ruby 2.2.10 through Ruby 2.6.
11
+ # @example
12
+ # backlog.push(serialized_event)
13
+ # @errors Invalid event types raise before entering storage.
14
+ # @performance Push and shift are bounded by the configured capacity.
15
+ class MemoryBacklog
16
+ attr_reader :capacity
17
+
18
+ def initialize(capacity)
19
+ unless capacity.is_a?(Integer) && capacity >= 0
20
+ raise ArgumentError, "capacity must be a non-negative integer"
21
+ end
22
+
23
+ @capacity = capacity
24
+ @items = []
25
+ @accepted = 0
26
+ @dropped = 0
27
+ @mutex = Mutex.new
28
+ end
29
+
30
+ def push(event)
31
+ unless event.is_a?(Core::SerializedEvent)
32
+ raise ArgumentError, "backlog accepts only sanitized serialized events"
33
+ end
34
+
35
+ @mutex.synchronize do
36
+ if @items.length >= capacity
37
+ @dropped += 1
38
+ return false
39
+ end
40
+ @items << event
41
+ @accepted += 1
42
+ true
43
+ end
44
+ end
45
+
46
+ def shift
47
+ @mutex.synchronize { @items.shift }
48
+ end
49
+
50
+ def size
51
+ @mutex.synchronize { @items.size }
52
+ end
53
+
54
+ def empty?
55
+ size.zero?
56
+ end
57
+
58
+ def stats
59
+ @mutex.synchronize do
60
+ {:size => @items.size, :capacity => capacity, :accepted => @accepted, :dropped => @dropped}
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
@@ -4,8 +4,8 @@ module Chronos
4
4
  #
5
5
  # @responsibility Start workers on first use, deliver events, flush, and shut down predictably.
6
6
  # @motivation Keep serialization and network delivery outside the caller's critical path.
7
- # @limits Version 0.1 does not retry failed deliveries or persist a backlog.
8
- # @collaborators BoundedQueue, Transport, and SafeLogger.
7
+ # @limits Retry policy belongs to the delivery collaborator.
8
+ # @collaborators BoundedQueue, DeliveryPipeline, and SafeLogger.
9
9
  # @thread_safety Internal state is synchronized and active delivery is counted.
10
10
  # @compatibility Ruby 2.2.10 through Ruby 2.6; workers are recreated after fork.
11
11
  # @example
@@ -16,9 +16,9 @@ module Chronos
16
16
  class WorkerPool
17
17
  POLL_INTERVAL = 0.05
18
18
 
19
- def initialize(queue, transport, worker_count, logger = nil)
19
+ def initialize(queue, delivery, worker_count, logger = nil)
20
20
  @queue = queue
21
- @transport = transport
21
+ @delivery = delivery
22
22
  @worker_count = worker_count
23
23
  @logger = logger || SafeLogger.new(nil)
24
24
  @mutex = Mutex.new
@@ -59,7 +59,6 @@ module Chronos
59
59
  flushed = flush_without_reopening(timeout)
60
60
  @queue.close
61
61
  join_workers(timeout)
62
- @transport.close
63
62
  flushed
64
63
  rescue StandardError => error
65
64
  @logger.warn("Chronos worker shutdown failed: #{error.class}")
@@ -87,7 +86,7 @@ module Chronos
87
86
 
88
87
  increment_active
89
88
  begin
90
- @transport.send_event(event)
89
+ @delivery.send_event(event)
91
90
  rescue StandardError => error
92
91
  @logger.warn("Chronos worker contained #{error.class}")
93
92
  ensure
@@ -4,17 +4,18 @@ module Chronos
4
4
  #
5
5
  # @responsibility Describe delivery outcome and retry classification.
6
6
  # @motivation Keep HTTP implementation details outside the application layer.
7
- # @limits It does not schedule retries; retry is outside version 0.1.
7
+ # @limits It classifies outcomes but does not schedule retries.
8
8
  # @thread_safety Immutable after construction.
9
9
  # @compatibility Ruby 2.2.10 through Ruby 2.6.
10
10
  class TransportResult
11
- attr_reader :status, :status_code, :retry_after, :error
11
+ attr_reader :status, :status_code, :retry_after, :error, :remote_configuration
12
12
 
13
13
  def initialize(status, options = {})
14
14
  @status = status
15
15
  @status_code = options[:status_code]
16
16
  @retry_after = options[:retry_after]
17
17
  @error = options[:error]
18
+ @remote_configuration = options[:remote_configuration]
18
19
  freeze
19
20
  end
20
21
 
@@ -23,7 +24,7 @@ module Chronos
23
24
  end
24
25
 
25
26
  def retryable?
26
- [:rate_limited, :server_error, :network_error].include?(status)
27
+ [:request_timeout, :rate_limited, :server_error, :network_error].include?(status)
27
28
  end
28
29
  end
29
30
 
@@ -1,4 +1,4 @@
1
1
  module Chronos
2
2
  # Current version of the legacy Chronos Ruby agent.
3
- VERSION = "0.1.0.pre.2".freeze
3
+ VERSION = "0.3.0.pre.1".freeze
4
4
  end
data/lib/chronos.rb CHANGED
@@ -11,12 +11,20 @@ require "chronos/core/backtrace_parser"
11
11
  require "chronos/core/exception_cause_collector"
12
12
  require "chronos/core/runtime_info"
13
13
  require "chronos/core/notice_builder"
14
+ require "chronos/core/sensitive_value_filter"
15
+ require "chronos/core/sanitizer"
16
+ require "chronos/core/safe_serializer"
14
17
  require "chronos/core/payload_serializer"
15
18
  require "chronos/ports/transport"
16
19
  require "chronos/internal/safe_logger"
17
20
  require "chronos/internal/bounded_queue"
21
+ require "chronos/internal/memory_backlog"
18
22
  require "chronos/internal/worker_pool"
19
23
  require "chronos/adapters/net_http_transport"
24
+ require "chronos/application/retry_policy"
25
+ require "chronos/application/circuit_breaker"
26
+ require "chronos/application/remote_configuration"
27
+ require "chronos/application/delivery_pipeline"
20
28
  require "chronos/application/capture_exception"
21
29
  require "chronos/agent"
22
30
 
@@ -24,7 +32,7 @@ require "chronos/agent"
24
32
  #
25
33
  # @responsibility Configure the agent and expose its small lifecycle API.
26
34
  # @motivation Give applications a stable entry point while internals evolve.
27
- # @limits Version 0.1 captures Ruby exceptions only; integrations arrive later.
35
+ # @limits Version 0.3 captures Ruby exceptions manually; integrations arrive later.
28
36
  # @collaborators Configuration and Agent.
29
37
  # @thread_safety Agent replacement and lookup are protected by a mutex.
30
38
  # @compatibility Ruby 2.2.10 through Ruby 2.6.
metadata CHANGED
@@ -1,11 +1,11 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: chronos-ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0.pre.2
4
+ version: 0.3.0.pre.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Antonio Jefferson
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
11
  date: 2026-07-20 00:00:00.000000000 Z
@@ -30,14 +30,20 @@ dependencies:
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '10.0'
33
+ version: '12.3'
34
+ - - ">="
35
+ - !ruby/object:Gem::Version
36
+ version: 12.3.3
34
37
  type: :development
35
38
  prerelease: false
36
39
  version_requirements: !ruby/object:Gem::Requirement
37
40
  requirements:
38
41
  - - "~>"
39
42
  - !ruby/object:Gem::Version
40
- version: '10.0'
43
+ version: '12.3'
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: 12.3.3
41
47
  - !ruby/object:Gem::Dependency
42
48
  name: rspec
43
49
  requirement: !ruby/object:Gem::Requirement
@@ -56,16 +62,16 @@ dependencies:
56
62
  name: rubocop
57
63
  requirement: !ruby/object:Gem::Requirement
58
64
  requirements:
59
- - - '='
65
+ - - "~>"
60
66
  - !ruby/object:Gem::Version
61
- version: 0.47.1
67
+ version: 0.49.0
62
68
  type: :development
63
69
  prerelease: false
64
70
  version_requirements: !ruby/object:Gem::Requirement
65
71
  requirements:
66
- - - '='
72
+ - - "~>"
67
73
  - !ruby/object:Gem::Version
68
- version: 0.47.1
74
+ version: 0.49.0
69
75
  description: Base do cliente Chronos para excecoes, telemetria e observabilidade em
70
76
  aplicacoes Ruby legadas.
71
77
  email:
@@ -87,6 +93,7 @@ files:
87
93
  - docs/adr/ADR-004-bounded-queue.md
88
94
  - docs/adr/ADR-005-sanitize-before-backlog.md
89
95
  - docs/adr/ADR-006-versioned-event-contract.md
96
+ - docs/adr/ADR-011-bounded-resilience-and-remote-control.md
90
97
  - docs/architecture.md
91
98
  - docs/compatibility.md
92
99
  - docs/configuration.md
@@ -95,6 +102,10 @@ files:
95
102
  - docs/modules/async-queue.md
96
103
  - docs/modules/configuration.md
97
104
  - docs/modules/notice-pipeline.md
105
+ - docs/modules/remote-configuration.md
106
+ - docs/modules/retry-backlog.md
107
+ - docs/modules/sanitization.md
108
+ - docs/modules/serialization.md
98
109
  - docs/modules/transport.md
99
110
  - docs/performance.md
100
111
  - docs/privacy-lgpd.md
@@ -105,6 +116,10 @@ files:
105
116
  - lib/chronos/agent.rb
106
117
  - lib/chronos/application.rb
107
118
  - lib/chronos/application/capture_exception.rb
119
+ - lib/chronos/application/circuit_breaker.rb
120
+ - lib/chronos/application/delivery_pipeline.rb
121
+ - lib/chronos/application/remote_configuration.rb
122
+ - lib/chronos/application/retry_policy.rb
108
123
  - lib/chronos/configuration.rb
109
124
  - lib/chronos/core.rb
110
125
  - lib/chronos/core/backtrace_parser.rb
@@ -113,9 +128,13 @@ files:
113
128
  - lib/chronos/core/notice_builder.rb
114
129
  - lib/chronos/core/payload_serializer.rb
115
130
  - lib/chronos/core/runtime_info.rb
131
+ - lib/chronos/core/safe_serializer.rb
132
+ - lib/chronos/core/sanitizer.rb
133
+ - lib/chronos/core/sensitive_value_filter.rb
116
134
  - lib/chronos/errors.rb
117
135
  - lib/chronos/internal.rb
118
136
  - lib/chronos/internal/bounded_queue.rb
137
+ - lib/chronos/internal/memory_backlog.rb
119
138
  - lib/chronos/internal/safe_logger.rb
120
139
  - lib/chronos/internal/worker_pool.rb
121
140
  - lib/chronos/ports.rb
@@ -131,7 +150,7 @@ metadata:
131
150
  homepage_uri: https://github.com/antoniojefferson/chronos-ruby
132
151
  source_code_uri: https://github.com/antoniojefferson/chronos-ruby
133
152
  changelog_uri: https://github.com/antoniojefferson/chronos-ruby/blob/main/CHANGELOG.md
134
- post_install_message:
153
+ post_install_message:
135
154
  rdoc_options: []
136
155
  require_paths:
137
156
  - lib
@@ -149,8 +168,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
149
168
  - !ruby/object:Gem::Version
150
169
  version: 1.3.1
151
170
  requirements: []
152
- rubygems_version: 3.0.3
153
- signing_key:
171
+ rubygems_version: 3.4.22
172
+ signing_key:
154
173
  specification_version: 4
155
174
  summary: Cliente Ruby para captura de eventos do Chronos
156
175
  test_files: []