lightstep 0.13.0 → 0.17.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: 412b678787b505c5c97155f3d702adf01e8ebd60254fb793a07e8ae4da2cd7fa
4
- data.tar.gz: bdd33820334d2306ce78b7e84928e4be5193211d0c359bba02b4032ed3c6fc42
3
+ metadata.gz: '0851600222a0920c097ddd71156bf77dbc9cc36858bc8335c8700b86e66c8b53'
4
+ data.tar.gz: 2b4d578ac10f3a5663fe687e3e3ff867d694e05b6bf436c32d7f3ed47bbbc069
5
5
  SHA512:
6
- metadata.gz: 8d1395123221d74ce722e748dc21951f8462103dd505edc42f3f04c32f3f9eed524358a684085cb8ba55acd35dc3909102447cb0133700f8b91016687bf0ba00
7
- data.tar.gz: 597593ee87d988b10f9c79fc80ddfa5e4b3f05290e5033873aeb1e7655d6562dacb5f81410a3d0db62d2a418958e9165557e17f062f188db4602c2e3c09a0b44
6
+ metadata.gz: 29ee1f57af4d7237db8f9b1dbceaba0e9d2b5769246a839a6c9ec1140aaae82b0b8ddcad55a13474f12192ed6980aa42f8e7a36ba051115469b1c4f2cd634249
7
+ data.tar.gz: 4dcbc11a5652ace492498b0889db92f790b90d80ad88d3e3ed94b0f6a102941fdc4c8cc10d82d0c2c7d5546f63f8c643ce78cf6287c7fb39c746ce42dbf16471
@@ -1,31 +1,40 @@
1
1
  version: 2
2
2
 
3
3
  jobs:
4
- test:
4
+ test-ruby-24:
5
+ docker:
6
+ - image: circleci/ruby:2.4-stretch
7
+ steps:
8
+ - checkout
9
+ - run: gem install --no-document bundler && bundle install --jobs=3 --retry=3
10
+ - run: bundle exec rake
11
+ test-ruby-25:
5
12
  docker:
6
- - image: circleci/ruby:2
13
+ - image: circleci/ruby:2.5-stretch
7
14
  steps:
8
15
  - checkout
9
- - restore_cache:
10
- keys:
11
- - gem-cache-v2-{{ .Branch }}-{{ checksum "Gemfile.lock" }}
12
- - gem-cache-v2-{{ .Branch }}-
13
- - gem-cache-v2-
14
- - run:
15
- name: "set up environment"
16
- command: |
17
- echo 'export BUNDLE_PATH="$HOME/project/.bundler_cache"' >> $BASH_ENV
18
- source $BASH_ENV
19
- - run: bundle
20
- - save_cache:
21
- paths:
22
- - ~/project/.bundler_cache
23
- key: gem-cache-v2-{{ .Branch }}-{{ checksum "Gemfile.lock" }}
24
- - run: make test
16
+ - run: gem install --no-document bundler && bundle install --jobs=3 --retry=3
17
+ - run: bundle exec rake
18
+ test-ruby-26:
19
+ docker:
20
+ - image: circleci/ruby:2.6-stretch
21
+ steps:
22
+ - checkout
23
+ - run: gem install --no-document bundler && bundle install --jobs=3 --retry=3
24
+ - run: bundle exec rake
25
+ test-ruby-30:
26
+ docker:
27
+ - image: circleci/ruby:3.0
28
+ steps:
29
+ - checkout
30
+ - run: gem install --no-document bundler && bundle install --jobs=3 --retry=3
31
+ - run: bundle exec rake
25
32
 
26
33
  workflows:
27
34
  version: 2
28
35
  test:
29
36
  jobs:
30
- - test
31
-
37
+ - test-ruby-24
38
+ - test-ruby-25
39
+ - test-ruby-26
40
+ - test-ruby-30
data/.gitignore CHANGED
@@ -9,3 +9,4 @@ coverage/
9
9
  *~
10
10
  lightstep-tracer*.gem
11
11
  lightstep*.gem
12
+ .idea/
@@ -0,0 +1,51 @@
1
+ # Changelog
2
+ All notable changes to this project will be documented in this file.
3
+
4
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
5
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
+
7
+ ## [Unreleased]
8
+
9
+ ## v0.17.0
10
+ ### Changed
11
+ - Add support for Ruby 3.0 ([#99](https://github.com/lightstep/lightstep-tracer-ruby/pull/99))
12
+
13
+ ## v0.16.1
14
+ ### Changed
15
+ - Bump json from 2.2.0 to 2.5.1 ([#98](https://github.com/lightstep/lightstep-tracer-ruby/pull/98))
16
+ - Bump rack from 2.0.7 to 2.2.3 ([#95](https://github.com/lightstep/lightstep-tracer-ruby/pull/98))
17
+ - Update rake requirement from ~> 11.3 to ~> 13.0 ([#94](https://github.com/lightstep/lightstep-tracer-ruby/pull/98))
18
+
19
+ ## v0.16.0
20
+ ### Added
21
+ - The tracer now supports B3 context propagation. Propagation can be set by using the `propagator` keyword argument to `LightStep.configure`. Valid values are `:lightstep` (default), and `:b3`.
22
+
23
+ ## v0.15.1
24
+ ### Fixed
25
+ - The tracer now closes the active scope or finishes the active span even if an error is raised from the yielded code.
26
+
27
+ ### Unreleased
28
+ - In-progress B3 support
29
+
30
+ ## v0.15.0
31
+ ### Added
32
+ - A Changelog
33
+ - Now supports Span#log_kv
34
+ - Updated to opentracing-ruby 0.5.0
35
+ - Now delegates Lightstep#active_span to the tracer
36
+ - Now supports passing a block to #start_span
37
+ - The block forms of #start_span and #start active_span now return the result of executing the block
38
+
39
+ ### Changed
40
+ - Tracer#extract now supports symbols in carrier
41
+
42
+ ### Deprecated
43
+ - Span#log (reflecting deprecation in opentracing 0.4.0)
44
+
45
+ ### Removed
46
+
47
+ ### Fixed
48
+ - Fix handling of non-string tag values in `start_span`.
49
+
50
+ ### Security
51
+
@@ -0,0 +1,58 @@
1
+ # LightStep Community Contributing Guide
2
+
3
+ First, 🎉 **thanks for contributing!** 🎉
4
+
5
+ ## Issues
6
+
7
+ You're encouraged to log issues for any questions or problems you might have. When in doubt, log an issue. The exception to this rule is [security disclosures](#reporting-security-issues).
8
+
9
+ Generally speaking, the more context you can provide, the better. Please add information such as what **version** you're using, **stack traces** and/or **logs** (to the extent that you're able to share them), and whatever else you think may be relevant. Project maintainers may ask for additional clarification, logs, and other pertinent metadata before we can address your issue.
10
+
11
+ For bug submission, we especially appreciate **details on how to reproduce the bug** to the extent you're able to provide them, e.g., an isolated repo or [gist](https://gist.github.com).
12
+
13
+ ### Reporting Security Issues
14
+
15
+ If you find a security issue, please **do not** file a public issue for it. Instead, send your report to us privately at [security@lightstep.com](mailto:security@lightstep.com).
16
+
17
+ ## Contributions
18
+
19
+ All contributions big and small are welcome, from typo corrections to bug fixes to suggested improvements!
20
+
21
+ Any changes to project resources in this repository must be made through a pull request. This includes, but is not limited to, changes affecting:
22
+
23
+ - Documentation
24
+ - Source code
25
+ - Binaries
26
+ - Sample projects or other examples
27
+
28
+ No pull request can be merged without at least one review from a maintainer.
29
+
30
+ By default, contributions are accepted once no committers object to the PR. Specific contributors may be suggested or required to review a pull request based on repository settings.
31
+
32
+ In the event of objections or disagreement, everyone involved should seek to arrive at a consensus around the expressed objections. These can take the form of addressing concerns through changes, compromising around the change, or withdrawing it entirely.
33
+
34
+ ## Development
35
+
36
+ ### Testing
37
+
38
+ To run the tests:
39
+
40
+ ```
41
+ make test
42
+ ```
43
+
44
+ ## Submitting a Pull Request
45
+
46
+ _Note that this section should be treated as a general guideline and replaced with language/repo specific instructions_
47
+
48
+ 1. [Fork the repository.](https://help.github.com/en/github/getting-started-with-github/fork-a-repo)
49
+ 1. Create a new branch.
50
+ 1. Add tests for your change.
51
+ 1. [Run the tests](#testing) to make sure that they don't already pass. If they do (and you're not backfilling test coverage), please modify them.
52
+ 1. Implement the change such that your new tests pass.
53
+ 1. [Commit and push your changes.](https://guides.github.com/introduction/flow/)
54
+ 1. [Submit your pull request.](https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/about-pull-requests)
55
+ 1. Adjust your pull request based on feedback.
56
+ 1. Get it merged! 🎉
57
+
58
+ We're happy to help with any questions you may have on the git or GitHub side, e.g., how to push a branch to your fork. Just create an issue and we'll try to help answer them :)
@@ -1,40 +1,41 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- lightstep (0.13.0)
4
+ lightstep (0.17.0)
5
5
  concurrent-ruby (~> 1.0)
6
- opentracing (~> 0.4.1)
6
+ opentracing (~> 0.5.0)
7
7
 
8
8
  GEM
9
9
  remote: https://rubygems.org/
10
10
  specs:
11
11
  bump (0.6.1)
12
- concurrent-ruby (1.0.5)
12
+ concurrent-ruby (1.1.8)
13
13
  diff-lcs (1.3)
14
- docile (1.3.1)
15
- json (2.1.0)
16
- opentracing (0.4.1)
17
- rack (2.0.5)
18
- rake (11.3.0)
19
- rspec (3.7.0)
20
- rspec-core (~> 3.7.0)
21
- rspec-expectations (~> 3.7.0)
22
- rspec-mocks (~> 3.7.0)
23
- rspec-core (3.7.1)
24
- rspec-support (~> 3.7.0)
25
- rspec-expectations (3.7.0)
14
+ docile (1.3.2)
15
+ json (2.5.1)
16
+ opentracing (0.5.0)
17
+ rack (2.2.3)
18
+ rake (13.0.1)
19
+ rspec (3.8.0)
20
+ rspec-core (~> 3.8.0)
21
+ rspec-expectations (~> 3.8.0)
22
+ rspec-mocks (~> 3.8.0)
23
+ rspec-core (3.8.2)
24
+ rspec-support (~> 3.8.0)
25
+ rspec-expectations (3.8.4)
26
26
  diff-lcs (>= 1.2.0, < 2.0)
27
- rspec-support (~> 3.7.0)
28
- rspec-mocks (3.7.0)
27
+ rspec-support (~> 3.8.0)
28
+ rspec-mocks (3.8.1)
29
29
  diff-lcs (>= 1.2.0, < 2.0)
30
- rspec-support (~> 3.7.0)
31
- rspec-support (3.7.1)
32
- simplecov (0.16.1)
30
+ rspec-support (~> 3.8.0)
31
+ rspec-support (3.8.2)
32
+ simplecov (0.17.0)
33
33
  docile (~> 1.1)
34
34
  json (>= 1.8, < 3)
35
35
  simplecov-html (~> 0.10.0)
36
36
  simplecov-html (0.10.2)
37
37
  timecop (0.8.1)
38
+ webrick (1.7.0)
38
39
 
39
40
  PLATFORMS
40
41
  ruby
@@ -43,10 +44,11 @@ DEPENDENCIES
43
44
  bump (~> 0.5)
44
45
  lightstep!
45
46
  rack (~> 2.0)
46
- rake (~> 11.3)
47
+ rake (~> 13.0)
47
48
  rspec (~> 3.0)
48
49
  simplecov (~> 0.16)
49
50
  timecop (~> 0.8.0)
51
+ webrick (~> 1.7)
50
52
 
51
53
  BUNDLED WITH
52
- 1.16.6
54
+ 2.2.3
data/Makefile CHANGED
@@ -14,10 +14,10 @@ benchmark:
14
14
  ruby benchmark/threading/thread_test.rb
15
15
 
16
16
  bump-version:
17
- # ruby -e 'require "bump"; Bump::Bump.run("patch")'
17
+ ruby -e 'require "bump"; Bump::Bump.run("$(RELEASE_TYPE)")'
18
18
  make build # rebuild after version increment
19
19
  git tag `ruby scripts/version.rb`
20
- # git push
20
+ git push
21
21
  git push --tags
22
22
 
23
23
  publish: build test benchmark bump-version
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # lightstep-tracer-ruby
2
2
 
3
- [![Gem Version](https://badge.fury.io/rb/lightstep-tracer.svg)](https://badge.fury.io/rb/lightstep-tracer) [![Circle CI](https://circleci.com/gh/lightstep/lightstep-tracer-ruby.svg?style=shield)](https://circleci.com/gh/lightstep/lightstep-tracer-ruby) [![MIT license](http://img.shields.io/badge/license-MIT-blue.svg)](http://opensource.org/licenses/MIT) [![Code Climate](https://codeclimate.com/github/lightstep/lightstep-tracer-ruby/badges/gpa.svg)](https://codeclimate.com/github/lightstep/lightstep-tracer-ruby)
3
+ [![Gem Version](https://badge.fury.io/rb/lightstep.svg)](https://badge.fury.io/rb/lightstep) [![Circle CI](https://circleci.com/gh/lightstep/lightstep-tracer-ruby.svg?style=shield)](https://circleci.com/gh/lightstep/lightstep-tracer-ruby) [![MIT license](http://img.shields.io/badge/license-MIT-blue.svg)](http://opensource.org/licenses/MIT) [![Code Climate](https://codeclimate.com/github/lightstep/lightstep-tracer-ruby/badges/gpa.svg)](https://codeclimate.com/github/lightstep/lightstep-tracer-ruby)
4
4
 
5
5
  The LightStep distributed tracing library for Ruby.
6
6
 
@@ -27,6 +27,9 @@ Or install it yourself as:
27
27
  # Initialize the singleton tracer
28
28
  LightStep.configure(component_name: 'lightstep/ruby/example', access_token: 'your_access_token')
29
29
 
30
+ # Specify a propagation format (options are :lightstep (default) and :b3)
31
+ LightStep.configure(component_name: 'lightstep/ruby/example', access_token: 'your_access_token', propagator: :b3)
32
+
30
33
  # Create a basic span and attach a log to the span
31
34
  span = LightStep.start_span('my_span')
32
35
  span.log(event: 'hello world', count: 42)
@@ -15,6 +15,8 @@ module LightStep
15
15
 
16
16
  def_delegator :instance, :configure
17
17
  def_delegator :instance, :start_span
18
+ def_delegator :instance, :start_active_span
19
+ def_delegator :instance, :active_span
18
20
  def_delegator :instance, :disable
19
21
  def_delegator :instance, :enable
20
22
  def_delegator :instance, :flush
@@ -0,0 +1,25 @@
1
+ #frozen_string_literal: true
2
+
3
+ require 'lightstep/propagation/lightstep_propagator'
4
+ require 'lightstep/propagation/b3_propagator'
5
+
6
+ module LightStep
7
+ module Propagation
8
+ PROPAGATOR_MAP = {
9
+ lightstep: LightStepPropagator,
10
+ b3: B3Propagator
11
+ }
12
+
13
+ class << self
14
+ # Constructs a propagator instance from the given propagator name. If the
15
+ # name is unknown returns the LightStepPropagator as a default
16
+ #
17
+ # @param [Symbol, String] propagator_name One of :lightstep or :b3
18
+ # @return [Propagator]
19
+ def [](propagator_name)
20
+ klass = PROPAGATOR_MAP[propagator_name.to_sym] || LightStepPropagator
21
+ klass.new
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,29 @@
1
+ #frozen_string_literal: true
2
+
3
+ module LightStep
4
+ module Propagation
5
+ class B3Propagator < LightStepPropagator
6
+ CARRIER_TRACER_STATE_PREFIX = 'x-b3-'
7
+ CARRIER_SPAN_ID = 'x-b3-spanid'
8
+ CARRIER_TRACE_ID = 'x-b3-traceid'
9
+ CARRIER_SAMPLED = 'x-b3-sampled'
10
+ TRUE_VALUES = %w[1 true].freeze
11
+
12
+ private
13
+
14
+ # propagate the full 128-bit trace id if the original id was 128-bit,
15
+ # use the 64 bit id otherwise
16
+ def trace_id_from_ctx(ctx)
17
+ ctx.id_truncated? ? ctx.trace_id128 : ctx.trace_id64
18
+ end
19
+
20
+ def sampled_flag_from_ctx(ctx)
21
+ ctx.sampled? ? '1' : '0'
22
+ end
23
+
24
+ def sampled_flag_from_carrier(carrier)
25
+ TRUE_VALUES.include?(carrier[self.class::CARRIER_SAMPLED])
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,127 @@
1
+ #frozen_string_literal: true
2
+
3
+ module LightStep
4
+ module Propagation
5
+ class LightStepPropagator
6
+ CARRIER_TRACER_STATE_PREFIX = 'ot-tracer-'
7
+ CARRIER_SPAN_ID = 'ot-tracer-spanid'
8
+ CARRIER_TRACE_ID = 'ot-tracer-traceid'
9
+ CARRIER_SAMPLED = 'ot-tracer-sampled'
10
+ CARRIER_BAGGAGE_PREFIX = 'ot-baggage-'
11
+
12
+ # Inject a SpanContext into the given carrier
13
+ #
14
+ # @param spancontext [SpanContext]
15
+ # @param format [OpenTracing::FORMAT_TEXT_MAP, OpenTracing::FORMAT_BINARY]
16
+ # @param carrier [Carrier] A carrier object of the type dictated by the specified `format`
17
+ def inject(span_context, format, carrier)
18
+ case format
19
+ when OpenTracing::FORMAT_TEXT_MAP
20
+ inject_to_text_map(span_context, carrier)
21
+ when OpenTracing::FORMAT_BINARY
22
+ warn 'Binary inject format not yet implemented'
23
+ when OpenTracing::FORMAT_RACK
24
+ inject_to_rack(span_context, carrier)
25
+ else
26
+ warn 'Unknown inject format'
27
+ end
28
+ end
29
+
30
+ # Extract a SpanContext from a carrier
31
+ # @param format [OpenTracing::FORMAT_TEXT_MAP, OpenTracing::FORMAT_BINARY, OpenTracing::FORMAT_RACK]
32
+ # @param carrier [Carrier] A carrier object of the type dictated by the specified `format`
33
+ # @return [SpanContext] the extracted SpanContext or nil if none could be found
34
+ def extract(format, carrier)
35
+ case format
36
+ when OpenTracing::FORMAT_TEXT_MAP
37
+ extract_from_text_map(carrier)
38
+ when OpenTracing::FORMAT_BINARY
39
+ warn 'Binary join format not yet implemented'
40
+ nil
41
+ when OpenTracing::FORMAT_RACK
42
+ extract_from_rack(carrier)
43
+ else
44
+ warn 'Unknown join format'
45
+ nil
46
+ end
47
+ end
48
+
49
+ private
50
+
51
+ def inject_to_text_map(span_context, carrier)
52
+ if trace_id = trace_id_from_ctx(span_context)
53
+ carrier[self.class::CARRIER_TRACE_ID] = trace_id
54
+ end
55
+ carrier[self.class::CARRIER_SPAN_ID] = span_context.id
56
+ carrier[self.class::CARRIER_SAMPLED] = sampled_flag_from_ctx(span_context)
57
+
58
+ span_context.baggage.each do |key, value|
59
+ carrier[self.class::CARRIER_BAGGAGE_PREFIX + key] = value
60
+ end
61
+ end
62
+
63
+ def extract_from_text_map(carrier)
64
+ # If the carrier does not have both the span_id and trace_id key
65
+ # skip the processing and just return a normal span
66
+ if !carrier.has_key?(self.class::CARRIER_SPAN_ID) || !carrier.has_key?(self.class::CARRIER_TRACE_ID)
67
+ return nil
68
+ end
69
+
70
+ baggage = carrier.reduce({}) do |baggage, (key, value)|
71
+ if key.start_with?(self.class::CARRIER_BAGGAGE_PREFIX)
72
+ plain_key = key.to_s[self.class::CARRIER_BAGGAGE_PREFIX.length..key.to_s.length]
73
+ baggage[plain_key] = value
74
+ end
75
+ baggage
76
+ end
77
+
78
+ SpanContext.new(
79
+ id: carrier[self.class::CARRIER_SPAN_ID],
80
+ trace_id: carrier[self.class::CARRIER_TRACE_ID],
81
+ sampled: sampled_flag_from_carrier(carrier),
82
+ baggage: baggage,
83
+ )
84
+ end
85
+
86
+ def inject_to_rack(span_context, carrier)
87
+ if trace_id = trace_id_from_ctx(span_context)
88
+ carrier[self.class::CARRIER_TRACE_ID] = trace_id
89
+ end
90
+ carrier[self.class::CARRIER_SPAN_ID] = span_context.id
91
+ carrier[self.class::CARRIER_SAMPLED] = sampled_flag_from_ctx(span_context)
92
+
93
+ span_context.baggage.each do |key, value|
94
+ if key =~ /[^A-Za-z0-9\-_]/
95
+ # TODO: log the error internally
96
+ next
97
+ end
98
+ carrier[self.class::CARRIER_BAGGAGE_PREFIX + key] = value
99
+ end
100
+ end
101
+
102
+ def extract_from_rack(env)
103
+ extract_from_text_map(env.reduce({}){|memo, (raw_header, value)|
104
+ header = raw_header.to_s.gsub(/^HTTP_/, '')
105
+ header.tr!('_', '-')
106
+ header.downcase!
107
+
108
+ memo[header] = value if header.start_with?(self.class::CARRIER_TRACER_STATE_PREFIX,
109
+ self.class::CARRIER_BAGGAGE_PREFIX)
110
+ memo
111
+ })
112
+ end
113
+
114
+ def trace_id_from_ctx(ctx)
115
+ ctx.trace_id
116
+ end
117
+
118
+ def sampled_flag_from_ctx(_)
119
+ 'true'
120
+ end
121
+
122
+ def sampled_flag_from_carrier(_)
123
+ true
124
+ end
125
+ end
126
+ end
127
+ end
@@ -42,7 +42,7 @@ module LightStep
42
42
  )
43
43
 
44
44
  @tags = Concurrent::Hash.new
45
- @tags.update(tags) unless tags.nil?
45
+ @tags.update(tags.each { |k, v| tags[k] = v.to_s }) unless tags.nil?
46
46
  @log_records = Concurrent::Array.new
47
47
  @dropped_logs = Concurrent::AtomicFixnum.new
48
48
  @max_log_records = max_log_records
@@ -56,7 +56,11 @@ module LightStep
56
56
  ref = ref.context if (Span === ref)
57
57
 
58
58
  if SpanContext === ref
59
- @context = SpanContext.new(id: LightStep.guid, trace_id: ref.trace_id)
59
+ @context = SpanContext.new(
60
+ id: LightStep.guid,
61
+ trace_id: ref.trace_id,
62
+ trace_id_upper64: ref.trace_id_upper64,
63
+ sampled: ref.sampled?)
60
64
  set_baggage(ref.baggage)
61
65
  set_tag(:parent_span_guid, ref.id)
62
66
  else
@@ -83,6 +87,8 @@ module LightStep
83
87
  @context = SpanContext.new(
84
88
  id: context.id,
85
89
  trace_id: context.trace_id,
90
+ trace_id_upper64: context.trace_id_upper64,
91
+ sampled: context.sampled?,
86
92
  baggage: context.baggage.merge({key => value})
87
93
  )
88
94
  self
@@ -94,6 +100,8 @@ module LightStep
94
100
  @context = SpanContext.new(
95
101
  id: context.id,
96
102
  trace_id: context.trace_id,
103
+ trace_id_upper64: context.trace_id_upper64,
104
+ sampled: context.sampled?,
97
105
  baggage: baggage
98
106
  )
99
107
  end
@@ -105,22 +113,35 @@ module LightStep
105
113
  context.baggage[key]
106
114
  end
107
115
 
116
+ # @deprecated Use {#log_kv} instead.
108
117
  # Add a log entry to this span
109
118
  # @param event [String] event name for the log
110
119
  # @param timestamp [Time] time of the log
111
- # @param fields [Hash] Additional information to log
120
+ # @param fields [Hash{Symbol=>Object}] Additional information to log
112
121
  def log(event: nil, timestamp: Time.now, **fields)
122
+ warn 'Span#log is deprecated. Please use Span#log_kv instead.'
113
123
  return unless tracer.enabled?
114
124
 
115
125
  fields = {} if fields.nil?
116
126
  unless event.nil?
117
127
  fields[:event] = event.to_s
118
128
  end
129
+
130
+ log_kv(timestamp: timestamp, **fields)
131
+ end
132
+
133
+ # Add a log entry to this span
134
+ # @param timestamp [Time] time of the log
135
+ # @param fields [Hash{Symbol=>Object}] Additional information to log
136
+ def log_kv(timestamp: Time.now, **fields)
137
+ return unless tracer.enabled?
138
+
139
+ fields = {} if fields.nil?
119
140
  record = {
120
141
  timestamp_micros: LightStep.micros(timestamp),
121
- fields: fields.to_a.map {|key, value|
122
- {Key: key.to_s, Value: value.to_s}
123
- },
142
+ fields: fields.to_a.map do |key, value|
143
+ { Key: key.to_s, Value: value.to_s }
144
+ end
124
145
  }
125
146
 
126
147
  log_records.push(record)
@@ -1,12 +1,45 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module LightStep
2
4
  # SpanContext holds the data for a span that gets inherited to child spans
3
5
  class SpanContext
4
- attr_reader :id, :trace_id, :baggage
6
+ attr_reader :id, :trace_id, :trace_id_upper64, :sampled, :baggage
7
+ alias_method :trace_id64, :trace_id
8
+ alias_method :sampled?, :sampled
9
+
10
+ ZERO_PADDING = '0' * 16
5
11
 
6
- def initialize(id:, trace_id:, baggage: {})
12
+ def initialize(id:, trace_id:, trace_id_upper64: nil, sampled: true, baggage: {})
7
13
  @id = id.freeze
8
- @trace_id = trace_id.freeze
14
+ @trace_id = truncate_id(trace_id).freeze
15
+ @trace_id_upper64 = trace_id_upper64 || extended_bits(trace_id).freeze
16
+ @sampled = sampled
9
17
  @baggage = baggage.freeze
10
18
  end
19
+
20
+ # Lazily initializes and returns a 128-bit representation of a 64-bit trace id
21
+ def trace_id128
22
+ @trace_id128 ||= "#{trace_id_upper64 || ZERO_PADDING}#{trace_id}"
23
+ end
24
+
25
+ # Returns true if the original trace_id was 128 bits
26
+ def id_truncated?
27
+ !@trace_id_upper64.nil?
28
+ end
29
+
30
+ private
31
+
32
+ # Truncates an id to 64 bits
33
+ def truncate_id(id)
34
+ return id unless id && id.size == 32
35
+ id[16..-1]
36
+ end
37
+
38
+ # Returns the most significant 64 bits of a 128 bit id or nil if the id
39
+ # is 64 bits
40
+ def extended_bits(id)
41
+ return unless id && id.size == 32
42
+ id[0...16]
43
+ end
11
44
  end
12
45
  end
@@ -5,6 +5,7 @@ require 'opentracing'
5
5
 
6
6
  require 'lightstep/span'
7
7
  require 'lightstep/reporter'
8
+ require 'lightstep/propagation'
8
9
  require 'lightstep/transport/http_json'
9
10
  require 'lightstep/transport/nil'
10
11
  require 'lightstep/transport/callback'
@@ -14,18 +15,33 @@ module LightStep
14
15
  class Error < LightStep::Error; end
15
16
  class ConfigurationError < LightStep::Tracer::Error; end
16
17
 
18
+ DEFAULT_MAX_LOG_RECORDS = 1000
19
+ MIN_MAX_LOG_RECORDS = 1
20
+ DEFAULT_MAX_SPAN_RECORDS = 1000
21
+ MIN_MAX_SPAN_RECORDS = 1
22
+
17
23
  attr_reader :access_token, :guid
18
24
 
19
25
  # Initialize a new tracer. Either an access_token or a transport must be
20
26
  # provided. A component_name is always required.
21
27
  # @param component_name [String] Component name to use for the tracer
22
28
  # @param access_token [String] The project access token when pushing to LightStep
23
- # @param transport [LightStep::Transport] How the data should be transported
29
+ # @param transport [LightStep::Transport::Base] How the data should be transported
24
30
  # @param tags [Hash] Tracer-level tags
31
+ # @param propagator [Propagator] Symbol one of :lightstep, :b3 indicating the propagator
32
+ # to use
25
33
  # @return LightStep::Tracer
26
34
  # @raise LightStep::ConfigurationError if the group name or access token is not a valid string.
27
- def initialize(component_name:, access_token: nil, transport: nil, tags: {})
28
- configure(component_name: component_name, access_token: access_token, transport: transport, tags: tags)
35
+ def initialize(component_name:,
36
+ access_token: nil,
37
+ transport: nil,
38
+ tags: {},
39
+ propagator: :lightstep)
40
+ configure(component_name: component_name,
41
+ access_token: access_token,
42
+ transport: transport,
43
+ tags: tags,
44
+ propagator: propagator)
29
45
  end
30
46
 
31
47
  def max_log_records
@@ -83,10 +99,12 @@ module LightStep
83
99
  # References#CHILD_OF reference to the ScopeManager#active.
84
100
  # @param finish_on_close [Boolean] whether span should automatically be
85
101
  # finished when Scope#close is called
86
- # @yield [Scope] If an optional block is passed to start_active it will
102
+ # @yield [Scope] If an optional block is passed to start_active_span it will
87
103
  # yield the newly-started Scope. If `finish_on_close` is true then the
88
104
  # Span will be finished automatically after the block is executed.
89
- # @return [Scope] The newly-started and activated Scope
105
+ # @return [Scope, Object] If passed an optional block, start_active_span
106
+ # returns the block's return value, otherwise it returns the newly-started
107
+ # and activated Scope
90
108
  def start_active_span(operation_name,
91
109
  child_of: nil,
92
110
  references: nil,
@@ -109,8 +127,11 @@ module LightStep
109
127
 
110
128
  scope_manager.activate(span: span, finish_on_close: finish_on_close).tap do |scope|
111
129
  if block_given?
112
- yield scope
113
- scope.close
130
+ begin
131
+ return yield scope
132
+ ensure
133
+ scope.close
134
+ end
114
135
  end
115
136
  end
116
137
  end
@@ -138,13 +159,19 @@ module LightStep
138
159
  # @param tags [Hash] Tags to assign to the Span at start time
139
160
  # @param ignore_active_scope [Boolean] whether to create an implicit
140
161
  # References#CHILD_OF reference to the ScopeManager#active.
141
- # @return [Span]
162
+ # @yield [Span] If passed an optional block, start_span will yield the
163
+ # newly-created span to the block. The span will be finished automatically
164
+ # after the block is executed.
165
+ # @return [Span, Object] If passed an optional block, start_span will return
166
+ # the block's return value, otherwise it returns the newly-started Span
167
+ # instance, which has not been automatically registered via the
168
+ # ScopeManager
142
169
  def start_span(operation_name, child_of: nil, references: nil, start_time: nil, tags: nil, ignore_active_scope: false)
143
170
  if child_of.nil? && references.nil? && !ignore_active_scope
144
171
  child_of = active_span
145
172
  end
146
173
 
147
- Span.new(
174
+ span_options = {
148
175
  tracer: self,
149
176
  operation_name: operation_name,
150
177
  child_of: child_of,
@@ -152,25 +179,27 @@ module LightStep
152
179
  start_micros: start_time.nil? ? LightStep.micros(Time.now) : LightStep.micros(start_time),
153
180
  tags: tags,
154
181
  max_log_records: max_log_records,
155
- )
182
+ }
183
+
184
+ Span.new(**span_options).tap do |span|
185
+ if block_given?
186
+ begin
187
+ return yield span
188
+ ensure
189
+ span.finish
190
+ end
191
+ end
192
+ end
156
193
  end
157
194
 
195
+
158
196
  # Inject a SpanContext into the given carrier
159
197
  #
160
198
  # @param spancontext [SpanContext]
161
199
  # @param format [OpenTracing::FORMAT_TEXT_MAP, OpenTracing::FORMAT_BINARY]
162
200
  # @param carrier [Carrier] A carrier object of the type dictated by the specified `format`
163
201
  def inject(span_context, format, carrier)
164
- case format
165
- when OpenTracing::FORMAT_TEXT_MAP
166
- inject_to_text_map(span_context, carrier)
167
- when OpenTracing::FORMAT_BINARY
168
- warn 'Binary inject format not yet implemented'
169
- when OpenTracing::FORMAT_RACK
170
- inject_to_rack(span_context, carrier)
171
- else
172
- warn 'Unknown inject format'
173
- end
202
+ @propagator.inject(span_context, format, carrier)
174
203
  end
175
204
 
176
205
  # Extract a SpanContext from a carrier
@@ -178,18 +207,7 @@ module LightStep
178
207
  # @param carrier [Carrier] A carrier object of the type dictated by the specified `format`
179
208
  # @return [SpanContext] the extracted SpanContext or nil if none could be found
180
209
  def extract(format, carrier)
181
- case format
182
- when OpenTracing::FORMAT_TEXT_MAP
183
- extract_from_text_map(carrier)
184
- when OpenTracing::FORMAT_BINARY
185
- warn 'Binary join format not yet implemented'
186
- nil
187
- when OpenTracing::FORMAT_RACK
188
- extract_from_rack(carrier)
189
- else
190
- warn 'Unknown join format'
191
- nil
192
- end
210
+ @propagator.extract(format, carrier)
193
211
  end
194
212
 
195
213
  # @return true if the tracer is enabled
@@ -226,7 +244,11 @@ module LightStep
226
244
 
227
245
  protected
228
246
 
229
- def configure(component_name:, access_token: nil, transport: nil, tags: {})
247
+ def configure(component_name:,
248
+ access_token: nil,
249
+ transport: nil, tags: {},
250
+ propagator: :lightstep)
251
+
230
252
  raise ConfigurationError, "component_name must be a string" unless component_name.is_a?(String)
231
253
  raise ConfigurationError, "component_name cannot be blank" if component_name.empty?
232
254
 
@@ -237,6 +259,8 @@ module LightStep
237
259
  raise ConfigurationError, "you must provide an access token or a transport" if transport.nil?
238
260
  raise ConfigurationError, "#{transport} is not a LightStep transport class" if !(LightStep::Transport::Base === transport)
239
261
 
262
+ @propagator = Propagation[propagator]
263
+
240
264
  @guid = LightStep.guid
241
265
 
242
266
  @reporter = LightStep::Reporter.new(
@@ -247,75 +271,5 @@ module LightStep
247
271
  tags: tags
248
272
  )
249
273
  end
250
-
251
- private
252
-
253
- CARRIER_TRACER_STATE_PREFIX = 'ot-tracer-'.freeze
254
- CARRIER_BAGGAGE_PREFIX = 'ot-baggage-'.freeze
255
-
256
- CARRIER_SPAN_ID = (CARRIER_TRACER_STATE_PREFIX + 'spanid').freeze
257
- CARRIER_TRACE_ID = (CARRIER_TRACER_STATE_PREFIX + 'traceid').freeze
258
- CARRIER_SAMPLED = (CARRIER_TRACER_STATE_PREFIX + 'sampled').freeze
259
-
260
- DEFAULT_MAX_LOG_RECORDS = 1000
261
- MIN_MAX_LOG_RECORDS = 1
262
- DEFAULT_MAX_SPAN_RECORDS = 1000
263
- MIN_MAX_SPAN_RECORDS = 1
264
-
265
- def inject_to_text_map(span_context, carrier)
266
- carrier[CARRIER_SPAN_ID] = span_context.id
267
- carrier[CARRIER_TRACE_ID] = span_context.trace_id unless span_context.trace_id.nil?
268
- carrier[CARRIER_SAMPLED] = 'true'
269
-
270
- span_context.baggage.each do |key, value|
271
- carrier[CARRIER_BAGGAGE_PREFIX + key] = value
272
- end
273
- end
274
-
275
- def extract_from_text_map(carrier)
276
- # If the carrier does not have both the span_id and trace_id key
277
- # skip the processing and just return a normal span
278
- if !carrier.has_key?(CARRIER_SPAN_ID) || !carrier.has_key?(CARRIER_TRACE_ID)
279
- return nil
280
- end
281
-
282
- baggage = carrier.reduce({}) do |baggage, tuple|
283
- key, value = tuple
284
- if key.start_with?(CARRIER_BAGGAGE_PREFIX)
285
- plain_key = key.to_s[CARRIER_BAGGAGE_PREFIX.length..key.to_s.length]
286
- baggage[plain_key] = value
287
- end
288
- baggage
289
- end
290
- SpanContext.new(
291
- id: carrier[CARRIER_SPAN_ID],
292
- trace_id: carrier[CARRIER_TRACE_ID],
293
- baggage: baggage,
294
- )
295
- end
296
-
297
- def inject_to_rack(span_context, carrier)
298
- carrier[CARRIER_SPAN_ID] = span_context.id
299
- carrier[CARRIER_TRACE_ID] = span_context.trace_id unless span_context.trace_id.nil?
300
- carrier[CARRIER_SAMPLED] = 'true'
301
-
302
- span_context.baggage.each do |key, value|
303
- if key =~ /[^A-Za-z0-9\-_]/
304
- # TODO: log the error internally
305
- next
306
- end
307
- carrier[CARRIER_BAGGAGE_PREFIX + key] = value
308
- end
309
- end
310
-
311
- def extract_from_rack(env)
312
- extract_from_text_map(env.reduce({}){|memo, tuple|
313
- raw_header, value = tuple
314
- header = raw_header.gsub(/^HTTP_/, '').tr('_', '-').downcase
315
-
316
- memo[header] = value if header.start_with?(CARRIER_TRACER_STATE_PREFIX, CARRIER_BAGGAGE_PREFIX)
317
- memo
318
- })
319
- end
320
274
  end
321
275
  end
@@ -4,12 +4,7 @@ require 'lightstep/transport/base'
4
4
  module LightStep
5
5
  module Transport
6
6
  # HTTPJSON is a transport that sends reports via HTTP in JSON format.
7
- # It is thread-safe, however it is *not* fork-safe. When forking, all items
8
- # in the queue will be copied and sent in duplicate.
9
- #
10
- # When forking, you should first `disable` the tracer, then `enable` it from
11
- # within the fork (and in the parent post-fork). See
12
- # `examples/fork_children/main.rb` for an example.
7
+ # It is thread-safe.
13
8
  class HTTPJSON < Base
14
9
  LIGHTSTEP_HOST = 'collector.lightstep.com'.freeze
15
10
  LIGHTSTEP_PORT = 443
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module LightStep
2
- VERSION = '0.13.0'.freeze
4
+ VERSION = '0.17.0'
3
5
  end
@@ -6,7 +6,7 @@ require 'lightstep/version'
6
6
  Gem::Specification.new do |spec|
7
7
  spec.name = 'lightstep'
8
8
  spec.version = LightStep::VERSION
9
- spec.authors = ['bcronin']
9
+ spec.authors = ['lightstep']
10
10
  spec.email = ['support@lightstep.com']
11
11
 
12
12
  spec.summary = 'LightStep OpenTracing Ruby bindings'
@@ -16,10 +16,15 @@ Gem::Specification.new do |spec|
16
16
  spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
17
17
  spec.require_paths = ['lib']
18
18
 
19
+ spec.metadata = {
20
+ "changelog_uri" => "https://github.com/lightstep/lightstep-tracer-ruby/blob/master/CHANGELOG.md",
21
+ }
22
+
19
23
  spec.add_dependency 'concurrent-ruby', '~> 1.0'
20
- spec.add_dependency 'opentracing', '~> 0.4.1'
21
- spec.add_development_dependency 'rake', '~> 11.3'
24
+ spec.add_dependency 'opentracing', '~> 0.5.0'
25
+ spec.add_development_dependency 'rake', '~> 13.0'
22
26
  spec.add_development_dependency 'rack', '~> 2.0'
27
+ spec.add_development_dependency 'webrick', '~> 1.7' # for examples/
23
28
  spec.add_development_dependency 'rspec', '~> 3.0'
24
29
  spec.add_development_dependency 'bump', '~> 0.5'
25
30
  spec.add_development_dependency 'simplecov', '~> 0.16'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lightstep
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.13.0
4
+ version: 0.17.0
5
5
  platform: ruby
6
6
  authors:
7
- - bcronin
8
- autorequire:
7
+ - lightstep
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-10-18 00:00:00.000000000 Z
11
+ date: 2021-01-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: concurrent-ruby
@@ -30,28 +30,28 @@ dependencies:
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: 0.4.1
33
+ version: 0.5.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.4.1
40
+ version: 0.5.0
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: rake
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: '11.3'
47
+ version: '13.0'
48
48
  type: :development
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: '11.3'
54
+ version: '13.0'
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: rack
57
57
  requirement: !ruby/object:Gem::Requirement
@@ -66,6 +66,20 @@ dependencies:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
68
  version: '2.0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: webrick
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '1.7'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '1.7'
69
83
  - !ruby/object:Gem::Dependency
70
84
  name: rspec
71
85
  requirement: !ruby/object:Gem::Requirement
@@ -122,7 +136,7 @@ dependencies:
122
136
  - - "~>"
123
137
  - !ruby/object:Gem::Version
124
138
  version: 0.8.0
125
- description:
139
+ description:
126
140
  email:
127
141
  - support@lightstep.com
128
142
  executables: []
@@ -133,6 +147,8 @@ files:
133
147
  - ".gitignore"
134
148
  - ".rspec"
135
149
  - ".rubocop.yml"
150
+ - CHANGELOG.md
151
+ - CONTRIBUTING.md
136
152
  - Gemfile
137
153
  - Gemfile.lock
138
154
  - LICENSE.txt
@@ -144,13 +160,15 @@ files:
144
160
  - benchmark/threading/thread_test.rb
145
161
  - bin/console
146
162
  - bin/setup
147
- - circle.yml
148
163
  - example.rb
149
164
  - examples/fork_children/main.rb
150
165
  - examples/rack/hello.rb
151
166
  - examples/rack/inject_extract.rb
152
167
  - lib/lightstep.rb
153
168
  - lib/lightstep/global_tracer.rb
169
+ - lib/lightstep/propagation.rb
170
+ - lib/lightstep/propagation/b3_propagator.rb
171
+ - lib/lightstep/propagation/lightstep_propagator.rb
154
172
  - lib/lightstep/reporter.rb
155
173
  - lib/lightstep/scope.rb
156
174
  - lib/lightstep/scope_manager.rb
@@ -167,8 +185,9 @@ files:
167
185
  homepage: https://github.com/lightstep/lightstep-tracer-ruby
168
186
  licenses:
169
187
  - MIT
170
- metadata: {}
171
- post_install_message:
188
+ metadata:
189
+ changelog_uri: https://github.com/lightstep/lightstep-tracer-ruby/blob/master/CHANGELOG.md
190
+ post_install_message:
172
191
  rdoc_options: []
173
192
  require_paths:
174
193
  - lib
@@ -183,9 +202,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
183
202
  - !ruby/object:Gem::Version
184
203
  version: '0'
185
204
  requirements: []
186
- rubyforge_project:
187
- rubygems_version: 2.7.6
188
- signing_key:
205
+ rubygems_version: 3.0.3
206
+ signing_key:
189
207
  specification_version: 4
190
208
  summary: LightStep OpenTracing Ruby bindings
191
209
  test_files: []
data/circle.yml DELETED
@@ -1,3 +0,0 @@
1
- machine:
2
- ruby:
3
- version: 2.2.3