gritz-otel 0.1.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 +7 -0
- data/CHANGELOG.md +5 -0
- data/LICENSE.txt +21 -0
- data/README.md +72 -0
- data/lib/gritz/otel/recorder.rb +83 -0
- data/lib/gritz/otel/tracing.rb +85 -0
- data/lib/gritz/otel/version.rb +7 -0
- data/lib/gritz/otel.rb +100 -0
- metadata +123 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 3c13de06e63ce826aa5008be7098af391057f6a1c37fc5f48c09cf4c2e0a2a53
|
|
4
|
+
data.tar.gz: 9d6dc0a2a2918d253944a33f239cf65294a43e08383373c1a0dfd5f3fe0f57bb
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 2e2f301f80ccbc3274444719b05d3f431456baa300753ef4d5a1ceef91b13470a259486538a26a875c1122d40d7042239fba1d4c295367520b63dc0b1499c5d0
|
|
7
|
+
data.tar.gz: 1346f9c98c2bce145ccbc172dc054f1183d7661c86d3591df14f84f9158ee1b870eebb86efe810b3f2905811ca2e3d6700e0734f8cbb97eb6932ce18acbd526c
|
data/CHANGELOG.md
ADDED
data/LICENSE.txt
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 ydah
|
|
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.
|
data/README.md
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# Gritz OpenTelemetry
|
|
2
|
+
|
|
3
|
+
Server and client spans and worker OTLP metrics for [Gritz](https://github.com/gritzrpc/gritz). SDK providers and exporters start in worker boot hooks, after fork. This optional integration depends on `gritz-core`; applications choose their transport separately.
|
|
4
|
+
|
|
5
|
+
Requires CRuby 3.3 or later and Gritz 0.4.0. The OpenTelemetry metrics SDK is currently alpha; this gem pins its supported minor versions.
|
|
6
|
+
|
|
7
|
+
## Installation and configuration
|
|
8
|
+
|
|
9
|
+
```ruby
|
|
10
|
+
gem "gritz", "~> 0.4.0"
|
|
11
|
+
gem "gritz-otel", git: "https://github.com/gritzrpc/gritz-otel.git", branch: "main"
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
The first `gritz-otel` release is being prepared. Until it is published, use the source dependency above. After publication, use `gem "gritz-otel", "~> 0.1.0"`.
|
|
15
|
+
|
|
16
|
+
In the Gritz configuration file:
|
|
17
|
+
|
|
18
|
+
```ruby
|
|
19
|
+
require "gritz/otel"
|
|
20
|
+
|
|
21
|
+
metrics_backend :otlp
|
|
22
|
+
opentelemetry do |sdk|
|
|
23
|
+
sdk.service_name = "greeter"
|
|
24
|
+
end
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Set `OTEL_EXPORTER_OTLP_ENDPOINT=http://collector:4318/` for OTLP/HTTP protobuf. Standard exporter endpoint, headers, certificate and compression environment variables are supported. Traces go to `/v1/traces` and metrics to `/v1/metrics`. With the default `metrics_backend :pipe`, the integration adds tracing while retaining the built-in Prometheus metrics.
|
|
28
|
+
|
|
29
|
+
For a configuration object, use `Gritz::Otel.install(config) { |sdk| ... }`. The SDK block executes in each worker; create custom processors or exporters inside that block. Register the integration before starting the server. The integration owns one SDK configuration per worker process and closes its providers after application shutdown hooks and final RPC observations.
|
|
30
|
+
|
|
31
|
+
## Tracing
|
|
32
|
+
|
|
33
|
+
Server spans surround complete dispatch, including streaming and error mapping. `Gritz::Client` spans surround complete outgoing calls and response consumption, with native cancellation on early exit. Incoming W3C `traceparent` and `tracestate` are extracted and outgoing child contexts are injected. Lazy clients retain the context captured when the call was created. Incoming credentials and baggage are not automatically forwarded.
|
|
34
|
+
|
|
35
|
+
Spans include the service, method and final gRPC status. They omit protobuf payloads and exception messages. See the [client guide](https://github.com/gritzrpc/gritz-core/blob/main/docs/guides/clients.md).
|
|
36
|
+
|
|
37
|
+
## Worker metrics
|
|
38
|
+
|
|
39
|
+
With `metrics_backend :otlp`, each worker records:
|
|
40
|
+
|
|
41
|
+
| Instrument | Meaning |
|
|
42
|
+
| --- | --- |
|
|
43
|
+
| `gritz.rpc.server.duration` | Completed RPC duration, in seconds |
|
|
44
|
+
| `gritz.rpc.server.requests`, `gritz.rpc.server.responses` | Messages per completed RPC |
|
|
45
|
+
| `gritz.rpc.server.rejected` | Overload rejections |
|
|
46
|
+
| `gritz.worker.inflight`, `gritz.worker.busy_threads`, `gritz.worker.capacity` | Worker occupancy and capacity |
|
|
47
|
+
| `gritz.worker.state` | Current lifecycle state |
|
|
48
|
+
| `gritz.worker.rss_bytes`, `gritz.worker.pss_bytes` | Actual Linux process memory |
|
|
49
|
+
|
|
50
|
+
Worker PID and index identify each observation; service/method/status identify RPC histograms. The collector receives cumulative SDK metrics from individual workers. Master restart counts and framework-wide totals remain available through Admin `/metrics`; OTLP continues to mirror RPC deltas to the built-in pipe backend.
|
|
51
|
+
|
|
52
|
+
Worker status heartbeats drive official SDK metric collection and HTTP export. Each heartbeat export is bounded by the smallest of one second, half `status_interval`, and a quarter of `shutdown_timeout`. A failed observation or export retains pipe data and does not fail the RPC. Final export and provider shutdown share the remaining graceful shutdown budget; telemetry may be dropped when that budget expires.
|
|
53
|
+
|
|
54
|
+
## Development and releases
|
|
55
|
+
|
|
56
|
+
```sh
|
|
57
|
+
bundle install
|
|
58
|
+
COVERAGE=1 bundle exec rake
|
|
59
|
+
bundle exec rubocop
|
|
60
|
+
bundle exec bundler-audit check --update
|
|
61
|
+
bundle exec rake build
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Tests include a real Linux three-service chain with an OTLP/HTTP protobuf collector. Core and native development dependencies use their Git repositories; runtime dependencies use published gems. See [CONTRIBUTING.md](CONTRIBUTING.md), [SECURITY.md](SECURITY.md) and the [release guide](docs/guides/releasing.md).
|
|
65
|
+
|
|
66
|
+
See the [three-service integration report](docs/reports/T4-08-client-chain.md) for the completion checks and reproduction commands.
|
|
67
|
+
|
|
68
|
+
The initial release is prepared for the project owner. Do not publish its first tag automatically.
|
|
69
|
+
|
|
70
|
+
## License
|
|
71
|
+
|
|
72
|
+
[MIT](LICENSE.txt).
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Gritz
|
|
4
|
+
module Otel
|
|
5
|
+
# Preserve pipe deltas while recording worker-local SDK instruments.
|
|
6
|
+
class Recorder < Gritz::Metrics::Recorder
|
|
7
|
+
def initialize(worker:, exporter: nil, timeout: 1.0)
|
|
8
|
+
super()
|
|
9
|
+
@exporter = exporter
|
|
10
|
+
@timeout = timeout
|
|
11
|
+
@attributes = { "worker.index" => worker, "process.pid" => Process.pid }
|
|
12
|
+
@rejected = 0
|
|
13
|
+
return unless exporter
|
|
14
|
+
|
|
15
|
+
meter = OpenTelemetry.meter_provider.meter("gritz", version: VERSION)
|
|
16
|
+
@duration = meter.create_histogram("gritz.rpc.server.duration", unit: "s")
|
|
17
|
+
@requests = meter.create_histogram("gritz.rpc.server.requests", unit: "{message}")
|
|
18
|
+
@responses = meter.create_histogram("gritz.rpc.server.responses", unit: "{message}")
|
|
19
|
+
@rejections = meter.create_counter("gritz.rpc.server.rejected", unit: "{request}")
|
|
20
|
+
@gauges = %w[inflight busy_threads capacity rss_bytes pss_bytes].to_h do |name|
|
|
21
|
+
[name, meter.create_gauge("gritz.worker.#{name}")]
|
|
22
|
+
end
|
|
23
|
+
@state = meter.create_gauge("gritz.worker.state")
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def record_rpc(service:, method:, code:, duration:, requests:, responses:)
|
|
27
|
+
super
|
|
28
|
+
return unless @exporter
|
|
29
|
+
|
|
30
|
+
attributes = @attributes.merge("rpc.system" => "grpc", "rpc.service" => service, "rpc.method" => method, "rpc.grpc.status_code" => code)
|
|
31
|
+
observe_telemetry do
|
|
32
|
+
@duration.record(duration, attributes:)
|
|
33
|
+
@requests.record(requests, attributes:)
|
|
34
|
+
@responses.record(responses, attributes:)
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def observe_rejected(total)
|
|
39
|
+
super
|
|
40
|
+
observe_telemetry do
|
|
41
|
+
@rejections&.add(total - @rejected, attributes: @attributes)
|
|
42
|
+
@rejected = total
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def observe_worker(status)
|
|
47
|
+
return unless @exporter
|
|
48
|
+
|
|
49
|
+
observe_telemetry do
|
|
50
|
+
@gauges.each { |name, gauge| gauge.record(status.fetch(name.to_sym, 0), attributes: @attributes) unless name.end_with?("_bytes") }
|
|
51
|
+
memory.each { |name, value| @gauges.fetch(name).record(value, attributes: @attributes) }
|
|
52
|
+
%w[booting ready draining failed stopped].each do |state|
|
|
53
|
+
@state.record(state == status[:state] ? 1 : 0, attributes: @attributes.merge("state" => state))
|
|
54
|
+
end
|
|
55
|
+
# The official exporter is also a MetricReader. Heartbeats drive bounded exports,
|
|
56
|
+
# avoiding the alpha SDK periodic reader's unbounded shutdown join.
|
|
57
|
+
@exporter.export(@exporter.collect, timeout: @timeout) unless status[:state] == "stopped"
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def close(timeout: @timeout)
|
|
62
|
+
Otel.shutdown(timeout:)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
private
|
|
66
|
+
|
|
67
|
+
def observe_telemetry
|
|
68
|
+
yield
|
|
69
|
+
rescue StandardError => e
|
|
70
|
+
OpenTelemetry.logger.warn("Gritz metrics observation failed (#{e.class})")
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def memory
|
|
74
|
+
return {} unless File.readable?("/proc/self/smaps_rollup")
|
|
75
|
+
|
|
76
|
+
File.read("/proc/self/smaps_rollup").scan(/^(Rss|Pss):\s+(\d+)\s+kB$/).to_h.transform_keys { |key| "#{key.downcase}_bytes" }
|
|
77
|
+
.transform_values { |value| value.to_i * 1024 }
|
|
78
|
+
rescue SystemCallError
|
|
79
|
+
{}
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Gritz
|
|
4
|
+
module Otel
|
|
5
|
+
# @api private
|
|
6
|
+
module Tracing
|
|
7
|
+
def self.within(context, kind:, parent:, &block)
|
|
8
|
+
OpenTelemetry::Context.with_current(parent) do
|
|
9
|
+
span = start_span(context, kind)
|
|
10
|
+
code = 0
|
|
11
|
+
begin
|
|
12
|
+
OpenTelemetry::Trace.with_span(span, &block)
|
|
13
|
+
rescue Gritz::Error => e
|
|
14
|
+
code = e.grpc_code
|
|
15
|
+
raise
|
|
16
|
+
rescue StandardError
|
|
17
|
+
code = 13
|
|
18
|
+
raise
|
|
19
|
+
ensure
|
|
20
|
+
code = 1 if code.zero? && context.cancelled?
|
|
21
|
+
finish_span(span, code)
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def self.start_span(context, kind)
|
|
27
|
+
attributes = { "rpc.system" => "grpc", "rpc.service" => context.method.service, "rpc.method" => context.method.name }
|
|
28
|
+
OpenTelemetry.tracer_provider.tracer("gritz", VERSION).start_span(context.method.full_name, kind:, attributes:)
|
|
29
|
+
rescue StandardError => e
|
|
30
|
+
OpenTelemetry.logger.warn("Gritz tracing failed to start (#{e.class})")
|
|
31
|
+
OpenTelemetry::Trace::Span::INVALID
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def self.finish_span(span, code)
|
|
35
|
+
span.set_attribute("rpc.grpc.status_code", code)
|
|
36
|
+
span.status = OpenTelemetry::Trace::Status.error("RPC failed") unless code.zero?
|
|
37
|
+
span.finish
|
|
38
|
+
rescue StandardError => e
|
|
39
|
+
OpenTelemetry.logger.warn("Gritz tracing failed to finish (#{e.class})")
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# Wraps the complete server dispatch, including streaming and error mapping.
|
|
44
|
+
class ServerTracing
|
|
45
|
+
def initialize(app) = @app = app
|
|
46
|
+
|
|
47
|
+
def call(context)
|
|
48
|
+
return @app.call(context) if ENV["OTEL_SDK_DISABLED"] == "true"
|
|
49
|
+
|
|
50
|
+
carrier = context.metadata.slice("traceparent", "tracestate").transform_values do |value|
|
|
51
|
+
value.is_a?(Array) ? value.join(",") : value
|
|
52
|
+
end
|
|
53
|
+
parent = OpenTelemetry.propagation.extract(carrier, context: OpenTelemetry::Context.empty)
|
|
54
|
+
Tracing.within(context, kind: :server, parent:) do
|
|
55
|
+
context.trace_context = OpenTelemetry::Context.current
|
|
56
|
+
@app.call(context)
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# Capture the caller when the invocation is created, before lazy stream consumption.
|
|
62
|
+
class ClientTracing
|
|
63
|
+
def initialize(app)
|
|
64
|
+
@app = app
|
|
65
|
+
@parent = OpenTelemetry::Context.current
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def call(context)
|
|
69
|
+
return @app.call(context) if ENV["OTEL_SDK_DISABLED"] == "true"
|
|
70
|
+
|
|
71
|
+
parent = context.parent&.trace_context
|
|
72
|
+
parent = @parent unless parent.is_a?(OpenTelemetry::Context)
|
|
73
|
+
Tracing.within(context, kind: :client, parent:) do
|
|
74
|
+
context.trace_context = OpenTelemetry::Context.current
|
|
75
|
+
carrier = {}
|
|
76
|
+
OpenTelemetry.propagation.inject(carrier)
|
|
77
|
+
context.metadata.delete("traceparent")
|
|
78
|
+
context.metadata.delete("tracestate")
|
|
79
|
+
context.metadata.merge!(carrier.slice("traceparent", "tracestate"))
|
|
80
|
+
@app.call(context)
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
end
|
data/lib/gritz/otel.rb
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "gritz/core"
|
|
4
|
+
require "opentelemetry-api"
|
|
5
|
+
require_relative "otel/version"
|
|
6
|
+
require_relative "otel/tracing"
|
|
7
|
+
require_relative "otel/recorder"
|
|
8
|
+
|
|
9
|
+
module Gritz
|
|
10
|
+
module Otel
|
|
11
|
+
# Configuration-file syntax for this optional integration.
|
|
12
|
+
module ConfigurationDSL
|
|
13
|
+
def opentelemetry(&) = Otel.install(@config, &)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
class << self
|
|
17
|
+
# Registration is safe before fork; SDK providers/exporters are built in the worker hook.
|
|
18
|
+
def install(config, &configure)
|
|
19
|
+
return config if config.middleware.entries.any? { |entry| entry.middleware == ServerTracing }
|
|
20
|
+
raise Gritz::ConfigurationError, "a metrics recorder is already installed" if config.metrics_recorder_factory
|
|
21
|
+
|
|
22
|
+
config.middleware.insert_after(Gritz::Middleware::Context, ServerTracing)
|
|
23
|
+
unless Gritz::Client.middleware.entries.any? { |entry| entry.middleware == ClientTracing }
|
|
24
|
+
Gritz::Client.middleware.use(ClientTracing)
|
|
25
|
+
end
|
|
26
|
+
config.add_hook(:on_worker_boot) { bootstrap(config, &configure) }
|
|
27
|
+
config.metrics_recorder_factory = ->(worker:) { Recorder.new(worker:, exporter: @metrics_exporter, timeout: export_timeout(config)) }
|
|
28
|
+
config
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# @api private
|
|
32
|
+
def bootstrap(config, &configure)
|
|
33
|
+
return if @pid == Process.pid
|
|
34
|
+
|
|
35
|
+
@metrics_exporter = @tracer_provider = @meter_provider = nil
|
|
36
|
+
return if ENV["OTEL_SDK_DISABLED"] == "true"
|
|
37
|
+
|
|
38
|
+
require "opentelemetry/sdk"
|
|
39
|
+
require "opentelemetry/exporter/otlp"
|
|
40
|
+
if config.metrics_backend == :otlp
|
|
41
|
+
require "opentelemetry-metrics-sdk"
|
|
42
|
+
require "opentelemetry-exporter-otlp-metrics"
|
|
43
|
+
@metrics_exporter = OpenTelemetry::Exporter::OTLP::Metrics::MetricsExporter.new
|
|
44
|
+
end
|
|
45
|
+
# SDK.configure swallows boot exceptions; the same official configurator
|
|
46
|
+
# lets an invalid worker configuration reach Gritz's startup failure path.
|
|
47
|
+
sdk = OpenTelemetry::SDK::Configurator.new
|
|
48
|
+
sdk.resource = OpenTelemetry::SDK::Resources::Resource.create("process.pid" => Process.pid, "service.instance.id" => Process.pid.to_s)
|
|
49
|
+
sdk.add_metric_reader(@metrics_exporter) if @metrics_exporter
|
|
50
|
+
# The metrics SDK patches the process-wide configurator once it is loaded.
|
|
51
|
+
# A trace-only worker must not create its default background metric reader.
|
|
52
|
+
if !@metrics_exporter && sdk.respond_to?(:add_metric_reader)
|
|
53
|
+
sdk.add_metric_reader(OpenTelemetry::SDK::Metrics::Export::MetricReader.new)
|
|
54
|
+
end
|
|
55
|
+
configure&.call(sdk)
|
|
56
|
+
sdk.configure
|
|
57
|
+
@tracer_provider = OpenTelemetry.tracer_provider
|
|
58
|
+
@meter_provider = OpenTelemetry.meter_provider if OpenTelemetry.respond_to?(:meter_provider)
|
|
59
|
+
if @metrics_exporter
|
|
60
|
+
{ "duration" => Metrics::Recorder::DURATION_BUCKETS, "requests" => Metrics::Recorder::MESSAGE_BUCKETS,
|
|
61
|
+
"responses" => Metrics::Recorder::MESSAGE_BUCKETS }.each do |name, bounds|
|
|
62
|
+
aggregation = OpenTelemetry::SDK::Metrics::Aggregation::ExplicitBucketHistogram.new(boundaries: bounds.select(&:finite?))
|
|
63
|
+
@meter_provider.add_view("gritz.rpc.server.#{name}", aggregation:, type: :histogram, meter_name: "gritz", meter_version: VERSION)
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
@pid = Process.pid
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# @api private
|
|
70
|
+
def shutdown(timeout:)
|
|
71
|
+
return unless @pid == Process.pid
|
|
72
|
+
|
|
73
|
+
@pid = nil
|
|
74
|
+
deadline = monotonic + timeout
|
|
75
|
+
if @metrics_exporter && timeout.positive?
|
|
76
|
+
shutdown_component { @metrics_exporter.export(@metrics_exporter.collect, timeout: timeout / 2.0) }
|
|
77
|
+
end
|
|
78
|
+
shutdown_component { @tracer_provider&.shutdown(timeout: [deadline - monotonic, 0].max) }
|
|
79
|
+
ensure
|
|
80
|
+
shutdown_component { @meter_provider&.shutdown(timeout: [deadline - monotonic, 0].max) } if deadline
|
|
81
|
+
@metrics_exporter = @tracer_provider = @meter_provider = nil if deadline
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
# Keep a slow collector within the worker's heartbeat and shutdown budgets.
|
|
85
|
+
# @api private
|
|
86
|
+
def export_timeout(config) = [1.0, config.status_interval / 2.0, config.shutdown_timeout / 4.0].min
|
|
87
|
+
def monotonic = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
88
|
+
|
|
89
|
+
private
|
|
90
|
+
|
|
91
|
+
def shutdown_component
|
|
92
|
+
yield
|
|
93
|
+
rescue StandardError => e
|
|
94
|
+
OpenTelemetry.logger.warn("Gritz telemetry shutdown failed (#{e.class})")
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
Gritz::DSL.prepend(Gritz::Otel::ConfigurationDSL)
|
metadata
ADDED
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: gritz-otel
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Yudai Takada
|
|
8
|
+
bindir: bin
|
|
9
|
+
cert_chain: []
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
|
+
dependencies:
|
|
12
|
+
- !ruby/object:Gem::Dependency
|
|
13
|
+
name: gritz-core
|
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
|
15
|
+
requirements:
|
|
16
|
+
- - '='
|
|
17
|
+
- !ruby/object:Gem::Version
|
|
18
|
+
version: 0.4.0
|
|
19
|
+
type: :runtime
|
|
20
|
+
prerelease: false
|
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
22
|
+
requirements:
|
|
23
|
+
- - '='
|
|
24
|
+
- !ruby/object:Gem::Version
|
|
25
|
+
version: 0.4.0
|
|
26
|
+
- !ruby/object:Gem::Dependency
|
|
27
|
+
name: opentelemetry-exporter-otlp
|
|
28
|
+
requirement: !ruby/object:Gem::Requirement
|
|
29
|
+
requirements:
|
|
30
|
+
- - "~>"
|
|
31
|
+
- !ruby/object:Gem::Version
|
|
32
|
+
version: 0.35.0
|
|
33
|
+
type: :runtime
|
|
34
|
+
prerelease: false
|
|
35
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
36
|
+
requirements:
|
|
37
|
+
- - "~>"
|
|
38
|
+
- !ruby/object:Gem::Version
|
|
39
|
+
version: 0.35.0
|
|
40
|
+
- !ruby/object:Gem::Dependency
|
|
41
|
+
name: opentelemetry-exporter-otlp-metrics
|
|
42
|
+
requirement: !ruby/object:Gem::Requirement
|
|
43
|
+
requirements:
|
|
44
|
+
- - "~>"
|
|
45
|
+
- !ruby/object:Gem::Version
|
|
46
|
+
version: 0.13.0
|
|
47
|
+
type: :runtime
|
|
48
|
+
prerelease: false
|
|
49
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
50
|
+
requirements:
|
|
51
|
+
- - "~>"
|
|
52
|
+
- !ruby/object:Gem::Version
|
|
53
|
+
version: 0.13.0
|
|
54
|
+
- !ruby/object:Gem::Dependency
|
|
55
|
+
name: opentelemetry-metrics-sdk
|
|
56
|
+
requirement: !ruby/object:Gem::Requirement
|
|
57
|
+
requirements:
|
|
58
|
+
- - "~>"
|
|
59
|
+
- !ruby/object:Gem::Version
|
|
60
|
+
version: 0.19.0
|
|
61
|
+
type: :runtime
|
|
62
|
+
prerelease: false
|
|
63
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
64
|
+
requirements:
|
|
65
|
+
- - "~>"
|
|
66
|
+
- !ruby/object:Gem::Version
|
|
67
|
+
version: 0.19.0
|
|
68
|
+
- !ruby/object:Gem::Dependency
|
|
69
|
+
name: opentelemetry-sdk
|
|
70
|
+
requirement: !ruby/object:Gem::Requirement
|
|
71
|
+
requirements:
|
|
72
|
+
- - "~>"
|
|
73
|
+
- !ruby/object:Gem::Version
|
|
74
|
+
version: 1.13.0
|
|
75
|
+
type: :runtime
|
|
76
|
+
prerelease: false
|
|
77
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
78
|
+
requirements:
|
|
79
|
+
- - "~>"
|
|
80
|
+
- !ruby/object:Gem::Version
|
|
81
|
+
version: 1.13.0
|
|
82
|
+
description: Server and client tracing and worker OTLP metrics for Gritz, initialized
|
|
83
|
+
after fork.
|
|
84
|
+
email:
|
|
85
|
+
- t.yudai92@gmail.com
|
|
86
|
+
executables: []
|
|
87
|
+
extensions: []
|
|
88
|
+
extra_rdoc_files: []
|
|
89
|
+
files:
|
|
90
|
+
- CHANGELOG.md
|
|
91
|
+
- LICENSE.txt
|
|
92
|
+
- README.md
|
|
93
|
+
- lib/gritz/otel.rb
|
|
94
|
+
- lib/gritz/otel/recorder.rb
|
|
95
|
+
- lib/gritz/otel/tracing.rb
|
|
96
|
+
- lib/gritz/otel/version.rb
|
|
97
|
+
homepage: https://github.com/gritzrpc/gritz-otel
|
|
98
|
+
licenses:
|
|
99
|
+
- MIT
|
|
100
|
+
metadata:
|
|
101
|
+
allowed_push_host: https://rubygems.org
|
|
102
|
+
homepage_uri: https://github.com/gritzrpc/gritz-otel/
|
|
103
|
+
source_code_uri: https://github.com/gritzrpc/gritz-otel
|
|
104
|
+
changelog_uri: https://github.com/gritzrpc/gritz-otel/blob/main/CHANGELOG.md
|
|
105
|
+
rubygems_mfa_required: 'true'
|
|
106
|
+
rdoc_options: []
|
|
107
|
+
require_paths:
|
|
108
|
+
- lib
|
|
109
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
110
|
+
requirements:
|
|
111
|
+
- - ">="
|
|
112
|
+
- !ruby/object:Gem::Version
|
|
113
|
+
version: '3.3'
|
|
114
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
115
|
+
requirements:
|
|
116
|
+
- - ">="
|
|
117
|
+
- !ruby/object:Gem::Version
|
|
118
|
+
version: '0'
|
|
119
|
+
requirements: []
|
|
120
|
+
rubygems_version: 4.0.16
|
|
121
|
+
specification_version: 4
|
|
122
|
+
summary: Fork-safe OpenTelemetry integration for Gritz
|
|
123
|
+
test_files: []
|