flare 0.4.0 → 1.0.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.
Potentially problematic release.
This version of flare might be problematic. Click here for more details.
- data/.document +5 -0
- data/.gitignore +22 -0
- data/LICENSE +20 -0
- data/README.rdoc +18 -0
- data/Rakefile +55 -0
- data/VERSION +1 -0
- data/flare.gemspec +66 -0
- data/lib/flare/active_record.rb +102 -0
- data/lib/flare/collection.rb +47 -0
- data/lib/flare/configuration.rb +64 -123
- data/lib/flare/index_builder.rb +24 -0
- data/lib/flare/session.rb +142 -0
- data/lib/flare/tasks.rb +18 -0
- data/lib/flare.rb +19 -537
- data/test/helper.rb +10 -0
- data/test/test_flare.rb +7 -0
- metadata +89 -242
- checksums.yaml +0 -7
- data/CHANGELOG.md +0 -3
- data/LICENSE.txt +0 -21
- data/README.md +0 -148
- data/app/controllers/flare/application_controller.rb +0 -30
- data/app/controllers/flare/jobs_controller.rb +0 -55
- data/app/controllers/flare/requests_controller.rb +0 -73
- data/app/controllers/flare/spans_controller.rb +0 -101
- data/app/helpers/flare/application_helper.rb +0 -168
- data/app/views/flare/jobs/index.html.erb +0 -69
- data/app/views/flare/jobs/show.html.erb +0 -323
- data/app/views/flare/requests/index.html.erb +0 -120
- data/app/views/flare/requests/show.html.erb +0 -498
- data/app/views/flare/spans/index.html.erb +0 -112
- data/app/views/flare/spans/show.html.erb +0 -184
- data/app/views/layouts/flare/application.html.erb +0 -126
- data/config/routes.rb +0 -20
- data/exe/flare +0 -9
- data/lib/flare/backoff_policy.rb +0 -73
- data/lib/flare/cli/doctor_command.rb +0 -129
- data/lib/flare/cli/output.rb +0 -45
- data/lib/flare/cli/setup_command.rb +0 -404
- data/lib/flare/cli/status_command.rb +0 -47
- data/lib/flare/cli.rb +0 -50
- data/lib/flare/client_headers.rb +0 -39
- data/lib/flare/deadline.rb +0 -27
- data/lib/flare/engine.rb +0 -45
- data/lib/flare/filtering_span_processor.rb +0 -429
- data/lib/flare/http_metrics_config.rb +0 -101
- data/lib/flare/http_transport.rb +0 -76
- data/lib/flare/lifecycle.rb +0 -39
- data/lib/flare/marker.rb +0 -106
- data/lib/flare/metric_counter.rb +0 -51
- data/lib/flare/metric_flusher.rb +0 -279
- data/lib/flare/metric_key.rb +0 -42
- data/lib/flare/metric_span_processor.rb +0 -470
- data/lib/flare/metric_storage.rb +0 -67
- data/lib/flare/metric_submitter.rb +0 -239
- data/lib/flare/recording_batch_span_processor.rb +0 -238
- data/lib/flare/rule_manager.rb +0 -141
- data/lib/flare/sampler.rb +0 -130
- data/lib/flare/source_location.rb +0 -113
- data/lib/flare/sqlite_exporter.rb +0 -334
- data/lib/flare/storage/sqlite.rb +0 -794
- data/lib/flare/storage.rb +0 -54
- data/lib/flare/trace_blob.rb +0 -116
- data/lib/flare/trace_exporter.rb +0 -182
- data/lib/flare/trace_health_reporter.rb +0 -74
- data/lib/flare/upload_url_pool.rb +0 -108
- data/lib/flare/version.rb +0 -5
- data/lib/flare/web_marker_subscriber.rb +0 -76
- data/public/flare-assets/flare.css +0 -1245
- data/public/flare-assets/images/flipper.png +0 -0
data/lib/flare/marker.rb
DELETED
|
@@ -1,106 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require "concurrent/map"
|
|
4
|
-
require "concurrent/atomic/atomic_fixnum"
|
|
5
|
-
|
|
6
|
-
module Flare
|
|
7
|
-
# Thread-safe registry of trace_ids that Path 2 (the WebMarkerSubscriber)
|
|
8
|
-
# has marked for export. FilteringSpanProcessor checks marked? on every
|
|
9
|
-
# on_finish; matching spans get forwarded to the trace exporter, the rest
|
|
10
|
-
# are dropped.
|
|
11
|
-
#
|
|
12
|
-
# Each entry records the OWNER span_id (the local rack server span the
|
|
13
|
-
# subscriber was inside when it marked the trace). Cleanup is keyed on
|
|
14
|
-
# the owner finishing, not the trace root finishing -- remote-parented
|
|
15
|
-
# rack spans aren't trace roots, and child spans can outlive their parent
|
|
16
|
-
# in OTel, so root-driven cleanup would leak on the dominant production
|
|
17
|
-
# case (web app behind a load balancer or service mesh).
|
|
18
|
-
#
|
|
19
|
-
# Bounded by:
|
|
20
|
-
# - sweep(): drops entries older than max_age (default 5 min) so a rack
|
|
21
|
-
# span that never finishes (process killed mid-request, exception path
|
|
22
|
-
# that skips ensure) doesn't leak forever.
|
|
23
|
-
# - hard ceiling at max_entries (default 10k): on overflow, drop oldest
|
|
24
|
-
# 10% by marked_at.
|
|
25
|
-
class Marker
|
|
26
|
-
Entry = Struct.new(:owner_span_id, :rule_id, :marked_at, keyword_init: true)
|
|
27
|
-
|
|
28
|
-
DEFAULT_MAX_ENTRIES = 10_000
|
|
29
|
-
DEFAULT_MAX_AGE = 5 * 60 # seconds
|
|
30
|
-
|
|
31
|
-
attr_reader :evicted_count
|
|
32
|
-
|
|
33
|
-
def initialize(max_entries: DEFAULT_MAX_ENTRIES, max_age: DEFAULT_MAX_AGE)
|
|
34
|
-
@entries = Concurrent::Map.new
|
|
35
|
-
@max_entries = max_entries
|
|
36
|
-
@max_age = max_age
|
|
37
|
-
@evicted_count = Concurrent::AtomicFixnum.new(0)
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
def mark(trace_id, owner_span_id:, rule_id:)
|
|
41
|
-
@entries[trace_id] = Entry.new(
|
|
42
|
-
owner_span_id: owner_span_id,
|
|
43
|
-
rule_id: rule_id,
|
|
44
|
-
marked_at: monotonic_now
|
|
45
|
-
)
|
|
46
|
-
maybe_evict_oldest
|
|
47
|
-
end
|
|
48
|
-
|
|
49
|
-
def marked?(trace_id)
|
|
50
|
-
@entries.key?(trace_id)
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
# True only when span_id matches the marker's owner -- the rack span
|
|
54
|
-
# that originally marked this trace. Used by FilteringSpanProcessor to
|
|
55
|
-
# decide when to unmark (only when that exact span finishes, not on
|
|
56
|
-
# every span that happens to have this trace_id).
|
|
57
|
-
def owner?(trace_id, span_id)
|
|
58
|
-
entry = @entries[trace_id]
|
|
59
|
-
!entry.nil? && entry.owner_span_id == span_id
|
|
60
|
-
end
|
|
61
|
-
|
|
62
|
-
def rule_id(trace_id)
|
|
63
|
-
entry = @entries[trace_id]
|
|
64
|
-
entry&.rule_id
|
|
65
|
-
end
|
|
66
|
-
|
|
67
|
-
def unmark(trace_id)
|
|
68
|
-
@entries.delete(trace_id)
|
|
69
|
-
end
|
|
70
|
-
|
|
71
|
-
def size
|
|
72
|
-
@entries.size
|
|
73
|
-
end
|
|
74
|
-
|
|
75
|
-
# Drop entries older than max_age. Call periodically (the RuleManager's
|
|
76
|
-
# scheduler is the natural place) to handle the rack-span-never-finishes
|
|
77
|
-
# leak case (CAF-7).
|
|
78
|
-
def sweep
|
|
79
|
-
threshold = monotonic_now - @max_age
|
|
80
|
-
evicted = 0
|
|
81
|
-
@entries.each_pair do |trace_id, entry|
|
|
82
|
-
if entry.marked_at < threshold
|
|
83
|
-
@entries.delete(trace_id)
|
|
84
|
-
evicted += 1
|
|
85
|
-
end
|
|
86
|
-
end
|
|
87
|
-
@evicted_count.increment(evicted) if evicted.positive?
|
|
88
|
-
evicted
|
|
89
|
-
end
|
|
90
|
-
|
|
91
|
-
private
|
|
92
|
-
|
|
93
|
-
def maybe_evict_oldest
|
|
94
|
-
return if @entries.size <= @max_entries
|
|
95
|
-
|
|
96
|
-
to_drop = (@max_entries * 0.1).ceil
|
|
97
|
-
sorted = @entries.each_pair.to_a.sort_by { |_, entry| entry.marked_at }
|
|
98
|
-
sorted.first(to_drop).each { |trace_id, _| @entries.delete(trace_id) }
|
|
99
|
-
@evicted_count.increment(to_drop)
|
|
100
|
-
end
|
|
101
|
-
|
|
102
|
-
def monotonic_now
|
|
103
|
-
Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
104
|
-
end
|
|
105
|
-
end
|
|
106
|
-
end
|
data/lib/flare/metric_counter.rb
DELETED
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require "concurrent/atomic/atomic_fixnum"
|
|
4
|
-
|
|
5
|
-
module Flare
|
|
6
|
-
# Thread-safe counter for metric aggregation.
|
|
7
|
-
# Uses atomic operations for lock-free increments.
|
|
8
|
-
#
|
|
9
|
-
# Note: Durations are stored as integer milliseconds. Sub-millisecond
|
|
10
|
-
# durations are truncated to 0. For very fast operations (e.g., cache hits),
|
|
11
|
-
# the sum_ms may undercount actual time spent.
|
|
12
|
-
class MetricCounter
|
|
13
|
-
def initialize
|
|
14
|
-
@count = Concurrent::AtomicFixnum.new(0)
|
|
15
|
-
@sum_ms = Concurrent::AtomicFixnum.new(0)
|
|
16
|
-
@error_count = Concurrent::AtomicFixnum.new(0)
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
def increment(duration_ms:, error: false)
|
|
20
|
-
@count.increment
|
|
21
|
-
@sum_ms.increment(duration_ms.to_i)
|
|
22
|
-
@error_count.increment if error
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
def add(count:, sum_ms:, error_count: 0)
|
|
26
|
-
@count.increment(count.to_i)
|
|
27
|
-
@sum_ms.increment(sum_ms.to_i)
|
|
28
|
-
@error_count.increment(error_count.to_i)
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
def count
|
|
32
|
-
@count.value
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
def sum_ms
|
|
36
|
-
@sum_ms.value
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
def error_count
|
|
40
|
-
@error_count.value
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
def to_h
|
|
44
|
-
{
|
|
45
|
-
count: @count.value,
|
|
46
|
-
sum_ms: @sum_ms.value,
|
|
47
|
-
error_count: @error_count.value
|
|
48
|
-
}
|
|
49
|
-
end
|
|
50
|
-
end
|
|
51
|
-
end
|
data/lib/flare/metric_flusher.rb
DELETED
|
@@ -1,279 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require "concurrent/timer_task"
|
|
4
|
-
require "concurrent/executor/fixed_thread_pool"
|
|
5
|
-
require "opentelemetry/sdk"
|
|
6
|
-
|
|
7
|
-
require_relative "deadline"
|
|
8
|
-
|
|
9
|
-
module Flare
|
|
10
|
-
# Background threads that periodically drain in-memory metrics and submit
|
|
11
|
-
# them via HTTP. Uses concurrent-ruby TimerTask + FixedThreadPool, matching
|
|
12
|
-
# the pattern in Flipper's telemetry.
|
|
13
|
-
#
|
|
14
|
-
# Fork-safe: detects forked processes and restarts automatically.
|
|
15
|
-
class MetricFlusher
|
|
16
|
-
SUCCESS = OpenTelemetry::SDK::Trace::Export::SUCCESS
|
|
17
|
-
FAILURE = OpenTelemetry::SDK::Trace::Export::FAILURE
|
|
18
|
-
TIMEOUT = OpenTelemetry::SDK::Trace::Export::TIMEOUT
|
|
19
|
-
DEFAULT_INTERVAL = 60 # seconds
|
|
20
|
-
DEFAULT_SHUTDOWN_TIMEOUT = 5 # seconds
|
|
21
|
-
|
|
22
|
-
attr_reader :interval, :shutdown_timeout
|
|
23
|
-
|
|
24
|
-
def initialize(storage:, submitter:, interval: DEFAULT_INTERVAL, shutdown_timeout: DEFAULT_SHUTDOWN_TIMEOUT, health_reporters: [])
|
|
25
|
-
@storage = storage
|
|
26
|
-
@submitter = submitter
|
|
27
|
-
@interval = interval
|
|
28
|
-
@shutdown_timeout = shutdown_timeout
|
|
29
|
-
@health_reporters = Array(health_reporters)
|
|
30
|
-
@pid = $$
|
|
31
|
-
@stopped = false
|
|
32
|
-
initialize_synchronization
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
def start
|
|
36
|
-
@stopped = false
|
|
37
|
-
|
|
38
|
-
@pool = Concurrent::FixedThreadPool.new(1, {
|
|
39
|
-
max_queue: 20,
|
|
40
|
-
fallback_policy: :discard,
|
|
41
|
-
name: "flare-metrics-submit-pool".freeze,
|
|
42
|
-
})
|
|
43
|
-
|
|
44
|
-
@timer = Concurrent::TimerTask.execute({
|
|
45
|
-
execution_interval: @interval,
|
|
46
|
-
name: "flare-metrics-drain-timer".freeze,
|
|
47
|
-
}) { post_to_pool }
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
def stop(timeout: @shutdown_timeout)
|
|
51
|
-
return if @stopped
|
|
52
|
-
|
|
53
|
-
deadline = Deadline.new(timeout)
|
|
54
|
-
@stopped = true
|
|
55
|
-
|
|
56
|
-
log "Shutting down metrics flusher, draining remaining metrics..."
|
|
57
|
-
|
|
58
|
-
if @timer
|
|
59
|
-
@timer.shutdown
|
|
60
|
-
@timer.wait_for_termination([deadline.remaining || 1, 1].min)
|
|
61
|
-
@timer.kill unless @timer.shutdown?
|
|
62
|
-
end
|
|
63
|
-
|
|
64
|
-
force_flush(timeout: deadline.remaining)
|
|
65
|
-
|
|
66
|
-
if @pool
|
|
67
|
-
@pool.shutdown
|
|
68
|
-
pool_terminated = @pool.wait_for_termination(deadline.remaining || @shutdown_timeout)
|
|
69
|
-
@pool.kill unless pool_terminated
|
|
70
|
-
end
|
|
71
|
-
|
|
72
|
-
log "Metrics flusher stopped"
|
|
73
|
-
end
|
|
74
|
-
|
|
75
|
-
def restart
|
|
76
|
-
@stopped = false
|
|
77
|
-
stop
|
|
78
|
-
start
|
|
79
|
-
end
|
|
80
|
-
|
|
81
|
-
# Manually trigger a flush (useful for testing or forced flushes).
|
|
82
|
-
def flush_now(timeout: nil)
|
|
83
|
-
return 0 unless @storage && @submitter
|
|
84
|
-
|
|
85
|
-
detect_forking
|
|
86
|
-
count, error, = flush_synchronously(Deadline.new(timeout))
|
|
87
|
-
if error
|
|
88
|
-
warn "[Flare] Metric submission error: #{error.message}"
|
|
89
|
-
end
|
|
90
|
-
count
|
|
91
|
-
rescue => e
|
|
92
|
-
warn "[Flare] Metric flush error: #{e.message}"
|
|
93
|
-
0
|
|
94
|
-
end
|
|
95
|
-
|
|
96
|
-
def force_flush(timeout: nil)
|
|
97
|
-
return SUCCESS unless @storage && @submitter
|
|
98
|
-
|
|
99
|
-
detect_forking
|
|
100
|
-
deadline = Deadline.new(timeout)
|
|
101
|
-
_count, error, timed_out = flush_synchronously(deadline)
|
|
102
|
-
return TIMEOUT if timed_out || deadline.expired?
|
|
103
|
-
return FAILURE if error
|
|
104
|
-
|
|
105
|
-
SUCCESS
|
|
106
|
-
rescue => e
|
|
107
|
-
warn "[Flare] Metric flush error: #{e.message}"
|
|
108
|
-
FAILURE
|
|
109
|
-
end
|
|
110
|
-
|
|
111
|
-
def running?
|
|
112
|
-
@timer&.running? || false
|
|
113
|
-
end
|
|
114
|
-
|
|
115
|
-
# Re-initialize after fork. Called automatically by MetricSpanProcessor
|
|
116
|
-
# on first span in the new process, or manually from Puma/Unicorn
|
|
117
|
-
# after_fork hooks.
|
|
118
|
-
def after_fork
|
|
119
|
-
@pid = $$
|
|
120
|
-
@storage.after_fork if @storage.respond_to?(:after_fork)
|
|
121
|
-
initialize_synchronization
|
|
122
|
-
@timer = nil
|
|
123
|
-
@pool = nil
|
|
124
|
-
start
|
|
125
|
-
end
|
|
126
|
-
|
|
127
|
-
private
|
|
128
|
-
|
|
129
|
-
def detect_forking
|
|
130
|
-
after_fork if @pid != $$
|
|
131
|
-
end
|
|
132
|
-
|
|
133
|
-
def initialize_synchronization
|
|
134
|
-
@submission_mutex = Mutex.new
|
|
135
|
-
@submission_condition = ConditionVariable.new
|
|
136
|
-
@pending_submissions = 0
|
|
137
|
-
@flush_owner = nil
|
|
138
|
-
end
|
|
139
|
-
|
|
140
|
-
def post_to_pool
|
|
141
|
-
return unless reserve_background_submission
|
|
142
|
-
|
|
143
|
-
record_health_metrics
|
|
144
|
-
drained = @storage.drain
|
|
145
|
-
if drained.empty?
|
|
146
|
-
log "No metrics to flush"
|
|
147
|
-
background_submission_finished
|
|
148
|
-
return
|
|
149
|
-
end
|
|
150
|
-
|
|
151
|
-
log "Drained #{drained.size} metric keys for submission"
|
|
152
|
-
posted = @pool.post do
|
|
153
|
-
submit_to_cloud(drained)
|
|
154
|
-
ensure
|
|
155
|
-
background_submission_finished
|
|
156
|
-
end
|
|
157
|
-
background_submission_finished unless posted
|
|
158
|
-
rescue => e
|
|
159
|
-
background_submission_finished
|
|
160
|
-
warn "[Flare] Metric drain error: #{e.message}"
|
|
161
|
-
end
|
|
162
|
-
|
|
163
|
-
def submit_to_cloud(drained)
|
|
164
|
-
_response, error = @submitter.submit(drained)
|
|
165
|
-
if error
|
|
166
|
-
warn "[Flare] Metric submission error: #{error.message}"
|
|
167
|
-
end
|
|
168
|
-
rescue => e
|
|
169
|
-
warn "[Flare] Metric submission error: #{e.message}"
|
|
170
|
-
end
|
|
171
|
-
|
|
172
|
-
def reserve_background_submission
|
|
173
|
-
@submission_mutex.synchronize do
|
|
174
|
-
return false if @flush_owner || @pending_submissions.positive?
|
|
175
|
-
|
|
176
|
-
@pending_submissions += 1
|
|
177
|
-
true
|
|
178
|
-
end
|
|
179
|
-
end
|
|
180
|
-
|
|
181
|
-
def background_submission_finished
|
|
182
|
-
@submission_mutex.synchronize do
|
|
183
|
-
@pending_submissions -= 1 if @pending_submissions.positive?
|
|
184
|
-
@submission_condition.broadcast
|
|
185
|
-
end
|
|
186
|
-
end
|
|
187
|
-
|
|
188
|
-
def flush_synchronously(deadline)
|
|
189
|
-
return [0, nil, true] unless begin_synchronous_flush(deadline)
|
|
190
|
-
|
|
191
|
-
record_health_metrics
|
|
192
|
-
drained = @storage.drain
|
|
193
|
-
return [0, nil, false] if drained.empty?
|
|
194
|
-
|
|
195
|
-
submit_with_deadline(drained, deadline)
|
|
196
|
-
ensure
|
|
197
|
-
finish_synchronous_flush if @flush_owner == Thread.current
|
|
198
|
-
end
|
|
199
|
-
|
|
200
|
-
def begin_synchronous_flush(deadline)
|
|
201
|
-
@submission_mutex.synchronize do
|
|
202
|
-
while @flush_owner && @flush_owner != Thread.current
|
|
203
|
-
return false if deadline.expired?
|
|
204
|
-
|
|
205
|
-
@submission_condition.wait(@submission_mutex, deadline.remaining)
|
|
206
|
-
end
|
|
207
|
-
@flush_owner = Thread.current
|
|
208
|
-
|
|
209
|
-
while @pending_submissions.positive?
|
|
210
|
-
return false if deadline.expired?
|
|
211
|
-
|
|
212
|
-
@submission_condition.wait(@submission_mutex, deadline.remaining)
|
|
213
|
-
end
|
|
214
|
-
end
|
|
215
|
-
true
|
|
216
|
-
end
|
|
217
|
-
|
|
218
|
-
def finish_synchronous_flush
|
|
219
|
-
@submission_mutex.synchronize do
|
|
220
|
-
@flush_owner = nil
|
|
221
|
-
@submission_condition.broadcast
|
|
222
|
-
end
|
|
223
|
-
end
|
|
224
|
-
|
|
225
|
-
def submit_metrics(drained, timeout:)
|
|
226
|
-
parameters = @submitter.method(:submit).parameters
|
|
227
|
-
accepts_timeout = parameters.any? do |type, name|
|
|
228
|
-
type == :keyrest || ([:key, :keyreq].include?(type) && name == :timeout)
|
|
229
|
-
end
|
|
230
|
-
|
|
231
|
-
if accepts_timeout
|
|
232
|
-
@submitter.submit(drained, timeout: timeout)
|
|
233
|
-
else
|
|
234
|
-
@submitter.submit(drained)
|
|
235
|
-
end
|
|
236
|
-
end
|
|
237
|
-
|
|
238
|
-
def submit_with_deadline(drained, deadline)
|
|
239
|
-
operation = { done: false, count: 0, error: nil }
|
|
240
|
-
@submission_mutex.synchronize { @pending_submissions += 1 }
|
|
241
|
-
Thread.new do
|
|
242
|
-
operation[:count], operation[:error] = submit_metrics(drained, timeout: deadline.remaining)
|
|
243
|
-
rescue => e
|
|
244
|
-
operation[:error] = e
|
|
245
|
-
ensure
|
|
246
|
-
@submission_mutex.synchronize do
|
|
247
|
-
operation[:done] = true
|
|
248
|
-
@pending_submissions -= 1
|
|
249
|
-
@submission_condition.broadcast
|
|
250
|
-
end
|
|
251
|
-
end
|
|
252
|
-
|
|
253
|
-
@submission_mutex.synchronize do
|
|
254
|
-
until operation[:done]
|
|
255
|
-
return [0, nil, true] if deadline.expired?
|
|
256
|
-
|
|
257
|
-
@submission_condition.wait(@submission_mutex, deadline.remaining)
|
|
258
|
-
end
|
|
259
|
-
end
|
|
260
|
-
|
|
261
|
-
timed_out = deadline.expired? || deadline_error?(operation[:error])
|
|
262
|
-
[operation[:count], operation[:error], timed_out]
|
|
263
|
-
end
|
|
264
|
-
|
|
265
|
-
def deadline_error?(error)
|
|
266
|
-
defined?(MetricSubmitter::DeadlineExceeded) && error.is_a?(MetricSubmitter::DeadlineExceeded)
|
|
267
|
-
end
|
|
268
|
-
|
|
269
|
-
def record_health_metrics
|
|
270
|
-
@health_reporters.each { |reporter| reporter.record(@storage) }
|
|
271
|
-
rescue => e
|
|
272
|
-
warn "[Flare] Health metric recording error: #{e.message}"
|
|
273
|
-
end
|
|
274
|
-
|
|
275
|
-
def log(message)
|
|
276
|
-
Flare.log(message) if Flare.respond_to?(:log)
|
|
277
|
-
end
|
|
278
|
-
end
|
|
279
|
-
end
|
data/lib/flare/metric_key.rb
DELETED
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Flare
|
|
4
|
-
# Identifies a unique metric for aggregation.
|
|
5
|
-
# Immutable and hashable for use as Concurrent::Map keys.
|
|
6
|
-
class MetricKey
|
|
7
|
-
attr_reader :bucket, :namespace, :service, :target, :operation
|
|
8
|
-
|
|
9
|
-
def initialize(bucket:, namespace:, service:, target:, operation:)
|
|
10
|
-
@bucket = bucket
|
|
11
|
-
@namespace = namespace.to_s.freeze
|
|
12
|
-
@service = service.to_s.freeze
|
|
13
|
-
@target = target&.to_s&.freeze
|
|
14
|
-
@operation = operation.to_s.freeze
|
|
15
|
-
freeze
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
def eql?(other)
|
|
19
|
-
self.class.eql?(other.class) &&
|
|
20
|
-
bucket == other.bucket &&
|
|
21
|
-
namespace == other.namespace &&
|
|
22
|
-
service == other.service &&
|
|
23
|
-
target == other.target &&
|
|
24
|
-
operation == other.operation
|
|
25
|
-
end
|
|
26
|
-
alias == eql?
|
|
27
|
-
|
|
28
|
-
def hash
|
|
29
|
-
[self.class, bucket, namespace, service, target, operation].hash
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
def to_h
|
|
33
|
-
{
|
|
34
|
-
bucket: bucket,
|
|
35
|
-
namespace: namespace,
|
|
36
|
-
service: service,
|
|
37
|
-
target: target,
|
|
38
|
-
operation: operation
|
|
39
|
-
}
|
|
40
|
-
end
|
|
41
|
-
end
|
|
42
|
-
end
|