chronos-ruby 0.8.0.pre.1 → 0.9.0.pre.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.
Files changed (53) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +58 -0
  3. data/README.md +40 -10
  4. data/SECURITY.md +2 -0
  5. data/contracts/deploy-v1.schema.json +26 -0
  6. data/contracts/event-v1.schema.json +15 -1
  7. data/docs/adr/ADR-017-deploy-events-and-correlation.md +25 -0
  8. data/docs/adr/ADR-018-pre-1.0-hardening.md +9 -0
  9. data/docs/architecture.md +7 -1
  10. data/docs/compatibility.md +7 -2
  11. data/docs/configuration.md +18 -3
  12. data/docs/data-collected.md +6 -3
  13. data/docs/deprecation-policy.md +7 -0
  14. data/docs/examples/plain-ruby.md +7 -1
  15. data/docs/migration-from-airbrake.md +18 -0
  16. data/docs/modules/active-job.md +7 -0
  17. data/docs/modules/configuration.md +2 -0
  18. data/docs/modules/dependencies.md +2 -2
  19. data/docs/modules/deploy-tracking.md +86 -0
  20. data/docs/modules/ignore-rules.md +11 -0
  21. data/docs/modules/rails-legacy.md +3 -3
  22. data/docs/modules/sidekiq-legacy.md +1 -1
  23. data/docs/modules/telemetry-events.md +3 -1
  24. data/docs/performance.md +26 -1
  25. data/docs/privacy-lgpd.md +11 -2
  26. data/docs/protocol-v1.md +5 -0
  27. data/docs/release-1.0-readiness.md +18 -0
  28. data/docs/security-review.md +16 -0
  29. data/docs/semver.md +11 -0
  30. data/docs/troubleshooting.md +12 -0
  31. data/lib/chronos/agent.rb +30 -2
  32. data/lib/chronos/application/capture_exception.rb +7 -0
  33. data/lib/chronos/application/capture_telemetry.rb +17 -0
  34. data/lib/chronos/application/dependency_reporter.rb +12 -1
  35. data/lib/chronos/application/ignore_policy.rb +54 -0
  36. data/lib/chronos/application/remote_configuration.rb +1 -1
  37. data/lib/chronos/capistrano.rb +4 -0
  38. data/lib/chronos/configuration/apm_validation.rb +11 -0
  39. data/lib/chronos/configuration/validation.rb +16 -1
  40. data/lib/chronos/configuration.rb +14 -3
  41. data/lib/chronos/core/correlation_context.rb +65 -0
  42. data/lib/chronos/core/deploy_normalizer.rb +102 -0
  43. data/lib/chronos/core/payload_serializer.rb +4 -1
  44. data/lib/chronos/core/telemetry_event.rb +31 -4
  45. data/lib/chronos/integrations/active_job.rb +119 -0
  46. data/lib/chronos/integrations/capistrano.rb +61 -0
  47. data/lib/chronos/observability_facade.rb +9 -2
  48. data/lib/chronos/rails/installer.rb +7 -0
  49. data/lib/chronos/rails/notifications_subscriber.rb +29 -1
  50. data/lib/chronos/rails.rb +1 -0
  51. data/lib/chronos/version.rb +1 -1
  52. data/lib/chronos.rb +11 -1
  53. metadata +19 -1
@@ -0,0 +1,102 @@
1
+ require "securerandom"
2
+ require "uri"
3
+
4
+ module Chronos
5
+ module Core
6
+ # Normalizes explicit deployment metadata into the versioned deploy payload.
7
+ #
8
+ # @responsibility Validate required deploy identity and bound every public API field.
9
+ # @motivation Deployment commands need predictable safe input independent of frameworks.
10
+ # @limits It does not inspect Git, environment variables, credentials, or deployment systems.
11
+ # @collaborators Chronos.notify_deploy, CorrelationContext, and Configuration::Snapshot.
12
+ # @thread_safety Stateless apart from immutable configuration and an injected ID generator.
13
+ # @compatibility Ruby 2.2.10 through Ruby 2.6.
14
+ # @example
15
+ # DeployNormalizer.new(config).call(:revision => "abc", :version => "1.2.3")
16
+ # @errors Missing environment or both revision/version raise ArgumentError for the agent to contain.
17
+ # @performance Constant work over nine bounded scalar fields.
18
+ class DeployNormalizer
19
+ def initialize(config, options = {})
20
+ @config = config
21
+ @id_generator = options[:id_generator] || proc { SecureRandom.uuid }
22
+ end
23
+
24
+ def call(attributes = {})
25
+ values = string_hash(attributes)
26
+ payload = {
27
+ "deploy_id" => deploy_id(values["deploy_id"] || @config.deploy_id),
28
+ "environment" => bounded(values["environment"] || @config.environment, 128),
29
+ "revision" => bounded(values["revision"] || @config.revision, 128),
30
+ "version" => bounded(values["version"] || @config.app_version, 128),
31
+ "repository" => repository(values["repository"]),
32
+ "actor" => bounded(values["actor"], 128),
33
+ "service" => bounded(values["service"] || @config.service_name, 128),
34
+ "region" => bounded(values["region"] || @config.region, 128),
35
+ "instance" => bounded(values["instance"] || @config.instance_id, 128)
36
+ }
37
+ validate!(payload)
38
+ payload
39
+ end
40
+
41
+ private
42
+
43
+ def validate!(payload)
44
+ raise ArgumentError, "deploy environment is required" if payload["environment"].to_s.empty?
45
+ return unless payload["revision"].to_s.empty? && payload["version"].to_s.empty?
46
+
47
+ raise ArgumentError, "deploy revision or version is required"
48
+ end
49
+
50
+ def generated_id
51
+ value = bounded(@id_generator.call, 128)
52
+ raise ArgumentError, "deploy ID is required" if value.to_s.empty?
53
+
54
+ value
55
+ end
56
+
57
+ def deploy_id(value)
58
+ normalized = bounded(value, 128)
59
+ normalized.to_s.empty? ? generated_id : normalized
60
+ end
61
+
62
+ def repository(value)
63
+ text = bounded(value, 512)
64
+ return nil if text.nil?
65
+
66
+ scp = text.match(/\A[^@]+@([^:]+):(.+)\z/)
67
+ return bounded("#{scp[1]}/#{scp[2]}", 512) if scp
68
+
69
+ uri = URI.parse(text)
70
+ return bounded("#{uri.host}#{uri.path}", 512) if uri.host
71
+ return bounded(uri.path, 512) unless uri.path.to_s.empty?
72
+
73
+ nil
74
+ rescue StandardError
75
+ nil
76
+ end
77
+
78
+ def string_hash(value)
79
+ raise ArgumentError, "deploy attributes must be a Hash" unless value.is_a?(Hash)
80
+
81
+ value.each_with_object({}) do |(key, child), result|
82
+ result[key.to_s] = child if key.is_a?(String) || key.is_a?(Symbol)
83
+ end
84
+ end
85
+
86
+ def bounded(value, limit)
87
+ return nil if value.nil?
88
+ return nil unless scalar?(value)
89
+
90
+ text = value.to_s
91
+ text = text.scrub("?") if text.respond_to?(:scrub)
92
+ text.bytesize > limit ? text.byteslice(0, limit) : text
93
+ rescue StandardError
94
+ nil
95
+ end
96
+
97
+ def scalar?(value)
98
+ value.is_a?(String) || value.is_a?(Symbol) || value.is_a?(Numeric)
99
+ end
100
+ end
101
+ end
102
+ end
@@ -44,6 +44,7 @@ module Chronos
44
44
  @sanitizer = options[:sanitizer] || Sanitizer.new(config)
45
45
  @safe_serializer = options[:safe_serializer] || SafeSerializer.new
46
46
  @max_payload_size = options[:max_payload_size] || proc { @config.max_payload_size }
47
+ @correlation = options[:correlation] || CorrelationContext.new(config)
47
48
  end
48
49
 
49
50
  def call(notice)
@@ -70,8 +71,10 @@ module Chronos
70
71
  "service" => {
71
72
  "name" => @config.service_name,
72
73
  "version" => @config.app_version,
73
- "instance_id" => notice.host
74
+ "instance_id" => @config.instance_id || notice.host
74
75
  },
76
+ "correlation" => @correlation.call("environment" => notice.environment,
77
+ "instance" => @config.instance_id || notice.host),
75
78
  "runtime" => notice.runtime,
76
79
  "context" => notice.context,
77
80
  "payload" => payload(notice)
@@ -16,7 +16,7 @@ module Chronos
16
16
  # @errors Unsupported types raise ArgumentError during construction.
17
17
  # @performance Construction is linear in supplied context and payload size.
18
18
  class TelemetryEvent
19
- TYPES = %w(request query job cache external_http dependencies metric_batch).freeze
19
+ TYPES = %w(request query job cache external_http dependencies deploy metric_batch).freeze
20
20
 
21
21
  attr_reader :event_id, :event_type, :timestamp, :context, :payload
22
22
 
@@ -68,6 +68,7 @@ module Chronos
68
68
  @safe_serializer = options[:safe_serializer] || SafeSerializer.new
69
69
  @max_payload_size = options[:max_payload_size] || proc { @config.max_payload_size }
70
70
  @runtime_info = RuntimeInfo.new
71
+ @correlation = options[:correlation] || CorrelationContext.new(config)
71
72
  end
72
73
 
73
74
  def call(event)
@@ -89,13 +90,39 @@ module Chronos
89
90
  "schema_version" => "1.0", "event_id" => event.event_id,
90
91
  "event_type" => event.event_type, "occurred_at" => event.timestamp,
91
92
  "sent_at" => @clock.call.utc.iso8601(6), "project_key" => @config.project_id,
92
- "environment" => @config.environment,
93
- "service" => {"name" => @config.service_name, "version" => @config.app_version,
94
- "instance_id" => runtime[:host]},
93
+ "environment" => event_environment(event),
94
+ "service" => event_service(event, runtime),
95
+ "correlation" => event_correlation(event, runtime),
95
96
  "runtime" => runtime[:runtime], "context" => event.context, "payload" => event.payload
96
97
  }
97
98
  end
98
99
 
100
+ def event_environment(event)
101
+ event.event_type == "deploy" ? event.payload["environment"] : @config.environment
102
+ end
103
+
104
+ def event_service(event, runtime)
105
+ deploy = event.event_type == "deploy" ? event.payload : {}
106
+ {
107
+ "name" => deploy["service"] || @config.service_name,
108
+ "version" => deploy["version"] || @config.app_version,
109
+ "instance_id" => deploy["instance"] || @config.instance_id || runtime[:host]
110
+ }
111
+ end
112
+
113
+ def event_correlation(event, runtime)
114
+ overrides = {"instance" => @config.instance_id || runtime[:host]}
115
+ if event.event_type == "deploy"
116
+ overrides.merge!(
117
+ "release" => event.payload["version"], "revision" => event.payload["revision"],
118
+ "deploy_id" => event.payload["deploy_id"], "environment" => event.payload["environment"],
119
+ "service" => event.payload["service"], "region" => event.payload["region"],
120
+ "instance" => event.payload["instance"]
121
+ )
122
+ end
123
+ @correlation.call(overrides)
124
+ end
125
+
99
126
  def compact_envelope(envelope)
100
127
  envelope["context"] = {"_truncated" => true}
101
128
  envelope["payload"] = {"_truncated" => true}
@@ -0,0 +1,119 @@
1
+ require "securerandom"
2
+
3
+ module Chronos
4
+ module Integrations
5
+ # Propagates bounded Chronos context through Active Job serialization.
6
+ #
7
+ # @responsibility Add trace/request identifiers to the job envelope and restore them while performing.
8
+ # @motivation Active Job adapters commonly cross process boundaries where thread-local context is lost.
9
+ # @limits It changes only a namespaced serialization field, never public job arguments or adapter behavior.
10
+ # @collaborators ActiveJob::Base serialization hooks and the Chronos facade.
11
+ # @thread_safety Installation is mutex-protected and each job owns its restored context.
12
+ # @compatibility Active Job shipped with Rails 4.2 through Rails 5.2.
13
+ # @example
14
+ # Chronos::Integrations::ActiveJob.install(ActiveJob::Base)
15
+ # @errors Context failures are contained so enqueue and perform semantics remain unchanged.
16
+ # @performance Adds at most two strings of 128 bytes to a serialized job.
17
+ module ActiveJob
18
+ CONTEXT_KEY = "chronos_context".freeze
19
+ SCHEMA_VERSION = "1.0".freeze
20
+ MAX_IDENTIFIER_BYTES = 128
21
+
22
+ @mutex = Mutex.new
23
+
24
+ class << self
25
+ def install(base = nil, notifier = Chronos)
26
+ target = base || (::ActiveJob::Base if defined?(::ActiveJob::Base))
27
+ return false unless target && target.respond_to?(:prepend)
28
+
29
+ @mutex.synchronize do
30
+ return false if target.ancestors.include?(JobExtensions)
31
+
32
+ JobExtensions.notifier = notifier
33
+ target.send(:prepend, JobExtensions)
34
+ end
35
+ true
36
+ rescue StandardError
37
+ false
38
+ end
39
+
40
+ def envelope(notifier)
41
+ source = notifier.respond_to?(:propagation_context) ? notifier.propagation_context : {}
42
+ source = {} unless source.is_a?(Hash)
43
+ context = %w(trace_id request_id).each_with_object({}) do |key, result|
44
+ value = source[key] || source[key.to_sym]
45
+ result[key] = bounded(value) unless value.to_s.empty?
46
+ end
47
+ context["trace_id"] = SecureRandom.uuid if context["trace_id"].to_s.empty?
48
+ {"schema_version" => SCHEMA_VERSION, "context" => context}
49
+ rescue StandardError
50
+ nil
51
+ end
52
+
53
+ def context(value)
54
+ return {} unless value.is_a?(Hash)
55
+ return {} unless (value["schema_version"] || value[:schema_version]).to_s == SCHEMA_VERSION
56
+
57
+ source = value["context"] || value[:context]
58
+ return {} unless source.is_a?(Hash)
59
+
60
+ %w(trace_id request_id).each_with_object({}) do |key, result|
61
+ candidate = source[key] || source[key.to_sym]
62
+ result[key] = bounded(candidate) unless candidate.to_s.empty?
63
+ end
64
+ rescue StandardError
65
+ {}
66
+ end
67
+
68
+ private
69
+
70
+ def bounded(value)
71
+ string = value.to_s
72
+ return string if string.bytesize <= MAX_IDENTIFIER_BYTES
73
+
74
+ string.byteslice(0, MAX_IDENTIFIER_BYTES)
75
+ rescue StandardError
76
+ ""
77
+ end
78
+ end
79
+
80
+ # Active Job instance hooks installed through Module#prepend.
81
+ module JobExtensions
82
+ class << self
83
+ attr_accessor :notifier
84
+ end
85
+
86
+ def serialize(*arguments)
87
+ data = super
88
+ begin
89
+ envelope = Chronos::Integrations::ActiveJob.envelope(JobExtensions.notifier || Chronos)
90
+ data[CONTEXT_KEY] = envelope if data.is_a?(Hash) && envelope
91
+ rescue StandardError
92
+ nil
93
+ end
94
+ data
95
+ end
96
+
97
+ def deserialize(job_data)
98
+ result = super
99
+ begin
100
+ @chronos_context = Chronos::Integrations::ActiveJob.context(
101
+ job_data.is_a?(Hash) ? (job_data[CONTEXT_KEY] || job_data[CONTEXT_KEY.to_sym]) : nil
102
+ )
103
+ rescue StandardError
104
+ @chronos_context = {}
105
+ end
106
+ result
107
+ end
108
+
109
+ def perform_now(*arguments, &block)
110
+ context = @chronos_context || {}
111
+ notifier = JobExtensions.notifier || Chronos
112
+ return super if context.empty? || !notifier.respond_to?(:with_context)
113
+
114
+ notifier.with_context(:context => context) { super }
115
+ end
116
+ end
117
+ end
118
+ end
119
+ end
@@ -0,0 +1,61 @@
1
+ module Chronos
2
+ module Integrations
3
+ # Optional Capistrano task installer using only the public task DSL.
4
+ #
5
+ # @responsibility Register one post-publish task that delegates explicit values to notify_deploy.
6
+ # @motivation Legacy deployments need release reporting without a Capistrano runtime dependency.
7
+ # @limits Values are read only from configured Capistrano variables; Git and ENV are not inspected.
8
+ # @collaborators Capistrano/Rake DSL and the Chronos public facade.
9
+ # @thread_safety Installation is idempotent per DSL object before task execution.
10
+ # @compatibility Capistrano task DSLs available to supported Ruby 2.2.10 through Ruby 2.6 apps.
11
+ # @example
12
+ # require "chronos/capistrano"
13
+ # @errors Missing DSL methods return false; notification failures are contained by Chronos.
14
+ # @performance Adds one task and one after hook; no background worker is created.
15
+ module Capistrano
16
+ INSTALLED_KEY = :@__chronos_capistrano_installed
17
+
18
+ class << self
19
+ def install(dsl)
20
+ return false if dsl.instance_variable_get(INSTALLED_KEY)
21
+ return false unless compatible?(dsl)
22
+
23
+ dsl.send(:namespace, :chronos) do
24
+ dsl.send(:desc, "Notify Chronos about the published deployment") if dsl.respond_to?(:desc, true)
25
+ dsl.send(:task, :notify_deploy) { notify(dsl) }
26
+ end
27
+ dsl.send(:after, "deploy:published", "chronos:notify_deploy")
28
+ dsl.instance_variable_set(INSTALLED_KEY, true)
29
+ true
30
+ rescue StandardError
31
+ false
32
+ end
33
+
34
+ def notify(dsl)
35
+ Chronos.notify_deploy(
36
+ :environment => value(dsl, :stage).to_s,
37
+ :revision => value(dsl, :current_revision) || value(dsl, :branch),
38
+ :version => value(dsl, :chronos_version) || value(dsl, :release_name),
39
+ :repository => value(dsl, :repo_url), :actor => value(dsl, :chronos_actor),
40
+ :deploy_id => value(dsl, :chronos_deploy_id), :service => value(dsl, :chronos_service),
41
+ :region => value(dsl, :chronos_region), :instance => value(dsl, :chronos_instance)
42
+ )
43
+ rescue StandardError
44
+ false
45
+ end
46
+
47
+ private
48
+
49
+ def compatible?(dsl)
50
+ [:namespace, :task, :after, :fetch].all? { |name| dsl.respond_to?(name, true) }
51
+ end
52
+
53
+ def value(dsl, name)
54
+ dsl.send(:fetch, name, nil)
55
+ rescue StandardError
56
+ nil
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
@@ -1,7 +1,7 @@
1
1
  module Chronos
2
- # Public entry points for optional version 0.8 observability integrations.
2
+ # Public entry points for optional observability and deployment integrations.
3
3
  #
4
- # @responsibility Delegate dependency, cache, and outbound HTTP integration calls to the agent.
4
+ # @responsibility Delegate dependency, cache, outbound HTTP, and deploy calls to the agent.
5
5
  # @motivation Keep the main public facade small while preserving one stable Chronos namespace.
6
6
  # @limits It installs only explicitly supplied Net::HTTP connections and never enables features.
7
7
  # @collaborators Chronos::Agent and Chronos::Integrations::NetHttp.
@@ -19,6 +19,13 @@ module Chronos
19
19
  false
20
20
  end
21
21
 
22
+ def notify_deploy(attributes = {}, timeout = Agent::DEFAULT_FLUSH_TIMEOUT)
23
+ agent = current_agent
24
+ agent ? agent.notify_deploy(attributes, timeout) : false
25
+ rescue StandardError
26
+ false
27
+ end
28
+
22
29
  def external_http_integration_options
23
30
  agent = current_agent
24
31
  agent ? agent.external_http_integration_options : {:enabled => false}
@@ -33,6 +33,7 @@ module Chronos
33
33
  return false if self.class.applications[application.object_id]
34
34
 
35
35
  install_middleware(application, options)
36
+ install_active_job
36
37
  @subscriber.install
37
38
  self.class.applications[application.object_id] = true
38
39
  end
@@ -58,6 +59,12 @@ module Chronos
58
59
  true
59
60
  end
60
61
 
62
+ def install_active_job
63
+ return false unless defined?(::ActiveJob::Base)
64
+
65
+ Chronos::Integrations::ActiveJob.install(::ActiveJob::Base, @notifier)
66
+ end
67
+
61
68
  def environment
62
69
  defined?(::Rails) && ::Rails.respond_to?(:env) ? ::Rails.env.to_s : nil
63
70
  end
@@ -144,11 +144,39 @@ module Chronos
144
144
 
145
145
  def active_job(payload, duration)
146
146
  job = value(payload, :job)
147
+ exception = job_exception(payload)
147
148
  data = {
148
149
  "kind" => "active_job", "class" => safe_class_name(job),
149
- "queue" => safe_job_value(job, :queue_name), "duration_ms" => duration
150
+ "adapter" => active_job_adapter(job), "job_id" => safe_job_value(job, :job_id),
151
+ "provider_job_id" => safe_job_value(job, :provider_job_id),
152
+ "queue" => safe_job_value(job, :queue_name), "attempts" => job_attempts(job),
153
+ "duration_ms" => duration, "status" => exception ? "failed" : "completed"
150
154
  }
155
+ data["error_class"] = exception.class.name.to_s if exception
151
156
  @notifier.record_event("job", data)
157
+ @notifier.notify_once(exception, :context => {"job" => data}) if exception
158
+ end
159
+
160
+ def job_exception(payload)
161
+ exception = value(payload, :exception_object)
162
+ details = value(payload, :exception)
163
+ exception ||= RuntimeError.new(Array(details).last.to_s) if details
164
+ exception
165
+ end
166
+
167
+ def active_job_adapter(job)
168
+ adapter = job.respond_to?(:queue_adapter) ? job.queue_adapter : nil
169
+ adapter = adapter.class if adapter && !adapter.is_a?(Class)
170
+ adapter ? adapter.name.to_s.split("::").last.to_s.sub(/Adapter$/, "") : ""
171
+ rescue StandardError
172
+ ""
173
+ end
174
+
175
+ def job_attempts(job)
176
+ value = job.respond_to?(:executions) ? job.executions : 0
177
+ value.is_a?(Numeric) ? value.to_i : 0
178
+ rescue StandardError
179
+ 0
152
180
  end
153
181
 
154
182
  def cache(name, payload, duration)
data/lib/chronos/rails.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  require "chronos"
2
2
  require "chronos/rails/notifications_subscriber"
3
+ require "chronos/integrations/active_job"
3
4
  require "chronos/rails/installer"
4
5
 
5
6
  require "chronos/rails/railtie" if defined?(::Rails::Railtie)
@@ -1,4 +1,4 @@
1
1
  module Chronos
2
2
  # Current version of the legacy Chronos Ruby agent.
3
- VERSION = "0.8.0.pre.1".freeze
3
+ VERSION = "0.9.0.pre.2".freeze
4
4
  end
data/lib/chronos.rb CHANGED
@@ -14,6 +14,8 @@ require "chronos/core/notice_builder"
14
14
  require "chronos/core/sensitive_value_filter"
15
15
  require "chronos/core/sanitizer"
16
16
  require "chronos/core/safe_serializer"
17
+ require "chronos/core/correlation_context"
18
+ require "chronos/core/deploy_normalizer"
17
19
  require "chronos/core/payload_serializer"
18
20
  require "chronos/core/telemetry_event"
19
21
  require "chronos/core/sql_normalizer"
@@ -31,6 +33,7 @@ require "chronos/core/breadcrumb"
31
33
  require "chronos/application/retry_policy"
32
34
  require "chronos/application/circuit_breaker"
33
35
  require "chronos/application/remote_configuration"
36
+ require "chronos/application/ignore_policy"
34
37
  require "chronos/application/delivery_pipeline"
35
38
  require "chronos/application/capture_exception"
36
39
  require "chronos/application/apm_error_classifier"
@@ -58,7 +61,7 @@ require "chronos/integrations/rack/middleware"
58
61
  # config.host = "https://chronos.example.com"
59
62
  # end
60
63
  # Chronos.notify(RuntimeError.new("failed"))
61
- module Chronos
64
+ module Chronos # rubocop:disable Metrics/ModuleLength
62
65
  extend ObservabilityFacade
63
66
 
64
67
  @mutex = Mutex.new
@@ -142,6 +145,13 @@ module Chronos
142
145
  false
143
146
  end
144
147
 
148
+ def ignore_if(&block)
149
+ agent = current_agent
150
+ agent ? agent.ignore_if(&block) : false
151
+ rescue StandardError
152
+ false
153
+ end
154
+
145
155
  def rails_integration_options(environment = nil, console = false)
146
156
  agent = current_agent
147
157
  agent ? agent.rails_integration_options(environment, console) : {:enabled => false}
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: chronos-ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.0.pre.1
4
+ version: 0.9.0.pre.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Antonio Jefferson
@@ -88,6 +88,7 @@ files:
88
88
  - SECURITY.md
89
89
  - contracts/apm-batch-v1.schema.json
90
90
  - contracts/dependencies-v1.schema.json
91
+ - contracts/deploy-v1.schema.json
91
92
  - contracts/event-v1.schema.json
92
93
  - contracts/rack-context-v1.schema.json
93
94
  - contracts/sidekiq-job-v1.schema.json
@@ -103,17 +104,24 @@ files:
103
104
  - docs/adr/ADR-014-sidekiq-envelope-context.md
104
105
  - docs/adr/ADR-015-bounded-apm-aggregation.md
105
106
  - docs/adr/ADR-016-explicit-observability-integrations.md
107
+ - docs/adr/ADR-017-deploy-events-and-correlation.md
108
+ - docs/adr/ADR-018-pre-1.0-hardening.md
106
109
  - docs/architecture.md
107
110
  - docs/compatibility.md
108
111
  - docs/configuration.md
109
112
  - docs/data-collected.md
113
+ - docs/deprecation-policy.md
110
114
  - docs/examples/plain-ruby.md
115
+ - docs/migration-from-airbrake.md
116
+ - docs/modules/active-job.md
111
117
  - docs/modules/apm-aggregation.md
112
118
  - docs/modules/async-queue.md
113
119
  - docs/modules/cache-observability.md
114
120
  - docs/modules/configuration.md
115
121
  - docs/modules/dependencies.md
122
+ - docs/modules/deploy-tracking.md
116
123
  - docs/modules/external-http.md
124
+ - docs/modules/ignore-rules.md
117
125
  - docs/modules/notice-pipeline.md
118
126
  - docs/modules/rack-context.md
119
127
  - docs/modules/rails-legacy.md
@@ -126,6 +134,10 @@ files:
126
134
  - docs/modules/transport.md
127
135
  - docs/performance.md
128
136
  - docs/privacy-lgpd.md
137
+ - docs/protocol-v1.md
138
+ - docs/release-1.0-readiness.md
139
+ - docs/security-review.md
140
+ - docs/semver.md
129
141
  - docs/troubleshooting.md
130
142
  - lib/chronos.rb
131
143
  - lib/chronos/adapters.rb
@@ -140,8 +152,10 @@ files:
140
152
  - lib/chronos/application/circuit_breaker.rb
141
153
  - lib/chronos/application/delivery_pipeline.rb
142
154
  - lib/chronos/application/dependency_reporter.rb
155
+ - lib/chronos/application/ignore_policy.rb
143
156
  - lib/chronos/application/remote_configuration.rb
144
157
  - lib/chronos/application/retry_policy.rb
158
+ - lib/chronos/capistrano.rb
145
159
  - lib/chronos/configuration.rb
146
160
  - lib/chronos/configuration/apm_validation.rb
147
161
  - lib/chronos/configuration/snapshot.rb
@@ -150,6 +164,8 @@ files:
150
164
  - lib/chronos/core/backtrace_parser.rb
151
165
  - lib/chronos/core/breadcrumb.rb
152
166
  - lib/chronos/core/cache_normalizer.rb
167
+ - lib/chronos/core/correlation_context.rb
168
+ - lib/chronos/core/deploy_normalizer.rb
153
169
  - lib/chronos/core/exception_cause_collector.rb
154
170
  - lib/chronos/core/metric_aggregate.rb
155
171
  - lib/chronos/core/notice.rb
@@ -163,6 +179,8 @@ files:
163
179
  - lib/chronos/core/telemetry_event.rb
164
180
  - lib/chronos/errors.rb
165
181
  - lib/chronos/integrations.rb
182
+ - lib/chronos/integrations/active_job.rb
183
+ - lib/chronos/integrations/capistrano.rb
166
184
  - lib/chronos/integrations/job_payload.rb
167
185
  - lib/chronos/integrations/net_http.rb
168
186
  - lib/chronos/integrations/rack.rb