Module: Honeycomb

Defined in:
lib/honeycomb/span.rb,
lib/honeycomb/client.rb,
lib/honeycomb/beeline/version.rb,
lib/honeycomb/instrumentations.rb

Defined Under Namespace

Modules: Beeline, Span

Constant Summary collapse

USER_AGENT_SUFFIX =
"#{Beeline::GEM_NAME}/#{Beeline::VERSION}"
INSTRUMENTATIONS =
[
  ActiveRecord::Honeycomb,
  Faraday::Honeycomb,
  Rack::Honeycomb,
  Sequel::Honeycomb,
].freeze

Class Attribute Summary collapse

Class Method Summary collapse

Class Attribute Details

.clientObject (readonly)

Returns the value of attribute client.



12
13
14
# File 'lib/honeycomb/client.rb', line 12

def client
  @client
end

.service_nameObject (readonly)

Returns the value of attribute service_name.



13
14
15
# File 'lib/honeycomb/client.rb', line 13

def service_name
  @service_name
end

Class Method Details

.after_init(label, &block) ⇒ Object

Raises:

  • (ArgumentError)


67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
# File 'lib/honeycomb/client.rb', line 67

def after_init(label, &block)
  raise ArgumentError unless block_given?

  hook = if block.arity == 0
           ->(_, _) { block.call }
         elsif block.arity == 1
           ->(client, _) { block.call client }
         elsif block.arity > 2
           raise ArgumentError, 'Honeycomb.after_init block should take 2 arguments'
         else
           block
         end

  if defined?(@initialized)
    @logger.debug "Running hook '#{label}' as Honeycomb already initialized" if @logger
    run_hook(label, hook)
  else
    after_init_hooks << [label, hook]
  end
end

.init(writekey: ENV['HONEYCOMB_WRITEKEY'], dataset: ENV['HONEYCOMB_DATASET'], service_name: ENV['HONEYCOMB_SERVICE'] || dataset, without: [], debug: ENV.key?('HONEYCOMB_DEBUG'), logger: nil, **options) ⇒ Object



15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# File 'lib/honeycomb/client.rb', line 15

def init(
  writekey: ENV['HONEYCOMB_WRITEKEY'],
  dataset: ENV['HONEYCOMB_DATASET'],
  service_name: ENV['HONEYCOMB_SERVICE'] || dataset,
  without: [],
  debug: ENV.key?('HONEYCOMB_DEBUG'),
  logger: nil,
  **options
)
  reset

  @without = without
  @service_name = service_name
  @logger = logger || Logger.new($stderr).tap {|l| l.level = Logger::WARN }
  @debug = debug
  if debug
    @logger ||= Logger.new($stderr)
  end

  options = options.merge(writekey: writekey, dataset: dataset)
  @client = new_client(options)

  after_init_hooks.each do |label, block|
    @logger.debug "Running hook '#{label}' after Honeycomb.init" if @logger
    run_hook(label, block)
  end

  @initialized = true
end

.new_client(options) ⇒ Object



45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
# File 'lib/honeycomb/client.rb', line 45

def new_client(options)
  client = options.delete :client

  options = {user_agent_addition: USER_AGENT_SUFFIX}.merge(options)
  if @debug
    raise ArgumentError, "can't specify both client and debug options", caller if client
    @logger.info 'logging events to standard error instead of sending to Honeycomb' if @logger
    client = Libhoney::LogClient.new(verbose: true, **options)
  else
    client ||= if options[:writekey] && options[:dataset]
      Libhoney::Client.new(options)
    else
      @logger.warn "#{self.name}: no #{options[:writekey] ? 'dataset' : 'writekey'} configured, disabling sending events" if @logger
      Libhoney::NullClient.new(options)
    end
  end
  client.add_field 'meta.beeline_version', Beeline::VERSION
  client.add_field 'meta.local_hostname', Socket.gethostname rescue nil
  client.add_field 'service_name',  @service_name
  client
end

.resetObject

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



95
96
97
98
99
100
101
102
103
104
105
106
107
# File 'lib/honeycomb/client.rb', line 95

def reset
  # TODO encapsulate all this into a Beeline object so we don't need
  # explicit cleanup

  shutdown

  @logger = nil
  @without = nil
  @service_name = nil
  @debug = nil
  @client = nil
  @initialized = false
end

.shutdownObject



88
89
90
91
92
# File 'lib/honeycomb/client.rb', line 88

def shutdown
  if defined?(@client) && @client
    @client.close
  end
end

.span(service_name:, name:, span_id: SecureRandom.uuid) ⇒ Object

TODO rethink this API



28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
# File 'lib/honeycomb/span.rb', line 28

def span(service_name:, name:, span_id: SecureRandom.uuid)
  event = client.event

  event.add_field 'trace.trace_id', trace_id if trace_id
  event.add_field 'service_name', service_name
  event.add_field 'name', name
  event.add_field 'trace.span_id', span_id

  start = Time.now
  with_span_id(span_id) do |parent_span_id|
    event.add_field 'trace.parent_id', parent_span_id if parent_span_id
    yield
  end
rescue Exception => e
  if event
    # TODO what should the prefix be?
    event.add_field 'app.error', e.class.name
    event.add_field 'app.error_detail', e.message
  end
  raise
ensure
  if start && event
    finish = Time.now
    duration = finish - start
    event.add_field 'duration_ms', duration * 1000
    event.send
  end
end

.trace_idObject



15
16
17
# File 'lib/honeycomb/span.rb', line 15

def trace_id
  Thread.current[:honeycomb_trace_id]
end

.with_span_id(span_id) ⇒ Object



19
20
21
22
23
24
25
# File 'lib/honeycomb/span.rb', line 19

def with_span_id(span_id)
  parent_span_id = Thread.current[:honeycomb_span_id]
  Thread.current[:honeycomb_span_id] = span_id
  yield parent_span_id
ensure
  Thread.current[:honeycomb_span_id] = parent_span_id
end

.with_trace_id(trace_id = SecureRandom.uuid) ⇒ Object



8
9
10
11
12
13
# File 'lib/honeycomb/span.rb', line 8

def with_trace_id(trace_id = SecureRandom.uuid)
  Thread.current[:honeycomb_trace_id] = trace_id
  yield trace_id
ensure
  Thread.current[:honeycomb_trace_id] = nil
end