flare 0.1.1 → 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 -109
- 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 -408
- data/test/helper.rb +10 -0
- data/test/test_flare.rb +7 -0
- metadata +89 -228
- checksums.yaml +0 -7
- data/CHANGELOG.md +0 -5
- data/LICENSE.txt +0 -21
- data/README.md +0 -148
- data/app/controllers/flare/application_controller.rb +0 -22
- 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/engine.rb +0 -43
- data/lib/flare/http_metrics_config.rb +0 -101
- data/lib/flare/metric_counter.rb +0 -45
- data/lib/flare/metric_flusher.rb +0 -124
- data/lib/flare/metric_key.rb +0 -42
- data/lib/flare/metric_span_processor.rb +0 -470
- data/lib/flare/metric_storage.rb +0 -42
- data/lib/flare/metric_submitter.rb +0 -221
- data/lib/flare/source_location.rb +0 -113
- data/lib/flare/sqlite_exporter.rb +0 -279
- data/lib/flare/storage/sqlite.rb +0 -789
- data/lib/flare/storage.rb +0 -54
- data/lib/flare/version.rb +0 -5
- data/public/flare-assets/flare.css +0 -1245
- data/public/flare-assets/images/flipper.png +0 -0
data/lib/flare/tasks.rb
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
require 'escape'
|
|
2
|
+
|
|
3
|
+
namespace :flare do
|
|
4
|
+
desc 'Rebuild the Solr index for all searchable models'
|
|
5
|
+
task :rebuild_index => :environment do
|
|
6
|
+
Flare.indexed_models.each do |model|
|
|
7
|
+
puts "Clearing index for #{model.name}..."
|
|
8
|
+
model.clear_solr_index
|
|
9
|
+
|
|
10
|
+
puts "Rebuilding index for #{model.name}..."
|
|
11
|
+
model.rebuild_solr_index
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
puts "Optimizing..."
|
|
15
|
+
Flare.session.commit
|
|
16
|
+
Flare.session.optimize
|
|
17
|
+
end
|
|
18
|
+
end
|
data/lib/flare.rb
CHANGED
|
@@ -1,415 +1,26 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
begin
|
|
2
|
+
# require 'time'
|
|
3
|
+
# require 'date'
|
|
4
|
+
require 'rsolr'
|
|
5
|
+
rescue LoadError
|
|
6
|
+
require 'rubygems'
|
|
7
|
+
require 'rsolr'
|
|
8
|
+
end
|
|
5
9
|
|
|
6
|
-
|
|
10
|
+
%w(configuration collection index_builder session active_record).each do |file|
|
|
11
|
+
require File.join(File.dirname(__FILE__), 'flare', file)
|
|
12
|
+
end
|
|
7
13
|
|
|
8
|
-
|
|
9
|
-
require_relative "flare/metric_key"
|
|
10
|
-
require_relative "flare/metric_storage"
|
|
11
|
-
require_relative "flare/metric_span_processor"
|
|
12
|
-
require_relative "flare/metric_flusher"
|
|
13
|
-
require_relative "flare/backoff_policy"
|
|
14
|
-
require_relative "flare/metric_submitter"
|
|
14
|
+
ActiveRecord::Base.send(:include, Flare::ActiveRecord)
|
|
15
15
|
|
|
16
16
|
module Flare
|
|
17
|
-
class
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
TRANSACTION_NAME_ATTRIBUTE = "flare.transaction_name" unless const_defined?(:TRANSACTION_NAME_ATTRIBUTE)
|
|
21
|
-
|
|
22
|
-
module_function
|
|
23
|
-
|
|
24
|
-
def configuration
|
|
25
|
-
@configuration ||= Configuration.new
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
def configure
|
|
29
|
-
yield(configuration) if block_given?
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
def enabled?
|
|
33
|
-
configuration.enabled
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
# Set the transaction name for the current span. This overrides the
|
|
37
|
-
# default name derived from Rails controller/action or job class.
|
|
38
|
-
#
|
|
39
|
-
# Useful for Rack middleware, mounted apps, or any request that
|
|
40
|
-
# doesn't go through the Rails router.
|
|
41
|
-
#
|
|
42
|
-
# Flare.transaction_name("RestApi::Routes::Audits#get")
|
|
43
|
-
#
|
|
44
|
-
def transaction_name(name)
|
|
45
|
-
span = OpenTelemetry::Trace.current_span
|
|
46
|
-
return unless span.respond_to?(:set_attribute)
|
|
47
|
-
|
|
48
|
-
span.set_attribute(TRANSACTION_NAME_ATTRIBUTE, name)
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
def logger
|
|
52
|
-
@logger ||= Logger.new(STDOUT)
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
def logger=(logger)
|
|
56
|
-
@logger = logger
|
|
57
|
-
end
|
|
58
|
-
|
|
59
|
-
def log(message)
|
|
60
|
-
return unless configuration.debug
|
|
61
|
-
|
|
62
|
-
logger.info("[Flare] #{message}")
|
|
63
|
-
end
|
|
64
|
-
|
|
65
|
-
def exporter
|
|
66
|
-
@exporter ||= begin
|
|
67
|
-
require_relative "flare/sqlite_exporter"
|
|
68
|
-
SQLiteExporter.new(configuration.database_path)
|
|
69
|
-
rescue LoadError
|
|
70
|
-
warn "[Flare] sqlite3 gem not found. Spans are disabled. Add `gem 'sqlite3'` to your Gemfile to enable the development dashboard."
|
|
71
|
-
configuration.spans_enabled = false
|
|
72
|
-
nil
|
|
17
|
+
class << self
|
|
18
|
+
def session
|
|
19
|
+
@session ||= Flare::Session.new
|
|
73
20
|
end
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
@exporter = exporter
|
|
78
|
-
end
|
|
79
|
-
|
|
80
|
-
def span_processor
|
|
81
|
-
@span_processor ||= OpenTelemetry::SDK::Trace::Export::BatchSpanProcessor.new(
|
|
82
|
-
exporter,
|
|
83
|
-
max_queue_size: 1000,
|
|
84
|
-
max_export_batch_size: 100,
|
|
85
|
-
schedule_delay: 1000 # 1 second
|
|
86
|
-
)
|
|
87
|
-
end
|
|
88
|
-
|
|
89
|
-
def span_processor=(span_processor)
|
|
90
|
-
@span_processor = span_processor
|
|
91
|
-
end
|
|
92
|
-
|
|
93
|
-
def tracer
|
|
94
|
-
@tracer ||= OpenTelemetry.tracer_provider.tracer("Flare", Flare::VERSION)
|
|
95
|
-
end
|
|
96
|
-
|
|
97
|
-
def untraced(&block)
|
|
98
|
-
OpenTelemetry::Common::Utilities.untraced(&block)
|
|
99
|
-
end
|
|
100
|
-
|
|
101
|
-
def metric_storage
|
|
102
|
-
@metric_storage
|
|
103
|
-
end
|
|
104
|
-
|
|
105
|
-
def metric_storage=(storage)
|
|
106
|
-
@metric_storage = storage
|
|
107
|
-
end
|
|
108
|
-
|
|
109
|
-
def metric_flusher
|
|
110
|
-
@metric_flusher
|
|
111
|
-
end
|
|
112
|
-
|
|
113
|
-
def metric_flusher=(flusher)
|
|
114
|
-
@metric_flusher = flusher
|
|
115
|
-
end
|
|
116
|
-
|
|
117
|
-
# Manually flush metrics (useful for testing or forced flushes).
|
|
118
|
-
def flush_metrics
|
|
119
|
-
@metric_flusher&.flush_now || 0
|
|
120
|
-
end
|
|
121
|
-
|
|
122
|
-
# Re-initialize metric flusher after fork.
|
|
123
|
-
# Call this from Puma/Unicorn after_fork hooks.
|
|
124
|
-
def after_fork
|
|
125
|
-
@metric_flusher&.after_fork
|
|
126
|
-
end
|
|
127
|
-
|
|
128
|
-
# Configure OpenTelemetry SDK and instrumentations. Must run before the
|
|
129
|
-
# middleware stack is built so Rack/ActionPack can insert their middleware.
|
|
130
|
-
# Note: metrics flusher is started separately via start_metrics_flusher
|
|
131
|
-
# after user initializers have run.
|
|
132
|
-
def configure_opentelemetry
|
|
133
|
-
return if @otel_configured
|
|
134
|
-
|
|
135
|
-
# Suppress noisy OTel INFO logs
|
|
136
|
-
OpenTelemetry.logger = Logger.new(STDOUT, level: Logger::WARN)
|
|
137
|
-
|
|
138
|
-
service_name = if defined?(Rails) && Rails.application
|
|
139
|
-
Rails.application.class.module_parent_name.underscore rescue "rails_app"
|
|
140
|
-
else
|
|
141
|
-
"app"
|
|
142
|
-
end
|
|
143
|
-
|
|
144
|
-
# Require only the instrumentations we want
|
|
145
|
-
require "opentelemetry-instrumentation-rack"
|
|
146
|
-
require "opentelemetry-instrumentation-net_http"
|
|
147
|
-
require "opentelemetry-instrumentation-active_support"
|
|
148
|
-
require "opentelemetry/instrumentation/active_support/span_subscriber"
|
|
149
|
-
require "opentelemetry-instrumentation-action_pack" if defined?(ActionController)
|
|
150
|
-
require "opentelemetry-instrumentation-action_view" if defined?(ActionView)
|
|
151
|
-
require "opentelemetry-instrumentation-active_job" if defined?(ActiveJob)
|
|
152
|
-
|
|
153
|
-
# Tell the SDK not to try configuring OTLP from env vars.
|
|
154
|
-
# Flare manages its own exporters (SQLite for spans, HTTP for metrics).
|
|
155
|
-
ENV["OTEL_TRACES_EXPORTER"] ||= "none"
|
|
156
|
-
|
|
157
|
-
log "Configuring OpenTelemetry (service=#{service_name})"
|
|
158
|
-
|
|
159
|
-
OpenTelemetry::SDK.configure do |c|
|
|
160
|
-
c.service_name = service_name
|
|
161
|
-
|
|
162
|
-
# Spans: detailed trace data stored in SQLite
|
|
163
|
-
if configuration.spans_enabled && exporter
|
|
164
|
-
c.add_span_processor(span_processor)
|
|
165
|
-
log "Spans enabled (database=#{configuration.database_path})"
|
|
166
|
-
end
|
|
167
|
-
|
|
168
|
-
# Configure specific instrumentations
|
|
169
|
-
c.use "OpenTelemetry::Instrumentation::Rack",
|
|
170
|
-
untraced_requests: ->(env) {
|
|
171
|
-
request = Rack::Request.new(env)
|
|
172
|
-
return true if request.path.start_with?("/flare")
|
|
173
|
-
|
|
174
|
-
configuration.ignore_request.call(request)
|
|
175
|
-
}
|
|
176
|
-
c.use "OpenTelemetry::Instrumentation::Net::HTTP"
|
|
177
|
-
c.use "OpenTelemetry::Instrumentation::ActiveSupport"
|
|
178
|
-
c.use "OpenTelemetry::Instrumentation::ActionPack" if defined?(ActionController)
|
|
179
|
-
c.use "OpenTelemetry::Instrumentation::ActionView" if defined?(ActionView)
|
|
180
|
-
c.use "OpenTelemetry::Instrumentation::ActiveJob" if defined?(ActiveJob)
|
|
181
|
-
end
|
|
182
|
-
|
|
183
|
-
# Subscribe to common ActiveSupport notification patterns
|
|
184
|
-
# This captures SQL, cache, mailer, and custom notifications.
|
|
185
|
-
# Required for both spans (detailed traces) and metrics (aggregated counters)
|
|
186
|
-
# because DB, cache, and mailer data flows through ActiveSupport notifications.
|
|
187
|
-
if configuration.spans_enabled || configuration.metrics_enabled
|
|
188
|
-
subscribe_to_notifications
|
|
189
|
-
end
|
|
190
|
-
|
|
191
|
-
at_exit do
|
|
192
|
-
log "Shutting down..."
|
|
193
|
-
if configuration.spans_enabled && @span_processor
|
|
194
|
-
span_processor.force_flush
|
|
195
|
-
span_processor.shutdown
|
|
196
|
-
log "Span processor flushed and stopped"
|
|
197
|
-
end
|
|
198
|
-
log "Shutdown complete"
|
|
199
|
-
end
|
|
200
|
-
|
|
201
|
-
@otel_configured = true
|
|
202
|
-
end
|
|
203
|
-
|
|
204
|
-
# Start the metrics flusher. Called from config.after_initialize so
|
|
205
|
-
# user configuration (metrics_enabled, flush_interval, etc.) is applied.
|
|
206
|
-
def start_metrics_flusher
|
|
207
|
-
return unless configuration.metrics_enabled
|
|
208
|
-
|
|
209
|
-
@metric_storage ||= MetricStorage.new
|
|
210
|
-
metric_processor = MetricSpanProcessor.new(
|
|
211
|
-
storage: @metric_storage,
|
|
212
|
-
http_metrics_config: configuration.http_metrics_config
|
|
213
|
-
)
|
|
214
|
-
OpenTelemetry.tracer_provider.add_span_processor(metric_processor)
|
|
215
|
-
|
|
216
|
-
log "Metrics enabled (endpoint=#{configuration.url} key=#{configuration.key ? 'present' : 'missing'})"
|
|
217
|
-
|
|
218
|
-
if configuration.metrics_submission_configured?
|
|
219
|
-
submitter = MetricSubmitter.new(
|
|
220
|
-
endpoint: configuration.url,
|
|
221
|
-
api_key: configuration.key
|
|
222
|
-
)
|
|
223
|
-
@metric_flusher = MetricFlusher.new(
|
|
224
|
-
storage: @metric_storage,
|
|
225
|
-
submitter: submitter,
|
|
226
|
-
interval: configuration.metrics_flush_interval
|
|
227
|
-
)
|
|
228
|
-
@metric_flusher.start
|
|
229
|
-
log "Metrics flusher started (interval=#{configuration.metrics_flush_interval}s)"
|
|
230
|
-
|
|
231
|
-
at_exit { @metric_flusher&.stop }
|
|
232
|
-
else
|
|
233
|
-
log "Metrics submission not configured (missing url or key)"
|
|
234
|
-
end
|
|
235
|
-
end
|
|
236
|
-
|
|
237
|
-
# Payload transformers for different notification types
|
|
238
|
-
NOTIFICATION_TRANSFORMERS = {
|
|
239
|
-
"sql.active_record" => ->(payload) {
|
|
240
|
-
attrs = {}
|
|
241
|
-
attrs["db.system"] = payload[:connection]&.adapter_name&.downcase rescue nil
|
|
242
|
-
attrs["db.statement"] = payload[:sql] if payload[:sql]
|
|
243
|
-
attrs["name"] = payload[:name] if payload[:name]
|
|
244
|
-
attrs["db.name"] = payload[:connection]&.pool&.db_config&.name rescue nil
|
|
245
|
-
# Capture source location (app code that triggered this query)
|
|
246
|
-
SourceLocation.add_to_attributes(attrs)
|
|
247
|
-
attrs
|
|
248
|
-
},
|
|
249
|
-
"instantiation.active_record" => ->(payload) {
|
|
250
|
-
attrs = {}
|
|
251
|
-
attrs["record_count"] = payload[:record_count] if payload[:record_count]
|
|
252
|
-
attrs["class_name"] = payload[:class_name] if payload[:class_name]
|
|
253
|
-
attrs
|
|
254
|
-
},
|
|
255
|
-
"cache_read.active_support" => ->(payload) {
|
|
256
|
-
store = payload[:store]
|
|
257
|
-
store_name = store.is_a?(String) ? store : store&.class&.name
|
|
258
|
-
{ "key" => payload[:key]&.to_s, "hit" => payload[:hit], "store" => store_name }
|
|
259
|
-
},
|
|
260
|
-
"cache_write.active_support" => ->(payload) {
|
|
261
|
-
store = payload[:store]
|
|
262
|
-
store_name = store.is_a?(String) ? store : store&.class&.name
|
|
263
|
-
{ "key" => payload[:key]&.to_s, "store" => store_name }
|
|
264
|
-
},
|
|
265
|
-
"cache_delete.active_support" => ->(payload) {
|
|
266
|
-
store = payload[:store]
|
|
267
|
-
store_name = store.is_a?(String) ? store : store&.class&.name
|
|
268
|
-
{ "key" => payload[:key]&.to_s, "store" => store_name }
|
|
269
|
-
},
|
|
270
|
-
"cache_exist?.active_support" => ->(payload) {
|
|
271
|
-
store = payload[:store]
|
|
272
|
-
store_name = store.is_a?(String) ? store : store&.class&.name
|
|
273
|
-
{ "key" => payload[:key]&.to_s, "exist" => payload[:exist], "store" => store_name }
|
|
274
|
-
},
|
|
275
|
-
"cache_fetch_hit.active_support" => ->(payload) {
|
|
276
|
-
store = payload[:store]
|
|
277
|
-
store_name = store.is_a?(String) ? store : store&.class&.name
|
|
278
|
-
{ "key" => payload[:key]&.to_s, "store" => store_name }
|
|
279
|
-
},
|
|
280
|
-
"deliver.action_mailer" => ->(payload) {
|
|
281
|
-
attrs = {}
|
|
282
|
-
attrs["mailer"] = payload[:mailer] if payload[:mailer]
|
|
283
|
-
attrs["message_id"] = payload[:message_id] if payload[:message_id]
|
|
284
|
-
attrs["to"] = Array(payload[:to]).join(", ") if payload[:to]
|
|
285
|
-
attrs["subject"] = payload[:subject] if payload[:subject]
|
|
286
|
-
attrs
|
|
287
|
-
},
|
|
288
|
-
"process.action_mailer" => ->(payload) {
|
|
289
|
-
attrs = {}
|
|
290
|
-
attrs["mailer"] = payload[:mailer] if payload[:mailer]
|
|
291
|
-
attrs["action"] = payload[:action] if payload[:action]
|
|
292
|
-
attrs
|
|
293
|
-
}
|
|
294
|
-
}.freeze
|
|
295
|
-
|
|
296
|
-
def subscribe_to_notifications
|
|
297
|
-
NOTIFICATION_TRANSFORMERS.each do |pattern, transformer|
|
|
298
|
-
OpenTelemetry::Instrumentation::ActiveSupport.subscribe(tracer, pattern, transformer)
|
|
299
|
-
rescue
|
|
300
|
-
# Ignore errors for patterns that don't exist
|
|
301
|
-
end
|
|
302
|
-
|
|
303
|
-
# Auto-subscribe to custom patterns (default: "app.*")
|
|
304
|
-
# This lets users just do: ActiveSupport::Notifications.instrument("app.whatever") { }
|
|
305
|
-
subscribe_to_custom_patterns
|
|
306
|
-
end
|
|
307
|
-
|
|
308
|
-
def subscribe_to_custom_patterns
|
|
309
|
-
configuration.subscribe_patterns.each do |prefix|
|
|
310
|
-
# Subscribe to all notifications starting with this prefix
|
|
311
|
-
pattern = /\A#{Regexp.escape(prefix)}/
|
|
312
|
-
default_transformer = ->(payload) {
|
|
313
|
-
attrs = payload.transform_keys(&:to_s).select { |_, v|
|
|
314
|
-
v.is_a?(String) || v.is_a?(Numeric) || v.is_a?(TrueClass) || v.is_a?(FalseClass)
|
|
315
|
-
}
|
|
316
|
-
SourceLocation.add_to_attributes(attrs)
|
|
317
|
-
attrs
|
|
318
|
-
}
|
|
319
|
-
OpenTelemetry::Instrumentation::ActiveSupport.subscribe(tracer, pattern, default_transformer)
|
|
21
|
+
|
|
22
|
+
def indexed_models
|
|
23
|
+
@@indexed_models ||= []
|
|
320
24
|
end
|
|
321
25
|
end
|
|
322
|
-
|
|
323
|
-
# Subscribe to any ActiveSupport::Notification and create spans for it
|
|
324
|
-
#
|
|
325
|
-
# @param pattern [String, Regexp] The notification pattern to subscribe to
|
|
326
|
-
# @param transformer [Proc, nil] Optional proc to transform payload into span attributes
|
|
327
|
-
# If nil, all payload keys become span attributes
|
|
328
|
-
#
|
|
329
|
-
# @example Subscribe to a custom notification
|
|
330
|
-
# Flare.subscribe("my_service.call")
|
|
331
|
-
#
|
|
332
|
-
# @example Subscribe with custom attribute transformer
|
|
333
|
-
# Flare.subscribe("stripe.charge") do |payload|
|
|
334
|
-
# { "charge_id" => payload[:id], "amount" => payload[:amount] }
|
|
335
|
-
# end
|
|
336
|
-
#
|
|
337
|
-
def subscribe(pattern, &transformer)
|
|
338
|
-
transformer ||= ->(payload) {
|
|
339
|
-
# Default: convert all payload keys to string attributes
|
|
340
|
-
payload.transform_keys(&:to_s).transform_values(&:to_s)
|
|
341
|
-
}
|
|
342
|
-
OpenTelemetry::Instrumentation::ActiveSupport.subscribe(tracer, pattern, transformer)
|
|
343
|
-
end
|
|
344
|
-
|
|
345
|
-
# Instrument a block of code, creating a span that shows up in Flare
|
|
346
|
-
#
|
|
347
|
-
# NOTE: This method only works when Flare is loaded (typically development).
|
|
348
|
-
# For instrumentation that works in all environments, use ActiveSupport::Notifications
|
|
349
|
-
# directly and subscribe with Flare.subscribe in your initializer.
|
|
350
|
-
#
|
|
351
|
-
# @param name [String] The name of the span (e.g., "my_service.call", "external_api.fetch")
|
|
352
|
-
# @param attributes [Hash] Optional attributes to add to the span
|
|
353
|
-
# @yield The block to instrument
|
|
354
|
-
# @return The return value of the block
|
|
355
|
-
#
|
|
356
|
-
# @example Basic usage (dev only)
|
|
357
|
-
# Flare.instrument("geocoding.lookup") do
|
|
358
|
-
# geocoder.lookup(address)
|
|
359
|
-
# end
|
|
360
|
-
#
|
|
361
|
-
# @example For all environments, use ActiveSupport::Notifications instead:
|
|
362
|
-
# # In your app code (works everywhere):
|
|
363
|
-
# ActiveSupport::Notifications.instrument("myapp.geocoding", address: addr) do
|
|
364
|
-
# geocoder.lookup(addr)
|
|
365
|
-
# end
|
|
366
|
-
#
|
|
367
|
-
# # In config/initializers/flare.rb (only loaded in dev):
|
|
368
|
-
# Flare.subscribe("myapp.geocoding")
|
|
369
|
-
#
|
|
370
|
-
def instrument(name, attributes = {}, &block)
|
|
371
|
-
return yield unless enabled?
|
|
372
|
-
|
|
373
|
-
# Add source location
|
|
374
|
-
location = SourceLocation.find
|
|
375
|
-
if location
|
|
376
|
-
attributes["code.filepath"] = location[:filepath]
|
|
377
|
-
attributes["code.lineno"] = location[:lineno]
|
|
378
|
-
attributes["code.function"] = location[:function] if location[:function]
|
|
379
|
-
end
|
|
380
|
-
|
|
381
|
-
tracer.in_span(name, attributes: attributes, kind: :internal) do |span|
|
|
382
|
-
yield span
|
|
383
|
-
end
|
|
384
|
-
end
|
|
385
|
-
|
|
386
|
-
def storage
|
|
387
|
-
@storage ||= begin
|
|
388
|
-
require_relative "flare/storage/sqlite"
|
|
389
|
-
Storage::SQLite.new(configuration.database_path)
|
|
390
|
-
rescue LoadError
|
|
391
|
-
warn "[Flare] sqlite3 gem not found. Dashboard is disabled. Add `gem 'sqlite3'` to your Gemfile to enable it."
|
|
392
|
-
configuration.spans_enabled = false
|
|
393
|
-
nil
|
|
394
|
-
end
|
|
395
|
-
end
|
|
396
|
-
|
|
397
|
-
def reset_storage!
|
|
398
|
-
@storage = nil
|
|
399
|
-
end
|
|
400
|
-
|
|
401
|
-
def reset!
|
|
402
|
-
@configuration = nil
|
|
403
|
-
@exporter = nil
|
|
404
|
-
@span_processor = nil
|
|
405
|
-
@tracer = nil
|
|
406
|
-
@storage = nil
|
|
407
|
-
@metric_flusher&.stop
|
|
408
|
-
@metric_flusher = nil
|
|
409
|
-
@metric_storage = nil
|
|
410
|
-
@otel_configured = false
|
|
411
|
-
end
|
|
412
|
-
end
|
|
413
|
-
|
|
414
|
-
require_relative "flare/storage"
|
|
415
|
-
require_relative "flare/engine" if defined?(Rails)
|
|
26
|
+
end
|
data/test/helper.rb
ADDED