Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
3dbb569
Instrument Servactory's `call` and `call!` methods with OpenTelemetry
afuno Feb 20, 2026
82e185f
Add Runner patch to instrument Servactory actions with OpenTelemetry
afuno Feb 20, 2026
9fe244b
Add compatibility check and patching logic for Servactory
afuno Feb 20, 2026
8c966ef
Refactor Callable patch to utilize Ruby's forwarding arguments
afuno Feb 20, 2026
adc9cfd
Update dependencies and Ruby version compatibility
afuno Feb 20, 2026
e3464fe
Add RSpec tests for Servactory instrumentation and example services
afuno Feb 20, 2026
6589b5f
Initialize OpenTelemetry SDK and configure RSpec for tracing
afuno Feb 20, 2026
dfb5244
Rename `fake_service.rb` to `example_services.rb` in support folder
afuno Feb 20, 2026
90c8784
Enhance Servactory instrumentation test coverage
afuno Feb 20, 2026
7ffc0eb
Merge branch 'main' of https://github.com/servactory/opentelemetry-in…
afuno Feb 20, 2026
137c028
Relax OpenTelemetry SDK version constraint in development dependencies
afuno Feb 20, 2026
b939c05
Document Servactory instrumentation setup and configuration
afuno Feb 20, 2026
56c81fd
Format Servactory usage examples for improved readability
afuno Feb 20, 2026
e613b42
Relax OpenTelemetry gem version constraints for broader compatibility
afuno Feb 20, 2026
524959f
Add Servactory system attributes to spans
afuno Feb 20, 2026
6105507
Prefix private patch methods with _otel_
afuno Feb 21, 2026
68440b9
Relax version constraints for OpenTelemetry dependencies
afuno Feb 21, 2026
e0060d0
Handle span lifecycle and improve exception handling in Callable
afuno Feb 21, 2026
c675c45
Handle exception propagation and span updates in Callable spec
afuno Feb 21, 2026
e66eb2d
Standardize boolean expectations formatting in Servactory tests
afuno Feb 21, 2026
ee729ad
Simplify and improve test readability in instrumentation specs
afuno Feb 21, 2026
ecd59c2
Remove `servactory.system` attribute from spans in instrumentation
afuno Feb 21, 2026
e4e269c
Remove reference to `servactory.system` in README
afuno Feb 21, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .ruby-version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
3.4.5
3.4.8
2 changes: 1 addition & 1 deletion .tool-versions
Original file line number Diff line number Diff line change
@@ -1 +1 @@
ruby 3.4.5
ruby 3.4.8
99 changes: 58 additions & 41 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,20 @@ PATH
remote: .
specs:
opentelemetry-instrumentation-servactory (0.1.0)
opentelemetry-api (~> 1.6.0)
opentelemetry-instrumentation-base (~> 0.23.0)
opentelemetry-api (~> 1.0)
opentelemetry-instrumentation-base (~> 0.22)

GEM
remote: https://rubygems.org/
specs:
activesupport (8.0.2.1)
activesupport (8.1.2)
base64
benchmark (>= 0.3)
bigdecimal
concurrent-ruby (~> 1.0, >= 1.3.1)
connection_pool (>= 2.2.5)
drb
i18n (>= 1.6, < 2)
json
logger (>= 1.4.2)
minitest (>= 5.1)
securerandom (>= 0.3)
Expand All @@ -27,73 +27,80 @@ GEM
thor (>= 0.14.0)
ast (2.4.3)
base64 (0.3.0)
benchmark (0.4.1)
bigdecimal (3.2.2)
concurrent-ruby (1.3.5)
connection_pool (2.5.3)
bigdecimal (4.0.1)
concurrent-ruby (1.3.6)
connection_pool (3.0.2)
diff-lcs (1.6.2)
drb (2.2.3)
i18n (1.14.7)
i18n (1.14.8)
concurrent-ruby (~> 1.0)
json (2.13.2)
json (2.18.1)
language_server-protocol (3.17.0.5)
lint_roller (1.1.0)
logger (1.7.0)
minitest (5.25.5)
opentelemetry-api (1.6.0)
opentelemetry-common (0.22.0)
opentelemetry-api (~> 1.0)
opentelemetry-instrumentation-base (0.23.0)
minitest (6.0.1)
prism (~> 1.5)
opentelemetry-api (1.7.0)
opentelemetry-common (0.23.0)
opentelemetry-api (~> 1.0)
opentelemetry-instrumentation-base (0.25.0)
opentelemetry-api (~> 1.7)
opentelemetry-common (~> 0.21)
opentelemetry-registry (~> 0.1)
opentelemetry-registry (0.4.0)
opentelemetry-api (~> 1.1)
opentelemetry-sdk (1.10.0)
opentelemetry-api (~> 1.1)
opentelemetry-common (~> 0.20)
opentelemetry-registry (~> 0.2)
opentelemetry-semantic_conventions
opentelemetry-semantic_conventions (1.36.0)
opentelemetry-api (~> 1.0)
parallel (1.27.0)
parser (3.3.9.0)
parser (3.3.10.2)
ast (~> 2.4.1)
racc
prism (1.4.0)
prism (1.9.0)
racc (1.8.1)
rack (3.2.0)
rack (3.2.5)
rainbow (3.1.1)
rake (13.3.0)
regexp_parser (2.11.2)
rspec (3.13.1)
rake (13.3.1)
regexp_parser (2.11.3)
rspec (3.13.2)
rspec-core (~> 3.13.0)
rspec-expectations (~> 3.13.0)
rspec-mocks (~> 3.13.0)
rspec-core (3.13.5)
rspec-core (3.13.6)
rspec-support (~> 3.13.0)
rspec-expectations (3.13.5)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.13.0)
rspec-mocks (3.13.5)
rspec-mocks (3.13.7)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.13.0)
rspec-support (3.13.5)
rubocop (1.80.0)
rspec-support (3.13.7)
rubocop (1.84.2)
json (~> 2.3)
language_server-protocol (~> 3.17.0.2)
lint_roller (~> 1.1.0)
parallel (~> 1.10)
parser (>= 3.3.0.2)
rainbow (>= 2.2.2, < 4.0)
regexp_parser (>= 2.9.3, < 3.0)
rubocop-ast (>= 1.46.0, < 2.0)
rubocop-ast (>= 1.49.0, < 2.0)
ruby-progressbar (~> 1.7)
unicode-display_width (>= 2.4.0, < 4.0)
rubocop-ast (1.46.0)
rubocop-ast (1.49.0)
parser (>= 3.3.7.2)
prism (~> 1.4)
rubocop-factory_bot (2.27.1)
prism (~> 1.7)
rubocop-factory_bot (2.28.0)
lint_roller (~> 1.1)
rubocop (~> 1.72, >= 1.72.1)
rubocop-performance (1.25.0)
rubocop-performance (1.26.1)
lint_roller (~> 1.1)
rubocop (>= 1.75.0, < 2.0)
rubocop-ast (>= 1.38.0, < 2.0)
rubocop-rails (2.33.3)
rubocop-ast (>= 1.47.1, < 2.0)
rubocop-rails (2.34.3)
activesupport (>= 4.2.0)
lint_roller (~> 1.1)
rack (>= 1.1)
Expand All @@ -102,15 +109,20 @@ GEM
rubocop-rake (0.7.1)
lint_roller (~> 1.1)
rubocop (>= 1.72.1)
rubocop-rspec (3.6.0)
rubocop-rspec (3.9.0)
lint_roller (~> 1.1)
rubocop (~> 1.72, >= 1.72.1)
rubocop-rspec_rails (2.31.0)
rubocop (~> 1.81)
rubocop-rspec_rails (2.32.0)
lint_roller (~> 1.1)
rubocop (~> 1.72, >= 1.72.1)
rubocop-rspec (~> 3.5)
ruby-progressbar (1.13.0)
securerandom (0.4.1)
servactory (3.0.2)
activesupport (>= 5.1)
i18n (>= 1.14)
stroma (>= 0.5, < 1.0)
zeitwerk (>= 2.6)
servactory-rubocop (0.9.0)
rubocop (>= 1.73)
rubocop-factory_bot (>= 2.27)
Expand All @@ -119,13 +131,16 @@ GEM
rubocop-rake (>= 0.7)
rubocop-rspec (>= 3.5)
rubocop-rspec_rails (>= 2.31)
thor (1.4.0)
stroma (0.5.0)
zeitwerk (>= 2.6)
thor (1.5.0)
tzinfo (2.0.6)
concurrent-ruby (~> 1.0)
unicode-display_width (3.1.5)
unicode-emoji (~> 4.0, >= 4.0.4)
unicode-emoji (4.0.4)
uri (1.0.3)
unicode-display_width (3.2.0)
unicode-emoji (~> 4.1)
unicode-emoji (4.2.0)
uri (1.1.1)
zeitwerk (2.7.5)

PLATFORMS
aarch64-linux-gnu
Expand All @@ -143,8 +158,10 @@ PLATFORMS
DEPENDENCIES
appraisal (>= 2.5)
opentelemetry-instrumentation-servactory!
opentelemetry-sdk (~> 1.4)
rspec (>= 3.13)
servactory (>= 2.16.0)
servactory-rubocop (>= 0.9)

BUNDLED WITH
2.7.1
4.0.6
73 changes: 67 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# OpenTelemetry Servactory Instrumentation

Todo: Add a description.
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.

## How do I get started?

Expand All @@ -10,33 +10,94 @@ Install the gem using:
gem install opentelemetry-instrumentation-servactory
```

Or, if you use [bundler][bundler-home], include `opentelemetry-instrumentation-servactory` in your `Gemfile`.
Or, if you use [bundler][bundler-home], include `opentelemetry-instrumentation-servactory` in your `Gemfile`:

```ruby
gem "opentelemetry-instrumentation-servactory"
```

## Requirements

| Requirement | Version |
| --- | --- |
| Servactory | `>= 2.16.0` |
| Ruby | `>= 3.2` |

## Usage

To use the instrumentation, call `use` with the name of the instrumentation:

```ruby
OpenTelemetry::SDK.configure do |c|
c.use 'OpenTelemetry::Instrumentation::Servactory'
c.use("OpenTelemetry::Instrumentation::Servactory")
end
```

Alternatively, you can also call `use_all` to install all the available instrumentation.
Alternatively, you can also call `use_all` to install all the available instrumentation:

```ruby
OpenTelemetry::SDK.configure do |c|
c.use_all
end
```

## Examples
## Configuration Options

| Option | Default | Type | Description |
| --- | --- | --- | --- |
| `trace_actions` | `true` | Boolean | Create child spans for each `make` action |
| `record_input_names` | `true` | Boolean | Record input names as a span attribute |
| `record_output_names` | `true` | Boolean | Record output names as a span attribute |

Example with custom configuration:

```ruby
OpenTelemetry::SDK.configure do |c|
c.use(
"OpenTelemetry::Instrumentation::Servactory", {
trace_actions: true,
record_input_names: false,
record_output_names: false
}
)
end
```

## Span Structure

Each `call`/`call!` invocation creates a root span. When `trace_actions` is enabled, each `make` action creates a child span.

```
Users::CreateService call (root span)
|-- Users::CreateService validate (child span per action)
|-- Users::CreateService create_user
|-- Users::CreateService send_email
```

### Span Attributes

| Attribute | Type | Description |
| --- | --- | --- |
| `code.namespace` | String | Service class name |
| `code.function` | String | Method name (`call`, `call!`, or action name) |
| `servactory.version` | String | Servactory library version |
| `servactory.result` | String | `success`, `failure`, or `error` |
| `servactory.input_names` | Array | Input attribute names (when `record_input_names` is enabled) |
| `servactory.output_names` | Array | Output attribute names (when `record_output_names` is enabled) |

### Failure Events

When a service fails via `fail!`, a `servactory.failure` event is added to the span with:

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)
| Attribute | Type | Description |
| --- | --- | --- |
| `servactory.failure.type` | String | Failure type (if provided) |
| `servactory.failure.message` | String | Failure message |

## License

The `opentelemetry-instrumentation-servactory` gem is distributed under the MIT license. See [LICENSE][license-github] for more information.

[servactory-home]: https://servactory.com
[bundler-home]: https://bundler.io
[license-github]: https://github.com/servactory/opentelemetry-instrumentation-servactory/blob/main/LICENSE
30 changes: 26 additions & 4 deletions lib/opentelemetry/instrumentation/servactory/instrumentation.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,42 @@ module OpenTelemetry
module Instrumentation
module Servactory
class Instrumentation < OpenTelemetry::Instrumentation::Base
instrumentation_version VERSION::STRING

MINIMUM_VERSION = Gem::Version.new("2.16.0")

install do |_config|
require_dependencies
patch_callable
patch_runner if config[:trace_actions]
end

present do
# TODO: Replace true with a definition check of the gem being instrumented
# Example: `defined?(::Rack)`
true
defined?(::Servactory)
end

compatible do
gem_version = Gem::Version.new(::Servactory::VERSION::STRING)
gem_version >= MINIMUM_VERSION
end

option :trace_actions, default: true, validate: :boolean
option :record_input_names, default: true, validate: :boolean
option :record_output_names, default: true, validate: :boolean

private

def require_dependencies
# TODO: Include instrumentation dependencies
require_relative "patches/callable"
require_relative "patches/runner"
end

def patch_callable
::Servactory::Context::Callable.prepend(Patches::Callable)
end

def patch_runner
::Servactory::Actions::Tools::Runner.prepend(Patches::Runner)
end
end
end
Expand Down
Loading