Class: Honeybadger::Agent

Inherits:
Object
  • Object
show all
Extended by:
Forwardable
Includes:
Logging::Helper
Defined in:
lib/honeybadger/agent.rb,
lib/honeybadger/agent/batch.rb,
lib/honeybadger/agent/worker.rb,
lib/honeybadger/agent/null_worker.rb,
lib/honeybadger/agent/metered_queue.rb,
lib/honeybadger/agent/trace_collection.rb,
lib/honeybadger/agent/metrics_collector.rb,
lib/honeybadger/agent/metrics_collection.rb

Overview

Internal: A broker for the configuration and the workers.

Defined Under Namespace

Classes: Batch, MeteredQueue, MetricsCollection, MetricsCollector, NullWorker, Thread, TraceCollection, Worker

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(config) ⇒ Agent

Returns a new instance of Agent.



137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
# File 'lib/honeybadger/agent.rb', line 137

def initialize(config)
  @config = config
  @delay = config.debug? ? 10 : 60
  @mutex = Mutex.new
  @pid = Process.pid

  unless config.backend.kind_of?(Backend::Server)
    warn('Initializing development backend: data will not be reported.')
  end

  init_workers
  init_traces
  init_metrics

  at_exit do
    # Fix for https://bugs.ruby-lang.org/issues/5218
    if defined?(RUBY_ENGINE) && RUBY_ENGINE == 'ruby' && RUBY_VERSION =~ /1\.9/
      exit_status = $!.status if $!.is_a?(SystemExit)
    end

    stop if config[:'send_data_at_exit']
    self.class.at_exit.call if self.class.at_exit

    exit(exit_status) if exit_status
  end
end

Instance Attribute Details

#delayObject (readonly)

Returns the value of attribute delay.



135
136
137
# File 'lib/honeybadger/agent.rb', line 135

def delay
  @delay
end

#metricsObject (readonly)

Returns the value of attribute metrics.



135
136
137
# File 'lib/honeybadger/agent.rb', line 135

def metrics
  @metrics
end

#pidObject (readonly)

Returns the value of attribute pid.



135
136
137
# File 'lib/honeybadger/agent.rb', line 135

def pid
  @pid
end

#threadObject (readonly)

Returns the value of attribute thread.



135
136
137
# File 'lib/honeybadger/agent.rb', line 135

def thread
  @thread
end

#tracesObject (readonly)

Returns the value of attribute traces.



135
136
137
# File 'lib/honeybadger/agent.rb', line 135

def traces
  @traces
end

#workersObject (readonly)

Returns the value of attribute workers.



135
136
137
# File 'lib/honeybadger/agent.rb', line 135

def workers
  @workers
end

Class Method Details

.at_exit(&block) ⇒ Object

Internal: Callback to perform after agent has been stopped at_exit.

block - An optional block to execute.

Returns Proc callback.



116
117
118
119
# File 'lib/honeybadger/agent.rb', line 116

def self.at_exit(&block)
  @at_exit = Proc.new if block_given?
  @at_exit
end

.callbacksObject



30
31
32
# File 'lib/honeybadger/agent.rb', line 30

def callbacks
  @callbacks ||= Config::Callbacks.new
end

.configObject

Internal: Not for public consumption. :)

Prefer dependency injection over accessing config directly, but some cases (such as the delayed_job plugin) necessitate it.

Returns the Agent’s config if running, otherwise default config



127
128
129
130
131
132
133
# File 'lib/honeybadger/agent.rb', line 127

def self.config
  if running?
    instance.send(:config)
  else
    @config ||= Config.new
  end
end

.flush(&block) ⇒ Object



101
102
103
104
105
106
107
108
109
# File 'lib/honeybadger/agent.rb', line 101

def self.flush(&block)
  if self.instance
    self.instance.flush(&block)
  elsif !block_given?
    false
  else
    yield
  end
end

.fork(*args) ⇒ Object



85
86
87
# File 'lib/honeybadger/agent.rb', line 85

def self.fork(*args)
  self.instance ? self.instance.fork(*args) : false
end

.increment(*args) ⇒ Object



97
98
99
# File 'lib/honeybadger/agent.rb', line 97

def self.increment(*args)
  self.instance ? self.instance.increment(*args) : false
end

.instanceObject



46
47
48
# File 'lib/honeybadger/agent.rb', line 46

def self.instance
  @instance
end

.running?Boolean

Returns:

  • (Boolean)


50
51
52
# File 'lib/honeybadger/agent.rb', line 50

def self.running?
  !instance.nil?
end

.start(config = {}) ⇒ Object



54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
# File 'lib/honeybadger/agent.rb', line 54

def self.start(config = {})
  return true if running?

  unless config.kind_of?(Config)
    config = Config.new(config)
  end

  if config[:disabled]
    config.logger.warn('Unable to start Honeybadger -- disabled by configuration.')
    return false
  elsif !config.valid?
    config.logger.warn('Unable to start Honeybadger -- api_key is missing or invalid.')
    return false
  end

  unless config.ping
    config.logger.warn('Failed to connect to Honeybadger service -- please verify that api.honeybadger.io is reachable (connection will be retried).')
  end

  config.logger.info("Starting Honeybadger version #{VERSION}")
  load_plugins(config)
  @instance = new(config)

  true
end

.stop(*args) ⇒ Object



80
81
82
83
# File 'lib/honeybadger/agent.rb', line 80

def self.stop(*args)
  @instance.stop(*args) if @instance
  @instance = nil
end

.timing(*args) ⇒ Object



93
94
95
# File 'lib/honeybadger/agent.rb', line 93

def self.timing(*args)
  self.instance ? self.instance.timing(*args) : false
end

.trace(*args) ⇒ Object



89
90
91
# File 'lib/honeybadger/agent.rb', line 89

def self.trace(*args)
  self.instance ? self.instance.trace(*args) : false
end

Instance Method Details

#flushObject

Internal: Flush the workers. See Honeybadger#flush.

block - an option block which is executed before flushing data.

Returns value from block if block is given, otherwise true.



258
259
260
261
262
263
264
265
# File 'lib/honeybadger/agent.rb', line 258

def flush
  return true unless block_given?
  yield
ensure
  flush_metrics
  flush_traces
  workers.values.each(&:flush)
end

#forkObject



203
204
205
# File 'lib/honeybadger/agent.rb', line 203

def fork
  # noop
end

#increment(*args, &block) ⇒ Object



244
245
246
247
248
249
250
251
# File 'lib/honeybadger/agent.rb', line 244

def increment(*args, &block)
  start

  mutex.synchronize { metrics.increment(*args, &block) }
  flush_metrics if metrics.flush?

  true
end

#notice(opts) ⇒ Object



207
208
209
210
211
212
213
214
215
216
217
218
219
# File 'lib/honeybadger/agent.rb', line 207

def notice(opts)
  opts.merge!(callbacks: self.class.callbacks)
  notice = Notice.new(config, opts)

  if !opts[:force] && notice.ignore?
    debug { sprintf('ignore notice feature=notices id=%s', notice.id) }
    false
  else
    debug { sprintf('notice feature=notices id=%s', notice.id) }
    push(:notices, notice)
    notice.id
  end
end

#startObject

Internal: Spawn the agent thread. This method is idempotent.

Returns false if the Agent is stopped, otherwise true.



167
168
169
170
171
172
173
174
175
176
177
178
179
# File 'lib/honeybadger/agent.rb', line 167

def start
  mutex.synchronize do
    return false unless pid
    return true if thread && thread.alive?

    debug { 'starting agent' }

    @pid = Process.pid
    @thread = Thread.new { run }
  end

  true
end

#stop(force = false) ⇒ Object



181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
# File 'lib/honeybadger/agent.rb', line 181

def stop(force = false)
  debug { 'stopping agent' }

  mutex.synchronize do
    @pid = nil
  end

  # Kill the collector
  Thread.kill(thread) if thread

  unless force
    flush_traces
    flush_metrics
  end

  workers.each_pair do |key, worker|
    worker.send(force ? :shutdown! : :shutdown)
  end

  true
end

#timing(*args, &block) ⇒ Object



235
236
237
238
239
240
241
242
# File 'lib/honeybadger/agent.rb', line 235

def timing(*args, &block)
  start

  mutex.synchronize { metrics.timing(*args, &block) }
  flush_metrics if metrics.flush?

  true
end

#trace(trace) ⇒ Object



221
222
223
224
225
226
227
228
229
230
231
232
233
# File 'lib/honeybadger/agent.rb', line 221

def trace(trace)
  start

  if trace.duration > config[:'traces.threshold']
    debug { sprintf('agent adding trace duration=%s feature=traces id=%s', trace.duration.round(2), trace.id) }
    mutex.synchronize { traces.push(trace) }
    flush_traces if traces.flush?
    true
  else
    debug { sprintf('agent discarding trace duration=%s feature=traces id=%s', trace.duration.round(2), trace.id) }
    false
  end
end