opentelemetry-instrumentation-servactory 0.1.0 → 0.2.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: 25e03df475b32f8de3c0c051a06a98b45ea31431ae23d7278fc68c4a2e1394b4
4
- data.tar.gz: 56df92c6a1b50927730560fdb429a261e26be897107beec0e513a5ebe2c757f1
3
+ metadata.gz: 9541337e57c8059897f3a1f6cb0fb152beb791f2aff6c18a07c0074e57cecb80
4
+ data.tar.gz: ac2dc1dc511b67ef5bd353e9affa7ae7cd7169fb550a2da3f83310bd9d67d237
5
5
  SHA512:
6
- metadata.gz: 1ba48f94bacee00877ce157069996c1d230bb105ccba488514f98174324706e03ccf7e1b751ab1855358f6e02a5bb36a39de1a042a7807f21c43f6324b07968b
7
- data.tar.gz: 9315ee5f78f885fd77f3c937e605b286c3dc22d7f16eb6e58127439f13b49c00d956c3f3c163a160803baa9bf34d72100b8f64214ff2416f59ee171aa9a79812
6
+ metadata.gz: 1fe3f6ba462a056bd0d272a8df0d6571aaee3789ff40bd23ba594dd7bec6f8bc4490538f43c67ed3372e823c98ab6378fe82bfe92f5b9ba7998d65e5897cadc4
7
+ data.tar.gz: 3e02ec2270c2f4c3f334bc5e50fb2947db67e1c2edb4c5ed0ba3b1ac28ae0da2c7d1ca68a473f10d28483e24193b6a3cf96680ce5979e702ef5a726fd1be1a53
data/CONTRIBUTING.md CHANGED
@@ -1,7 +1,65 @@
1
1
  # Contributing
2
2
 
3
- 1. Fork it (https://github.com/servactory/opentelemetry-instrumentation-servactory/fork);
4
- 2. Create your feature branch (`git checkout -b my-new-feature`);
5
- 3. Commit your changes (`git commit -am "Add some feature"`);
6
- 4. Push to the branch (`git push origin my-new-feature`);
7
- 5. Create a new Pull Request.
3
+ We welcome contributions to OpenTelemetry Instrumentation for Servactory! This guide will help you get started with contributing to the project.
4
+
5
+ ## Getting Started
6
+
7
+ Before you begin, please make sure you have a [GitHub account](https://github.com/signup) and are familiar with Git workflows.
8
+
9
+ ## Contribution Workflow
10
+
11
+ ### 1. Fork the Repository
12
+
13
+ Start by forking the [opentelemetry-instrumentation-servactory repository](https://github.com/servactory/opentelemetry-instrumentation-servactory/fork) to your GitHub account.
14
+
15
+ ### 2. Clone Your Fork
16
+
17
+ ```bash
18
+ git clone https://github.com/YOUR_USERNAME/opentelemetry-instrumentation-servactory.git
19
+ cd opentelemetry-instrumentation-servactory
20
+ ```
21
+
22
+ ### 3. Create a Feature Branch
23
+
24
+ ```bash
25
+ git checkout -b my-new-feature
26
+ ```
27
+
28
+ Use a descriptive branch name that reflects the changes you're making (e.g., `fix-validation-bug`, `add-logging-support`).
29
+
30
+ ### 4. Make Your Changes
31
+
32
+ - Write clean, readable code that follows the project's coding standards
33
+ - Add tests for new functionality
34
+ - Update documentation as needed
35
+
36
+ ### 5. Commit Your Changes
37
+
38
+ ```bash
39
+ git commit -am "Add some feature"
40
+ ```
41
+
42
+ Write clear, concise commit messages that describe what changed and why.
43
+
44
+ ### 6. Push to Your Fork
45
+
46
+ ```bash
47
+ git push origin my-new-feature
48
+ ```
49
+
50
+ ### 7. Create a Pull Request
51
+
52
+ Visit the [original repository](https://github.com/servactory/opentelemetry-instrumentation-servactory) and create a new Pull Request from your feature branch.
53
+
54
+ In your PR description:
55
+ - Clearly describe the changes you've made
56
+ - Reference any related issues
57
+ - Explain the reasoning behind your approach
58
+
59
+ ## Questions?
60
+
61
+ If you have questions about contributing, feel free to open an issue in the [main repository](https://github.com/servactory/opentelemetry-instrumentation-servactory/issues).
62
+
63
+ ---
64
+
65
+ Thank you for contributing to OpenTelemetry Instrumentation for Servactory! 🎉
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # OpenTelemetry Servactory Instrumentation
2
2
 
3
- Todo: Add a description.
3
+ Instrumentation for the [Servactory][servactory-home] service object framework. Automatically traces `call`/`call!` invocations and individual actions with span attributes, failure detection, and error recording.
4
4
 
5
5
  ## How do I get started?
6
6
 
@@ -10,7 +10,18 @@ Install the gem using:
10
10
  gem install opentelemetry-instrumentation-servactory
11
11
  ```
12
12
 
13
- Or, if you use [bundler][bundler-home], include `opentelemetry-instrumentation-servactory` in your `Gemfile`.
13
+ Or, if you use [bundler][bundler-home], include `opentelemetry-instrumentation-servactory` in your `Gemfile`:
14
+
15
+ ```ruby
16
+ gem "opentelemetry-instrumentation-servactory"
17
+ ```
18
+
19
+ ## Requirements
20
+
21
+ | Requirement | Version |
22
+ | --- | --- |
23
+ | Servactory | `>= 2.16.0` |
24
+ | Ruby | `>= 3.2` |
14
25
 
15
26
  ## Usage
16
27
 
@@ -18,11 +29,11 @@ To use the instrumentation, call `use` with the name of the instrumentation:
18
29
 
19
30
  ```ruby
20
31
  OpenTelemetry::SDK.configure do |c|
21
- c.use 'OpenTelemetry::Instrumentation::Servactory'
32
+ c.use("OpenTelemetry::Instrumentation::Servactory")
22
33
  end
23
34
  ```
24
35
 
25
- Alternatively, you can also call `use_all` to install all the available instrumentation.
36
+ Alternatively, you can also call `use_all` to install all the available instrumentation:
26
37
 
27
38
  ```ruby
28
39
  OpenTelemetry::SDK.configure do |c|
@@ -30,13 +41,64 @@ OpenTelemetry::SDK.configure do |c|
30
41
  end
31
42
  ```
32
43
 
33
- ## Examples
44
+ ## Configuration Options
45
+
46
+ | Option | Default | Type | Description |
47
+ | --- | --- | --- | --- |
48
+ | `trace_actions` | `true` | Boolean | Create child spans for each `make` action |
49
+ | `record_input_names` | `true` | Boolean | Record input names as a span attribute |
50
+ | `record_output_names` | `true` | Boolean | Record output names as a span attribute |
51
+
52
+ Example with custom configuration:
53
+
54
+ ```ruby
55
+ OpenTelemetry::SDK.configure do |c|
56
+ c.use(
57
+ "OpenTelemetry::Instrumentation::Servactory",
58
+ {
59
+ trace_actions: true,
60
+ record_input_names: false,
61
+ record_output_names: false
62
+ }
63
+ )
64
+ end
65
+ ```
66
+
67
+ ## Span Structure
68
+
69
+ Each `call`/`call!` invocation creates a root span. When `trace_actions` is enabled, each `make` action creates a child span.
70
+
71
+ ```
72
+ Users::CreateService call (root span)
73
+ |-- Users::CreateService validate (child span per action)
74
+ |-- Users::CreateService create_user
75
+ |-- Users::CreateService send_email
76
+ ```
77
+
78
+ ### Span Attributes
79
+
80
+ | Attribute | Type | Description |
81
+ | --- | --- | --- |
82
+ | `code.namespace` | String | Service class name |
83
+ | `code.function` | String | Method name (`call`, `call!`, or action name) |
84
+ | `servactory.version` | String | Servactory library version |
85
+ | `servactory.result` | String | `success`, `failure`, or `error` |
86
+ | `servactory.input_names` | Array | Input attribute names (when `record_input_names` is enabled) |
87
+ | `servactory.output_names` | Array | Output attribute names (when `record_output_names` is enabled) |
88
+
89
+ ### Failure Events
90
+
91
+ When a service fails via `fail!`, a `servactory.failure` event is added to the span with:
34
92
 
35
- Example usage can be seen in the [`./example/trace_demonstration.rb` file](https://github.com/servactory/opentelemetry-instrumentation-servactory/blob/main/example/trace_demonstration.rb)
93
+ | Attribute | Type | Description |
94
+ | --- | --- | --- |
95
+ | `servactory.failure.type` | String | Failure type (if provided) |
96
+ | `servactory.failure.message` | String | Failure message |
36
97
 
37
98
  ## License
38
99
 
39
100
  The `opentelemetry-instrumentation-servactory` gem is distributed under the MIT license. See [LICENSE][license-github] for more information.
40
101
 
102
+ [servactory-home]: https://servactory.com
41
103
  [bundler-home]: https://bundler.io
42
104
  [license-github]: https://github.com/servactory/opentelemetry-instrumentation-servactory/blob/main/LICENSE
@@ -4,20 +4,42 @@ module OpenTelemetry
4
4
  module Instrumentation
5
5
  module Servactory
6
6
  class Instrumentation < OpenTelemetry::Instrumentation::Base
7
+ instrumentation_version VERSION::STRING
8
+
9
+ MINIMUM_VERSION = Gem::Version.new("2.16.0")
10
+
7
11
  install do |_config|
8
12
  require_dependencies
13
+ patch_callable
14
+ patch_runner if config[:trace_actions]
9
15
  end
10
16
 
11
17
  present do
12
- # TODO: Replace true with a definition check of the gem being instrumented
13
- # Example: `defined?(::Rack)`
14
- true
18
+ defined?(::Servactory)
15
19
  end
16
20
 
21
+ compatible do
22
+ gem_version = Gem::Version.new(::Servactory::VERSION::STRING)
23
+ gem_version >= MINIMUM_VERSION
24
+ end
25
+
26
+ option :trace_actions, default: true, validate: :boolean
27
+ option :record_input_names, default: true, validate: :boolean
28
+ option :record_output_names, default: true, validate: :boolean
29
+
17
30
  private
18
31
 
19
32
  def require_dependencies
20
- # TODO: Include instrumentation dependencies
33
+ require_relative "patches/callable"
34
+ require_relative "patches/runner"
35
+ end
36
+
37
+ def patch_callable
38
+ ::Servactory::Context::Callable.prepend(Patches::Callable)
39
+ end
40
+
41
+ def patch_runner
42
+ ::Servactory::Actions::Tools::Runner.prepend(Patches::Runner)
21
43
  end
22
44
  end
23
45
  end
@@ -0,0 +1,140 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OpenTelemetry
4
+ module Instrumentation
5
+ module Servactory
6
+ module Patches
7
+ module Callable # rubocop:disable Metrics/ModuleLength
8
+ def call(...) # rubocop:disable Metrics/MethodLength
9
+ service_name = name || "AnonymousService"
10
+ attributes = _otel_build_span_attributes(service_name, "call")
11
+
12
+ span = _otel_tracer.start_span("#{service_name} call", attributes:, kind: :internal)
13
+ OpenTelemetry::Trace.with_span(span) do
14
+ result = super
15
+ _otel_record_result(span, result)
16
+ result
17
+ rescue StandardError => e
18
+ _otel_record_exception_on_span(span, e)
19
+ raise
20
+ ensure
21
+ span.finish
22
+ end
23
+ end
24
+
25
+ def call!(...) # rubocop:disable Metrics/MethodLength
26
+ service_name = name || "AnonymousService"
27
+ attributes = _otel_build_span_attributes(service_name, "call!")
28
+
29
+ span = _otel_tracer.start_span("#{service_name} call!", attributes:, kind: :internal)
30
+ OpenTelemetry::Trace.with_span(span) do
31
+ result = super
32
+ _otel_mark_span_success(span)
33
+ result
34
+ rescue StandardError => e
35
+ _otel_record_exception_on_span(span, e)
36
+ raise
37
+ ensure
38
+ span.finish
39
+ end
40
+ end
41
+
42
+ private
43
+
44
+ def _otel_build_span_attributes(service_name, method_name)
45
+ attributes = {
46
+ "code.namespace" => service_name,
47
+ "code.function" => method_name,
48
+ "servactory.version" => ::Servactory::VERSION::STRING
49
+ }
50
+ _otel_append_attribute_names(attributes)
51
+ attributes
52
+ end
53
+
54
+ def _otel_append_attribute_names(attributes)
55
+ config = OpenTelemetry::Instrumentation::Servactory::Instrumentation.instance.config
56
+
57
+ if config[:record_input_names]
58
+ names = _otel_input_names
59
+ attributes["servactory.input_names"] = names unless names.empty?
60
+ end
61
+
62
+ return unless config[:record_output_names]
63
+
64
+ names = _otel_output_names
65
+ attributes["servactory.output_names"] = names unless names.empty?
66
+ end
67
+
68
+ def _otel_input_names
69
+ send(:collection_of_inputs).names.map(&:to_s)
70
+ rescue StandardError => e
71
+ OpenTelemetry.handle_error(exception: e, message: "Failed to collect Servactory input names")
72
+ []
73
+ end
74
+
75
+ def _otel_output_names
76
+ send(:collection_of_outputs).names.map(&:to_s)
77
+ rescue StandardError => e
78
+ OpenTelemetry.handle_error(exception: e, message: "Failed to collect Servactory output names")
79
+ []
80
+ end
81
+
82
+ def _otel_record_result(span, result)
83
+ if result.respond_to?(:failure?) && result.failure?
84
+ _otel_record_failure_on_span(span, result)
85
+ span.set_attribute("servactory.result", "failure")
86
+ else
87
+ _otel_mark_span_success(span)
88
+ end
89
+ end
90
+
91
+ def _otel_mark_span_success(span)
92
+ span.set_attribute("servactory.result", "success")
93
+ span.status = OpenTelemetry::Trace::Status.ok
94
+ end
95
+
96
+ def _otel_record_failure_on_span(span, result)
97
+ error = result.respond_to?(:error) ? result.error : nil
98
+ message = _otel_error_message_for(error)
99
+
100
+ span.add_event("servactory.failure", attributes: _otel_failure_attributes(error))
101
+ span.status = OpenTelemetry::Trace::Status.error(message)
102
+ end
103
+
104
+ def _otel_record_exception_on_span(span, exception)
105
+ span.record_exception(exception)
106
+
107
+ if exception.respond_to?(:type)
108
+ span.set_attribute("servactory.result", "failure")
109
+ span.status = OpenTelemetry::Trace::Status.error(_otel_error_message_for(exception))
110
+ else
111
+ span.set_attribute("servactory.result", "error")
112
+ span.status = OpenTelemetry::Trace::Status.error("Unhandled exception of type: #{exception.class}")
113
+ end
114
+ end
115
+
116
+ def _otel_error_message_for(error)
117
+ return "Service failure" unless error
118
+
119
+ if error.respond_to?(:message)
120
+ error.message.to_s
121
+ else
122
+ error.to_s
123
+ end
124
+ end
125
+
126
+ def _otel_failure_attributes(error)
127
+ attrs = {}
128
+ attrs["servactory.failure.type"] = error.type.to_s if error.respond_to?(:type) && error.type
129
+ attrs["servactory.failure.message"] = error.message.to_s if error.respond_to?(:message) && error.message
130
+ attrs
131
+ end
132
+
133
+ def _otel_tracer
134
+ OpenTelemetry::Instrumentation::Servactory::Instrumentation.instance.tracer
135
+ end
136
+ end
137
+ end
138
+ end
139
+ end
140
+ end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OpenTelemetry
4
+ module Instrumentation
5
+ module Servactory
6
+ module Patches
7
+ module Runner
8
+ private
9
+
10
+ def call_action(action)
11
+ span = _otel_start_action_span(action)
12
+ OpenTelemetry::Trace.with_span(span) do
13
+ super
14
+ rescue StandardError => e
15
+ span.record_exception(e)
16
+ span.status = OpenTelemetry::Trace::Status.error("Unhandled exception of type: #{e.class}")
17
+ raise
18
+ ensure
19
+ span.finish
20
+ end
21
+ end
22
+
23
+ def _otel_start_action_span(action)
24
+ service_name = @context&.class&.name || "AnonymousService"
25
+ attributes = _otel_build_action_attributes(service_name, action.name.to_s)
26
+
27
+ _otel_tracer.start_span("#{service_name} #{action.name}", attributes:, kind: :internal)
28
+ end
29
+
30
+ def _otel_build_action_attributes(service_name, action_name)
31
+ {
32
+ "code.namespace" => service_name,
33
+ "code.function" => action_name,
34
+ "servactory.version" => ::Servactory::VERSION::STRING
35
+ }
36
+ end
37
+
38
+ def _otel_tracer
39
+ OpenTelemetry::Instrumentation::Servactory::Instrumentation.instance.tracer
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -5,7 +5,7 @@ module OpenTelemetry
5
5
  module Servactory
6
6
  module VERSION
7
7
  MAJOR = 0
8
- MINOR = 1
8
+ MINOR = 2
9
9
  PATCH = 0
10
10
  PRE = nil
11
11
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: opentelemetry-instrumentation-servactory
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Anton Sokolov
@@ -15,28 +15,28 @@ dependencies:
15
15
  requirements:
16
16
  - - "~>"
17
17
  - !ruby/object:Gem::Version
18
- version: 1.6.0
18
+ version: '1.0'
19
19
  type: :runtime
20
20
  prerelease: false
21
21
  version_requirements: !ruby/object:Gem::Requirement
22
22
  requirements:
23
23
  - - "~>"
24
24
  - !ruby/object:Gem::Version
25
- version: 1.6.0
25
+ version: '1.0'
26
26
  - !ruby/object:Gem::Dependency
27
27
  name: opentelemetry-instrumentation-base
28
28
  requirement: !ruby/object:Gem::Requirement
29
29
  requirements:
30
30
  - - "~>"
31
31
  - !ruby/object:Gem::Version
32
- version: 0.23.0
32
+ version: '0.22'
33
33
  type: :runtime
34
34
  prerelease: false
35
35
  version_requirements: !ruby/object:Gem::Requirement
36
36
  requirements:
37
37
  - - "~>"
38
38
  - !ruby/object:Gem::Version
39
- version: 0.23.0
39
+ version: '0.22'
40
40
  - !ruby/object:Gem::Dependency
41
41
  name: appraisal
42
42
  requirement: !ruby/object:Gem::Requirement
@@ -51,6 +51,20 @@ dependencies:
51
51
  - - ">="
52
52
  - !ruby/object:Gem::Version
53
53
  version: '2.5'
54
+ - !ruby/object:Gem::Dependency
55
+ name: opentelemetry-sdk
56
+ requirement: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - "~>"
59
+ - !ruby/object:Gem::Version
60
+ version: '1.4'
61
+ type: :development
62
+ prerelease: false
63
+ version_requirements: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - "~>"
66
+ - !ruby/object:Gem::Version
67
+ version: '1.4'
54
68
  - !ruby/object:Gem::Dependency
55
69
  name: rspec
56
70
  requirement: !ruby/object:Gem::Requirement
@@ -65,6 +79,20 @@ dependencies:
65
79
  - - ">="
66
80
  - !ruby/object:Gem::Version
67
81
  version: '3.13'
82
+ - !ruby/object:Gem::Dependency
83
+ name: servactory
84
+ requirement: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ version: 2.16.0
89
+ type: :development
90
+ prerelease: false
91
+ version_requirements: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - ">="
94
+ - !ruby/object:Gem::Version
95
+ version: 2.16.0
68
96
  - !ruby/object:Gem::Dependency
69
97
  name: servactory-rubocop
70
98
  requirement: !ruby/object:Gem::Requirement
@@ -93,6 +121,8 @@ files:
93
121
  - lib/opentelemetry/instrumentation.rb
94
122
  - lib/opentelemetry/instrumentation/servactory.rb
95
123
  - lib/opentelemetry/instrumentation/servactory/instrumentation.rb
124
+ - lib/opentelemetry/instrumentation/servactory/patches/callable.rb
125
+ - lib/opentelemetry/instrumentation/servactory/patches/runner.rb
96
126
  - lib/opentelemetry/instrumentation/servactory/version.rb
97
127
  - lib/opentelemetry_instrumentation_servactory.rb
98
128
  homepage: https://github.com/servactory/opentelemetry-instrumentation-servactory
@@ -119,7 +149,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
119
149
  - !ruby/object:Gem::Version
120
150
  version: '0'
121
151
  requirements: []
122
- rubygems_version: 3.7.1
152
+ rubygems_version: 4.0.6
123
153
  specification_version: 4
124
154
  summary: Servactory instrumentation for the OpenTelemetry framework
125
155
  test_files: []