bugsnag-maze-runner 9.32.3 → 9.33.0
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/bin/benchmarks-to-datadog +186 -0
- data/lib/maze/aws_public_ip.rb +2 -1
- data/lib/maze/hooks/appium_hooks.rb +0 -7
- data/lib/maze/plugins/datadog_metrics_plugin.rb +2 -1
- data/lib/maze.rb +1 -1
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 36d5614273840b3532dae2fc1c515389dec6e36c99b348bd1cc6a91b3d3da656
|
4
|
+
data.tar.gz: 6c0ee4526be46ba9b322f625701e00e00ec8af6001d3d8f12fa7fa32e4005dc3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3ccaff84971397feaca6de27dd8db438a3e51de38b002956c1076e1e85aa496b99d059e67dfaa4491cc22248c5e337348eb80fe112b480d8e413deee12498db3
|
7
|
+
data.tar.gz: e2b77ff39efc000d8f6db1d910d414a3f8428cf0f21b2e2b62c592b5879ca7e746cb681e963215c37cf5e3b3e23215527f528cbd217a2bae85fd76573ac5b3f6
|
@@ -0,0 +1,186 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require 'csv'
|
5
|
+
require 'time'
|
6
|
+
require 'optimist'
|
7
|
+
require 'datadog_api_client'
|
8
|
+
|
9
|
+
require_relative '../lib/maze'
|
10
|
+
require_relative '../lib/maze/loggers/logger'
|
11
|
+
|
12
|
+
class DatadogMetricsIngester
|
13
|
+
def initialize(api_key:, app_key:, host: 'platforms-benchmark')
|
14
|
+
configuration = DatadogAPIClient::Configuration.new
|
15
|
+
configuration.api_key['apiKeyAuth'] = api_key
|
16
|
+
configuration.api_key['appKeyAuth'] = app_key
|
17
|
+
|
18
|
+
api_client = DatadogAPIClient::APIClient.new(configuration)
|
19
|
+
@api = DatadogAPIClient::V2::MetricsAPI.new(api_client)
|
20
|
+
@host = host
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.run(args)
|
24
|
+
parser = Optimist::Parser.new do
|
25
|
+
text 'Ingest CSV metrics into Datadog'
|
26
|
+
opt :csv_file, 'Path to the CSV file containing metrics', type: :string, required: true
|
27
|
+
opt :api_key, 'Datadog API key', type: :string
|
28
|
+
opt :app_key, 'Datadog App key', type: :string
|
29
|
+
end
|
30
|
+
|
31
|
+
opts = Optimist::with_standard_exception_handling(parser) do
|
32
|
+
raise Optimist::HelpNeeded if args.empty?
|
33
|
+
parser.parse(args)
|
34
|
+
end
|
35
|
+
|
36
|
+
csv_file = opts[:csv_file]
|
37
|
+
api_key = opts[:api_key] || ENV['DATADOG_API_KEY']
|
38
|
+
app_key = opts[:app_key] || ENV['DATADOG_APP_KEY']
|
39
|
+
|
40
|
+
abort_with_help(parser, "CSV file is missing") if csv_file.to_s.empty?
|
41
|
+
abort_with_help(parser, "API key is missing") if api_key.to_s.empty?
|
42
|
+
abort_with_help(parser, "App key is missing") if app_key.to_s.empty?
|
43
|
+
|
44
|
+
new(api_key: api_key, app_key: app_key).ingest_csv(csv_file)
|
45
|
+
end
|
46
|
+
|
47
|
+
def self.abort_with_help(parser, message)
|
48
|
+
$logger.warn message
|
49
|
+
Optimist::with_standard_exception_handling(parser) { raise Optimist::HelpNeeded }
|
50
|
+
end
|
51
|
+
|
52
|
+
def ingest_csv(file_path)
|
53
|
+
total_rows = 0
|
54
|
+
|
55
|
+
CSV.foreach(file_path, headers: true) do |row|
|
56
|
+
next unless valid_benchmark_row?(row)
|
57
|
+
|
58
|
+
total_rows += 1
|
59
|
+
benchmark_name = row['benchmark']
|
60
|
+
tags = build_tags(row)
|
61
|
+
timestamp = parse_timestamp(row['timestamp'])
|
62
|
+
|
63
|
+
$logger.info "Processing row #{total_rows}: #{benchmark_name} at #{row['timestamp']}"
|
64
|
+
|
65
|
+
process_cpu_metrics(row, tags, timestamp)
|
66
|
+
process_run_metrics(row, tags, timestamp)
|
67
|
+
process_total_metrics(row, tags, timestamp)
|
68
|
+
|
69
|
+
$logger.info "Completed processing #{benchmark_name}"
|
70
|
+
$logger.info '-' * 60
|
71
|
+
|
72
|
+
# Sleep briefly to avoid overwhelming the Datadog API
|
73
|
+
sleep(0.1)
|
74
|
+
end
|
75
|
+
|
76
|
+
$logger.info "Ingestion Summary:"
|
77
|
+
$logger.info "Total rows processed: #{total_rows}"
|
78
|
+
end
|
79
|
+
|
80
|
+
def valid_benchmark_row?(row)
|
81
|
+
row['benchmark'] && !row['benchmark'].strip.empty?
|
82
|
+
end
|
83
|
+
|
84
|
+
def parse_timestamp(timestamp_str)
|
85
|
+
Time.strptime(timestamp_str, "%a %b %d %H:%M:%S GMT %Y").to_i
|
86
|
+
rescue ArgumentError
|
87
|
+
Time.now.to_i
|
88
|
+
end
|
89
|
+
|
90
|
+
def build_tags(row)
|
91
|
+
tags = ["env:platforms-testing", "benchmark:#{row['benchmark']}"]
|
92
|
+
tags << "cpu_intensive:true" if row['cpu'] == 'true'
|
93
|
+
tags << "memory_intensive:true" if row['memory'] == 'true'
|
94
|
+
tags << "rendering_enabled:true" if row['rendering'] == 'true'
|
95
|
+
tags
|
96
|
+
end
|
97
|
+
|
98
|
+
def send_metric(name, value, tags, type = DatadogAPIClient::V2::MetricIntakeType::GAUGE, timestamp = Time.now.to_i)
|
99
|
+
metric_series = DatadogAPIClient::V2::MetricSeries.new(
|
100
|
+
metric: name,
|
101
|
+
type: type,
|
102
|
+
points: [
|
103
|
+
DatadogAPIClient::V2::MetricPoint.new(timestamp: timestamp, value: value)
|
104
|
+
],
|
105
|
+
tags: tags,
|
106
|
+
resources: [
|
107
|
+
DatadogAPIClient::V2::MetricResource.new(name: @host, type: "host")
|
108
|
+
]
|
109
|
+
)
|
110
|
+
|
111
|
+
payload = DatadogAPIClient::V2::MetricPayload.new(series: [metric_series])
|
112
|
+
|
113
|
+
begin
|
114
|
+
@api.submit_metrics(payload)
|
115
|
+
rescue DatadogAPIClient::APIError => e
|
116
|
+
$logger.error "Failed to send metric #{name}: #{e.message}"
|
117
|
+
$logger.error "HTTP status code: #{e.code}"
|
118
|
+
$logger.error "Response body: #{e.response_body}"
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
def process_cpu_metrics(row, tags, timestamp)
|
123
|
+
# Select all headers matching cpuUse.<number> pattern and extract their float values
|
124
|
+
cpu_values = row.headers.grep(/^cpuUse\.\d+$/).map { |key|
|
125
|
+
val = row[key]
|
126
|
+
val&.empty? ? nil : val.to_f
|
127
|
+
}.compact
|
128
|
+
|
129
|
+
return if cpu_values.empty?
|
130
|
+
|
131
|
+
avg_cpu = cpu_values.sum / cpu_values.size
|
132
|
+
send_metric('benchmark.cpu_usage_percent', avg_cpu, tags, timestamp)
|
133
|
+
end
|
134
|
+
|
135
|
+
def process_run_metrics(row, base_tags, timestamp)
|
136
|
+
# Extract unique run indices from headers like measuredTime.1, iterations.2, etc.
|
137
|
+
run_indices = row.headers
|
138
|
+
.grep(/^(measuredTime|iterations|timeTaken|excludedTime)\.(\d+)$/)
|
139
|
+
.map { |key| key.split('.').last.to_i } # Extract the run index number
|
140
|
+
.uniq
|
141
|
+
.sort
|
142
|
+
|
143
|
+
run_indices.each do |i|
|
144
|
+
run_tags = base_tags + ["run:#{i}"]
|
145
|
+
|
146
|
+
{
|
147
|
+
'benchmark.measured_time_ns' => row["measuredTime.#{i}"],
|
148
|
+
'benchmark.iterations' => row["iterations.#{i}"],
|
149
|
+
'benchmark.time_taken_ns' => row["timeTaken.#{i}"],
|
150
|
+
'benchmark.excluded_time_ns' => row["excludedTime.#{i}"]
|
151
|
+
}.each do |metric, value|
|
152
|
+
send_if_valid(metric, value, run_tags, timestamp)
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
def process_total_metrics(row, tags, timestamp)
|
158
|
+
totals = {
|
159
|
+
'benchmark.total_measured_time_ns' => row['totalMeasuredTime'],
|
160
|
+
'benchmark.total_iterations' => row['totalIterations'],
|
161
|
+
'benchmark.total_time_taken_ns' => row['totalTimeTaken'],
|
162
|
+
'benchmark.total_excluded_time_ns' => row['totalExcludedTime']
|
163
|
+
}
|
164
|
+
|
165
|
+
totals.each { |metric, value| send_if_valid(metric, value, tags, timestamp) }
|
166
|
+
|
167
|
+
if valid_value?(row['totalMeasuredTime']) && valid_value?(row['totalIterations'])
|
168
|
+
total_time = row['totalMeasuredTime'].to_f
|
169
|
+
total_iters = row['totalIterations'].to_f
|
170
|
+
if total_iters > 0
|
171
|
+
avg = total_time / total_iters
|
172
|
+
send_metric('benchmark.avg_time_per_iteration_ns', avg, tags, timestamp)
|
173
|
+
end
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
def valid_value?(value)
|
178
|
+
value && !value.empty? && value.to_f > 0
|
179
|
+
end
|
180
|
+
|
181
|
+
def send_if_valid(metric, value, tags, timestamp)
|
182
|
+
send_metric(metric, value.to_f, tags, timestamp) if valid_value?(value)
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
DatadogMetricsIngester.run(ARGV)
|
data/lib/maze/aws_public_ip.rb
CHANGED
@@ -34,7 +34,8 @@ module Maze
|
|
34
34
|
def determine_public_ip
|
35
35
|
# 169.254.169.254 is the address of the AWS instance metadata service
|
36
36
|
# See https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/instancedata-data-retrieval.html
|
37
|
-
`curl --silent -
|
37
|
+
token = `curl --silent -H "X-aws-ec2-metadata-token-ttl-seconds: 120" -XPUT http://169.254.169.254/latest/api/token`
|
38
|
+
`curl -H "X-aws-ec2-metadata-token: #{token}" --silent -XGET http://169.254.169.254/latest/meta-data/public-ipv4`
|
38
39
|
end
|
39
40
|
|
40
41
|
# Determines the external port of the running Docker container that's associated with the port given
|
@@ -7,7 +7,6 @@ module Maze
|
|
7
7
|
@client
|
8
8
|
|
9
9
|
def before_all
|
10
|
-
Maze::Plugins::DatadogMetricsPlugin.send_increment('appium.test_started')
|
11
10
|
@client = Maze::Client::Appium.start
|
12
11
|
rescue => error
|
13
12
|
# Notify and re-raise for Cucumber to handle
|
@@ -55,12 +54,6 @@ module Maze
|
|
55
54
|
end
|
56
55
|
|
57
56
|
def after_all
|
58
|
-
if $success
|
59
|
-
Maze::Plugins::DatadogMetricsPlugin.send_increment('appium.test_succeeded')
|
60
|
-
else
|
61
|
-
Maze::Plugins::DatadogMetricsPlugin.send_increment('appium.test_failed')
|
62
|
-
end
|
63
|
-
|
64
57
|
if @client
|
65
58
|
@client.log_run_outro
|
66
59
|
$logger.info 'Stopping the Appium session'
|
@@ -63,7 +63,8 @@ module Maze
|
|
63
63
|
#
|
64
64
|
# @returns [String] The local ipv4 address the Datadog agent is running on
|
65
65
|
def aws_instance_ip
|
66
|
-
`curl --silent -
|
66
|
+
token = `curl --silent -H "X-aws-ec2-metadata-token-ttl-seconds: 120" -XPUT http://169.254.169.254/latest/api/token`
|
67
|
+
`curl -H "X-aws-ec2-metadata-token: #{token}" --silent -XGET http://169.254.169.254/latest/meta-data/local-ipv4`
|
67
68
|
end
|
68
69
|
end
|
69
70
|
end
|
data/lib/maze.rb
CHANGED
@@ -8,7 +8,7 @@ require_relative 'maze/timers'
|
|
8
8
|
# providing an alternative to the proliferation of global variables or singletons.
|
9
9
|
module Maze
|
10
10
|
|
11
|
-
VERSION = '9.
|
11
|
+
VERSION = '9.33.0'
|
12
12
|
|
13
13
|
class << self
|
14
14
|
attr_accessor :check, :driver, :internal_hooks, :mode, :start_time, :dynamic_retry, :public_address,
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bugsnag-maze-runner
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 9.
|
4
|
+
version: 9.33.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Steve Kirkland
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2025-
|
11
|
+
date: 2025-08-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: cucumber
|
@@ -379,6 +379,7 @@ email:
|
|
379
379
|
- steve@bugsnag.com
|
380
380
|
executables:
|
381
381
|
- bb-failed-sessions
|
382
|
+
- benchmarks-to-datadog
|
382
383
|
- bugsnag-print-load-paths
|
383
384
|
- download-logs
|
384
385
|
- maze-runner
|
@@ -388,6 +389,7 @@ extensions: []
|
|
388
389
|
extra_rdoc_files: []
|
389
390
|
files:
|
390
391
|
- bin/bb-failed-sessions
|
392
|
+
- bin/benchmarks-to-datadog
|
391
393
|
- bin/bugsnag-print-load-paths
|
392
394
|
- bin/download-logs
|
393
395
|
- bin/maze-runner
|