traces 0.1.0 → 0.3.2

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: af4a77480dd1e8a5f9805b47410c4cfc10736776eb3d0e240256eecdb9aef998
4
- data.tar.gz: 945a6a8c0fec8382d3c3770e011ec102c4be998df3af84d77b7cc99596a75c86
3
+ metadata.gz: 17d36e478e92a07d18262c627d9c2986004a2fe81985fd80721da6adf4d2c282
4
+ data.tar.gz: 44c0dd539bcda08a88d69478c56eeaa7eaa52f34b4bc2941510b7996d4b2bf28
5
5
  SHA512:
6
- metadata.gz: 3410ef5b66b6d647a37c44374453759dc191c3366b614093604981a57304dc5b3ff43a026207b7364886cbad43400aeb65652ee3aef6ab68694e52379018956e
7
- data.tar.gz: 73dc84b89273d731f0baa1839c8ef54d9ab292558b2ee5d99acc9c6dbf937510db3381b48a179d952faa1728c203142cff08ddd211a9960aafda05f320e5af43
6
+ metadata.gz: 5684c47004efb75753fed8f3c7d980cd72d6646c8eaa2eafc2fc001d25a96c80c7c3ad590d01fb7859544e8567c4318a29892cba70ec2fcaeefd81219ce6f34d
7
+ data.tar.gz: 8c8f7abd2de878319c61b8ffa491d8946f9fc8b782aad65911520948bc1efe4d545e10829fe0ee63b465443358ad858430429e485d3378238cd6e70e70464d06
checksums.yaml.gz.sig ADDED
@@ -0,0 +1,3 @@
1
+ )���pGRW*M��y�CS4+� x+v?�X���w
2
+ �v��Ҟ��W(��| ��5�Z��>�gpYު߇�Ǒ��%i�kk*�E���7�l>�O��.S�O8Ac S�}t�0\▩v\��b D>_K�7�N7��|�[W`4?1b��>lU��\&q� �IG���>`z~ �3t�/T�?n�BM(z�����B'P�o�O���@�8{�
3
+ �o�b5x���r{H��߰2�A�1��x/����5�n�HR���w���/*�2?�j۶F�_I�W2��ֈ�F�%�у��!�¹“�m@v���/H�ˡd�O��V�Y� ���Б�><1'��P�V��@h]Yv��I��Ҭ�k"�c9'u\���l�<[�f�-M�
@@ -20,16 +20,71 @@
20
20
  # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
21
  # THE SOFTWARE.
22
22
 
23
+ require_relative '../context'
24
+
23
25
  require 'console'
26
+ require 'fiber'
27
+
28
+ class Fiber
29
+ attr_accessor :traces_backend_context
30
+ end
24
31
 
25
32
  module Traces
26
33
  module Backend
27
- private
28
-
29
- def trace(name, parent = nil, attributes: nil, &block)
30
- Console.logger.measure(self, name, **attributes) do
31
- yield
34
+ module Console
35
+ # A span which validates tag assignment.
36
+ class Span
37
+ def initialize(context, instance, name)
38
+ @context = context
39
+ @instance = instance
40
+ @name = name
41
+ end
42
+
43
+ attr :context
44
+
45
+ # Assign some metadata to the span.
46
+ # @parameter key [String] The metadata key.
47
+ # @parameter value [Object] The metadata value. Should be coercable to a string.
48
+ def []= key, value
49
+ ::Console.logger.info(@context, @name, "#{key} = #{value}")
50
+ end
51
+ end
52
+
53
+ private
54
+
55
+ # Trace the given block of code and log the execution.
56
+ # @parameter name [String] A useful name/annotation for the recorded span.
57
+ # @parameter attributes [Hash] Metadata for the recorded span.
58
+ def trace(name, attributes: {}, &block)
59
+ context = Context.nested(Fiber.current.traces_backend_context)
60
+ Fiber.current.traces_backend_context = context
61
+
62
+ ::Console.logger.info(self, name, attributes)
63
+
64
+ if block.arity.zero?
65
+ yield
66
+ else
67
+ yield Span.new(context, self, name)
68
+ end
69
+ end
70
+
71
+ # Assign a trace context to the current execution scope.
72
+ def trace_context= context
73
+ Fiber.current.traces_backend_context = context
74
+ end
75
+
76
+ # Get a trace context from the current execution scope.
77
+ # @parameter span [Span] An optional span from which to extract the context.
78
+ def trace_context(span = nil)
79
+ if span
80
+ span.context
81
+ else
82
+ Fiber.current.traces_backend_context
83
+ end
32
84
  end
33
85
  end
86
+
87
+ # This is the default.
88
+ self.include(Console)
34
89
  end
35
90
  end
@@ -20,14 +20,75 @@
20
20
  # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
21
  # THE SOFTWARE.
22
22
 
23
- require 'console'
23
+ require_relative '../context'
24
+ require 'fiber'
25
+
26
+ class Fiber
27
+ attr_accessor :traces_backend_context
28
+ end
24
29
 
25
30
  module Traces
26
31
  module Backend
27
- private
28
-
29
- def trace(name, parent = nil, attributes: nil, &block)
30
- yield
32
+ module Test
33
+ # A span which validates tag assignment.
34
+ class Span
35
+ def initialize(context)
36
+ @context = context
37
+ end
38
+
39
+ attr :context
40
+
41
+ # Assign some metadata to the span.
42
+ # @parameter key [String] The metadata key.
43
+ # @parameter value [Object] The metadata value. Should be coercable to a string.
44
+ def []= key, value
45
+ unless key.is_a?(String)
46
+ raise ArgumentError, "Invalid name!"
47
+ end
48
+
49
+ unless String(value)
50
+ raise ArgumentError, "Invalid value!"
51
+ end
52
+ end
53
+ end
54
+
55
+ private
56
+
57
+ # Trace the given block of code and validate the interface usage.
58
+ # @parameter name [String] A useful name/annotation for the recorded span.
59
+ # @parameter attributes [Hash] Metadata for the recorded span.
60
+ def trace(name, attributes: nil, &block)
61
+ unless name.is_a?(String)
62
+ raise ArgumentError, "Invalid name!"
63
+ end
64
+
65
+ context = Context.nested(Fiber.current.traces_backend_context)
66
+ Fiber.current.traces_backend_context = context
67
+
68
+ if block.arity.zero?
69
+ yield
70
+ else
71
+ span = Span.new(context)
72
+ yield span
73
+ end
74
+ end
75
+
76
+ # Assign a trace context to the current execution scope.
77
+ def trace_context= context
78
+ Fiber.current.traces_backend_context = context
79
+ end
80
+
81
+ # Get a trace context from the current execution scope.
82
+ # @parameter span [Span] An optional span from which to extract the context.
83
+ def trace_context(span = nil)
84
+ if span
85
+ span.context
86
+ else
87
+ Fiber.current.traces_backend_context
88
+ end
89
+ end
31
90
  end
91
+
92
+ self.include(Test)
32
93
  end
33
- end
94
+ end
@@ -21,10 +21,14 @@
21
21
  # THE SOFTWARE.
22
22
 
23
23
  module Traces
24
+ # Require a specific trace backend.
24
25
  def self.require_backend(env = ENV)
26
+ if const_defined?(:Backend)
27
+ raise RuntimeError, "Backend already required!"
28
+ end
29
+
25
30
  if backend = env['TRACES_BACKEND']
26
- path = File.join('backend', backend)
27
- require_relative(path)
31
+ require(backend)
28
32
  end
29
33
  end
30
34
  end
@@ -20,15 +20,19 @@
20
20
  # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
21
  # THE SOFTWARE.
22
22
 
23
+ require 'securerandom'
24
+
23
25
  module Traces
24
- # A generic representation of the current span.
25
- # We follow the <https://github.com/openzipkin/b3-propagation> model.
26
+ # A generic representation of the current tracing context.
26
27
  class Context
27
- def self.parse(parent, state = nil)
28
+ # Parse a string representation of a distributed trace.
29
+ # @parameter parent [String] The parent trace context.
30
+ # @parameter state [Array(String)] Any attached trace state.
31
+ def self.parse(parent, state = nil, **options)
28
32
  version, trace_id, parent_id, flags = parent.split('-')
29
33
 
30
- if version = '00'
31
- flags = Integer(trace_flags, 16)
34
+ if version == '00'
35
+ flags = Integer(flags, 16)
32
36
 
33
37
  if state.is_a?(String)
34
38
  state = state.split(',')
@@ -38,7 +42,23 @@ module Traces
38
42
  state = state.map{|item| item.split('=')}
39
43
  end
40
44
 
41
- self.new(trace_id, parent_id, flags, state)
45
+ self.new(trace_id, parent_id, flags, state, **options)
46
+ end
47
+ end
48
+
49
+ # Create a local trace context which is likley to be globally unique.
50
+ # @parameter flags [Integer] Any trace context flags.
51
+ def self.local(flags = 0, **options)
52
+ self.new(SecureRandom.hex(16), SecureRandom.hex(8), flags, **options)
53
+ end
54
+
55
+ # Nest a local trace context in an optional parent context.
56
+ # @parameter parent [Context] An optional parent context.
57
+ def self.nested(parent, flags = 0)
58
+ if parent
59
+ parent.nested(flags)
60
+ else
61
+ self.local(flags)
42
62
  end
43
63
  end
44
64
 
@@ -46,25 +66,40 @@ module Traces
46
66
 
47
67
  def initialize(trace_id, parent_id, flags, state = nil, remote: false)
48
68
  @trace_id = trace_id
49
- @parent_id = span_id
69
+ @parent_id = parent_id
50
70
  @flags = flags
51
71
  @state = state
52
72
  @remote = remote
53
73
  end
54
74
 
75
+ # Create a new nested trace context in which spans can be recorded.
76
+ def nested(flags = @flags)
77
+ Context.new(@trace_id, SecureRandom.hex(8), flags, @state, remote: @remote)
78
+ end
79
+
80
+ # The ID of the whole trace forest and is used to uniquely identify a distributed trace through a system. It is represented as a 16-byte array, for example, 4bf92f3577b34da6a3ce929d0e0e4736. All bytes as zero (00000000000000000000000000000000) is considered an invalid value.
55
81
  attr :trace_id
56
- attr :span_id
82
+
83
+ # The ID of this request as known by the caller (in some tracing systems, this is known as the span-id, where a span is the execution of a client request). It is represented as an 8-byte array, for example, 00f067aa0ba902b7. All bytes as zero (0000000000000000) is considered an invalid value.
84
+ attr :parent_id
85
+
86
+ # An 8-bit field that controls tracing flags such as sampling, trace level, etc. These flags are recommendations given by the caller rather than strict rules.
57
87
  attr :flags
88
+
89
+ # Provides additional vendor-specific trace identification information across different distributed tracing systems. Conveys information about the request’s position in multiple distributed tracing graphs.
58
90
  attr :state
59
91
 
92
+ # Denotes that the caller may have recorded trace data. When unset, the caller did not record trace data out-of-band.
60
93
  def sampled?
61
94
  @flags & SAMPLED
62
95
  end
63
96
 
97
+ # Whether this context was created from a distributed trace header.
64
98
  def remote?
65
99
  @remote
66
100
  end
67
101
 
102
+ # A string representation of the trace context (excluding trace state).
68
103
  def to_s
69
104
  "00-#{@trace_id}-#{@parent_id}-#{@flags.to_s(16)}"
70
105
  end
@@ -23,19 +23,20 @@
23
23
  require_relative 'backend'
24
24
 
25
25
  module Traces
26
+ # A module which contains tracing specific wrappers.
26
27
  module Provider
27
- def trace_provider
28
- @trace_provider ||= Module.new
28
+ def traces_provider
29
+ @traces_provider ||= Module.new
29
30
  end
30
31
  end
31
32
 
32
33
  # Bail out if there is no backend configured.
33
- if Traces.const_defined?(:Backend)
34
+ if self.const_defined?(:Backend)
35
+ # Extend the specified class in order to emit traces.
34
36
  def self.Provider(klass, &block)
35
37
  klass.extend(Provider)
36
- klass.prepend(Backend)
37
38
 
38
- provider = klass.trace_provider
39
+ provider = klass.traces_provider
39
40
  provider.prepend(Backend)
40
41
 
41
42
  klass.prepend(provider)
@@ -21,5 +21,5 @@
21
21
  # THE SOFTWARE.
22
22
 
23
23
  module Traces
24
- VERSION = "0.1.0"
24
+ VERSION = "0.3.2"
25
25
  end
data.tar.gz.sig ADDED
Binary file
metadata CHANGED
@@ -1,14 +1,42 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: traces
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.3.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Samuel Williams
8
8
  autorequire:
9
9
  bindir: bin
10
- cert_chain: []
11
- date: 2021-10-09 00:00:00.000000000 Z
10
+ cert_chain:
11
+ - |
12
+ -----BEGIN CERTIFICATE-----
13
+ MIIEhDCCAuygAwIBAgIBATANBgkqhkiG9w0BAQsFADA3MTUwMwYDVQQDDCxzYW11
14
+ ZWwud2lsbGlhbXMvREM9b3Jpb250cmFuc2Zlci9EQz1jby9EQz1uejAeFw0yMTA4
15
+ MTYwNjMzNDRaFw0yMjA4MTYwNjMzNDRaMDcxNTAzBgNVBAMMLHNhbXVlbC53aWxs
16
+ aWFtcy9EQz1vcmlvbnRyYW5zZmVyL0RDPWNvL0RDPW56MIIBojANBgkqhkiG9w0B
17
+ AQEFAAOCAY8AMIIBigKCAYEAyXLSS/cw+fXJ5e7hi+U/TeChPWeYdwJojDsFY1xr
18
+ xvtqbTTL8gbLHz5LW3QD2nfwCv3qTlw0qI3Ie7a9VMJMbSvgVEGEfQirqIgJXWMj
19
+ eNMDgKsMJtC7u/43abRKx7TCURW3iWyR19NRngsJJmaR51yGGGm2Kfsr+JtKKLtL
20
+ L188Wm3f13KAx7QJU8qyuBnj1/gWem076hzdA7xi1DbrZrch9GCRz62xymJlrJHn
21
+ 9iZEZ7AxrS7vokhMlzSr/XMUihx/8aFKtk+tMLClqxZSmBWIErWdicCGTULXCBNb
22
+ E/mljo4zEVKhlTWpJklMIhr55ZRrSarKFuW7en0+tpJrfsYiAmXMJNi4XAYJH7uL
23
+ rgJuJwSaa/dMz+VmUoo7VKtSfCoOI+6v5/z0sK3oT6sG6ZwyI47DBq2XqNC6tnAj
24
+ w+XmCywiTQrFzMMAvcA7rPI4F0nU1rZId51rOvvfxaONp+wgTi4P8owZLw0/j0m4
25
+ 8C20DYi6EYx4AHDXiLpElWh3AgMBAAGjgZowgZcwCQYDVR0TBAIwADALBgNVHQ8E
26
+ BAMCBLAwHQYDVR0OBBYEFB6ZaeWKxQjGTI+pmz7cKRmMIywwMC4GA1UdEQQnMCWB
27
+ I3NhbXVlbC53aWxsaWFtc0BvcmlvbnRyYW5zZmVyLmNvLm56MC4GA1UdEgQnMCWB
28
+ I3NhbXVlbC53aWxsaWFtc0BvcmlvbnRyYW5zZmVyLmNvLm56MA0GCSqGSIb3DQEB
29
+ CwUAA4IBgQBVoM+pu3dpdUhZM1w051iw5GfiqclAr1Psypf16Tiod/ho//4oAu6T
30
+ 9fj3DPX/acWV9P/FScvqo4Qgv6g4VWO5ZU7z2JmPoTXZtYMunRAmQPFL/gSUc6aK
31
+ vszMHIyhtyzRc6DnfW2AiVOjMBjaYv8xXZc9bduniRVPrLR4J7ozmGLh4o4uJp7w
32
+ x9KCFaR8Lvn/r0oJWJOqb/DMAYI83YeN2Dlt3jpwrsmsONrtC5S3gOUle5afSGos
33
+ bYt5ocnEpKSomR9ZtnCGljds/aeO1Xgpn2r9HHcjwnH346iNrnHmMlC7BtHUFPDg
34
+ Ts92S47PTOXzwPBDsrFiq3VLbRjHSwf8rpqybQBH9MfzxGGxTaETQYOd6b4e4Ag6
35
+ y92abGna0bmIEb4+Tx9rQ10Uijh1POzvr/VTH4bbIPy9FbKrRsIQ24qDbNJRtOpE
36
+ RAOsIl+HOBTb252nx1kIRN5hqQx272AJCbCjKx8egcUQKffFVVCI0nye09v5CK+a
37
+ HiLJ8VOFx6w=
38
+ -----END CERTIFICATE-----
39
+ date: 2021-10-18 00:00:00.000000000 Z
12
40
  dependencies:
13
41
  - !ruby/object:Gem::Dependency
14
42
  name: rspec
@@ -33,13 +61,11 @@ files:
33
61
  - lib/traces.rb
34
62
  - lib/traces/backend.rb
35
63
  - lib/traces/backend/console.rb
36
- - lib/traces/backend/datadog.rb
37
- - lib/traces/backend/open_telemetry.rb
38
64
  - lib/traces/backend/test.rb
39
65
  - lib/traces/context.rb
40
66
  - lib/traces/provider.rb
41
67
  - lib/traces/version.rb
42
- homepage: https://github.com/socketry/trace
68
+ homepage: https://github.com/socketry/traces
43
69
  licenses:
44
70
  - MIT
45
71
  metadata: {}
@@ -58,7 +84,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
58
84
  - !ruby/object:Gem::Version
59
85
  version: '0'
60
86
  requirements: []
61
- rubygems_version: 3.2.22
87
+ rubygems_version: 3.1.6
62
88
  signing_key:
63
89
  specification_version: 4
64
90
  summary: Application instrumentation and tracing.
metadata.gz.sig ADDED
Binary file
@@ -1,70 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # Copyright, 2021, by Samuel G. D. Williams. <http://www.codeotaku.com>
4
- #
5
- # Permission is hereby granted, free of charge, to any person obtaining a copy
6
- # of this software and associated documentation files (the "Software"), to deal
7
- # in the Software without restriction, including without limitation the rights
8
- # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- # copies of the Software, and to permit persons to whom the Software is
10
- # furnished to do so, subject to the following conditions:
11
- #
12
- # The above copyright notice and this permission notice shall be included in
13
- # all copies or substantial portions of the Software.
14
- #
15
- # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
- # THE SOFTWARE.
22
-
23
- require_relative '../context'
24
-
25
- require 'ddtrace'
26
-
27
- module Traces
28
- module Backend
29
- private
30
-
31
- def trace(name, parent = nil, attributes: nil, &block)
32
- if parent
33
- parent = ::Datadog::Context.new(
34
- trace_id: parent.trace_id,
35
- span_id: parent.span_id,
36
- sampled: parent.sampled?,
37
- )
38
- end
39
-
40
- ::Datadog.tracer.trace(name, child_of: parent, tags: attributes) do |span|
41
- begin
42
- if block.arity.zero?
43
- yield
44
- else
45
- yield trace_span_context(span)
46
- end
47
- rescue Exception => error
48
- Console.logger.error(self, error)
49
- raise
50
- end
51
- end
52
- end
53
-
54
- def trace_span_context(span)
55
- flags = 0
56
-
57
- if span.sampled
58
- flags |= Context::SAMPLED
59
- end
60
-
61
- return Context.new(
62
- span.trace_id,
63
- span.span_id,
64
- flags,
65
- nil,
66
- remote: false
67
- )
68
- end
69
- end
70
- end
@@ -1,76 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # Copyright, 2021, by Samuel G. D. Williams. <http://www.codeotaku.com>
4
- #
5
- # Permission is hereby granted, free of charge, to any person obtaining a copy
6
- # of this software and associated documentation files (the "Software"), to deal
7
- # in the Software without restriction, including without limitation the rights
8
- # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- # copies of the Software, and to permit persons to whom the Software is
10
- # furnished to do so, subject to the following conditions:
11
- #
12
- # The above copyright notice and this permission notice shall be included in
13
- # all copies or substantial portions of the Software.
14
- #
15
- # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
- # THE SOFTWARE.
22
-
23
- require_relative '../context'
24
-
25
- require 'opentelemetry/sdk'
26
-
27
- module Traces
28
- module Backend
29
- private
30
-
31
- # Provides a backend that writes data to OpenTelemetry.
32
- # See <https://github.com/open-telemetry/opentelemetry-ruby> for more details.
33
- TRACER = ::OpenTelemetry.tracer_provider.tracer(Traces, Traces::VERSION)
34
-
35
- def trace(name, parent = nil, attributes: nil, &block)
36
- if parent
37
- # Convert it to the required object:
38
- parent = ::OpenTelemetry::Traces::SpanContext.new(
39
- trace_id: parent.trace_id,
40
- span_id: parent.span_id,
41
- trace_flags: ::OpenTelemetry::Traces::TracesFlags.from_byte(parent.flags),
42
- tracestate: parent.state,
43
- remote: parent.remote?
44
- )
45
- end
46
-
47
- span = TRACER.start_span(name, with_parent: parent, attributes: attributes)
48
-
49
- begin
50
- if block.arity.zero?
51
- yield
52
- else
53
- yield trace_span_context(span)
54
- end
55
- rescue Exception => error
56
- span&.record_exception(error)
57
- span&.status = ::OpenTelemetry::Traces::Status.error("Unhandled exception of type: #{error.class}")
58
- raise
59
- ensure
60
- span&.finish
61
- end
62
- end
63
-
64
- def trace_span_context(span)
65
- context = span.context
66
-
67
- return Context.new(
68
- context.trace_id,
69
- context.span_id,
70
- context.trace_flags,
71
- context.tracestate,
72
- remote: context.remote?
73
- )
74
- end
75
- end
76
- end