Module: Buildkite::TestCollector
- Defined in:
- lib/buildkite/test_collector.rb,
lib/buildkite/test_collector.rb,
lib/buildkite/test_collector/otel.rb,
lib/buildkite/test_collector/error.rb,
lib/buildkite/test_collector/trace.rb,
lib/buildkite/test_collector/object.rb,
lib/buildkite/test_collector/tracer.rb,
lib/buildkite/test_collector/network.rb,
lib/buildkite/test_collector/session.rb,
lib/buildkite/test_collector/version.rb,
lib/buildkite/test_collector/uploader.rb,
lib/buildkite/test_collector/http_client.rb,
lib/buildkite/test_collector/otel/execution_child_forwarder.rb,
lib/buildkite/test_collector/otel/root_span_metrics_reporter.rb
Defined Under Namespace
Modules: CucumberPlugin, MinitestPlugin, OTel, RSpecPlugin Classes: CI, Error, HTTPClient, MinDurationSpanFilter, Network, Object, Session, TimeoutError, Trace, Tracer, UUID, Uploader
Constant Summary collapse
- DEFAULT_URL =
"https://analytics-api.buildkite.com/v1/uploads"- DEFAULT_UPLOAD_BATCH_SIZE =
500- VERSION =
"2.15.0"- NAME =
"buildkite-test_collector"
Class Attribute Summary collapse
-
.api_token ⇒ Object
Returns the value of attribute api_token.
-
.artifact_path ⇒ Object
Returns the value of attribute artifact_path.
-
.batch_size ⇒ Object
Returns the value of attribute batch_size.
-
.env ⇒ Object
Returns the value of attribute env.
-
.location_prefix ⇒ Object
Returns the value of attribute location_prefix.
-
.otel_only ⇒ Object
Returns the value of attribute otel_only.
-
.session ⇒ Object
Returns the value of attribute session.
-
.span_filters ⇒ Object
Returns the value of attribute span_filters.
-
.tags ⇒ Object
Returns the value of attribute tags.
-
.test_runner ⇒ Object
Returns the value of attribute test_runner.
-
.trace_min_duration ⇒ Object
Returns the value of attribute trace_min_duration.
-
.tracing_enabled ⇒ Object
Returns the value of attribute tracing_enabled.
-
.uploader ⇒ Object
Returns the value of attribute uploader.
-
.url ⇒ Object
Returns the value of attribute url.
Class Method Summary collapse
- .annotate(content) ⇒ Object
- .configure(hook:, token: nil, url: nil, tracing_enabled: true, artifact_path: nil, location_prefix: nil, env: {}, tags: {}, otel_enabled: nil, otel_instrumentations: nil, otel_only: false) ⇒ Object
- .enable_tracing! ⇒ Object
- .hook_into(hook) ⇒ Object
- .otel_only? ⇒ Boolean
- .start_otel ⇒ Object
-
.tag_execution(key, value) ⇒ Object
Set a key=value tag on the current test execution.
-
.warn_otel_only_disabled ⇒ Object
In otel_only mode OTLP is the only upload method, so if OpenTelemetry could not be set up (see the warning OTel.configure! just printed) there is nothing to fall back to: the suite still runs, but no results are uploaded at all.
Class Attribute Details
.api_token ⇒ Object
Returns the value of attribute api_token.
34 35 36 |
# File 'lib/buildkite/test_collector.rb', line 34 def api_token @api_token end |
.artifact_path ⇒ Object
Returns the value of attribute artifact_path.
39 40 41 |
# File 'lib/buildkite/test_collector.rb', line 39 def artifact_path @artifact_path end |
.batch_size ⇒ Object
Returns the value of attribute batch_size.
45 46 47 |
# File 'lib/buildkite/test_collector.rb', line 45 def batch_size @batch_size end |
.env ⇒ Object
Returns the value of attribute env.
42 43 44 |
# File 'lib/buildkite/test_collector.rb', line 42 def env @env end |
.location_prefix ⇒ Object
Returns the value of attribute location_prefix.
40 41 42 |
# File 'lib/buildkite/test_collector.rb', line 40 def location_prefix @location_prefix end |
.otel_only ⇒ Object
Returns the value of attribute otel_only.
44 45 46 |
# File 'lib/buildkite/test_collector.rb', line 44 def otel_only @otel_only end |
.session ⇒ Object
Returns the value of attribute session.
37 38 39 |
# File 'lib/buildkite/test_collector.rb', line 37 def session @session end |
.span_filters ⇒ Object
Returns the value of attribute span_filters.
47 48 49 |
# File 'lib/buildkite/test_collector.rb', line 47 def span_filters @span_filters end |
.tags ⇒ Object
Returns the value of attribute tags.
43 44 45 |
# File 'lib/buildkite/test_collector.rb', line 43 def @tags end |
.test_runner ⇒ Object
Returns the value of attribute test_runner.
41 42 43 |
# File 'lib/buildkite/test_collector.rb', line 41 def test_runner @test_runner end |
.trace_min_duration ⇒ Object
Returns the value of attribute trace_min_duration.
46 47 48 |
# File 'lib/buildkite/test_collector.rb', line 46 def trace_min_duration @trace_min_duration end |
.tracing_enabled ⇒ Object
Returns the value of attribute tracing_enabled.
38 39 40 |
# File 'lib/buildkite/test_collector.rb', line 38 def tracing_enabled @tracing_enabled end |
.uploader ⇒ Object
Returns the value of attribute uploader.
36 37 38 |
# File 'lib/buildkite/test_collector.rb', line 36 def uploader @uploader end |
.url ⇒ Object
Returns the value of attribute url.
35 36 37 |
# File 'lib/buildkite/test_collector.rb', line 35 def url @url end |
Class Method Details
.annotate(content) ⇒ Object
164 165 166 167 168 169 170 171 172 173 |
# File 'lib/buildkite/test_collector.rb', line 164 def self.annotate(content) # Keep the OpenTelemetry span identical in both export modes. The # standard mode additionally records the annotation in its JSON trace. Buildkite::TestCollector::OTel.annotate(content) return if otel_only? tracer = Buildkite::TestCollector::Uploader.tracer tracer&.enter("annotation", **{ content: content }) tracer&.leave end |
.configure(hook:, token: nil, url: nil, tracing_enabled: true, artifact_path: nil, location_prefix: nil, env: {}, tags: {}, otel_enabled: nil, otel_instrumentations: nil, otel_only: false) ⇒ Object
50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 |
# File 'lib/buildkite/test_collector.rb', line 50 def self.configure(hook:, token: nil, url: nil, tracing_enabled: true, artifact_path: nil, location_prefix: nil, env: {}, tags: {}, otel_enabled: nil, otel_instrumentations: nil, otel_only: false) if otel_only && hook.to_sym != :rspec raise ArgumentError.new("otel_only is currently only supported with the rspec hook") end # They name one choice of upload mode, not two independent switches, so # any explicit otel_enabled (even false) contradicts otel_only. Its nil # default keeps unspecified distinct from an explicit value. if otel_only && !otel_enabled.nil? raise ArgumentError.new("otel_enabled and otel_only are mutually exclusive; pass at most one") end self.api_token = (token || ENV["BUILDKITE_ANALYTICS_TOKEN"])&.strip self.url = url || ENV["BUILDKITE_ANALYTICS_ENDPOINT"] || DEFAULT_URL self.tracing_enabled = tracing_enabled self.artifact_path = artifact_path self.location_prefix = location_prefix || ENV["BUILDKITE_ANALYTICS_LOCATION_PREFIX"] self.test_runner = hook.to_s self.env = env self. = worker_id_tag.merge() self.otel_only = otel_only self.batch_size = ENV.fetch("BUILDKITE_ANALYTICS_UPLOAD_BATCH_SIZE") { DEFAULT_UPLOAD_BATCH_SIZE }.to_i trace_min_ms_string = ENV["BUILDKITE_ANALYTICS_TRACE_MIN_MS"] self.trace_min_duration = if trace_min_ms_string && !trace_min_ms_string.empty? Float(trace_min_ms_string) / 1000 end self.span_filters = [] unless self.trace_min_duration.nil? self.span_filters << MinDurationSpanFilter.new(self.trace_min_duration) end # Defer OTel setup until RSpec's before(:suite), after application and support files have loaded. # otel_only already guarantees the rspec hook (checked above), so both # modes use exactly the same OpenTelemetry setup. @otel_options = nil if otel_only || (otel_enabled && test_runner == "rspec") @otel_options = { # Undocumented, for development purposes. endpoint: ENV["BUILDKITE_ANALYTICS_OTLP_ENDPOINT"] || Buildkite::TestCollector::OTel::DEFAULT_ENDPOINT, api_token: api_token, run_env: Buildkite::TestCollector::CI.env, instrumentations: otel_instrumentations, # Tags describe the whole run, so they ride along as resource # attributes on every exported span. The merged self.tags, not the # raw argument, so the automatic ci.worker.id tag comes too. resource_attributes: self., } end self.hook_into(hook) enable_tracing! if test_runner == "rspec" && !otel_only? end |
.enable_tracing! ⇒ Object
187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 |
# File 'lib/buildkite/test_collector.rb', line 187 def self.enable_tracing! return unless self.tracing_enabled Buildkite::TestCollector::Network.configure Buildkite::TestCollector::Object.configure return unless defined?(ActiveSupport) require "active_support/notifications" return if @active_support_tracing_enabled ActiveSupport::Notifications.subscribe("sql.active_record") do |name, start, finish, id, payload| Buildkite::TestCollector::Uploader.tracer&.backfill(:sql, finish - start, **{ query: payload[:sql] }) end @active_support_tracing_enabled = true end |
.hook_into(hook) ⇒ Object
145 146 147 148 149 150 |
# File 'lib/buildkite/test_collector.rb', line 145 def self.hook_into(hook) file = "test_collector/library_hooks/#{hook}" require_relative file rescue LoadError raise ArgumentError.new("#{hook.inspect} is not a supported Buildkite Analytics Test library hook.") end |
.otel_only? ⇒ Boolean
113 114 115 |
# File 'lib/buildkite/test_collector.rb', line 113 def self.otel_only? !!otel_only end |
.start_otel ⇒ Object
104 105 106 107 108 109 110 111 |
# File 'lib/buildkite/test_collector.rb', line 104 def self.start_otel = @otel_options @otel_options = nil return unless Buildkite::TestCollector::OTel.configure!(**) warn_otel_only_disabled if otel_only? && !Buildkite::TestCollector::OTel.enabled? end |
.tag_execution(key, value) ⇒ Object
Set a key=value tag on the current test execution.
176 177 178 179 180 181 182 183 184 185 |
# File 'lib/buildkite/test_collector.rb', line 176 def self.tag_execution(key, value) = Thread.current[:_buildkite_tags] raise "_buildkite_tags not available" unless unless key.is_a?(String) && value.is_a?(String) raise ArgumentError, "tag key and value expected string" end [key] = value end |
.warn_otel_only_disabled ⇒ Object
In otel_only mode OTLP is the only upload method, so if OpenTelemetry could not be set up (see the warning OTel.configure! just printed) there is nothing to fall back to: the suite still runs, but no results are uploaded at all. That deserves more than one easily-missed line.
121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 |
# File 'lib/buildkite/test_collector.rb', line 121 def self.warn_otel_only_disabled # Buildkite log output renders ANSI colour even though it isn't a TTY. red, reset = if $stderr.tty? || ENV["BUILDKITE"] ["\e[31;1m", "\e[0m"] else ["", ""] end warn <<~MESSAGE #{red} ############################################################ ## ## ## buildkite-test_collector: NO TEST RESULTS UPLOADED! ## ## ## ## otel_only is set, but OpenTelemetry could not be ## ## configured (see the warning above). This mode has no ## ## JSON fallback, so this run will upload NO results to ## ## Buildkite Test Engine. ## ## ## ############################################################ #{reset} MESSAGE end |