honeycomb-beeline 2.8.2 → 2.9.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: 2dd1c8587f1aaa8ca239aa4a526f1be4aea49814f3c92134a9dd59ecdb79f4dc
4
+ data.tar.gz: cc1e21f4d0e2d5e65d58502196fd74eb862d5890b577f789875b4427c66c2d0f
5
5
  SHA512:
6
- metadata.gz: dee1ffab32296f88e2f2fff6a53045e390f9dc7cd12a37dc016ed3d3555e022f90de689ce980293ef0b8080dab2ece6fab61056addbe0802a80bc3d0e53918d9
7
- data.tar.gz: 7ccccb62ef9ef6b9f93fa9e9aa2178dd028239614955e12409a66e06be9c01579ded06ae6c8a995bb1aaec37a947d24f66ac0a19ea92073eef77eb02b73c63a5
6
+ metadata.gz: 53765870c5c3d5b2eda2992e472f270412548a0f5f71e5ed36fa005129d9ae831bbb1ad19903797c558909fc9d2e93e42002d0d15fba05756fa4a785064f1eb9
7
+ data.tar.gz: c3be19aed350b937ff3ec4d9789861f609afc490f16670c370d9a60f263eea4759198ce4a93ec3802cd42948abc87745f1a8b06cd0c56c4f1fcfe8b6a25a31a4
data/.rubocop.yml CHANGED
@@ -26,6 +26,7 @@ Metrics/MethodLength:
26
26
  - lib/generators/honeycomb/honeycomb_generator.rb
27
27
 
28
28
  Metrics/LineLength:
29
+ Max: 100
29
30
  Exclude:
30
31
  - spec/honeycomb/integrations/active_support_spec.rb
31
32
  - spec/support/event_data_shared_examples.rb
@@ -71,3 +72,6 @@ Style/AsciiComments:
71
72
 
72
73
  Style/Alias:
73
74
  EnforcedStyle: prefer_alias_method
75
+
76
+ Style/IfUnlessModifier:
77
+ Enabled: false
data/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # beeline-ruby changelog
2
2
 
3
+ ## 2.9.0 2022-03-23
4
+
5
+ ### Enhancements
6
+
7
+ - Add Environment and Services support (#196) | [@MikeGoldsmith](https://github.com/MikeGoldsmith)
8
+
3
9
  ## 2.8.2 2022-02-02
4
10
 
5
11
  ### Maintenance
@@ -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.9.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
@@ -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
 
@@ -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
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.9.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-03-24 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