rack-honeycomb 0.2.2 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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