honeycomb-beeline 2.8.2 → 2.11.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: 124e1b05ae5609ab32eae6a0340171848bb3bdd8e4291ea082e1da5c706a9eec
4
- data.tar.gz: f77c6cc246e8801386f09dee46fae845997aa4b1a9e978ac03d9c5e254ca9d49
3
+ metadata.gz: fb1cdd573575f99c826f6c98a20184dca3585ca9725f78373086c4b6dbac9a8a
4
+ data.tar.gz: 84d8b9c5e0d3e98a86f469245b8981c74861b92c591a1b399ebbcb786f18749e
5
5
  SHA512:
6
- metadata.gz: dee1ffab32296f88e2f2fff6a53045e390f9dc7cd12a37dc016ed3d3555e022f90de689ce980293ef0b8080dab2ece6fab61056addbe0802a80bc3d0e53918d9
7
- data.tar.gz: 7ccccb62ef9ef6b9f93fa9e9aa2178dd028239614955e12409a66e06be9c01579ded06ae6c8a995bb1aaec37a947d24f66ac0a19ea92073eef77eb02b73c63a5
6
+ metadata.gz: 7d9700b19010094ec5c130af68cf6d07b91d493e60b560b48ec89012680d9102c82249a16e131adec06db3463cec5113dc68977bc0b8a1dccf8a1171f412674a
7
+ data.tar.gz: 25f56bc53a4debe90efb86dbc00152129fc7fe80a1e682a9d3efc33294b2d8fe87139fb87aa3e5cca0f03f76c238a41e5508208f3df0246792f841e0c265013e
data/.rubocop.yml CHANGED
@@ -13,6 +13,7 @@ Metrics/BlockLength:
13
13
  Exclude:
14
14
  - honeycomb-beeline.gemspec
15
15
  - spec/**/*.rb
16
+ - spec/**/*.rake
16
17
 
17
18
  Metrics/AbcSize:
18
19
  Max: 50
@@ -26,6 +27,7 @@ Metrics/MethodLength:
26
27
  - lib/generators/honeycomb/honeycomb_generator.rb
27
28
 
28
29
  Metrics/LineLength:
30
+ Max: 100
29
31
  Exclude:
30
32
  - spec/honeycomb/integrations/active_support_spec.rb
31
33
  - spec/support/event_data_shared_examples.rb
@@ -71,3 +73,6 @@ Style/AsciiComments:
71
73
 
72
74
  Style/Alias:
73
75
  EnforcedStyle: prefer_alias_method
76
+
77
+ Style/IfUnlessModifier:
78
+ Enabled: false
data/CHANGELOG.md CHANGED
@@ -1,5 +1,27 @@
1
1
  # beeline-ruby changelog
2
2
 
3
+ ## 2.11.0 2022-06-01
4
+
5
+ ### Improvements
6
+
7
+ - Let Rake spans be disabled programmatically (#200) | [ajvondrak](https://github.com/ajvondrak)
8
+
9
+ ## 2.10.0 2022-04-08
10
+
11
+ ### Improvements
12
+
13
+ - Add HTTP referer to rack integration (#197) | [@bgitt](https://github.com/bgitt)
14
+
15
+ ### Fixed
16
+
17
+ - Fix regression with mid vs leaf meta.span_type detection (#194) | [@ajvondrak](https://github.com/ajvondrak)
18
+
19
+ ## 2.9.0 2022-03-23
20
+
21
+ ### Enhancements
22
+
23
+ - Add Environment and Services support (#196) | [@MikeGoldsmith](https://github.com/MikeGoldsmith)
24
+
3
25
  ## 2.8.2 2022-02-02
4
26
 
5
27
  ### Maintenance
data/bin/console CHANGED
@@ -2,7 +2,7 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  require "bundler/setup"
5
- require "honeycomb/beeline"
5
+ require_relative "../lib/honeycomb-beeline"
6
6
 
7
7
  # You can add fixtures and/or initialization code here to make experimenting
8
8
  # with your gem easier. You can also use a different console, if you like.
@@ -11,7 +11,7 @@ class HoneycombGenerator < Rails::Generators::Base
11
11
 
12
12
  argument :write_key, required: true, desc: "required"
13
13
 
14
- class_option :dataset, type: :string, default: "rails"
14
+ class_option :service_name, type: :string, default: "rails"
15
15
 
16
16
  gem "honeycomb-beeline"
17
17
 
@@ -22,7 +22,7 @@ class HoneycombGenerator < Rails::Generators::Base
22
22
  <<-RUBY.strip_heredoc
23
23
  Honeycomb.configure do |config|
24
24
  config.write_key = #{write_key.inspect}
25
- config.dataset = #{options['dataset'].inspect}
25
+ config.service_name = #{options['service_name'].inspect}
26
26
  config.presend_hook do |fields|
27
27
  if fields["name"] == "redis" && fields.has_key?("redis.command")
28
28
  # remove potential PII from the redis command
@@ -3,7 +3,7 @@
3
3
  module Honeycomb
4
4
  module Beeline
5
5
  NAME = "honeycomb-beeline".freeze
6
- VERSION = "2.8.2".freeze
6
+ VERSION = "2.11.0".freeze
7
7
  USER_AGENT_SUFFIX = "#{NAME}/#{VERSION}".freeze
8
8
  end
9
9
  end
@@ -30,8 +30,11 @@ module Honeycomb
30
30
 
31
31
  # maybe make `service_name` a required parameter
32
32
  @libhoney.add_field "service_name", configuration.service_name
33
+ @libhoney.add_field "service.name", configuration.service_name
33
34
  @context = Context.new
34
35
 
36
+ @context.classic = classic_write_key?(configuration.write_key)
37
+
35
38
  @additional_trace_options = {
36
39
  presend_hook: configuration.presend_hook,
37
40
  sample_hook: configuration.sample_hook,
@@ -125,5 +128,9 @@ module Honeycomb
125
128
  span.add_field("error_backtrace_limit", error_backtrace_limit)
126
129
  span.add_field("error_backtrace_total_length", exception.backtrace.length)
127
130
  end
131
+
132
+ def classic_write_key?(write_key)
133
+ write_key.nil? || write_key.length == 32
134
+ end
128
135
  end
129
136
  end
@@ -2,16 +2,16 @@
2
2
 
3
3
  require "socket"
4
4
  require "honeycomb/propagation/default"
5
+ require "honeycomb/propagation/default_modern"
5
6
 
6
7
  module Honeycomb
7
8
  # Used to configure the Honeycomb client
8
9
  class Configuration
9
10
  attr_accessor :write_key,
10
- :dataset,
11
11
  :api_host,
12
12
  :debug
13
13
 
14
- attr_writer :service_name, :client, :host_name
14
+ attr_writer :service_name, :client, :host_name, :dataset
15
15
  attr_reader :error_backtrace_limit
16
16
 
17
17
  def initialize
@@ -23,8 +23,31 @@ module Honeycomb
23
23
  @client = nil
24
24
  end
25
25
 
26
+ def classic?
27
+ @write_key.nil? || @write_key.length == 32
28
+ end
29
+
26
30
  def service_name
27
- @service_name || dataset
31
+ return @service_name if service_name_given?
32
+ return @dataset if classic?
33
+
34
+ "unknown_service:" + $PROGRAM_NAME.split("/").last
35
+ end
36
+
37
+ def dataset
38
+ return @dataset if classic?
39
+ return "unknown_service" if service_name.nil?
40
+
41
+ stripped_service_name = service_name.strip
42
+
43
+ warn("found extra whitespace in service name") if stripped_service_name != service_name
44
+
45
+ if stripped_service_name.empty? || stripped_service_name.start_with?("unknown_service")
46
+ # don't use process name in dataset
47
+ "unknown_service"
48
+ else
49
+ stripped_service_name
50
+ end
28
51
  end
29
52
 
30
53
  def error_backtrace_limit=(val)
@@ -39,6 +62,7 @@ module Honeycomb
39
62
  if debug
40
63
  Libhoney::LogClient.new
41
64
  else
65
+ validate_options
42
66
  Libhoney::Client.new(**libhoney_client_options)
43
67
  end
44
68
  end
@@ -73,9 +97,11 @@ module Honeycomb
73
97
  @http_trace_parser_hook = hook
74
98
  elsif @http_trace_parser_hook
75
99
  @http_trace_parser_hook
100
+ elsif classic?
101
+ DefaultPropagation::UnmarshalTraceContext.method(:parse_rack_env)
76
102
  else
77
103
  # by default we try to parse incoming honeycomb traces
78
- DefaultPropagation::UnmarshalTraceContext.method(:parse_rack_env)
104
+ DefaultModernPropagation::UnmarshalTraceContext.method(:parse_rack_env)
79
105
  end
80
106
  end
81
107
 
@@ -84,9 +110,11 @@ module Honeycomb
84
110
  @http_trace_propagation_hook = hook
85
111
  elsif @http_trace_propagation_hook
86
112
  @http_trace_propagation_hook
113
+ elsif classic?
114
+ HoneycombPropagation::MarshalTraceContext.method(:parse_faraday_env)
87
115
  else
88
116
  # by default we send outgoing honeycomb trace headers
89
- HoneycombPropagation::MarshalTraceContext.method(:parse_faraday_env)
117
+ HoneycombModernPropagation::MarshalTraceContext.method(:parse_faraday_env)
90
118
  end
91
119
  end
92
120
 
@@ -102,5 +130,31 @@ module Honeycomb
102
130
  options[:api_host] = api_host if api_host
103
131
  end
104
132
  end
133
+
134
+ def validate_options
135
+ warn("missing write_key") if write_key.nil? || write_key.empty?
136
+ if classic?
137
+ validate_options_classic
138
+ else
139
+ warn("service_name is unknown, will set to " + service_name) \
140
+ if service_name.start_with?("unknown_service")
141
+ warn("dataset will be ignored, sending data to " + service_name) \
142
+ if dataset_given?
143
+ end
144
+ end
145
+
146
+ def validate_options_classic
147
+ warn("empty service_name option") unless service_name_given?
148
+ warn("empty dataset option") unless dataset_given?
149
+ end
150
+
151
+ def service_name_given?
152
+ # check the instance variables, not the accessor method
153
+ @service_name && !@service_name.empty?
154
+ end
155
+
156
+ def dataset_given?
157
+ @dataset && !@dataset.empty?
158
+ end
105
159
  end
106
160
  end
@@ -3,6 +3,7 @@
3
3
  module Honeycomb
4
4
  # Stores the current span and trace context
5
5
  class Context
6
+ attr_writer :classic
6
7
  def current_trace
7
8
  return if current_span.nil?
8
9
 
@@ -23,6 +24,10 @@ module Honeycomb
23
24
  spans.pop
24
25
  end
25
26
 
27
+ def classic?
28
+ @classic
29
+ end
30
+
26
31
  private
27
32
 
28
33
  def spans
@@ -22,6 +22,7 @@ module Honeycomb
22
22
  ["CONTENT_TYPE", "request.header.content_type"],
23
23
  ["HTTP_USER_AGENT", "request.header.user_agent"],
24
24
  ["rack.url_scheme", "request.scheme"],
25
+ ["HTTP_REFERER", "request.header.referer"],
25
26
  ].freeze
26
27
 
27
28
  attr_reader :app, :client
@@ -22,7 +22,11 @@ module Honeycomb
22
22
  end
23
23
  end
24
24
 
25
+ attr_writer :honeycomb_client
26
+
25
27
  def honeycomb_client
28
+ return @honeycomb_client if defined?(@honeycomb_client)
29
+
26
30
  application.honeycomb_client
27
31
  end
28
32
  end
@@ -35,7 +39,9 @@ module Honeycomb
35
39
  attr_writer :honeycomb_client
36
40
 
37
41
  def honeycomb_client
38
- @honeycomb_client || Honeycomb.client
42
+ return @honeycomb_client if defined?(@honeycomb_client)
43
+
44
+ Honeycomb.client
39
45
  end
40
46
  end
41
47
  end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "honeycomb/propagation/honeycomb_modern"
4
+ require "honeycomb/propagation/w3c"
5
+
6
+ module Honeycomb
7
+ # Default behavior for handling trace propagation
8
+ module DefaultModernPropagation
9
+ # Parse incoming trace headers.
10
+ #
11
+ # Checks for and parses Honeycomb's trace header or, if not found,
12
+ # then checks for and parses W3C trace parent header.
13
+ module UnmarshalTraceContext
14
+ def parse_rack_env(env)
15
+ if env["HTTP_X_HONEYCOMB_TRACE"]
16
+ HoneycombModernPropagation::UnmarshalTraceContext.parse_rack_env env
17
+ elsif env["HTTP_TRACEPARENT"]
18
+ W3CPropagation::UnmarshalTraceContext.parse_rack_env env
19
+ else
20
+ [nil, nil, nil, nil]
21
+ end
22
+ end
23
+ # rubocop:disable Style/AccessModifierDeclarations
24
+ module_function :parse_rack_env
25
+ public :parse_rack_env
26
+ # rubocop:enable Style/AccessModifierDeclarations
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,89 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "base64"
4
+ require "json"
5
+ require "uri"
6
+
7
+ module Honeycomb
8
+ # Parsing and propagation for honeycomb trace headers
9
+ module HoneycombModernPropagation
10
+ # Parse trace headers
11
+ module UnmarshalTraceContext
12
+ def parse_rack_env(env)
13
+ parse env["HTTP_X_HONEYCOMB_TRACE"]
14
+ end
15
+
16
+ def parse(serialized_trace)
17
+ unless serialized_trace.nil?
18
+ version, payload = serialized_trace.split(";", 2)
19
+
20
+ if version == "1"
21
+ trace_id, parent_span_id, trace_fields = parse_v1(payload)
22
+
23
+ if !trace_id.nil? && !parent_span_id.nil?
24
+ return [trace_id, parent_span_id, trace_fields, nil]
25
+ end
26
+ end
27
+ end
28
+
29
+ [nil, nil, nil, nil]
30
+ end
31
+
32
+ def parse_v1(payload)
33
+ trace_id, parent_span_id, trace_fields = nil
34
+ payload.split(",").each do |entry|
35
+ key, value = entry.split("=", 2)
36
+ case key.downcase
37
+ when "trace_id"
38
+ trace_id = value
39
+ when "parent_id"
40
+ parent_span_id = value
41
+ when "context"
42
+ Base64.decode64(value).tap do |json|
43
+ begin
44
+ trace_fields = JSON.parse json
45
+ rescue JSON::ParserError
46
+ trace_fields = {}
47
+ end
48
+ end
49
+ end
50
+ end
51
+
52
+ [trace_id, parent_span_id, trace_fields, nil]
53
+ end
54
+
55
+ module_function :parse_rack_env, :parse, :parse_v1
56
+ public :parse_rack_env, :parse
57
+ end
58
+
59
+ # Serialize trace headers
60
+ module MarshalTraceContext
61
+ def to_trace_header
62
+ context = Base64.urlsafe_encode64(JSON.generate(trace.fields)).strip
63
+ data_to_propogate = [
64
+ "trace_id=#{trace.id}",
65
+ "parent_id=#{id}",
66
+ "context=#{context}",
67
+ ]
68
+ "1;#{data_to_propogate.join(',')}"
69
+ end
70
+
71
+ def self.parse_faraday_env(_env, propagation_context)
72
+ {
73
+ "X-Honeycomb-Trace" => to_trace_header(propagation_context),
74
+ }
75
+ end
76
+
77
+ def self.to_trace_header(propagation_context)
78
+ fields = propagation_context.trace_fields
79
+ context = Base64.urlsafe_encode64(JSON.generate(fields)).strip
80
+ data_to_propogate = [
81
+ "trace_id=#{propagation_context.trace_id}",
82
+ "parent_id=#{propagation_context.parent_id}",
83
+ "context=#{context}",
84
+ ]
85
+ "1;#{data_to_propogate.join(',')}"
86
+ end
87
+ end
88
+ end
89
+ end
@@ -31,12 +31,8 @@ module Honeycomb
31
31
  def parse_v1(payload)
32
32
  trace_id, parent_span_id, trace_flags = payload.split("-", 3)
33
33
 
34
- if trace_flags.nil?
35
- # if trace_flags is nil, it means a field is missing
36
- return [nil, nil]
37
- end
38
-
39
- if trace_id == INVALID_TRACE_ID || parent_span_id == INVALID_SPAN_ID
34
+ # if trace_flags is nil, it means a field is missing
35
+ if trace_flags.nil? || trace_id == INVALID_TRACE_ID || parent_span_id == INVALID_SPAN_ID
40
36
  return [nil, nil]
41
37
  end
42
38
 
@@ -50,6 +50,7 @@ module Honeycomb
50
50
  # compatability
51
51
  @parent_id = parent_id
52
52
  @is_root = is_root
53
+ @is_leaf = true
53
54
  end
54
55
 
55
56
  def parse_hooks(sample_hook: nil,
@@ -71,6 +72,7 @@ module Honeycomb
71
72
  presend_hook: presend_hook,
72
73
  propagation_hook: propagation_hook).tap do |c|
73
74
  children << c
75
+ @is_leaf = false
74
76
  end
75
77
  end
76
78
 
@@ -132,6 +134,10 @@ module Honeycomb
132
134
  @is_root
133
135
  end
134
136
 
137
+ def leaf?
138
+ @is_leaf
139
+ end
140
+
135
141
  def send_internal
136
142
  add_additional_fields
137
143
  send_children
@@ -180,7 +186,7 @@ module Honeycomb
180
186
  def span_type
181
187
  if root?
182
188
  parent_id.nil? ? "root" : "subroot"
183
- elsif children.empty?
189
+ elsif leaf?
184
190
  "leaf"
185
191
  else
186
192
  "mid"
@@ -9,7 +9,6 @@ require "honeycomb/rollup_fields"
9
9
  module Honeycomb
10
10
  # Represents a Honeycomb trace, which groups spans together
11
11
  class Trace
12
- include PropagationParser
13
12
  include RollupFields
14
13
  extend Forwardable
15
14
 
@@ -19,9 +18,14 @@ module Honeycomb
19
18
 
20
19
  def initialize(builder:, context:, serialized_trace: nil, **options)
21
20
  trace_id, parent_span_id, trace_fields, dataset =
22
- internal_parse(serialized_trace: serialized_trace, **options)
21
+ internal_parse(context: context, serialized_trace: serialized_trace, **options)
22
+
23
+ # if dataset is not nil,
24
+ # set trace's builder.dataset = dataset from trace header
25
+ if context.classic?
26
+ dataset && builder.dataset = dataset
27
+ end
23
28
 
24
- dataset && builder.dataset = dataset
25
29
  @id = trace_id || generate_trace_id
26
30
  @fields = trace_fields || {}
27
31
  @root_span = Span.new(trace: self,
@@ -47,15 +51,17 @@ module Honeycomb
47
51
  end
48
52
  end
49
53
 
50
- def internal_parse(serialized_trace: nil, parser_hook: nil, **_options)
54
+ def internal_parse(context:, serialized_trace: nil, parser_hook: nil, **_options)
51
55
  # previously we passed in the header directly as a string for us to parse
52
56
  # now we get passed the rack env to use as an argument to the provided
53
57
  # parser_hook. This preserves the current behaviour and allows us to
54
58
  # move forward with the new behaviour without breaking changes
55
59
  if serialized_trace.is_a?(Hash) && parser_hook
56
60
  parser_hook.call(serialized_trace)
61
+ elsif context.classic?
62
+ HoneycombPropagation::UnmarshalTraceContext.parse serialized_trace
57
63
  else
58
- parse serialized_trace
64
+ HoneycombModernPropagation::UnmarshalTraceContext.parse serialized_trace
59
65
  end
60
66
  end
61
67
  end
@@ -25,7 +25,7 @@ module Honeycomb
25
25
  extend Forwardable
26
26
  attr_reader :client
27
27
 
28
- def_delegators :@client, :libhoney, :start_span, :add_field,
28
+ def_delegators :client, :libhoney, :start_span, :add_field,
29
29
  :add_field_to_trace, :current_span, :current_trace,
30
30
  :with_field, :with_trace_field
31
31
 
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: 2.8.2
4
+ version: 2.11.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Martin Holman
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-02-02 00:00:00.000000000 Z
11
+ date: 2022-06-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: libhoney
@@ -288,7 +288,9 @@ files:
288
288
  - lib/honeycomb/propagation/aws.rb
289
289
  - lib/honeycomb/propagation/context.rb
290
290
  - lib/honeycomb/propagation/default.rb
291
+ - lib/honeycomb/propagation/default_modern.rb
291
292
  - lib/honeycomb/propagation/honeycomb.rb
293
+ - lib/honeycomb/propagation/honeycomb_modern.rb
292
294
  - lib/honeycomb/propagation/w3c.rb
293
295
  - lib/honeycomb/rollup_fields.rb
294
296
  - lib/honeycomb/span.rb