rack-honeycomb 0.2.2 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ef7c4729ce175288104850f4fe2202cf8cb51efa5b65b6e2cb4083df152c9368
4
- data.tar.gz: 53be46494b255ff4bc3fed40ef1d6e7a2bd529238dcca359098d06671c16a759
3
+ metadata.gz: d71737f6f10436e9df8ccf2589fa626b720baf0eca15dd764496daa6028d3be1
4
+ data.tar.gz: 132781010ca1cf718553c968961bf10f3ec683b891b53fb800c5539148d357c7
5
5
  SHA512:
6
- metadata.gz: f710981f56110b49ebec88e178255c63d330bdedb2a97a7133eacc5cebd6912259b9318828f277017d51254dee23362acbbde803b70b1645524ede3d3bad7c79
7
- data.tar.gz: 7041b6dbec9a01c3a0e18c0885fd7d4c1b85238768af9c6c088d1be436d986b00af0b9716ed00a008450c47a35fbeff091e9c0cf712bcf9df25aa7dcfc55d09f
6
+ metadata.gz: e698f60be56541bd891ad9b2e00c897553fd2851127524e9726394ca28d1af80c6929cb01a6ba40286e8fc326d5df21009ace359f7ee718139e42368630738db
7
+ data.tar.gz: 7aa9fd274977bd1dc31985eb66f37f28ac433aa6d3632f192b8640f897203c3ea80b260a217f6bd562b85cb80eaa830fc54450cdfb36a895fae8b4debca147b9
data/.gitignore CHANGED
@@ -42,7 +42,7 @@ build-iPhoneSimulator/
42
42
 
43
43
  # for a library or gem, you might want to ignore these files since the code is
44
44
  # intended to run in multiple environments; otherwise, check them in:
45
- Gemfile.lock
45
+ Gemfile*.lock
46
46
  .ruby-version
47
47
  .ruby-gemset
48
48
 
@@ -50,3 +50,4 @@ Gemfile.lock
50
50
  .rvmrc
51
51
 
52
52
  *~
53
+ log
data/.travis.yml CHANGED
@@ -3,6 +3,11 @@ rvm:
3
3
  - 2.2
4
4
  - 2.3
5
5
  - 2.4
6
+ - 2.5
7
+ gemfile:
8
+ - Gemfile
9
+ - Gemfile.rails3.rb
10
+ - Gemfile.rails4.rb
6
11
  deploy:
7
12
  provider: rubygems
8
13
  gem: rack-honeycomb
data/Gemfile.rails3.rb ADDED
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+ source "https://rubygems.org"
3
+
4
+ gemspec
5
+
6
+ gem 'rails', '< 4'
7
+ gem 'test-unit', '~> 3.0'
data/Gemfile.rails4.rb ADDED
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+ source "https://rubygems.org"
3
+
4
+ gemspec
5
+
6
+ gem 'rails', '< 5'
data/README.md CHANGED
@@ -13,26 +13,28 @@ Attaching the middleware is simple. Inside handlers, you also have the choice of
13
13
  require 'sinatra'
14
14
  require 'rack/honeycomb'
15
15
 
16
- use Rack::Honeycomb::Middleware, writekey: "<YOUR WRITEKEY HERE>", dataset: "<YOUR DATASET NAME HERE>"
16
+ use Rack::Honeycomb::Middleware, writekey: "<YOUR WRITEKEY HERE>", dataset: "<YOUR DATASET NAME HERE>", is_sinatra: true
17
17
 
18
18
  get('/hello') do
19
- Rack::Honeycomb.add_field :greeting, 'hello'
19
+ Rack::Honeycomb.add_field env, :greeting, 'hello'
20
20
  "Hello, world!\n"
21
21
  end
22
22
  ```
23
23
 
24
24
  ## Adding instrumentation to a Rails application
25
25
 
26
- For more fully-featured Rails support, see [honeycomb-rails](https://github.com/honeycombio/honeycomb-rails).
26
+ For more fully-featured Rails support, see [beeline-ruby](https://github.com/honeycombio/beeline-ruby).
27
27
 
28
- If honeycomb-rails doesn't work for you, this Rack middleware should work for Rails apps too:
28
+ [beeline-ruby](https://github.com/honeycombio/beeline-ruby) includes this gem along with active record support.
29
+
30
+ If beeline-ruby doesn't work for you, you can include this middleware standalone
29
31
 
30
32
  ```ruby
31
33
  # config/application.rb
32
34
  require 'rack/honeycomb'
33
35
 
34
36
  class Application < Rails::Application
35
- config.middleware.use Rack::Honeycomb::Middleware, writekey: "<YOUR WRITEKEY HERE>", dataset: "<YOUR DATASET NAME HERE>"
37
+ config.middleware.use Rack::Honeycomb::Middleware, writekey: "<YOUR WRITEKEY HERE>", dataset: "<YOUR DATASET NAME HERE>", is_rails: true
36
38
  end
37
39
  ```
38
40
 
@@ -4,33 +4,46 @@ module Rack
4
4
  module AutoInstall
5
5
  class << self
6
6
  def available?(logger: nil)
7
- gem 'rack'
8
- logger.debug "#{self.name}: detected rack" if logger
9
- gem 'sinatra'
10
- logger.debug "#{self.name}: detected sinatra, okay to autoinitialise" if logger
11
- true
12
- rescue Gem::LoadError => e
13
- if e.name == 'sinatra'
14
- logger.debug "Couldn't detect web framework, not autoinitialising rack-honeycomb" if logger
7
+ @logger = logger
8
+
9
+ unless has_gem? 'rack'
10
+ debug 'not autoinitialising rack-honeycomb'
11
+ return false
15
12
  end
16
- false
13
+
14
+ @has_sinatra = has_gem? 'sinatra'
15
+ @has_rails = has_gem? 'rails'
16
+
17
+ unless @has_sinatra || @has_rails
18
+ debug "Couldn't detect web framework, not autoinitialising rack-honeycomb"
19
+ return false
20
+ end
21
+
22
+ true
17
23
  end
18
24
 
19
25
  def auto_install!(honeycomb_client:, logger: nil)
20
- require 'rack'
21
- require 'sinatra/base'
26
+ @logger = logger
22
27
 
28
+ require 'rack'
23
29
  require 'rack-honeycomb'
24
30
 
31
+ auto_install_sinatra!(honeycomb_client, logger) if @has_sinatra
32
+ auto_install_rails!(honeycomb_client, logger) if @has_rails
33
+ end
34
+
35
+ def auto_install_sinatra!(honeycomb_client, logger)
36
+ require 'sinatra/base'
37
+
25
38
  class << ::Sinatra::Base
26
39
  alias build_without_honeycomb build
27
40
  end
28
41
 
29
42
  ::Sinatra::Base.define_singleton_method(:build) do |*args, &block|
30
43
  if !AutoInstall.already_added
31
- logger.debug "Adding Rack::Honeycomb::Middleware to #{self}" if logger
44
+ AutoInstall.debug "Adding Rack::Honeycomb::Middleware to #{self}"
32
45
 
33
- self.use Rack::Honeycomb::Middleware, client: honeycomb_client, logger: logger
46
+ self.use Rack::Honeycomb::Middleware, client: honeycomb_client, logger: logger, is_sinatra: true
34
47
  AutoInstall.already_added = true
35
48
  else
36
49
  # In the case of nested Sinatra apps - apps composed of other apps
@@ -40,7 +53,7 @@ module Rack
40
53
  # middleware reliably - so instead, we just want to warn the user
41
54
  # and avoid doing anything silly.
42
55
  unless AutoInstall.already_warned
43
- logger.warn "Honeycomb auto-instrumentation of Sinatra will probably not work, try manual installation" if logger
56
+ AutoInstall.warn 'Honeycomb auto-instrumentation of Sinatra will probably not work, try manual installation'
44
57
  AutoInstall.already_warned = true
45
58
  end
46
59
  end
@@ -54,8 +67,35 @@ module Rack
54
67
  end)
55
68
  end
56
69
 
70
+ def auto_install_rails!(honeycomb_client, logger)
71
+ require 'rack-honeycomb/railtie'
72
+ ::Rack::Honeycomb::Railtie.init(
73
+ honeycomb_client: honeycomb_client,
74
+ logger: logger,
75
+ )
76
+ debug 'Loaded Railtie'
77
+ end
78
+
57
79
  attr_accessor :already_added
58
80
  attr_accessor :already_warned
81
+
82
+ def debug(msg)
83
+ @logger.debug "#{self.name}: #{msg}" if @logger
84
+ end
85
+
86
+ def warn(msg)
87
+ @logger.warn "#{self.name}: #{msg}" if @logger
88
+ end
89
+
90
+ private
91
+ def has_gem?(gem_name)
92
+ gem gem_name
93
+ debug "detected #{gem_name}"
94
+ true
95
+ rescue Gem::LoadError => e
96
+ debug "#{gem_name} not detected (#{e.class}: #{e.message})"
97
+ false
98
+ end
59
99
  end
60
100
  end
61
101
  end
@@ -0,0 +1,26 @@
1
+ require 'rails'
2
+
3
+ module Rack
4
+ module Honeycomb
5
+ class Railtie < ::Rails::Railtie
6
+ class << self
7
+ attr_reader :honeycomb_client, :logger
8
+
9
+ def init(honeycomb_client:, logger: nil)
10
+ @honeycomb_client = honeycomb_client
11
+ @logger = logger
12
+
13
+ logger.debug "#{self}: initialized with #{honeycomb_client.class}" if logger
14
+ end
15
+ end
16
+
17
+ initializer 'honeycomb.add_rack_middleware' do |app|
18
+ app.middleware.use ::Rack::Honeycomb::Middleware,
19
+ client: Railtie.honeycomb_client,
20
+ logger: Railtie.logger,
21
+ is_rails: true
22
+ Railtie.logger.debug "#{Railtie}: Added rack-honeycomb middleware to #{app.class}" if Railtie.logger
23
+ end
24
+ end
25
+ end
26
+ end
@@ -20,18 +20,38 @@ module Rack
20
20
  USER_AGENT_SUFFIX = "rack-honeycomb/#{VERSION}"
21
21
  EVENT_TYPE = 'http_server'.freeze
22
22
 
23
+ RAILS_SPECIAL_PARAMS = %w(controller action).freeze
24
+
23
25
  ##
24
26
  # @param [#call] app
25
27
  # @param [Hash{Symbol => Object}] options
26
28
  # @option options [String] :writekey (nil)
27
29
  # @option options [String] :dataset (nil)
28
30
  # @option options [String] :api_host (nil)
31
+ # @option options [Boolean] :is_sinatra (false)
32
+ # @option options [Boolean] :is_rails (false)
29
33
  def initialize(app, options = {})
30
34
  @app, @options = app, options
31
35
 
32
36
  @logger = options.delete(:logger)
33
37
  @logger ||= ::Honeycomb.logger if defined?(::Honeycomb.logger)
34
38
 
39
+ @is_sinatra = options.delete(:is_sinatra)
40
+ debug 'Enabling Sinatra-specific fields' if @is_sinatra
41
+ @is_rails = options.delete(:is_rails)
42
+ debug 'Enabling Rails-specific fields' if @is_rails
43
+
44
+ # report meta.package = rack only if we have no better information
45
+ package = 'rack'
46
+ package_version = RACK_VERSION
47
+ if @is_rails
48
+ package = 'rails'
49
+ package_version = ::Rails::VERSION::STRING
50
+ elsif @is_sinatra
51
+ package = 'sinatra'
52
+ package_version = ::Sinatra::VERSION
53
+ end
54
+
35
55
  honeycomb = if client = options.delete(:client)
36
56
  debug "initialized with #{client.class.name} via :client option"
37
57
  client
@@ -44,13 +64,11 @@ module Rack
44
64
  end
45
65
  @builder = honeycomb.builder.
46
66
  add(
47
- 'meta.package' => 'rack',
48
- 'meta.package_version' => RACK_VERSION,
67
+ 'meta.package' => package,
68
+ 'meta.package_version' => package_version,
49
69
  'type' => EVENT_TYPE,
50
70
  'meta.local_hostname' => Socket.gethostname,
51
71
  )
52
-
53
- @service_name = options.delete(:service_name) || :rack
54
72
  end
55
73
 
56
74
  def call(env)
@@ -63,8 +81,6 @@ module Rack
63
81
  @app.call(env)
64
82
  end
65
83
 
66
- add_app_fields(ev, env)
67
-
68
84
  add_response_fields(ev, status, headers, body)
69
85
 
70
86
  [status, headers, body]
@@ -79,6 +95,11 @@ module Rack
79
95
  finish = Time.now
80
96
  ev.add_field('duration_ms', (finish - start) * 1000)
81
97
 
98
+ add_sinatra_fields(ev, env) if @is_sinatra
99
+ add_rails_fields(ev, env) if @is_rails
100
+
101
+ add_app_fields(ev, env)
102
+
82
103
  ev.send
83
104
  end
84
105
  end
@@ -90,6 +111,8 @@ module Rack
90
111
 
91
112
  def add_request_fields(event, env)
92
113
  event.add_field('name', "#{env['REQUEST_METHOD']} #{env['PATH_INFO']}")
114
+ # N.B. 'name' may be overwritten later by add_sinatra_fields or
115
+ # add_rails_fields
93
116
 
94
117
  event.add_field('request.method', env['REQUEST_METHOD'])
95
118
  event.add_field('request.path', env['PATH_INFO'])
@@ -105,6 +128,59 @@ module Rack
105
128
  event.add_field('request.header.user_agent', env['HTTP_USER_AGENT'])
106
129
  end
107
130
 
131
+ def add_sinatra_fields(event, env)
132
+ route = env['sinatra.route']
133
+ event.add_field('request.route', route)
134
+ # overwrite 'name' (previously set in add_request_fields)
135
+ event.add_field('name', route)
136
+ end
137
+
138
+ def add_rails_fields(event, env)
139
+ rails_params = env['action_dispatch.request.parameters']
140
+ unless rails_params.kind_of? Hash
141
+ debug "Got unexpected type #{rails_params.class} for env['action_dispatch.request.parameters']"
142
+ return
143
+ end
144
+
145
+ rails_params.each do |param, value|
146
+ if RAILS_SPECIAL_PARAMS.include?(param)
147
+ event.add_field("request.#{param}", value)
148
+ else
149
+ event.add_field("request.params.#{param}", value)
150
+ end
151
+ end
152
+
153
+ # overwrite 'name' (previously set in add_request_fields)
154
+ event.add_field('name', "#{rails_params[:controller]}##{rails_params[:action]}")
155
+
156
+ event.add_field('request.route', extract_rails_route(env))
157
+ end
158
+
159
+ def extract_rails_route(env)
160
+ # egregious and probably slow hack to get the formatted route
161
+ # TODO there must be a better way
162
+ routes = env['action_dispatch.routes']
163
+ request = ::ActionDispatch::Request.new(env)
164
+
165
+ formatted_route = nil
166
+
167
+ routes.router.recognize(request) do |route, _|
168
+ # make a hash where each param ("part") in the route is given its
169
+ # own name as a value, e.g. {:id => ":id"}
170
+ symbolic_params = {}
171
+ route.required_parts.each do |part|
172
+ symbolic_params[part] = ":#{part}"
173
+ end
174
+ # then ask the route to format itself using those param "values"
175
+ formatted_route = route.format(symbolic_params)
176
+ end
177
+
178
+ "#{env['REQUEST_METHOD']} #{formatted_route}"
179
+ rescue StandardError => e
180
+ debug "couldn't extract named route for request: #{e.class}: #{e}"
181
+ nil
182
+ end
183
+
108
184
  def add_app_fields(event, env)
109
185
  # Pull arbitrary metadata off `env` if the caller attached
110
186
  # anything inside the Rack handler.
@@ -1,5 +1,5 @@
1
1
  module Rack
2
2
  module Honeycomb
3
- VERSION="0.2.2"
3
+ VERSION="0.3.0"
4
4
  end
5
5
  end
@@ -34,6 +34,7 @@ Gem::Specification.new do |spec|
34
34
  spec.add_runtime_dependency 'libhoney', '>= 1.5.0'
35
35
  spec.add_development_dependency 'rspec'
36
36
  spec.add_development_dependency 'rack-test'
37
+ spec.add_development_dependency 'rails'
37
38
  spec.add_development_dependency 'sinatra'
38
39
  spec.add_development_dependency 'yard'
39
40
  spec.add_development_dependency 'pry-byebug'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rack-honeycomb
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.2
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - The Honeycomb.io Team
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-06-07 00:00:00.000000000 Z
11
+ date: 2018-11-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bump
@@ -108,6 +108,20 @@ dependencies:
108
108
  - - ">="
109
109
  - !ruby/object:Gem::Version
110
110
  version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: rails
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
111
125
  - !ruby/object:Gem::Dependency
112
126
  name: sinatra
113
127
  requirement: !ruby/object:Gem::Requirement
@@ -161,11 +175,14 @@ files:
161
175
  - ".travis.yml"
162
176
  - CONTRIBUTORS
163
177
  - Gemfile
178
+ - Gemfile.rails3.rb
179
+ - Gemfile.rails4.rb
164
180
  - LICENSE
165
181
  - README.md
166
182
  - Rakefile
167
183
  - lib/rack-honeycomb.rb
168
184
  - lib/rack-honeycomb/auto_install.rb
185
+ - lib/rack-honeycomb/railtie.rb
169
186
  - lib/rack/honeycomb.rb
170
187
  - lib/rack/honeycomb/middleware.rb
171
188
  - lib/rack/honeycomb/version.rb