honeycomb-beeline 0.5.0 → 0.6.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: fc4528a9aaab86b940cc602a90134618ff588f88d25d8eaa8408edcc294ea987
4
- data.tar.gz: f7fb9cafa295258ad9e96fe3116e8e81f8f4a27a3affa29db9eec63207cbf6a9
3
+ metadata.gz: 0e5338862ac2eed88b9a4c9712bf47d63652531c0a6c9c06d8e2e4f0f62c2650
4
+ data.tar.gz: 7e70234ac75d0361578905460c92625744f70fae73a050db386ab5b0614870e7
5
5
  SHA512:
6
- metadata.gz: '08e93b50154976fc28a3408df22a4b4e347d2236cf18673a4adef9092a4d739ff083772260e96a1d058efa6674b9afc24cc2b7d7c6156078dfd7d2847edec2c4'
7
- data.tar.gz: 78287f73733f6cce17d28fb5c58afdd8e99a4bcf8c56cc7af01c97b03a3e8aab7d7947e68e9ee6afef201fb38c0541e08ed34c912994907a09a6bfc3d9a1c27c
6
+ metadata.gz: 3730b7e2add547932ce15ed3ec4a18ab52a65c20c65542547fa8c8a6a15e19aa0a2aff498d85b8237a5603099cbca3824e5dc3e4a9ba9d260dc26ec0cf3f2d62
7
+ data.tar.gz: ac42934a9679810c693d673d88aa656ca36f7c17cbccc66cca1cd4cadb3ce0969f50926efdb4a4716913a728235b6368bef20264ebc9d7aa374ce55cdb618f8f
data/README.md CHANGED
@@ -6,217 +6,31 @@
6
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
7
  - [Usage and Examples](https://docs.honeycomb.io/getting-data-in/beelines/ruby-beeline/)
8
8
 
9
- Requires Ruby 2.2 or later. Sign up for a [Honeycomb
9
+ Sign up for a [Honeycomb
10
10
  trial](https://ui.honeycomb.io/signup) to obtain an API key before starting.
11
11
 
12
- ## Installation
12
+ ## Compatible with
13
13
 
14
- Add `honeycomb-beeline` to your Gemfile:
14
+ Requires Ruby version 2.2 or later
15
15
 
16
- ```ruby
17
- gem 'honeycomb-beeline'
18
- ```
19
- Now run `bundle install` to install the gem.
16
+ Built in instrumentation for:
20
17
 
21
- ## Setup
18
+ - Active Record 4 or later
19
+ - Rails 4 or later
20
+ - Faraday 0.8 or later
21
+ - Sequel
22
+ - Rack 1 or greater
22
23
 
23
- In your app's startup script - e.g. config.ru or app.rb - add the following
24
- code:
24
+ ## Get in touch
25
25
 
26
- ```ruby
27
- require 'honeycomb-beeline'
26
+ Please reach out to [support@honeycomb.io](mailto:support@honeycomb.io) or ping
27
+ us with the chat bubble on [our website](https://www.honeycomb.io) for any
28
+ assistance. We also welcome [bug reports](https://github.com/honeycombio/beeline-ruby/issues).
28
29
 
29
- Honeycomb.init # pulls configuration from the environment - see below
30
- ```
30
+ ## Contributions
31
31
 
32
- ## Configuration
32
+ Features, bug fixes and other changes to `beeline-ruby` are gladly accepted. Please
33
+ open issues or a pull request with your change. Remember to add your name to the
34
+ CONTRIBUTORS file!
33
35
 
34
- You'll need to configure your Honeycomb API key so that your app can
35
- identify itself to Honeycomb. You can find your API key on [your Account
36
- page](https://ui.honeycomb.io/account).
37
-
38
- You'll also need to configure the name of a dataset in your Honeycomb account to
39
- send events to. The name of your app is a good choice.
40
-
41
- You can specify the configuration either via environment variables, or by
42
- passing arguments to `Honeycomb.init`:
43
-
44
- ### Configuration via environment variables
45
-
46
- * `HONEYCOMB_WRITEKEY` - specifies the API key (aka "write key")
47
- * `HONEYCOMB_DATASET` - specifies the dataset
48
- * `HONEYCOMB_SERVICE` - specifies the name of your app (defaults to the dataset
49
- name)
50
-
51
- ### Configuration via code
52
-
53
- ```ruby
54
- Honeycomb.init(
55
- writekey: '<MY HONEYCOMB API KEY>',
56
- dataset: 'my-app',
57
- service_name: 'my-app'
58
- )
59
- ```
60
-
61
- Note that Honeycomb API keys have the ability to create and delete data, and
62
- should be managed in the same way as your other application secrets. For example
63
- you might prefer to configure production API keys via environment variables,
64
- rather than checking them into version control.
65
-
66
- ## Example questions
67
-
68
- Now your app is instrumented and sending events, try using Honeycomb to ask
69
- these questions:
70
-
71
- * Which of my app's routes are the slowest?
72
- ```
73
- BREAKDOWN: request.path
74
- CALCULATE: P99(duration_ms)
75
- FILTER: type == http_server
76
- ORDER BY: P99(duration_ms) DESC
77
- ```
78
- * Where's my app spending the most time?
79
- ```
80
- BREAKDOWN: type
81
- CALCULATE: SUM(duration_ms)
82
- ORDER BY: SUM(duration_ms) DESC
83
- ```
84
- * Which users are using the endpoint that I'd like to deprecate? First add a
85
- [custom field](#adding-additional-context) `user.email`, then try:
86
- ```
87
- BREAKDOWN: app.user.email
88
- CALCULATE: COUNT
89
- FILTER: request.path == /my/deprecated/endpoint
90
- ```
91
-
92
- ## Example event
93
-
94
- Here is an example of an `http_server` event (recording that your web app
95
- processed an incoming HTTP request) emitted by the Beeline:
96
-
97
- ```json
98
- {
99
- "meta.beeline_version": "0.2.0",
100
- "meta.local_hostname": "killerbee",
101
- "service_name": "my-test-app",
102
- "meta.package": "rack",
103
- "meta.package_version": "1.3",
104
- "type": "http_server",
105
- "name": "GET /dashboard",
106
- "request.method": "GET",
107
- "request.path": "/dashboard",
108
- "request.protocol": "https",
109
- "request.http_version": "HTTP/1.1",
110
- "request.host": "my-test-app.example.com",
111
- "request.remote_addr": "172.217.1.238",
112
- "request.header.user_agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36",
113
- "trace.trace_id": "b694512a-833f-4b35-be5f-6c742ba18e12",
114
- "trace.span_id": "c35cc326-ed90-4881-a4a8-68526d252f2e",
115
- "response.status_code": 200,
116
- "duration_ms": 303.057396
117
- }
118
- ```
119
-
120
- ## Adding additional context
121
-
122
- The Beeline will automatically instrument your incoming HTTP requests, database
123
- queries and outbound HTTP requests to send events to Honeycomb. However, it can
124
- be very helpful to extend these events with additional context specific to your
125
- app. You can add your own fields by calling `Rack::Honeycomb.add_field`. For
126
- example, this snippet shows how to associate the currently logged-in user with
127
- each `http_server` event:
128
-
129
- ```ruby
130
- get '/hello' do
131
- user = authenticate_user()
132
-
133
- # this will add a custom field 'app.user.email' to the http_server event
134
- Rack::Honeycomb.add_field(env, 'user.email', user.email)
135
-
136
- "Hello, #{user.name}!"
137
- end
138
- ```
139
-
140
- ## Instrumented packages
141
-
142
- The Beeline will automatically send the following events if you are using one of
143
- the listed packages:
144
-
145
- ### `http_server` (incoming HTTP requests)
146
-
147
- * [Sinatra](http://sinatrarb.com) - via [rack-honeycomb](https://github.com/honeycombio/rack-honeycomb)
148
- * Any other [Rack](https://rack.github.io)-based web app - via [rack-honeycomb](https://github.com/honeycombio/rack-honeycomb) (requires manually adding the middleware)
149
-
150
- ### `db` (database queries)
151
-
152
- * [ActiveRecord](https://rubygems.org/gems/activerecord) - via
153
- [activerecord-honeycomb](https://github.com/honeycombio/activerecord-honeycomb)
154
- * [Sequel](https://sequel.jeremyevans.net/) - via
155
- [sequel-honeycomb](https://github.com/honeycombio/sequel-honeycomb)
156
-
157
- ### `http_client` (outbound HTTP requests)
158
-
159
- * [Faraday](https://github.com/lostisland/faraday) - via
160
- [faraday-honeycomb](https://github.com/honeycombio/faraday-honeycomb)
161
-
162
- ## Known limitations
163
-
164
- * The Beeline will try to autodetect your web framework and automatically
165
- install its middleware. Currently this only works for Sinatra apps, and
166
- also fails in some more exotic configurations of Sinatra. If you find you
167
- aren't seeing any events for processing web requests, you can install the
168
- [middleware](https://www.rubydoc.info/gems/rack-honeycomb) manually: e.g.
169
- `use Rack::Honeycomb::Middleware`.
170
- * Rails apps should work after installing the middleware as above, but are
171
- currently better supported by our dedicated [Rails
172
- integration](https://github.com/honeycombio/honeycomb-rails).
173
- * Alternative concurrency models such as EventMachine or Celluloid are not
174
- currently supported.
175
-
176
- If support for one of these scenarios is important to you, please [let us
177
- know](#get-in-touch)!
178
-
179
- ## Troubleshooting
180
-
181
- If you've setup the Beeline as above but you aren't seeing data for your app in
182
- Honeycomb, or you're seeing errors on startup, here are a few things to try:
183
-
184
- ### Debug mode
185
-
186
- To verify the Beeline is working as expected, try running it in debug mode:
187
-
188
- ```ruby
189
- Honeycomb.init(debug: true)
190
- ```
191
-
192
- Alternatively, you can also enable debug mode with no code changes by setting
193
- `HONEYCOMB_DEBUG=true` in your environment.
194
-
195
- In debug mode, the Beeline will not send any events to Honeycomb, but will
196
- instead print them to your app's standard error. It will also log startup
197
- messages to standard error.
198
-
199
- ### Logging
200
-
201
- By default the Beeline will log errors but otherwise keep quiet. To see more
202
- detail about what it's doing, you can pass a logger object (compliant with the
203
- [stdlib Logger API](https://ruby-doc.org/stdlib-2.4.1/libdoc/logger/rdoc/)) to
204
- `Honeycomb.init`:
205
-
206
- ```ruby
207
- require 'logger'
208
- logger = Logger.new($stderr)
209
- logger.level = Logger::INFO # determine how much detail you want to see
210
- Honeycomb.init(logger: logger)
211
- ```
212
-
213
- A level of `Logger::DEBUG` will show you detail about each library being instrumented,
214
- whereas a level of `Logger::INFO` will just print a few progress messages.
215
-
216
- ### Get in touch
217
-
218
- This beeline is still young, so please reach out to
219
- [support@honeycomb.io](mailto:support@honeycomb.io) or ping us with the chat
220
- bubble on [our website](https://www.honeycomb.io) for assistance. We also
221
- welcome [bug reports](https://github.com/honeycombio/beeline-ruby/issues) and
222
- [contributions](https://github.com/honeycombio/beeline-ruby/blob/master/CONTRIBUTING.md).
36
+ All contributions will be released under the Apache License 2.0.
@@ -1,6 +1,6 @@
1
1
  module Honeycomb
2
2
  module Beeline
3
3
  GEM_NAME = 'honeycomb-beeline'
4
- VERSION = '0.5.0'
4
+ VERSION = '0.6.0'
5
5
  end
6
6
  end
@@ -72,7 +72,7 @@ module Honeycomb
72
72
  @client = new_client(options)
73
73
 
74
74
  after_init_hooks.each do |label, block|
75
- @logger.debug "Running hook '#{label}' after Honeycomb.init" if @logger
75
+ debug "Running hook '#{label}' after Honeycomb.init"
76
76
  run_hook(label, block)
77
77
  end
78
78
 
@@ -106,6 +106,16 @@ module Honeycomb
106
106
  end
107
107
 
108
108
  private
109
+ def debug(msg)
110
+ logger.debug msg if logger
111
+ end
112
+ def info(msg)
113
+ logger.info msg if logger
114
+ end
115
+ def warn(msg)
116
+ logger.warn msg if logger
117
+ end
118
+
109
119
  def after_init_hooks
110
120
  @after_init_hooks ||= []
111
121
  end
@@ -116,13 +126,13 @@ module Honeycomb
116
126
  options = {user_agent_addition: USER_AGENT_SUFFIX}.merge(options)
117
127
  if @debug
118
128
  raise ArgumentError, "can't specify both client and debug options", caller if client
119
- @logger.info 'logging events to standard error instead of sending to Honeycomb' if @logger
129
+ info 'logging events to standard error instead of sending to Honeycomb'
120
130
  client = Libhoney::LogClient.new(verbose: true, **options)
121
131
  else
122
132
  client ||= if options[:writekey] && options[:dataset]
123
133
  Libhoney::Client.new(options)
124
134
  else
125
- @logger.warn "#{self.name}: no #{options[:writekey] ? 'dataset' : 'writekey'} configured, disabling sending events" if @logger
135
+ warn "#{self.name}: no #{options[:writekey] ? 'dataset' : 'writekey'} configured, disabling sending events"
126
136
  Libhoney::NullClient.new(options)
127
137
  end
128
138
  end
@@ -146,7 +156,7 @@ module Honeycomb
146
156
  end
147
157
 
148
158
  if defined?(@initialized)
149
- @logger.debug "Running hook '#{label}' as Honeycomb already initialized" if @logger
159
+ debug "Running hook '#{label}' as Honeycomb already initialized"
150
160
  run_hook(label, hook)
151
161
  else
152
162
  after_init_hooks << [label, hook]
@@ -155,12 +165,12 @@ module Honeycomb
155
165
 
156
166
  def run_hook(label, block)
157
167
  if @without.include?(label)
158
- @logger.debug "Skipping hook '#{label}' due to opt-out" if @logger
168
+ debug "Skipping hook '#{label}' due to opt-out"
159
169
  else
160
170
  block.call @client, @logger
161
171
  end
162
172
  rescue => e
163
- @logger.warn "Honeycomb.init hook '#{label}' raised #{e.class}: #{e}" if @logger
173
+ warn "Honeycomb.init hook '#{label}' raised #{e.class}: #{e}"
164
174
  end
165
175
  end
166
176
 
@@ -1,42 +1,50 @@
1
+ require 'base64'
2
+ require 'json'
1
3
  require 'securerandom'
2
4
 
3
5
  module Honeycomb
4
6
  class << self
5
- # @api private
6
- def with_trace_id(trace_id = SecureRandom.uuid)
7
- Thread.current[:honeycomb_trace_id] = trace_id
8
- yield trace_id
9
- ensure
10
- Thread.current[:honeycomb_trace_id] = nil
11
- end
7
+ # Start a new trace. Calling {.span} will automatically start a new trace if
8
+ # one is not already active, so you do not need to call this explicitly
9
+ # unless you want to specify the trace id or parent span id (e.g. to
10
+ # propagate a trace id received from upstream).
11
+ def trace(trace_id: nil, parent_span_id: nil, context: {}, **extra_context)
12
+ context = context.merge(extra_context)
12
13
 
13
- # @api private
14
- def trace_id
15
- Thread.current[:honeycomb_trace_id]
14
+ with_trace trace_id: trace_id, parent_span_id: parent_span_id, context: context do
15
+ yield
16
+ end
16
17
  end
17
18
 
18
- # @api private
19
- def with_span_id(span_id)
20
- parent_span_id = Thread.current[:honeycomb_span_id]
21
- Thread.current[:honeycomb_span_id] = span_id
22
- yield parent_span_id
23
- ensure
24
- Thread.current[:honeycomb_span_id] = parent_span_id
19
+ # Continue a trace from a serialized trace context, e.g. propagated from
20
+ # another process.
21
+ def trace_from_encoded_context(encoded_context = nil, additional_context: {})
22
+ trace_context = decode_trace_context(encoded_context) || {}
23
+ trace_id = trace_context[:trace_id]
24
+ parent_span_id = trace_context[:parent_span_id]
25
+ context = trace_context[:context] || {}
26
+
27
+ trace(trace_id: trace_id, parent_span_id: parent_span_id, context: context.merge(additional_context)) do
28
+ yield
29
+ end
25
30
  end
26
31
 
27
- # @api private
28
- def span(service_name:, name:, span_id: SecureRandom.uuid)
32
+ # Start a new span, and send it at the end of the supplied code block. This
33
+ # will start a new trace if one is not already active.
34
+ def span(name = nil, type: 'app', fields: {}, **extra_fields)
35
+ fields = fields.merge(extra_fields)
36
+
37
+ start = nil
38
+
29
39
  event = client.event
40
+ span_for_existing_event(event, name: name, type: type) do |span_id, trace_id|
41
+ fields.each do |field, value|
42
+ event.add_field "app.#{field}", value
43
+ end
30
44
 
31
- event.add_field 'trace.trace_id', trace_id if trace_id
32
- event.add_field 'service_name', service_name
33
- event.add_field 'name', name
34
- event.add_field 'trace.span_id', span_id
45
+ start = Time.now
35
46
 
36
- start = Time.now
37
- with_span_id(span_id) do |parent_span_id|
38
- event.add_field 'trace.parent_id', parent_span_id if parent_span_id
39
- yield
47
+ yield span_id, trace_id
40
48
  end
41
49
  rescue Exception => e
42
50
  if event
@@ -53,5 +61,235 @@ module Honeycomb
53
61
  event.send
54
62
  end
55
63
  end
64
+
65
+ # Start a new span, and annotate an existing {Libhoney::Event} with its
66
+ # tracing fields. Most users should call {.span} instead, since it has
67
+ # simpler semantics (e.g. it will time the execution of the code block for
68
+ # you, record any exceptions that were thrown, and send the event at the end
69
+ # of the code block). This method is mainly useful if you are writing a
70
+ # library instrumentation which needs to also work independently of the
71
+ # Beeline, and which therefore needs to implement those semantics itself; or
72
+ # which needs custom error handling, e.g. adding custom fields in case of
73
+ # error.
74
+ def span_for_existing_event(event, name:, type:)
75
+ with_trace do |trace_id, context|
76
+ with_span do |parent_span_id, span_id|
77
+ event.add_field 'trace.trace_id', trace_id
78
+ event.add_field 'trace.parent_id', parent_span_id if parent_span_id
79
+ event.add_field 'trace.span_id', span_id
80
+ event.add_field 'name', name if name
81
+ event.add_field 'type', type
82
+
83
+ context.each do |field, value|
84
+ event.add_field "app.#{field}", value
85
+ end
86
+
87
+ yield span_id, trace_id
88
+ end
89
+ end
90
+ end
91
+
92
+ # Add a trace field, which will get added to all spans sent after this call.
93
+ def add_trace_field(name, value)
94
+ self.active_trace_context[name] = value
95
+ # TODO right now this will only add the field to all spans *started* after
96
+ # this call, which unfortunately excludes the actual active span when the
97
+ # call was made. One way to fix this is to change .span_for_existing_event
98
+ # to add fields from .active_trace_context _after_ the yield (in a
99
+ # begin/ensure block) instead of before.
100
+ end
101
+
102
+ def decode_trace_context(encoded_context)
103
+ return nil unless encoded_context
104
+ version, payload = encoded_context.split(';', 2)
105
+ case version
106
+ when '1'
107
+ decode_payload_v1(payload)
108
+ else
109
+ warn "#{self}.decode_trace_context: unrecognized trace context version #{version.inspect}"
110
+ nil
111
+ end
112
+ end
113
+
114
+ def encode_trace_context_v1(trace_id, parent_span_id, context)
115
+ version = 1
116
+
117
+ encoded_payload = encode_payload_v1(
118
+ trace_id: trace_id,
119
+ parent_id: parent_span_id,
120
+ context: context,
121
+ )
122
+
123
+ "#{version};#{encoded_payload}"
124
+ end
125
+ alias encode_trace_context encode_trace_context_v1
126
+
127
+ def active_trace_id
128
+ Thread.current[:honeycomb_trace_id]
129
+ end
130
+ def active_trace_id=(trace_id)
131
+ Thread.current[:honeycomb_trace_id] = trace_id
132
+ end
133
+
134
+ def active_parent_span_id
135
+ Thread.current[:honeycomb_parent_span_id]
136
+ end
137
+ def active_parent_span_id=(parent_span_id)
138
+ Thread.current[:honeycomb_parent_span_id] = parent_span_id
139
+ end
140
+
141
+ def active_trace_context
142
+ Thread.current[:honeycomb_trace_context]
143
+ end
144
+ def active_trace_context=(trace_context)
145
+ Thread.current[:honeycomb_trace_context] = trace_context
146
+ end
147
+
148
+ private
149
+ def with_trace(trace_id: nil, parent_span_id: nil, context: nil)
150
+ if self.active_trace_id
151
+ if trace_id
152
+ warn "#{self}.with_trace called while another trace is already active; ignoring supplied trace_id and preserving existing one"
153
+ end
154
+ yield self.active_trace_id, self.active_trace_context
155
+ else
156
+ begin
157
+ trace_id, context = start_trace!(trace_id: trace_id, parent_span_id: parent_span_id, context: context)
158
+
159
+ yield trace_id, context
160
+ ensure
161
+ finish_trace!
162
+ end
163
+ end
164
+ end
165
+
166
+ def start_trace!(trace_id: nil, parent_span_id: nil, context: nil)
167
+ raise "#{self}.start_trace! called while another trace is already active" if self.active_trace_id
168
+
169
+ trace_id ||= SecureRandom.uuid
170
+ self.active_trace_id = trace_id
171
+
172
+ self.active_parent_span_id = parent_span_id if parent_span_id
173
+
174
+ context ||= {}
175
+ self.active_trace_context = context
176
+
177
+ [trace_id, context]
178
+ end
179
+
180
+ def finish_trace!
181
+ self.active_trace_id = nil
182
+ self.active_parent_span_id = nil
183
+ self.active_trace_context = nil
184
+ end
185
+
186
+ def with_span
187
+ parent_span_id, span_id = start_span!
188
+
189
+ yield parent_span_id, span_id
190
+ ensure
191
+ finish_span!(parent_span_id)
192
+ end
193
+
194
+ def start_span!
195
+ span_id = SecureRandom.uuid
196
+
197
+ parent_span_id = self.active_parent_span_id
198
+ self.active_parent_span_id = span_id
199
+
200
+ return parent_span_id, span_id
201
+ end
202
+
203
+ def finish_span!(parent_span_id)
204
+ self.active_parent_span_id = parent_span_id
205
+ end
206
+
207
+ def decode_payload_v1(encoded_payload)
208
+ trace_id, parent_span_id, context = nil
209
+
210
+ encoded_payload.split(',').each do |entry|
211
+ k, v = entry.split('=', 2)
212
+ case k
213
+ when 'trace_id'
214
+ trace_id = v
215
+ when 'parent_id'
216
+ parent_span_id = v
217
+ when 'context'
218
+ context = decode_payload_context_v1(v)
219
+ else
220
+ debug "#{self}.decode_payload_v1: unrecognized payload key #{k.inspect}"
221
+ end
222
+ end
223
+
224
+ if trace_id.nil?
225
+ warn "#{self}.decode_payload_v1: no trace_id in context"
226
+ return nil
227
+ elsif parent_span_id.nil?
228
+ warn "#{self}.decode_payload_v1: no parent_id in context"
229
+ return nil
230
+ end
231
+
232
+ payload = {
233
+ trace_id: trace_id,
234
+ parent_span_id: parent_span_id,
235
+ }
236
+ payload[:context] = context if context
237
+ payload
238
+ rescue StandardError => e
239
+ warn "#{self}.decode_payload_v1: encountered #{e.class} decoding payload: #{e}"
240
+ nil
241
+ end
242
+
243
+ def decode_payload_context_v1(encoded_payload_context)
244
+ return {} if encoded_payload_context.empty?
245
+ json = Base64.decode64(encoded_payload_context)
246
+ JSON.parse(json)
247
+ end
248
+
249
+ def encode_payload_v1(payload_parts)
250
+ payload_parts.map do |k, v|
251
+ encoded_part = encode_payload_part_v1(k, v)
252
+ encoded_part ? "#{k}=#{encoded_part}" : nil
253
+ end
254
+ .compact # strip out parts that failed to encode
255
+ .join(',')
256
+ end
257
+
258
+ def encode_payload_part_v1(param, value)
259
+ case param
260
+ when :trace_id, :parent_id
261
+ encode_payload_id_v1(value)
262
+ when :context
263
+ encode_payload_context_v1(value)
264
+ end
265
+ end
266
+
267
+ def encode_payload_id_v1(id)
268
+ case id
269
+ when nil
270
+ nil
271
+ when String, Symbol
272
+ id = id.to_s
273
+ if id.include? ','
274
+ raise ArgumentError, "can't include ','"
275
+ end
276
+ id
277
+ when Numeric
278
+ id.to_s
279
+ else
280
+ raise ArgumentError, "invalid type #{id.class}"
281
+ end
282
+ end
283
+
284
+ def encode_payload_context_v1(context)
285
+ case context
286
+ when nil
287
+ nil
288
+ when Hash
289
+ Base64.urlsafe_encode64(JSON.generate(context)).strip
290
+ else
291
+ raise ArgumentError, "invalid type #{context.class}"
292
+ end
293
+ end
56
294
  end
57
295
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: honeycomb-beeline
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sam Stokes
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-11-19 00:00:00.000000000 Z
11
+ date: 2018-11-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: libhoney
@@ -30,56 +30,56 @@ dependencies:
30
30
  requirements:
31
31
  - - ">="
32
32
  - !ruby/object:Gem::Version
33
- version: 0.3.0
33
+ version: 0.4.0
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - ">="
39
39
  - !ruby/object:Gem::Version
40
- version: 0.3.0
40
+ version: 0.4.0
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: rack-honeycomb
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - ">="
46
46
  - !ruby/object:Gem::Version
47
- version: 0.3.0
47
+ version: 0.4.0
48
48
  type: :runtime
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - ">="
53
53
  - !ruby/object:Gem::Version
54
- version: 0.3.0
54
+ version: 0.4.0
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: faraday-honeycomb
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
59
  - - ">="
60
60
  - !ruby/object:Gem::Version
61
- version: 0.2.1
61
+ version: 0.3.0
62
62
  type: :runtime
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
66
  - - ">="
67
67
  - !ruby/object:Gem::Version
68
- version: 0.2.1
68
+ version: 0.3.0
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: sequel-honeycomb
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
73
  - - ">="
74
74
  - !ruby/object:Gem::Version
75
- version: 0.2.1
75
+ version: 0.4.0
76
76
  type: :runtime
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
80
  - - ">="
81
81
  - !ruby/object:Gem::Version
82
- version: 0.2.1
82
+ version: 0.4.0
83
83
  - !ruby/object:Gem::Dependency
84
84
  name: activerecord
85
85
  requirement: !ruby/object:Gem::Requirement