Module: Beacon
- Defined in:
- lib/beacon/rails.rb,
lib/beacon.rb,
lib/beacon/lru.rb,
lib/beacon/queue.rb,
lib/beacon/client.rb,
lib/beacon/flusher.rb,
lib/beacon/testing.rb,
lib/beacon/version.rb,
lib/beacon/transport.rb,
lib/beacon/enrichment.rb,
lib/beacon/middleware.rb,
lib/beacon/fingerprint.rb,
lib/beacon/log_throttle.rb,
lib/beacon/configuration.rb,
lib/beacon/path_normalizer.rb,
lib/beacon/integrations/active_job.rb,
lib/beacon/integrations/action_mailer.rb
Overview
ActionMailer integration. Captures delivery errors as Beacon error events via the same fingerprint algorithm the Rack middleware uses.
# config/initializers/beacon.rb
require "beacon/integrations/action_mailer"
Beacon::Integrations::ActionMailer.install
Defined Under Namespace
Modules: Enrichment, Fingerprint, Integrations, PathNormalizer, Testing, Transport Classes: Client, Configuration, Error, Flusher, LRU, LogThrottle, Middleware, Queue, Railtie
Constant Summary collapse
- CLIENT_MUTEX =
Mutex.new
- EMPTY_FLUSHER_STATS =
{ sent: 0, last_flush_at: nil, last_flush_status: nil, circuit_open: false, consecutive_failures: 0, }.freeze
- VERSION =
ENV.fetch("BEACON_VERSION", "0.0.0-dev")
Class Method Summary collapse
-
.client ⇒ Object
Thread-safe lazy singleton.
- .config ⇒ Object
- .configure {|config| ... } ⇒ Object
- .flush ⇒ Object
- .shutdown ⇒ Object
-
.stats ⇒ Object
Operator-visible introspection.
- .track(name, properties = {}) ⇒ Object
Class Method Details
.client ⇒ Object
Thread-safe lazy singleton. Two Puma threads racing on the first request used to be able to create two Clients (each with its own flusher thread) — the second one leaked forever. The Mutex serializes every access.
Why not a double-checked-locking fast path? Under MRI’s GVL it would be safe; under TruffleRuby / JRuby it isn’t — a reader could observe @client as non-nil while the Client’s own fields are still half-written (no memory barrier on the unsynchronized read). Taking the Mutex every call costs ~100ns on MRI, and Beacon.client is called per-Client-lifetime, not per-request.
43 44 45 46 47 |
# File 'lib/beacon.rb', line 43 def client CLIENT_MUTEX.synchronize do @client ||= Client.new(config: config) end end |
.config ⇒ Object
28 29 30 |
# File 'lib/beacon.rb', line 28 def config @config ||= Configuration.new end |
.configure {|config| ... } ⇒ Object
19 20 21 22 23 24 25 26 |
# File 'lib/beacon.rb', line 19 def configure yield config warn_if_unusable_endpoint # Drop any existing client so the next Beacon.client call picks # up the freshly-configured Configuration. shutdown config end |
.flush ⇒ Object
85 86 87 |
# File 'lib/beacon.rb', line 85 def flush client.flush end |
.shutdown ⇒ Object
89 90 91 92 93 94 |
# File 'lib/beacon.rb', line 89 def shutdown CLIENT_MUTEX.synchronize do @client&.shutdown @client = nil end end |
.stats ⇒ Object
Operator-visible introspection. Returns a flat hash describing the client’s current internal state — queue depth, the drop counter, flusher counters, and transport counters. Used by smoke tests and rake tasks; also the primary signal operators have when something gets weird at 3am.
Flusher stats are fetched ONCE into a local so the result hash is a consistent snapshot — without this, a flush happening mid-build could leave ‘sent` and `last_flush_at` disagreeing.
62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 |
# File 'lib/beacon.rb', line 62 def stats c = @client return disabled_stats unless c fstats = c.flusher&.stats || EMPTY_FLUSHER_STATS { queue_depth: c.queue.length, queue_max: config.queue_size, dropped: c.queue.dropped, sent: fstats[:sent] || 0, last_flush_at: fstats[:last_flush_at], last_flush_status: fstats[:last_flush_status], circuit_open: fstats[:circuit_open] || false, consecutive_failures: fstats[:consecutive_failures] || 0, reconnects: c.transport_reconnects, enabled: c.enabled?, } end |
.track(name, properties = {}) ⇒ Object
49 50 51 |
# File 'lib/beacon.rb', line 49 def track(name, properties = {}) client.track(name, properties) end |