google-cloud-logging 0.20.1 → 0.21.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/google-cloud-logging.rb +27 -32
- data/lib/google/cloud/logging.rb +134 -44
- data/lib/google/cloud/logging/async_writer.rb +399 -0
- data/lib/google/cloud/logging/credentials.rb +10 -0
- data/lib/google/cloud/logging/entry.rb +22 -32
- data/lib/google/cloud/logging/entry/list.rb +10 -15
- data/lib/google/cloud/logging/logger.rb +93 -18
- data/lib/google/cloud/logging/metric.rb +8 -12
- data/lib/google/cloud/logging/metric/list.rb +10 -15
- data/lib/google/cloud/logging/middleware.rb +135 -0
- data/lib/google/cloud/logging/project.rb +138 -76
- data/lib/google/cloud/logging/rails.rb +121 -0
- data/lib/google/cloud/logging/resource.rb +2 -3
- data/lib/google/cloud/logging/resource_descriptor.rb +4 -6
- data/lib/google/cloud/logging/resource_descriptor/list.rb +10 -15
- data/lib/google/cloud/logging/service.rb +146 -141
- data/lib/google/cloud/logging/sink.rb +9 -11
- data/lib/google/cloud/logging/sink/list.rb +10 -15
- data/lib/google/cloud/logging/v2/config_service_v2_api.rb +93 -27
- data/lib/google/cloud/logging/v2/logging_service_v2_api.rb +118 -29
- data/lib/google/cloud/logging/v2/metrics_service_v2_api.rb +78 -10
- data/lib/google/cloud/logging/version.rb +1 -1
- data/lib/google/logging/v2/logging_config_pb.rb +1 -0
- data/lib/google/logging/v2/logging_config_services_pb.rb +1 -1
- data/lib/google/logging/v2/logging_metrics_pb.rb +6 -0
- data/lib/google/logging/v2/logging_pb.rb +1 -0
- data/lib/google/logging/v2/logging_services_pb.rb +0 -3
- metadata +84 -11
@@ -25,6 +25,16 @@ module Google
|
|
25
25
|
PATH_ENV_VARS = %w(LOGGING_KEYFILE GOOGLE_CLOUD_KEYFILE GCLOUD_KEYFILE)
|
26
26
|
JSON_ENV_VARS = %w(LOGGING_KEYFILE_JSON GOOGLE_CLOUD_KEYFILE_JSON
|
27
27
|
GCLOUD_KEYFILE_JSON)
|
28
|
+
|
29
|
+
##
|
30
|
+
# @private Create credentials with given scope and/or keyfile
|
31
|
+
def self.credentials_with_scope keyfile, scope = nil
|
32
|
+
if keyfile.nil?
|
33
|
+
default(scope: scope)
|
34
|
+
else
|
35
|
+
new(keyfile, scope: scope)
|
36
|
+
end
|
37
|
+
end
|
28
38
|
end
|
29
39
|
end
|
30
40
|
end
|
@@ -39,16 +39,15 @@ module Google
|
|
39
39
|
# applications. For example, the log `compute.googleapis.com/activity_log`
|
40
40
|
# is produced by Google Compute Engine. Logs are simply referenced by name
|
41
41
|
# in google-cloud. There is no `Log` type in google-cloud or `Log`
|
42
|
-
# resource in the
|
42
|
+
# resource in the Stackdriver Logging API.
|
43
43
|
#
|
44
44
|
# @see https://cloud.google.com/logging/docs/view/logs_index List of Log
|
45
45
|
# Types
|
46
46
|
#
|
47
47
|
# @example
|
48
|
-
# require "google/cloud"
|
48
|
+
# require "google/cloud/logging"
|
49
49
|
#
|
50
|
-
#
|
51
|
-
# logging = gcloud.logging
|
50
|
+
# logging = Google::Cloud::Logging.new
|
52
51
|
#
|
53
52
|
# entry = logging.entry payload: "Job started.", log_name: "my_app_log"
|
54
53
|
# entry.resource.type = "gae_app"
|
@@ -112,10 +111,9 @@ module Google
|
|
112
111
|
# Sets the severity level to `:DEFAULT`.
|
113
112
|
#
|
114
113
|
# @example
|
115
|
-
# require "google/cloud"
|
114
|
+
# require "google/cloud/logging"
|
116
115
|
#
|
117
|
-
#
|
118
|
-
# logging = gcloud.logging
|
116
|
+
# logging = Google::Cloud::Logging.new
|
119
117
|
#
|
120
118
|
# entry = logging.entry
|
121
119
|
# entry.severity = :DEBUG
|
@@ -137,10 +135,9 @@ module Google
|
|
137
135
|
# Sets the severity level to `:DEBUG`.
|
138
136
|
#
|
139
137
|
# @example
|
140
|
-
# require "google/cloud"
|
138
|
+
# require "google/cloud/logging"
|
141
139
|
#
|
142
|
-
#
|
143
|
-
# logging = gcloud.logging
|
140
|
+
# logging = Google::Cloud::Logging.new
|
144
141
|
#
|
145
142
|
# entry = logging.entry
|
146
143
|
# entry.severity #=> :DEFAULT
|
@@ -162,10 +159,9 @@ module Google
|
|
162
159
|
# Sets the severity level to `:INFO`.
|
163
160
|
#
|
164
161
|
# @example
|
165
|
-
# require "google/cloud"
|
162
|
+
# require "google/cloud/logging"
|
166
163
|
#
|
167
|
-
#
|
168
|
-
# logging = gcloud.logging
|
164
|
+
# logging = Google::Cloud::Logging.new
|
169
165
|
#
|
170
166
|
# entry = logging.entry
|
171
167
|
# entry.severity #=> :DEFAULT
|
@@ -187,10 +183,9 @@ module Google
|
|
187
183
|
# Sets the severity level to `:NOTICE`.
|
188
184
|
#
|
189
185
|
# @example
|
190
|
-
# require "google/cloud"
|
186
|
+
# require "google/cloud/logging"
|
191
187
|
#
|
192
|
-
#
|
193
|
-
# logging = gcloud.logging
|
188
|
+
# logging = Google::Cloud::Logging.new
|
194
189
|
#
|
195
190
|
# entry = logging.entry
|
196
191
|
# entry.severity #=> :DEFAULT
|
@@ -212,10 +207,9 @@ module Google
|
|
212
207
|
# Sets the severity level to `:WARNING`.
|
213
208
|
#
|
214
209
|
# @example
|
215
|
-
# require "google/cloud"
|
210
|
+
# require "google/cloud/logging"
|
216
211
|
#
|
217
|
-
#
|
218
|
-
# logging = gcloud.logging
|
212
|
+
# logging = Google::Cloud::Logging.new
|
219
213
|
#
|
220
214
|
# entry = logging.entry
|
221
215
|
# entry.severity #=> :DEFAULT
|
@@ -237,10 +231,9 @@ module Google
|
|
237
231
|
# Sets the severity level to `:ERROR`.
|
238
232
|
#
|
239
233
|
# @example
|
240
|
-
# require "google/cloud"
|
234
|
+
# require "google/cloud/logging"
|
241
235
|
#
|
242
|
-
#
|
243
|
-
# logging = gcloud.logging
|
236
|
+
# logging = Google::Cloud::Logging.new
|
244
237
|
#
|
245
238
|
# entry = logging.entry
|
246
239
|
# entry.severity #=> :DEFAULT
|
@@ -262,10 +255,9 @@ module Google
|
|
262
255
|
# Sets the severity level to `:CRITICAL`.
|
263
256
|
#
|
264
257
|
# @example
|
265
|
-
# require "google/cloud"
|
258
|
+
# require "google/cloud/logging"
|
266
259
|
#
|
267
|
-
#
|
268
|
-
# logging = gcloud.logging
|
260
|
+
# logging = Google::Cloud::Logging.new
|
269
261
|
#
|
270
262
|
# entry = logging.entry
|
271
263
|
# entry.severity #=> :DEFAULT
|
@@ -287,10 +279,9 @@ module Google
|
|
287
279
|
# Sets the severity level to `:ALERT`.
|
288
280
|
#
|
289
281
|
# @example
|
290
|
-
# require "google/cloud"
|
282
|
+
# require "google/cloud/logging"
|
291
283
|
#
|
292
|
-
#
|
293
|
-
# logging = gcloud.logging
|
284
|
+
# logging = Google::Cloud::Logging.new
|
294
285
|
#
|
295
286
|
# entry = logging.entry
|
296
287
|
# entry.severity #=> :DEFAULT
|
@@ -312,10 +303,9 @@ module Google
|
|
312
303
|
# Sets the severity level to `:EMERGENCY`.
|
313
304
|
#
|
314
305
|
# @example
|
315
|
-
# require "google/cloud"
|
306
|
+
# require "google/cloud/logging"
|
316
307
|
#
|
317
|
-
#
|
318
|
-
# logging = gcloud.logging
|
308
|
+
# logging = Google::Cloud::Logging.new
|
319
309
|
#
|
320
310
|
# entry = logging.entry
|
321
311
|
# entry.severity #=> :DEFAULT
|
@@ -461,7 +451,7 @@ module Google
|
|
461
451
|
# @private Get a Time object from a Google::Protobuf::Timestamp object.
|
462
452
|
def self.extract_timestamp grpc
|
463
453
|
return nil if grpc.timestamp.nil?
|
464
|
-
Time.at grpc.timestamp.seconds, grpc.timestamp.nanos
|
454
|
+
Time.at grpc.timestamp.seconds, Rational(grpc.timestamp.nanos, 1000)
|
465
455
|
end
|
466
456
|
end
|
467
457
|
end
|
@@ -39,10 +39,9 @@ module Google
|
|
39
39
|
# @return [Boolean]
|
40
40
|
#
|
41
41
|
# @example
|
42
|
-
# require "google/cloud"
|
42
|
+
# require "google/cloud/logging"
|
43
43
|
#
|
44
|
-
#
|
45
|
-
# logging = gcloud.logging
|
44
|
+
# logging = Google::Cloud::Logging.new
|
46
45
|
#
|
47
46
|
# entries = logging.entries
|
48
47
|
# if entries.next?
|
@@ -59,10 +58,9 @@ module Google
|
|
59
58
|
# @return [Sink::List]
|
60
59
|
#
|
61
60
|
# @example
|
62
|
-
# require "google/cloud"
|
61
|
+
# require "google/cloud/logging"
|
63
62
|
#
|
64
|
-
#
|
65
|
-
# logging = gcloud.logging
|
63
|
+
# logging = Google::Cloud::Logging.new
|
66
64
|
#
|
67
65
|
# entries = dataset.entries
|
68
66
|
# if entries.next?
|
@@ -97,10 +95,9 @@ module Google
|
|
97
95
|
# @return [Enumerator]
|
98
96
|
#
|
99
97
|
# @example Iterating each log entry by passing a block:
|
100
|
-
# require "google/cloud"
|
98
|
+
# require "google/cloud/logging"
|
101
99
|
#
|
102
|
-
#
|
103
|
-
# logging = gcloud.logging
|
100
|
+
# logging = Google::Cloud::Logging.new
|
104
101
|
# entries = logging.entries order: "timestamp desc"
|
105
102
|
#
|
106
103
|
# entries.all do |entry|
|
@@ -108,10 +105,9 @@ module Google
|
|
108
105
|
# end
|
109
106
|
#
|
110
107
|
# @example Using the enumerator by not passing a block:
|
111
|
-
# require "google/cloud"
|
108
|
+
# require "google/cloud/logging"
|
112
109
|
#
|
113
|
-
#
|
114
|
-
# logging = gcloud.logging
|
110
|
+
# logging = Google::Cloud::Logging.new
|
115
111
|
# entries = logging.entries order: "timestamp desc"
|
116
112
|
#
|
117
113
|
# all_payloads = entries.all.map do |entry|
|
@@ -119,10 +115,9 @@ module Google
|
|
119
115
|
# end
|
120
116
|
#
|
121
117
|
# @example Limit the number of API calls made:
|
122
|
-
# require "google/cloud"
|
118
|
+
# require "google/cloud/logging"
|
123
119
|
#
|
124
|
-
#
|
125
|
-
# logging = gcloud.logging
|
120
|
+
# logging = Google::Cloud::Logging.new
|
126
121
|
# entries = logging.entries order: "timestamp desc"
|
127
122
|
#
|
128
123
|
# entries.all(request_limit: 10) do |entry|
|
@@ -13,6 +13,8 @@
|
|
13
13
|
# limitations under the License.
|
14
14
|
|
15
15
|
|
16
|
+
require "orderedhash"
|
17
|
+
|
16
18
|
module Google
|
17
19
|
module Cloud
|
18
20
|
module Logging
|
@@ -22,10 +24,9 @@ module Google
|
|
22
24
|
# A (mostly) API-compatible logger for ruby's Logger.
|
23
25
|
#
|
24
26
|
# @example
|
25
|
-
# require "google/cloud"
|
27
|
+
# require "google/cloud/logging"
|
26
28
|
#
|
27
|
-
#
|
28
|
-
# logging = gcloud.logging
|
29
|
+
# logging = Google::Cloud::Logging.new
|
29
30
|
#
|
30
31
|
# resource = logging.resource "gae_app",
|
31
32
|
# module_id: "1",
|
@@ -36,29 +37,71 @@ module Google
|
|
36
37
|
#
|
37
38
|
class Logger
|
38
39
|
##
|
39
|
-
#
|
40
|
-
|
40
|
+
# The Google Cloud writer object that calls to {#write_entries} are made
|
41
|
+
# on. Either an AsyncWriter or Project object.
|
42
|
+
attr_reader :writer
|
41
43
|
|
42
44
|
##
|
43
|
-
#
|
45
|
+
# The Google Cloud log_name to write the log entry with.
|
44
46
|
attr_reader :log_name
|
45
47
|
|
46
48
|
##
|
47
|
-
#
|
49
|
+
# The Google Cloud resource to write the log entry with.
|
48
50
|
attr_reader :resource
|
49
51
|
|
50
52
|
##
|
51
|
-
#
|
53
|
+
# The Google Cloud labels to write the log entry with.
|
52
54
|
attr_reader :labels
|
53
55
|
|
54
56
|
##
|
55
|
-
#
|
56
|
-
|
57
|
-
|
57
|
+
# A OrderedHash of Thread IDs to Stackdriver request trace ID. The
|
58
|
+
# Stackdriver trace ID is a shared request identifier across all
|
59
|
+
# Stackdriver services.
|
60
|
+
attr_reader :trace_ids
|
61
|
+
|
62
|
+
##
|
63
|
+
# Create a new Logger instance.
|
64
|
+
#
|
65
|
+
# @param [#write_entries] writer The object that will transmit log
|
66
|
+
# entries. Generally, to create a logger that blocks on transmitting
|
67
|
+
# log entries, pass the Project; otherwise, to create a logger that
|
68
|
+
# transmits log entries in the background, pass an AsyncWriter. You
|
69
|
+
# may also pass any other object that responds to #write_entries.
|
70
|
+
# @param [String] log_name A log resource name to be associated with the
|
71
|
+
# written log entries.
|
72
|
+
# @param [Google::Cloud::Logging::Resource] resource The monitored
|
73
|
+
# resource to be associated with written log entries.
|
74
|
+
# @param [Hash] labels A set of user-defined data to be associated with
|
75
|
+
# written log entries.
|
76
|
+
#
|
77
|
+
# @return [Google::Cloud::Logging::Logger] a Logger object that can be
|
78
|
+
# used in place of a ruby standard library logger object.
|
79
|
+
#
|
80
|
+
# @example
|
81
|
+
# require "google/cloud/logging"
|
82
|
+
#
|
83
|
+
# logging = Google::Cloud::Logging.new
|
84
|
+
#
|
85
|
+
# writer = logging.async_writer max_queue_size: 1000
|
86
|
+
#
|
87
|
+
# resource = logging.resource "gae_app", labels: {
|
88
|
+
# "module_id" => "1",
|
89
|
+
# "version_id" => "20150925t173233" }
|
90
|
+
# }
|
91
|
+
#
|
92
|
+
# logger = Google::Cloud::Logging::Logger.new writer,
|
93
|
+
# "my_app_log",
|
94
|
+
# resource,
|
95
|
+
# env: :production
|
96
|
+
# logger.info "Job started."
|
97
|
+
#
|
98
|
+
def initialize writer, log_name, resource, labels = nil
|
99
|
+
@writer = writer
|
58
100
|
@log_name = log_name
|
59
101
|
@resource = resource
|
60
102
|
@labels = labels
|
61
103
|
@level = 0 # DEBUG is the default behavior
|
104
|
+
@trace_ids = OrderedHash.new
|
62
105
|
end
|
63
106
|
|
64
107
|
##
|
@@ -243,10 +286,9 @@ module Google
|
|
243
286
|
# name of the severity level
|
244
287
|
#
|
245
288
|
# @example
|
246
|
-
# require "google/cloud"
|
289
|
+
# require "google/cloud/logging"
|
247
290
|
#
|
248
|
-
#
|
249
|
-
# logging = gcloud.logging
|
291
|
+
# logging = Google::Cloud::Logging.new
|
250
292
|
#
|
251
293
|
# resource = logging.resource "gae_app",
|
252
294
|
# module_id: "1",
|
@@ -264,19 +306,46 @@ module Google
|
|
264
306
|
end
|
265
307
|
alias_method :sev_threshold=, :level=
|
266
308
|
|
309
|
+
##
|
310
|
+
# Track a given trace_id by associating it with the current
|
311
|
+
# Thread
|
312
|
+
#
|
313
|
+
# @param [String] trace_id The HTTP_X_CLOUD_TRACE_CONTEXT HTTP request
|
314
|
+
# header that's shared and tracked by all Stackdriver services
|
315
|
+
def add_trace_id trace_id
|
316
|
+
trace_ids[current_thread_id] = trace_id
|
317
|
+
|
318
|
+
# Start removing old entries if hash gets too large.
|
319
|
+
# This should never happen, because middleware should automatically
|
320
|
+
# remove entries when a request is finished
|
321
|
+
trace_ids.shift if trace_ids.size > 10_000
|
322
|
+
end
|
323
|
+
|
324
|
+
##
|
325
|
+
# Untrack the trace_id that's associated with current Thread
|
326
|
+
#
|
327
|
+
# @return The trace_id that's being deleted
|
328
|
+
def delete_trace_id
|
329
|
+
trace_ids.delete current_thread_id
|
330
|
+
end
|
331
|
+
|
267
332
|
protected
|
268
333
|
|
269
334
|
##
|
270
335
|
# @private Write a log entry to the Stackdriver Logging service.
|
271
336
|
def write_entry severity, message
|
272
|
-
entry =
|
337
|
+
entry = Entry.new.tap do |e|
|
273
338
|
e.severity = gcloud_severity(severity)
|
274
339
|
e.payload = message
|
275
340
|
end
|
276
341
|
|
277
|
-
|
278
|
-
|
279
|
-
|
342
|
+
# merge input labels and trace_id
|
343
|
+
trace_id = trace_ids[current_thread_id]
|
344
|
+
merged_labels = trace_id.nil? ? {} : { traceId: trace_id }
|
345
|
+
merged_labels = labels.merge(merged_labels) unless labels.nil?
|
346
|
+
|
347
|
+
writer.write_entries entry, log_name: log_name, resource: resource,
|
348
|
+
labels: merged_labels
|
280
349
|
end
|
281
350
|
|
282
351
|
##
|
@@ -303,6 +372,12 @@ module Google
|
|
303
372
|
rescue
|
304
373
|
:DEFAULT
|
305
374
|
end
|
375
|
+
|
376
|
+
##
|
377
|
+
# @private Get current thread id
|
378
|
+
def current_thread_id
|
379
|
+
Thread.current.object_id
|
380
|
+
end
|
306
381
|
end
|
307
382
|
end
|
308
383
|
end
|
@@ -32,10 +32,9 @@ module Google
|
|
32
32
|
# @see https://cloud.google.com/monitoring/docs Google Cloud Monitoring
|
33
33
|
#
|
34
34
|
# @example
|
35
|
-
# require "google/cloud"
|
35
|
+
# require "google/cloud/logging"
|
36
36
|
#
|
37
|
-
#
|
38
|
-
# logging = gcloud.logging
|
37
|
+
# logging = Google::Cloud::Logging.new
|
39
38
|
# metric = logging.create_metric "errors", "severity>=ERROR"
|
40
39
|
#
|
41
40
|
class Metric
|
@@ -95,10 +94,9 @@ module Google
|
|
95
94
|
# Updates the logs-based metric.
|
96
95
|
#
|
97
96
|
# @example
|
98
|
-
# require "google/cloud"
|
97
|
+
# require "google/cloud/logging"
|
99
98
|
#
|
100
|
-
#
|
101
|
-
# logging = gcloud.logging
|
99
|
+
# logging = Google::Cloud::Logging.new
|
102
100
|
# metric = logging.metric "severe_errors"
|
103
101
|
# metric.filter = "logName:syslog AND severity>=ERROR"
|
104
102
|
# metric.save
|
@@ -114,10 +112,9 @@ module Google
|
|
114
112
|
# service.
|
115
113
|
#
|
116
114
|
# @example
|
117
|
-
# require "google/cloud"
|
115
|
+
# require "google/cloud/logging"
|
118
116
|
#
|
119
|
-
#
|
120
|
-
# logging = gcloud.logging
|
117
|
+
# logging = Google::Cloud::Logging.new
|
121
118
|
# metric = logging.metric "severe_errors"
|
122
119
|
# metric.filter = "Unwanted value"
|
123
120
|
# metric.reload!
|
@@ -136,10 +133,9 @@ module Google
|
|
136
133
|
# @return [Boolean] Returns `true` if the metric was deleted.
|
137
134
|
#
|
138
135
|
# @example
|
139
|
-
# require "google/cloud"
|
136
|
+
# require "google/cloud/logging"
|
140
137
|
#
|
141
|
-
#
|
142
|
-
# logging = gcloud.logging
|
138
|
+
# logging = Google::Cloud::Logging.new
|
143
139
|
# metric = logging.metric "severe_errors"
|
144
140
|
# metric.delete
|
145
141
|
#
|
@@ -40,10 +40,9 @@ module Google
|
|
40
40
|
# @return [Boolean]
|
41
41
|
#
|
42
42
|
# @example
|
43
|
-
# require "google/cloud"
|
43
|
+
# require "google/cloud/logging"
|
44
44
|
#
|
45
|
-
#
|
46
|
-
# logging = gcloud.logging
|
45
|
+
# logging = Google::Cloud::Logging.new
|
47
46
|
#
|
48
47
|
# metrics = logging.metrics
|
49
48
|
# if metrics.next?
|
@@ -60,10 +59,9 @@ module Google
|
|
60
59
|
# @return [Sink::List]
|
61
60
|
#
|
62
61
|
# @example
|
63
|
-
# require "google/cloud"
|
62
|
+
# require "google/cloud/logging"
|
64
63
|
#
|
65
|
-
#
|
66
|
-
# logging = gcloud.logging
|
64
|
+
# logging = Google::Cloud::Logging.new
|
67
65
|
#
|
68
66
|
# metrics = dataset.metrics
|
69
67
|
# if metrics.next?
|
@@ -96,10 +94,9 @@ module Google
|
|
96
94
|
# @return [Enumerator]
|
97
95
|
#
|
98
96
|
# @example Iterating each metric by passing a block:
|
99
|
-
# require "google/cloud"
|
97
|
+
# require "google/cloud/logging"
|
100
98
|
#
|
101
|
-
#
|
102
|
-
# logging = gcloud.logging
|
99
|
+
# logging = Google::Cloud::Logging.new
|
103
100
|
# metrics = logging.metrics
|
104
101
|
#
|
105
102
|
# metrics.all do |metric|
|
@@ -107,10 +104,9 @@ module Google
|
|
107
104
|
# end
|
108
105
|
#
|
109
106
|
# @example Using the enumerator by not passing a block:
|
110
|
-
# require "google/cloud"
|
107
|
+
# require "google/cloud/logging"
|
111
108
|
#
|
112
|
-
#
|
113
|
-
# logging = gcloud.logging
|
109
|
+
# logging = Google::Cloud::Logging.new
|
114
110
|
# metrics = logging.metrics
|
115
111
|
#
|
116
112
|
# all_names = metrics.all.map do |metric|
|
@@ -118,10 +114,9 @@ module Google
|
|
118
114
|
# end
|
119
115
|
#
|
120
116
|
# @example Limit the number of API calls made:
|
121
|
-
# require "google/cloud"
|
117
|
+
# require "google/cloud/logging"
|
122
118
|
#
|
123
|
-
#
|
124
|
-
# logging = gcloud.logging
|
119
|
+
# logging = Google::Cloud::Logging.new
|
125
120
|
# metrics = logging.metrics
|
126
121
|
#
|
127
122
|
# metrics.all(request_limit: 10) do |metric|
|