honeycomb-beeline 1.0.0.pre.alpha → 1.0.0.pre.alpha1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +13 -0
- data/.overcommit.yml +8 -0
- data/.rspec +3 -0
- data/.rubocop.yml +56 -0
- data/.ruby-version +1 -0
- data/.travis.yml +48 -0
- data/Appraisals +61 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +8 -0
- data/Gemfile.lock +126 -0
- data/LICENSE +201 -0
- data/README.md +37 -0
- data/Rakefile +16 -0
- data/UPGRADING.md +82 -0
- data/bin/console +15 -0
- data/bin/setup +8 -0
- data/bundler_version.sh +12 -0
- data/honeycomb-beeline.gemspec +54 -0
- data/lib/generators/honeycomb/honeycomb_generator.rb +37 -0
- data/lib/honeycomb-beeline.rb +74 -0
- data/lib/honeycomb/beeline/version.rb +9 -0
- data/lib/honeycomb/client.rb +79 -0
- data/lib/honeycomb/context.rb +40 -0
- data/lib/honeycomb/integrations/active_support.rb +68 -0
- data/lib/honeycomb/integrations/faraday.rb +57 -0
- data/lib/honeycomb/integrations/rack.rb +94 -0
- data/lib/honeycomb/integrations/rails.rb +47 -0
- data/lib/honeycomb/integrations/sequel.rb +31 -0
- data/lib/honeycomb/integrations/sinatra.rb +18 -0
- data/lib/honeycomb/propagation.rb +58 -0
- data/lib/honeycomb/span.rb +125 -0
- data/lib/honeycomb/trace.rb +40 -0
- data/lib/sequel/extensions/honeycomb.rb +3 -0
- metadata +37 -3
data/README.md
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
# Honeycomb Beeline for Ruby
|
2
|
+
|
3
|
+
[![Build Status](https://travis-ci.org/honeycombio/beeline-ruby.svg?branch=master)](https://travis-ci.org/honeycombio/beeline-ruby)
|
4
|
+
[![Gem Version](https://badge.fury.io/rb/honeycomb-beeline.svg)](https://badge.fury.io/rb/honeycomb-beeline)
|
5
|
+
|
6
|
+
This package makes it easy to instrument your Ruby web app to send useful events to [Honeycomb](https://www.honeycomb.io), a service for debugging your software in production.
|
7
|
+
- [Usage and Examples](https://docs.honeycomb.io/getting-data-in/beelines/ruby-beeline/)
|
8
|
+
|
9
|
+
Sign up for a [Honeycomb
|
10
|
+
trial](https://ui.honeycomb.io/signup) to obtain an API key before starting.
|
11
|
+
|
12
|
+
## Compatible with
|
13
|
+
|
14
|
+
Requires Ruby version 2.2 or later
|
15
|
+
|
16
|
+
Built in instrumentation for:
|
17
|
+
|
18
|
+
- Active Support
|
19
|
+
- Faraday
|
20
|
+
- Rack
|
21
|
+
- Rails
|
22
|
+
- Sequel
|
23
|
+
- Sinatra
|
24
|
+
|
25
|
+
## Get in touch
|
26
|
+
|
27
|
+
Please reach out to [support@honeycomb.io](mailto:support@honeycomb.io) or ping
|
28
|
+
us with the chat bubble on [our website](https://www.honeycomb.io) for any
|
29
|
+
assistance. We also welcome [bug reports](https://github.com/honeycombio/beeline-ruby/issues).
|
30
|
+
|
31
|
+
## Contributions
|
32
|
+
|
33
|
+
Features, bug fixes and other changes to `beeline-ruby` are gladly accepted. Please
|
34
|
+
open issues or a pull request with your change. Remember to add your name to the
|
35
|
+
CONTRIBUTORS file!
|
36
|
+
|
37
|
+
All contributions will be released under the Apache License 2.0.
|
data/Rakefile
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "bundler/gem_tasks"
|
4
|
+
require "rspec/core/rake_task"
|
5
|
+
require "rubocop/rake_task"
|
6
|
+
require "appraisal"
|
7
|
+
|
8
|
+
RSpec::Core::RakeTask.new(:spec)
|
9
|
+
|
10
|
+
RuboCop::RakeTask.new(:rubocop)
|
11
|
+
|
12
|
+
task test: :spec
|
13
|
+
|
14
|
+
task default: %i[rubocop test]
|
15
|
+
|
16
|
+
!ENV["APPRAISAL_INITIALIZED"] && !ENV["TRAVIS"] && task(default: :appraisal)
|
data/UPGRADING.md
ADDED
@@ -0,0 +1,82 @@
|
|
1
|
+
# Upgrade Guide
|
2
|
+
|
3
|
+
## 0.8.0 - 1.0.0
|
4
|
+
|
5
|
+
1. If you have a web application, remove beeline configuration from the `config.ru` file
|
6
|
+
1. If you have a rails application, run the honeycomb generator `bundle exec rails generate honeycomb {writekey}`
|
7
|
+
1. Replace call to `Honeycomb.init` with the following (if using rails, this will now live in `config/initializers/honeycomb.rb`)
|
8
|
+
```ruby
|
9
|
+
Honeycomb.configure do |config|
|
10
|
+
config.write_key = "{writekey}"
|
11
|
+
config.dataset = "rails"
|
12
|
+
end
|
13
|
+
```
|
14
|
+
1. Replace any `Rack::Honeycomb.add_field` calls with the following
|
15
|
+
```ruby
|
16
|
+
Honeycomb.client.add_field("name", "value")
|
17
|
+
```
|
18
|
+
1. Replace any `Honeycomb.span` calls with the following
|
19
|
+
```ruby
|
20
|
+
Honeycomb.start_span(name: "interesting") do |span|
|
21
|
+
span.add_field("name", "value")
|
22
|
+
end
|
23
|
+
```
|
24
|
+
|
25
|
+
## honeycomb-rails to beeline-ruby
|
26
|
+
|
27
|
+
1. Update Gemfile, remove `honeycomb-rails` and add `beeline-ruby`
|
28
|
+
1. Run `bundle install`
|
29
|
+
1. Remove the `honeycomb.rb` initializer from `config/initializers`
|
30
|
+
1. Add the following to the `config.ru` file
|
31
|
+
```ruby
|
32
|
+
# config.ru
|
33
|
+
require 'honeycomb-beeline'
|
34
|
+
|
35
|
+
Honeycomb.init(writekey: 'YOUR_API_KEY', dataset: 'YOUR_DATASET')
|
36
|
+
|
37
|
+
# these next two lines should already exist in some form in this file, it's important to init the honeycomb library before this
|
38
|
+
require ::File.expand_path('../config/environment', __FILE__)
|
39
|
+
run Rails.application
|
40
|
+
```
|
41
|
+
1. You can use the same write key and dataset from the honeycomb initialiser above, note: the honeycomb-beeline only supports sending events to one dataset. This is due to the fact that the new beeline will include traces for your application by default and these are only viewable from within the same dataset
|
42
|
+
1. Replace any `honeycomb_metadata` calls in your controllers like the following
|
43
|
+
```ruby
|
44
|
+
def index
|
45
|
+
@bees = Bee.all
|
46
|
+
Rack::Honeycomb.add_field(request.env, :bees_count, @bees.count)
|
47
|
+
# honeycomb_metadata[:bees_count] = @bees.count
|
48
|
+
end
|
49
|
+
```
|
50
|
+
1. If you are manually using the libhoney client as well, it is suggested that you remove the usages of it and rely on the beeline.
|
51
|
+
1. Instrument interesting calls using the new `span` API as per the example below
|
52
|
+
```ruby
|
53
|
+
class HomeController < ApplicationController
|
54
|
+
def index
|
55
|
+
Honeycomb.span do
|
56
|
+
@interesting_information = perform_intensive_calculations(params[:honey])
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
```
|
61
|
+
1. `honeycomb-rails` had the ability to automatically populate user information onto your events. Unfortunately `beeline-ruby` does not support this out of the box. You can use something like this snippet below to continue populating this (example for Devise)
|
62
|
+
```ruby
|
63
|
+
class ApplicationController < ActionController::Base
|
64
|
+
before_action do
|
65
|
+
Rack::Honeycomb.add_field(request.env, "user.id", current_user.id)
|
66
|
+
Rack::Honeycomb.add_field(request.env, "user.email", current_user.email)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
```
|
70
|
+
1. (Optional) If you are using `Sequel` for database access there are some additional steps to configure
|
71
|
+
```ruby
|
72
|
+
# config.ru
|
73
|
+
require 'honeycomb-beeline'
|
74
|
+
require 'sequel-honeycomb/auto_install'
|
75
|
+
|
76
|
+
Honeycomb.init(writekey: 'YOUR_API_KEY', dataset: 'YOUR_DATASET')
|
77
|
+
Sequel::Honeycomb::AutoInstall.auto_install!(honeycomb_client: Honeycomb.client, logger: Honeycomb.logger)
|
78
|
+
|
79
|
+
# these next two lines should already exist in some form in this file, it's important to init the honeycomb library before this
|
80
|
+
require ::File.expand_path('../config/environment', __FILE__)
|
81
|
+
run Rails.application
|
82
|
+
```
|
data/bin/console
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require "bundler/setup"
|
5
|
+
require "honeycomb/beeline"
|
6
|
+
|
7
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
8
|
+
# with your gem easier. You can also use a different console, if you like.
|
9
|
+
|
10
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
11
|
+
# require "pry"
|
12
|
+
# Pry.start
|
13
|
+
|
14
|
+
require "irb"
|
15
|
+
IRB.start(__FILE__)
|
data/bin/setup
ADDED
data/bundler_version.sh
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
#!/usr/bin/env bash
|
2
|
+
|
3
|
+
set -uex
|
4
|
+
|
5
|
+
if [[ "$BUNDLE_GEMFILE" =~ (rails_41.gemfile|rails_42.gemfile)$ ]]; then
|
6
|
+
if [[ "$TRAVIS_RUBY_VERSION" =~ ^(2.3)$ ]]; then
|
7
|
+
gem uninstall -v '>= 2' -i $(rvm gemdir) -ax bundler
|
8
|
+
elif [[ "$TRAVIS_RUBY_VERSION" =~ ^(2.4|2.5)$ ]]; then
|
9
|
+
gem uninstall -v '>= 2' -i $(rvm gemdir)@global -ax bundler
|
10
|
+
fi
|
11
|
+
gem install bundler -v '< 2'
|
12
|
+
fi
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
lib = File.expand_path("lib", __dir__)
|
4
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
5
|
+
require "honeycomb/beeline/version"
|
6
|
+
|
7
|
+
Gem::Specification.new do |spec|
|
8
|
+
spec.name = Honeycomb::Beeline::NAME
|
9
|
+
spec.version = Honeycomb::Beeline::VERSION
|
10
|
+
spec.authors = ["Martin Holman"]
|
11
|
+
spec.email = ["martin@honeycomb.io"]
|
12
|
+
|
13
|
+
spec.summary = "Instrument your Ruby apps with Honeycomb"
|
14
|
+
spec.homepage = "https://honeycomb.io"
|
15
|
+
|
16
|
+
spec.license = 'Apache-2.0'
|
17
|
+
|
18
|
+
spec.required_ruby_version = ">= 2.2.0"
|
19
|
+
|
20
|
+
if spec.respond_to?(:metadata)
|
21
|
+
spec.metadata["homepage_uri"] = spec.homepage
|
22
|
+
spec.metadata["source_code_uri"] = "https://github.com/honeycombio/beeline-ruby"
|
23
|
+
else
|
24
|
+
raise "RubyGems 2.0 or newer is required to protect against " \
|
25
|
+
"public gem pushes."
|
26
|
+
end
|
27
|
+
|
28
|
+
# Specify which files should be added to the gem when it is released.
|
29
|
+
# The `git ls-files -z` loads the files in the RubyGem that have been added
|
30
|
+
# into git.
|
31
|
+
spec.files = Dir.chdir(File.dirname(__FILE__)) do
|
32
|
+
`git ls-files -z`.split("\x0").reject do |file|
|
33
|
+
file.match(%r{^(test|spec|features|examples|gemfiles)/})
|
34
|
+
end
|
35
|
+
end
|
36
|
+
spec.bindir = "exe"
|
37
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
38
|
+
spec.require_paths = ["lib"]
|
39
|
+
|
40
|
+
spec.add_dependency "libhoney", "~> 1.8"
|
41
|
+
|
42
|
+
spec.add_development_dependency "appraisal"
|
43
|
+
spec.add_development_dependency "bump"
|
44
|
+
spec.add_development_dependency "bundler"
|
45
|
+
spec.add_development_dependency "overcommit", "~> 0.46.0"
|
46
|
+
spec.add_development_dependency "pry-byebug"
|
47
|
+
spec.add_development_dependency "rake"
|
48
|
+
spec.add_development_dependency "rspec", "~> 3.0"
|
49
|
+
spec.add_development_dependency "rubocop", "< 0.69"
|
50
|
+
spec.add_development_dependency "rubocop-performance", "< 1.3.0"
|
51
|
+
spec.add_development_dependency "simplecov"
|
52
|
+
spec.add_development_dependency "simplecov-console"
|
53
|
+
spec.add_development_dependency "webmock"
|
54
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "rails/generators"
|
4
|
+
|
5
|
+
##
|
6
|
+
# Generates an intializer for configuring the Honeycomb beeline
|
7
|
+
#
|
8
|
+
class HoneycombGenerator < Rails::Generators::Base
|
9
|
+
source_root File.expand_path("templates", __dir__)
|
10
|
+
|
11
|
+
argument :write_key, required: true, desc: "required"
|
12
|
+
|
13
|
+
gem "honeycomb-beeline"
|
14
|
+
|
15
|
+
desc "Configures honeycomb with your write key"
|
16
|
+
|
17
|
+
def create_initializer_file
|
18
|
+
initializer "honeycomb.rb" do
|
19
|
+
<<-RUBY.strip_heredoc
|
20
|
+
Honeycomb.configure do |config|
|
21
|
+
config.write_key = #{write_key.inspect}
|
22
|
+
config.dataset = "rails"
|
23
|
+
config.notification_events = %w[
|
24
|
+
sql.active_record
|
25
|
+
render_template.action_view
|
26
|
+
render_partial.action_view
|
27
|
+
render_collection.action_view
|
28
|
+
process_action.action_controller
|
29
|
+
send_file.action_controller
|
30
|
+
send_data.action_controller
|
31
|
+
deliver.action_mailer
|
32
|
+
].freeze
|
33
|
+
end
|
34
|
+
RUBY
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "libhoney"
|
4
|
+
|
5
|
+
require "honeycomb/beeline/version"
|
6
|
+
require "honeycomb/client"
|
7
|
+
require "honeycomb/trace"
|
8
|
+
|
9
|
+
# main module
|
10
|
+
module Honeycomb
|
11
|
+
class << self
|
12
|
+
attr_reader :client
|
13
|
+
|
14
|
+
def configure
|
15
|
+
Configuration.new.tap do |config|
|
16
|
+
yield config
|
17
|
+
@client = Honeycomb::Client.new(client: config.client,
|
18
|
+
service_name: config.service_name)
|
19
|
+
config.after_initialize(@client)
|
20
|
+
end
|
21
|
+
|
22
|
+
@client
|
23
|
+
end
|
24
|
+
|
25
|
+
def start_span(name:, &block)
|
26
|
+
client.start_span(name: name, &block)
|
27
|
+
end
|
28
|
+
|
29
|
+
def load_integrations
|
30
|
+
%i[faraday rack sinatra rails sequel active_support].each do |integration|
|
31
|
+
begin
|
32
|
+
require "honeycomb/integrations/#{integration}"
|
33
|
+
rescue LoadError
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
# Used to configure the Honeycomb client
|
40
|
+
class Configuration
|
41
|
+
attr_accessor :write_key,
|
42
|
+
:dataset,
|
43
|
+
:api_host
|
44
|
+
|
45
|
+
attr_writer :service_name, :client
|
46
|
+
|
47
|
+
def initialize
|
48
|
+
@write_key = ENV["HONEYCOMB_WRITEKEY"]
|
49
|
+
@dataset = ENV["HONEYCOMB_DATASET"]
|
50
|
+
@service_name = ENV["HONEYCOMB_SERVICE"]
|
51
|
+
@client = nil
|
52
|
+
end
|
53
|
+
|
54
|
+
def service_name
|
55
|
+
@service_name || dataset
|
56
|
+
end
|
57
|
+
|
58
|
+
def client
|
59
|
+
options = {}.tap do |o|
|
60
|
+
o[:writekey] = write_key
|
61
|
+
o[:dataset] = dataset
|
62
|
+
api_host && o[:api_host] = api_host
|
63
|
+
end
|
64
|
+
|
65
|
+
@client || Libhoney::Client.new(options)
|
66
|
+
end
|
67
|
+
|
68
|
+
def after_initialize(client)
|
69
|
+
super(client) if defined?(super)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
Honeycomb.load_integrations unless ENV["HONEYCOMB_DISABLE_AUTOCONFIGURE"]
|
@@ -0,0 +1,79 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "socket"
|
4
|
+
require "forwardable"
|
5
|
+
require "honeycomb/beeline/version"
|
6
|
+
require "honeycomb/context"
|
7
|
+
|
8
|
+
module Honeycomb
|
9
|
+
# The Honeycomb Beeline client
|
10
|
+
class Client
|
11
|
+
extend Forwardable
|
12
|
+
|
13
|
+
def initialize(client:, service_name: nil)
|
14
|
+
# attempt to set the user_agent_addition, this will only work if the
|
15
|
+
# client has not sent an event prior to being passed in here. This should
|
16
|
+
# be most cases
|
17
|
+
client.instance_variable_set(:@user_agent_addition,
|
18
|
+
Honeycomb::Beeline::USER_AGENT_SUFFIX)
|
19
|
+
client.add_field "meta.beeline_version", Honeycomb::Beeline::VERSION
|
20
|
+
client.add_field "meta.local_hostname", host_name
|
21
|
+
|
22
|
+
# maybe make `service_name` a required parameter
|
23
|
+
client.add_field "service_name", service_name
|
24
|
+
@client = client
|
25
|
+
@context = Context.new
|
26
|
+
|
27
|
+
at_exit do
|
28
|
+
client.close
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def start_span(name:, serialized_trace: nil)
|
33
|
+
if context.current_trace.nil?
|
34
|
+
Trace.new(serialized_trace: serialized_trace,
|
35
|
+
builder: client.builder,
|
36
|
+
context: context)
|
37
|
+
else
|
38
|
+
context.current_span.create_child
|
39
|
+
end
|
40
|
+
|
41
|
+
context.current_span.add_field("name", name)
|
42
|
+
|
43
|
+
if block_given?
|
44
|
+
begin
|
45
|
+
yield context.current_span
|
46
|
+
rescue StandardError => e
|
47
|
+
context.current_span.add_field("request.error", e.class.name)
|
48
|
+
context.current_span.add_field("request.error_detail", e.message)
|
49
|
+
raise e
|
50
|
+
ensure
|
51
|
+
context.current_span.send
|
52
|
+
end
|
53
|
+
else
|
54
|
+
context.current_span
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def add_field(key, value)
|
59
|
+
return if context.current_span.nil?
|
60
|
+
|
61
|
+
context.current_span.add_field("app.#{key}", value)
|
62
|
+
end
|
63
|
+
|
64
|
+
def add_field_to_trace(key, value)
|
65
|
+
return if context.current_span.nil?
|
66
|
+
|
67
|
+
context.current_span.trace.add_field("app.#{key}", value)
|
68
|
+
end
|
69
|
+
|
70
|
+
private
|
71
|
+
|
72
|
+
attr_reader :client, :context
|
73
|
+
|
74
|
+
def host_name
|
75
|
+
# Send the heroku dyno name instead of hostname if available
|
76
|
+
ENV["DYNO"] || Socket.gethostname
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Honeycomb
|
4
|
+
# Stores the current span and trace context
|
5
|
+
class Context
|
6
|
+
def current_trace
|
7
|
+
return if current_span.nil?
|
8
|
+
|
9
|
+
current_span.trace
|
10
|
+
end
|
11
|
+
|
12
|
+
def current_span
|
13
|
+
spans.last
|
14
|
+
end
|
15
|
+
|
16
|
+
def current_span=(span)
|
17
|
+
spans << span
|
18
|
+
end
|
19
|
+
|
20
|
+
def span_sent(span)
|
21
|
+
spans.last != span && raise(ArgumentError, "Incorrect span sent")
|
22
|
+
|
23
|
+
spans.pop
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def spans
|
29
|
+
storage["spans"] ||= []
|
30
|
+
end
|
31
|
+
|
32
|
+
def storage
|
33
|
+
Thread.current[thread_key] ||= {}
|
34
|
+
end
|
35
|
+
|
36
|
+
def thread_key
|
37
|
+
@thread_key ||= ["honeycomb", self.class.name, object_id].join("-")
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|