Class: CincOtel::Handler
- Inherits:
-
Chef::EventDispatch::Base
- Object
- Chef::EventDispatch::Base
- CincOtel::Handler
- Defined in:
- lib/cinc_otel/handler.rb
Overview
Emits an OpenTelemetry trace for the Cinc Client run: a root span for the run, child spans for each phase (node load, cookbook sync, compilation, converge, ...) and one span per resource action.
Enable it from client.rb (or solo.rb):
require "cinc-otel"
CincOtel::Handler.register!
Exporter and endpoint are configured through the standard OTEL_* environment variables. The opentelemetry-sdk gem (and opentelemetry-exporter-otlp for the default OTLP exporter) are runtime dependencies, so they are always available.
Spans can be tagged with a __tenant resource attribute (used by Tempo multi-tenancy for search and tail-sampling routing) either through the standard env var:
OTEL_RESOURCE_ATTRIBUTES=__tenant=controlplane
or explicitly, which takes precedence over the env var:
CincOtel::Handler.register!(tenant: "controlplane")
Class Method Summary collapse
-
.register!(**opts) ⇒ Object
Adds the handler to Chef::Config.
Instance Method Summary collapse
- #deprecation(message, location = nil) ⇒ Object
-
#initialize(tracer_provider: nil, tenant: nil) ⇒ Handler
constructor
A new instance of Handler.
- #node_load_success(node) ⇒ Object
- #ohai_completed(node) ⇒ Object
- #resource_action_start(resource, action, notification_type = nil, notifier = nil) ⇒ Object
- #resource_completed(resource) ⇒ Object
- #resource_failed(resource, action, exception) ⇒ Object
- #resource_failed_retriable(resource, action, retry_count, exception) ⇒ Object
- #resource_skipped(resource, action, conditional) ⇒ Object
- #resource_up_to_date(resource, action) ⇒ Object
- #resource_updated(resource, action) ⇒ Object
- #run_completed(node, run_status) ⇒ Object
- #run_failed(exception, run_status) ⇒ Object
- #run_start(version, run_status) ⇒ Object
Constructor Details
#initialize(tracer_provider: nil, tenant: nil) ⇒ Handler
Returns a new instance of Handler.
66 67 68 69 70 |
# File 'lib/cinc_otel/handler.rb', line 66 def initialize(tracer_provider: nil, tenant: nil) @stack = [] @tracer_provider = tracer_provider || default_tracer_provider(tenant) @tracer = @tracer_provider&.tracer("cinc-otel", CincOtel::VERSION) end |
Class Method Details
.register!(**opts) ⇒ Object
Adds the handler to Chef::Config. Idempotent, because some applications (chef-solo) evaluate the config file more than once and a second handler would emit every span twice.
60 61 62 63 64 |
# File 'lib/cinc_otel/handler.rb', line 60 def self.register!(**opts) return if Chef::Config[:event_handlers].any? { |handler| handler.is_a?(self) } Chef::Config[:event_handlers] << new(**opts) end |
Instance Method Details
#deprecation(message, location = nil) ⇒ Object
98 99 100 101 102 103 |
# File 'lib/cinc_otel/handler.rb', line 98 def deprecation(, location = nil) text = .respond_to?(:message) ? ..to_s : .to_s attributes = { "chef.deprecation.message" => text } attributes["chef.deprecation.location"] = location.to_s if location current_span&.add_event("deprecation", attributes:) end |
#node_load_success(node) ⇒ Object
89 90 91 92 |
# File 'lib/cinc_otel/handler.rb', line 89 def node_load_success(node) root_span&.set_attribute("chef.node.name", node.name.to_s) root_span&.set_attribute("chef.environment", node.chef_environment.to_s) end |
#ohai_completed(node) ⇒ Object
94 95 96 |
# File 'lib/cinc_otel/handler.rb', line 94 def ohai_completed(node) current_span&.add_event("ohai_completed") end |
#resource_action_start(resource, action, notification_type = nil, notifier = nil) ⇒ Object
143 144 145 146 147 148 149 150 151 152 153 154 |
# File 'lib/cinc_otel/handler.rb', line 143 def resource_action_start(resource, action, notification_type = nil, notifier = nil) attributes = { "chef.resource.type" => resource.resource_name.to_s, "chef.resource.name" => resource.name.to_s, "chef.resource.action" => action.to_s, } attributes["chef.resource.cookbook"] = resource.cookbook_name.to_s if resource.cookbook_name attributes["chef.resource.recipe"] = resource.recipe_name.to_s if resource.recipe_name attributes["chef.resource.notification_type"] = notification_type.to_s if notification_type attributes["chef.resource.notifying_resource"] = notifier.to_s if notifier start_span(resource.to_s, attributes) end |
#resource_completed(resource) ⇒ Object
187 188 189 |
# File 'lib/cinc_otel/handler.rb', line 187 def resource_completed(resource) end_span(resource.to_s) end |
#resource_failed(resource, action, exception) ⇒ Object
172 173 174 175 176 177 178 |
# File 'lib/cinc_otel/handler.rb', line 172 def resource_failed(resource, action, exception) span = current_span return unless span span.record_exception(exception) span.status = OpenTelemetry::Trace::Status.error(exception.) end |
#resource_failed_retriable(resource, action, retry_count, exception) ⇒ Object
180 181 182 183 184 185 |
# File 'lib/cinc_otel/handler.rb', line 180 def resource_failed_retriable(resource, action, retry_count, exception) current_span&.add_event("retry", attributes: { "chef.resource.retries_remaining" => retry_count, "exception.message" => exception., }) end |
#resource_skipped(resource, action, conditional) ⇒ Object
164 165 166 167 168 169 170 |
# File 'lib/cinc_otel/handler.rb', line 164 def resource_skipped(resource, action, conditional) span = current_span return unless span span.set_attribute("chef.resource.skipped", true) span.set_attribute("chef.resource.skip_reason", conditional.to_text) end |
#resource_up_to_date(resource, action) ⇒ Object
160 161 162 |
# File 'lib/cinc_otel/handler.rb', line 160 def resource_up_to_date(resource, action) current_span&.set_attribute("chef.resource.updated", false) end |
#resource_updated(resource, action) ⇒ Object
156 157 158 |
# File 'lib/cinc_otel/handler.rb', line 156 def resource_updated(resource, action) current_span&.set_attribute("chef.resource.updated", true) end |
#run_completed(node, run_status) ⇒ Object
79 80 81 82 |
# File 'lib/cinc_otel/handler.rb', line 79 def run_completed(node, run_status) end_span("chef.run", ok: true) @tracer_provider&.force_flush end |
#run_failed(exception, run_status) ⇒ Object
84 85 86 87 |
# File 'lib/cinc_otel/handler.rb', line 84 def run_failed(exception, run_status) end_span("chef.run", error: exception) @tracer_provider&.force_flush end |
#run_start(version, run_status) ⇒ Object
72 73 74 75 76 77 |
# File 'lib/cinc_otel/handler.rb', line 72 def run_start(version, run_status) start_span("chef.run", { "chef.version" => version.to_s, "chef.run_id" => run_status.run_id.to_s, }, with_parent: remote_parent_context) end |