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.

Files changed (70) hide show
  1. data/.document +5 -0
  2. data/.gitignore +22 -0
  3. data/LICENSE +20 -0
  4. data/README.rdoc +18 -0
  5. data/Rakefile +55 -0
  6. data/VERSION +1 -0
  7. data/flare.gemspec +66 -0
  8. data/lib/flare/active_record.rb +102 -0
  9. data/lib/flare/collection.rb +47 -0
  10. data/lib/flare/configuration.rb +64 -123
  11. data/lib/flare/index_builder.rb +24 -0
  12. data/lib/flare/session.rb +142 -0
  13. data/lib/flare/tasks.rb +18 -0
  14. data/lib/flare.rb +19 -537
  15. data/test/helper.rb +10 -0
  16. data/test/test_flare.rb +7 -0
  17. metadata +89 -242
  18. checksums.yaml +0 -7
  19. data/CHANGELOG.md +0 -3
  20. data/LICENSE.txt +0 -21
  21. data/README.md +0 -148
  22. data/app/controllers/flare/application_controller.rb +0 -30
  23. data/app/controllers/flare/jobs_controller.rb +0 -55
  24. data/app/controllers/flare/requests_controller.rb +0 -73
  25. data/app/controllers/flare/spans_controller.rb +0 -101
  26. data/app/helpers/flare/application_helper.rb +0 -168
  27. data/app/views/flare/jobs/index.html.erb +0 -69
  28. data/app/views/flare/jobs/show.html.erb +0 -323
  29. data/app/views/flare/requests/index.html.erb +0 -120
  30. data/app/views/flare/requests/show.html.erb +0 -498
  31. data/app/views/flare/spans/index.html.erb +0 -112
  32. data/app/views/flare/spans/show.html.erb +0 -184
  33. data/app/views/layouts/flare/application.html.erb +0 -126
  34. data/config/routes.rb +0 -20
  35. data/exe/flare +0 -9
  36. data/lib/flare/backoff_policy.rb +0 -73
  37. data/lib/flare/cli/doctor_command.rb +0 -129
  38. data/lib/flare/cli/output.rb +0 -45
  39. data/lib/flare/cli/setup_command.rb +0 -404
  40. data/lib/flare/cli/status_command.rb +0 -47
  41. data/lib/flare/cli.rb +0 -50
  42. data/lib/flare/client_headers.rb +0 -39
  43. data/lib/flare/deadline.rb +0 -27
  44. data/lib/flare/engine.rb +0 -45
  45. data/lib/flare/filtering_span_processor.rb +0 -429
  46. data/lib/flare/http_metrics_config.rb +0 -101
  47. data/lib/flare/http_transport.rb +0 -76
  48. data/lib/flare/lifecycle.rb +0 -39
  49. data/lib/flare/marker.rb +0 -106
  50. data/lib/flare/metric_counter.rb +0 -51
  51. data/lib/flare/metric_flusher.rb +0 -279
  52. data/lib/flare/metric_key.rb +0 -42
  53. data/lib/flare/metric_span_processor.rb +0 -470
  54. data/lib/flare/metric_storage.rb +0 -67
  55. data/lib/flare/metric_submitter.rb +0 -239
  56. data/lib/flare/recording_batch_span_processor.rb +0 -238
  57. data/lib/flare/rule_manager.rb +0 -141
  58. data/lib/flare/sampler.rb +0 -130
  59. data/lib/flare/source_location.rb +0 -113
  60. data/lib/flare/sqlite_exporter.rb +0 -334
  61. data/lib/flare/storage/sqlite.rb +0 -794
  62. data/lib/flare/storage.rb +0 -54
  63. data/lib/flare/trace_blob.rb +0 -116
  64. data/lib/flare/trace_exporter.rb +0 -182
  65. data/lib/flare/trace_health_reporter.rb +0 -74
  66. data/lib/flare/upload_url_pool.rb +0 -108
  67. data/lib/flare/version.rb +0 -5
  68. data/lib/flare/web_marker_subscriber.rb +0 -76
  69. data/public/flare-assets/flare.css +0 -1245
  70. data/public/flare-assets/images/flipper.png +0 -0
data/lib/flare.rb CHANGED
@@ -1,544 +1,26 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative "flare/version"
4
- require_relative "flare/configuration"
5
-
6
- require "opentelemetry/sdk"
1
+ begin
2
+ # require 'time'
3
+ # require 'date'
4
+ require 'rsolr'
5
+ rescue LoadError
6
+ require 'rubygems'
7
+ require 'rsolr'
8
+ end
7
9
 
8
- require_relative "flare/client_headers"
9
- require_relative "flare/source_location"
10
- require_relative "flare/metric_key"
11
- require_relative "flare/metric_storage"
12
- require_relative "flare/metric_span_processor"
13
- require_relative "flare/metric_flusher"
14
- require_relative "flare/backoff_policy"
15
- require_relative "flare/metric_submitter"
16
- require_relative "flare/recording_batch_span_processor"
17
- require_relative "flare/lifecycle"
10
+ %w(configuration collection index_builder session active_record).each do |file|
11
+ require File.join(File.dirname(__FILE__), 'flare', file)
12
+ end
18
13
 
19
- require_relative "flare/sampler"
20
- require_relative "flare/marker"
21
- require_relative "flare/web_marker_subscriber"
22
- require_relative "flare/filtering_span_processor"
23
- require_relative "flare/upload_url_pool"
24
- require_relative "flare/trace_exporter"
25
- require_relative "flare/rule_manager"
26
- require_relative "flare/trace_health_reporter"
14
+ ActiveRecord::Base.send(:include, Flare::ActiveRecord)
27
15
 
28
16
  module Flare
29
- class Error < StandardError; end
30
-
31
- MISSING_PARENT_ID = "0000000000000000"
32
- TRANSACTION_NAME_ATTRIBUTE = "flare.transaction_name" unless const_defined?(:TRANSACTION_NAME_ATTRIBUTE)
33
-
34
- module_function
35
-
36
- def configuration
37
- @configuration ||= Configuration.new
38
- end
39
-
40
- def configure
41
- yield(configuration) if block_given?
42
- end
43
-
44
- def enabled?
45
- configuration.enabled
46
- end
47
-
48
- # Set the transaction name for the current span. This overrides the
49
- # default name derived from Rails controller/action or job class.
50
- #
51
- # Useful for Rack middleware, mounted apps, or any request that
52
- # doesn't go through the Rails router.
53
- #
54
- # Flare.transaction_name("RestApi::Routes::Audits#get")
55
- #
56
- def transaction_name(name)
57
- span = OpenTelemetry::Trace.current_span
58
- return unless span.respond_to?(:set_attribute)
59
-
60
- span.set_attribute(TRANSACTION_NAME_ATTRIBUTE, name)
61
- end
62
-
63
- def logger
64
- @logger ||= Logger.new(STDOUT)
65
- end
66
-
67
- def logger=(logger)
68
- @logger = logger
69
- end
70
-
71
- def log(message)
72
- return unless configuration.debug
73
-
74
- logger.info("[Flare] #{message}")
75
- end
76
-
77
- def exporter
78
- @exporter ||= begin
79
- require_relative "flare/sqlite_exporter"
80
- SQLiteExporter.new(configuration.database_path)
81
- rescue LoadError
82
- warn "[Flare] sqlite3 gem not found. Spans are disabled. Add `gem 'sqlite3'` to your Gemfile to enable the development dashboard."
83
- configuration.spans_enabled = false
84
- nil
85
- end
86
- end
87
-
88
- def exporter=(exporter)
89
- @exporter = exporter
90
- end
91
-
92
- def span_processor
93
- @span_processor ||= RecordingBatchSpanProcessor.new(
94
- exporter,
95
- max_queue_size: 1000,
96
- max_export_batch_size: 100,
97
- schedule_delay: 1000 # 1 second
98
- )
99
- end
100
-
101
- def span_processor=(span_processor)
102
- @span_processor = span_processor
103
- end
104
-
105
- def tracer
106
- @tracer ||= OpenTelemetry.tracer_provider.tracer("Flare", Flare::VERSION)
107
- end
108
-
109
- def untraced(&block)
110
- OpenTelemetry::Common::Utilities.untraced(&block)
111
- end
112
-
113
- def metric_storage
114
- @metric_storage
115
- end
116
-
117
- def metric_storage=(storage)
118
- @metric_storage = storage
119
- end
120
-
121
- def metric_flusher
122
- @metric_flusher
123
- end
124
-
125
- def metric_flusher=(flusher)
126
- @metric_flusher = flusher
127
- end
128
-
129
- # Trace-sampling components, exposed for tests + manual after_fork wiring.
130
- def sampler = @sampler
131
- def marker = @marker
132
- def upload_url_pool = @upload_url_pool
133
- def rule_manager = @rule_manager
134
- def trace_span_processor = @trace_span_processor
135
- def trace_health_reporter = @trace_health_reporter
136
-
137
- # Manually flush metrics (useful for testing or forced flushes).
138
- def flush_metrics
139
- @metric_flusher&.flush_now || 0
140
- end
141
-
142
- # Default project key, derived from the host Rails app's module name.
143
- # Customers can override by configuring something else once we expose
144
- # configuration.project; for v0.3 this matches MetricSubmitter's behavior.
145
- def service_name_for_app
146
- if defined?(Rails) && Rails.respond_to?(:application) && Rails.application
147
- Rails.application.class.module_parent_name.underscore rescue "rails_app"
148
- else
149
- "app"
17
+ class << self
18
+ def session
19
+ @session ||= Flare::Session.new
150
20
  end
151
- end
152
-
153
- def rails_env_name
154
- if defined?(Rails) && Rails.respond_to?(:env)
155
- Rails.env.to_s
156
- else
157
- ENV.fetch("RACK_ENV", "development")
21
+
22
+ def indexed_models
23
+ @@indexed_models ||= []
158
24
  end
159
25
  end
160
-
161
- # Re-initialize background threads after fork.
162
- # Call this from Puma/Unicorn after_fork hooks.
163
- def after_fork
164
- @metric_flusher&.after_fork
165
- @rule_manager&.after_fork
166
- end
167
-
168
- # Configure OpenTelemetry SDK and instrumentations. Must run before the
169
- # middleware stack is built so Rack/ActionPack can insert their middleware.
170
- # Note: metrics flusher is started separately via start_metrics_flusher
171
- # after user initializers have run.
172
- def configure_opentelemetry
173
- return if @otel_configured
174
-
175
- # Suppress noisy OTel INFO logs
176
- OpenTelemetry.logger = Logger.new(STDOUT, level: Logger::WARN)
177
-
178
- service_name = service_name_for_app
179
-
180
- # Require flare's bundled instrumentations
181
- require "opentelemetry-instrumentation-rack"
182
- require "opentelemetry-instrumentation-net_http"
183
- require "opentelemetry-instrumentation-active_support"
184
- require "opentelemetry/instrumentation/active_support/span_subscriber"
185
- require "opentelemetry-instrumentation-action_pack" if defined?(ActionController)
186
- require "opentelemetry-instrumentation-action_view" if defined?(ActionView)
187
- require "opentelemetry-instrumentation-active_job" if defined?(ActiveJob)
188
-
189
- # Tell the SDK not to try configuring OTLP from env vars.
190
- # Flare manages its own exporters (SQLite for spans, HTTP for metrics).
191
- ENV["OTEL_TRACES_EXPORTER"] ||= "none"
192
-
193
- log "Configuring OpenTelemetry (service=#{service_name})"
194
-
195
- OpenTelemetry::SDK.configure do |c|
196
- c.service_name = service_name
197
-
198
- # Spans: detailed trace data stored in SQLite
199
- if configuration.spans_enabled && exporter
200
- c.add_span_processor(span_processor)
201
- log "Spans enabled (database=#{configuration.database_path})"
202
- end
203
-
204
- # Auto-detect and install all OTel instrumentation gems in the bundle.
205
- # Apps can add gems like opentelemetry-instrumentation-sidekiq to their
206
- # Gemfile and they'll be picked up automatically.
207
- c.use_all(
208
- "OpenTelemetry::Instrumentation::Rack" => {
209
- untraced_requests: ->(env) {
210
- request = Rack::Request.new(env)
211
- return true if request.path.start_with?("/flare")
212
-
213
- configuration.ignore_request.call(request)
214
- }
215
- },
216
- # Name Sidekiq job spans after the worker class (e.g. "MyWorker
217
- # process") instead of the upstream default of the queue name
218
- # ("default process"), matching how ActiveJob spans are named.
219
- "OpenTelemetry::Instrumentation::Sidekiq" => {
220
- span_naming: :job_class,
221
- }
222
- )
223
- end
224
-
225
- # Subscribe to common ActiveSupport notification patterns
226
- # This captures SQL, cache, mailer, and custom notifications.
227
- # Required for both spans (detailed traces) and metrics (aggregated counters)
228
- # because DB, cache, and mailer data flows through ActiveSupport notifications.
229
- if configuration.spans_enabled || configuration.metrics_enabled
230
- subscribe_to_notifications
231
- end
232
-
233
- at_exit do
234
- log "Shutting down..."
235
- if configuration.spans_enabled && @span_processor
236
- span_processor.force_flush
237
- span_processor.shutdown
238
- log "Span processor flushed and stopped"
239
- end
240
- if @trace_span_processor
241
- @trace_span_processor.force_flush
242
- @trace_span_processor.shutdown
243
- log "Trace span processor flushed and stopped"
244
- end
245
- log "Shutdown complete"
246
- end
247
-
248
- @otel_configured = true
249
- end
250
-
251
- # Start the trace-rules poller. Polls GET /api/rules every
252
- # tracing_poll_interval (default 30s) so the in-process sampler + URL
253
- # pool stay current. Called from config.after_initialize -- after the
254
- # user's configure block has run -- so configuration.url / .key /
255
- # .tracing_enabled are settled.
256
- def start_rule_manager
257
- return unless configuration.tracing_submission_configured?
258
-
259
- setup_tracing_components
260
- return unless @sampler && @marker && @upload_url_pool
261
-
262
- @rule_manager = RuleManager.new(
263
- sampler: @sampler,
264
- marker: @marker,
265
- pool: @upload_url_pool,
266
- base_url: configuration.url,
267
- api_key: configuration.key,
268
- project: service_name_for_app,
269
- environment: rails_env_name,
270
- interval: configuration.tracing_poll_interval
271
- )
272
- @rule_manager.start
273
- log "Rule manager started (poll=#{configuration.tracing_poll_interval}s)"
274
-
275
- at_exit { @rule_manager&.stop }
276
- end
277
-
278
- def setup_tracing_components
279
- return if @trace_span_processor
280
-
281
- @sampler = Sampler.new
282
- @marker = Marker.new
283
- @upload_url_pool = UploadUrlPool.new
284
-
285
- # Trace sampling: server-controlled per-route capture. The sampler runs
286
- # at span start; for routes it can't decide there (Rails web spans get
287
- # their controller#action attributes set post-routing) the marker +
288
- # WebMarkerSubscriber handle it. The RECORD_ONLY delegates keep children
289
- # of unsampled local and remote parents recording so processors still see
290
- # web requests that arrive with an unsampled traceparent header.
291
- #
292
- # Sampler is set on the tracer_provider AFTER SDK.configure -- the SDK's
293
- # Configurator block doesn't expose a `sampler=`; the provider does.
294
- OpenTelemetry.tracer_provider.sampler =
295
- OpenTelemetry::SDK::Trace::Samplers.parent_based(
296
- root: @sampler,
297
- remote_parent_sampled: ALWAYS_RECORD_ONLY,
298
- remote_parent_not_sampled: ALWAYS_RECORD_ONLY,
299
- local_parent_not_sampled: ALWAYS_RECORD_ONLY
300
- )
301
-
302
- @trace_exporter = TraceExporter.new(
303
- pool: @upload_url_pool,
304
- notify_url: "#{configuration.url.to_s.chomp('/')}/api/traces",
305
- api_key: configuration.key,
306
- project: service_name_for_app,
307
- environment: rails_env_name
308
- )
309
-
310
- @trace_span_processor = FilteringSpanProcessor.new(
311
- exporter: @trace_exporter,
312
- marker: @marker,
313
- max_queue: configuration.tracing_max_queue
314
- )
315
- OpenTelemetry.tracer_provider.add_span_processor(@trace_span_processor)
316
-
317
- @trace_health_reporter = TraceHealthReporter.new(
318
- processor: @trace_span_processor,
319
- pool: @upload_url_pool,
320
- exporter: @trace_exporter
321
- )
322
-
323
- # Path 2 trace marking. Rails-only -- in non-Rails contexts the
324
- # subscriber would never fire but creating it is harmless.
325
- if defined?(ActiveSupport::Notifications)
326
- @web_marker_subscriber = WebMarkerSubscriber.new(sampler: @sampler, marker: @marker).start
327
- end
328
-
329
- log "Tracing enabled (poll=#{configuration.tracing_poll_interval}s)"
330
- end
331
-
332
- # Start the metrics flusher. Called from config.after_initialize so
333
- # user configuration (metrics_enabled, flush_interval, etc.) is applied.
334
- def start_metrics_flusher
335
- return unless configuration.metrics_enabled
336
-
337
- @metric_storage ||= MetricStorage.new
338
- metric_processor = MetricSpanProcessor.new(
339
- storage: @metric_storage,
340
- http_metrics_config: configuration.http_metrics_config
341
- )
342
- OpenTelemetry.tracer_provider.add_span_processor(metric_processor)
343
-
344
- log "Metrics enabled (endpoint=#{configuration.url} key=#{configuration.key ? 'present' : 'missing'})"
345
-
346
- if configuration.metrics_submission_configured?
347
- submitter = MetricSubmitter.new(
348
- endpoint: configuration.url,
349
- api_key: configuration.key
350
- )
351
- @metric_flusher = MetricFlusher.new(
352
- storage: @metric_storage,
353
- submitter: submitter,
354
- interval: configuration.metrics_flush_interval,
355
- health_reporters: @trace_health_reporter ? [@trace_health_reporter] : []
356
- )
357
- @metric_flusher.start
358
- log "Metrics flusher started (interval=#{configuration.metrics_flush_interval}s)"
359
-
360
- at_exit { @metric_flusher&.stop }
361
- else
362
- log "Metrics submission not configured (missing url or key)"
363
- end
364
- end
365
-
366
- # Payload transformers for different notification types
367
- NOTIFICATION_TRANSFORMERS = {
368
- "sql.active_record" => ->(payload) {
369
- attrs = {}
370
- attrs["db.system"] = payload[:connection]&.adapter_name&.downcase rescue nil
371
- attrs["db.statement"] = payload[:sql] if payload[:sql]
372
- attrs["name"] = payload[:name] if payload[:name]
373
- attrs["db.name"] = payload[:connection]&.pool&.db_config&.name rescue nil
374
- # Capture source location (app code that triggered this query)
375
- SourceLocation.add_to_attributes(attrs)
376
- attrs
377
- },
378
- "instantiation.active_record" => ->(payload) {
379
- attrs = {}
380
- attrs["record_count"] = payload[:record_count] if payload[:record_count]
381
- attrs["class_name"] = payload[:class_name] if payload[:class_name]
382
- attrs
383
- },
384
- "cache_read.active_support" => ->(payload) {
385
- store = payload[:store]
386
- store_name = store.is_a?(String) ? store : store&.class&.name
387
- { "key" => payload[:key]&.to_s, "hit" => payload[:hit], "store" => store_name }
388
- },
389
- "cache_write.active_support" => ->(payload) {
390
- store = payload[:store]
391
- store_name = store.is_a?(String) ? store : store&.class&.name
392
- { "key" => payload[:key]&.to_s, "store" => store_name }
393
- },
394
- "cache_delete.active_support" => ->(payload) {
395
- store = payload[:store]
396
- store_name = store.is_a?(String) ? store : store&.class&.name
397
- { "key" => payload[:key]&.to_s, "store" => store_name }
398
- },
399
- "cache_exist?.active_support" => ->(payload) {
400
- store = payload[:store]
401
- store_name = store.is_a?(String) ? store : store&.class&.name
402
- { "key" => payload[:key]&.to_s, "exist" => payload[:exist], "store" => store_name }
403
- },
404
- "cache_fetch_hit.active_support" => ->(payload) {
405
- store = payload[:store]
406
- store_name = store.is_a?(String) ? store : store&.class&.name
407
- { "key" => payload[:key]&.to_s, "store" => store_name }
408
- },
409
- "deliver.action_mailer" => ->(payload) {
410
- attrs = {}
411
- attrs["mailer"] = payload[:mailer] if payload[:mailer]
412
- attrs["message_id"] = payload[:message_id] if payload[:message_id]
413
- attrs["to"] = Array(payload[:to]).join(", ") if payload[:to]
414
- attrs["subject"] = payload[:subject] if payload[:subject]
415
- attrs
416
- },
417
- "process.action_mailer" => ->(payload) {
418
- attrs = {}
419
- attrs["mailer"] = payload[:mailer] if payload[:mailer]
420
- attrs["action"] = payload[:action] if payload[:action]
421
- attrs
422
- }
423
- }.freeze
424
-
425
- def subscribe_to_notifications
426
- NOTIFICATION_TRANSFORMERS.each do |pattern, transformer|
427
- OpenTelemetry::Instrumentation::ActiveSupport.subscribe(tracer, pattern, transformer)
428
- rescue
429
- # Ignore errors for patterns that don't exist
430
- end
431
-
432
- # Auto-subscribe to custom patterns (default: "app.*")
433
- # This lets users just do: ActiveSupport::Notifications.instrument("app.whatever") { }
434
- subscribe_to_custom_patterns
435
- end
436
-
437
- def subscribe_to_custom_patterns
438
- configuration.subscribe_patterns.each do |prefix|
439
- # Subscribe to all notifications starting with this prefix
440
- pattern = /\A#{Regexp.escape(prefix)}/
441
- default_transformer = ->(payload) {
442
- attrs = payload.transform_keys(&:to_s).select { |_, v|
443
- v.is_a?(String) || v.is_a?(Numeric) || v.is_a?(TrueClass) || v.is_a?(FalseClass)
444
- }
445
- SourceLocation.add_to_attributes(attrs)
446
- attrs
447
- }
448
- OpenTelemetry::Instrumentation::ActiveSupport.subscribe(tracer, pattern, default_transformer)
449
- end
450
- end
451
-
452
- # Subscribe to any ActiveSupport::Notification and create spans for it
453
- #
454
- # @param pattern [String, Regexp] The notification pattern to subscribe to
455
- # @param transformer [Proc, nil] Optional proc to transform payload into span attributes
456
- # If nil, all payload keys become span attributes
457
- #
458
- # @example Subscribe to a custom notification
459
- # Flare.subscribe("my_service.call")
460
- #
461
- # @example Subscribe with custom attribute transformer
462
- # Flare.subscribe("stripe.charge") do |payload|
463
- # { "charge_id" => payload[:id], "amount" => payload[:amount] }
464
- # end
465
- #
466
- def subscribe(pattern, &transformer)
467
- transformer ||= ->(payload) {
468
- # Default: convert all payload keys to string attributes
469
- payload.transform_keys(&:to_s).transform_values(&:to_s)
470
- }
471
- OpenTelemetry::Instrumentation::ActiveSupport.subscribe(tracer, pattern, transformer)
472
- end
473
-
474
- # Instrument a block of code, creating a span that shows up in Flare
475
- #
476
- # NOTE: This method only works when Flare is loaded (typically development).
477
- # For instrumentation that works in all environments, use ActiveSupport::Notifications
478
- # directly and subscribe with Flare.subscribe in your initializer.
479
- #
480
- # @param name [String] The name of the span (e.g., "my_service.call", "external_api.fetch")
481
- # @param attributes [Hash] Optional attributes to add to the span
482
- # @yield The block to instrument
483
- # @return The return value of the block
484
- #
485
- # @example Basic usage (dev only)
486
- # Flare.instrument("geocoding.lookup") do
487
- # geocoder.lookup(address)
488
- # end
489
- #
490
- # @example For all environments, use ActiveSupport::Notifications instead:
491
- # # In your app code (works everywhere):
492
- # ActiveSupport::Notifications.instrument("myapp.geocoding", address: addr) do
493
- # geocoder.lookup(addr)
494
- # end
495
- #
496
- # # In config/initializers/flare.rb (only loaded in dev):
497
- # Flare.subscribe("myapp.geocoding")
498
- #
499
- def instrument(name, attributes = {}, &block)
500
- return yield unless enabled?
501
-
502
- # Add source location
503
- location = SourceLocation.find
504
- if location
505
- attributes["code.filepath"] = location[:filepath]
506
- attributes["code.lineno"] = location[:lineno]
507
- attributes["code.function"] = location[:function] if location[:function]
508
- end
509
-
510
- tracer.in_span(name, attributes: attributes, kind: :internal) do |span|
511
- yield span
512
- end
513
- end
514
-
515
- def storage
516
- @storage ||= begin
517
- require_relative "flare/storage/sqlite"
518
- Storage::SQLite.new(configuration.database_path)
519
- rescue LoadError
520
- warn "[Flare] sqlite3 gem not found. Dashboard is disabled. Add `gem 'sqlite3'` to your Gemfile to enable it."
521
- configuration.spans_enabled = false
522
- nil
523
- end
524
- end
525
-
526
- def reset_storage!
527
- @storage = nil
528
- end
529
-
530
- def reset!
531
- @configuration = nil
532
- @exporter = nil
533
- @span_processor = nil
534
- @tracer = nil
535
- @storage = nil
536
- @metric_flusher&.stop
537
- @metric_flusher = nil
538
- @metric_storage = nil
539
- @otel_configured = false
540
- end
541
- end
542
-
543
- require_relative "flare/storage"
544
- require_relative "flare/engine" if defined?(Rails)
26
+ end
data/test/helper.rb ADDED
@@ -0,0 +1,10 @@
1
+ require 'rubygems'
2
+ require 'test/unit'
3
+ require 'shoulda'
4
+
5
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
6
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
7
+ require 'flare'
8
+
9
+ class Test::Unit::TestCase
10
+ end
@@ -0,0 +1,7 @@
1
+ require 'helper'
2
+
3
+ class TestFlare < Test::Unit::TestCase
4
+ should "probably rename this file and start testing for real" do
5
+ flunk "hey buddy, you should probably rename this file and start testing for real"
6
+ end
7
+ end