launchdarkly-observability 0.2.0 → 0.2.2
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 +4 -4
- data/CHANGELOG.md +14 -0
- data/README.md +1 -1
- data/lib/launchdarkly_observability/hook.rb +20 -10
- data/lib/launchdarkly_observability/plugin.rb +9 -0
- data/lib/launchdarkly_observability/rails.rb +64 -49
- data/lib/launchdarkly_observability/version.rb +1 -1
- metadata +4 -4
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: d46f86b88f2c7b3dfd876ef07b2135e8d11f8939c66a1071246ebb627b387f0d
|
|
4
|
+
data.tar.gz: 28d3c8ab27674a1e4ca3996c805d97136782198b2da0a96e8f64902d49ed1f4e
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: cd64fc216a9af53ec0c78bc4af429edf051e0da37b8568e4611d78bd0863711d2ca0b94fb8de97c39b30de4f0828c4eb2a874ce5148e0491f0ba320f716ad96f
|
|
7
|
+
data.tar.gz: 40114279e622a08632d68b63f5faebb4f77230cfe72f8a7a723b2a27898f81bf1c7a2179204068ebb3c178451339f8de7e0ca52840a77fe8d68c9e0721151663
|
data/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,20 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [0.2.2](https://github.com/launchdarkly/observability-sdk/compare/launchdarkly-observability-ruby/0.2.1...launchdarkly-observability-ruby/0.2.2) (2026-06-22)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Bug Fixes
|
|
12
|
+
|
|
13
|
+
* **ruby:** omit nil feature_flag.context.id for invalid contexts ([#641](https://github.com/launchdarkly/observability-sdk/issues/641)) ([587e2e4](https://github.com/launchdarkly/observability-sdk/commit/587e2e40764bade29198c47e6746887f1af6d856))
|
|
14
|
+
|
|
15
|
+
## [0.2.1](https://github.com/launchdarkly/observability-sdk/compare/launchdarkly-observability-ruby/0.2.0...launchdarkly-observability-ruby/0.2.1) (2026-06-02)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
### Bug Fixes
|
|
19
|
+
|
|
20
|
+
* **ruby:** observability plugin compatibility — require server-sdk >= 8.11.0 and fix Rails Railtie load order ([#575](https://github.com/launchdarkly/observability-sdk/issues/575)) ([e9d8310](https://github.com/launchdarkly/observability-sdk/commit/e9d8310c0d0d53c20ee8a48f31279a386988d27a))
|
|
21
|
+
|
|
8
22
|
## [0.2.0](https://github.com/launchdarkly/observability-sdk/compare/launchdarkly-observability-ruby-0.1.0...launchdarkly-observability-ruby/0.2.0) (2026-03-27)
|
|
9
23
|
|
|
10
24
|
|
data/README.md
CHANGED
|
@@ -35,7 +35,7 @@ gem install launchdarkly-observability
|
|
|
35
35
|
### Dependencies
|
|
36
36
|
|
|
37
37
|
The gem includes everything needed for traces and logs out of the box:
|
|
38
|
-
- `launchdarkly-server-sdk` >= 8.0
|
|
38
|
+
- `launchdarkly-server-sdk` >= 8.11.0 (plugin support was added in 8.11.0)
|
|
39
39
|
- `opentelemetry-sdk` ~> 1.4
|
|
40
40
|
- `opentelemetry-exporter-otlp` ~> 0.28
|
|
41
41
|
- `opentelemetry-instrumentation-all` ~> 0.62
|
|
@@ -91,12 +91,23 @@ module LaunchDarklyObservability
|
|
|
91
91
|
FEATURE_FLAG_PROVIDER_NAME => 'LaunchDarkly'
|
|
92
92
|
}
|
|
93
93
|
|
|
94
|
-
|
|
95
|
-
if context
|
|
96
|
-
attrs[FEATURE_FLAG_CONTEXT_ID] = context.fully_qualified_key
|
|
97
|
-
end
|
|
94
|
+
attrs[FEATURE_FLAG_CONTEXT_ID] = context_id_for(series_context)
|
|
98
95
|
|
|
99
|
-
|
|
96
|
+
# OpenTelemetry rejects nil attribute values and logs an error for each
|
|
97
|
+
# one. Drop nils centrally so individual call sites cannot reintroduce the
|
|
98
|
+
# "invalid attribute value type NilClass" noise (e.g. an invalid context
|
|
99
|
+
# whose fully_qualified_key is nil).
|
|
100
|
+
attrs.compact
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
# Returns the fully-qualified context key, or nil if unavailable.
|
|
104
|
+
#
|
|
105
|
+
# An invalid context (e.g. a non-string context kind) is still a non-nil
|
|
106
|
+
# object but yields a nil fully_qualified_key. OpenTelemetry rejects nil
|
|
107
|
+
# attribute values ("invalid attribute value type NilClass"), so callers
|
|
108
|
+
# must omit the attribute entirely when this returns nil.
|
|
109
|
+
def context_id_for(series_context)
|
|
110
|
+
series_context.context&.fully_qualified_key
|
|
100
111
|
end
|
|
101
112
|
|
|
102
113
|
def serialize_value(value)
|
|
@@ -127,10 +138,7 @@ module LaunchDarklyObservability
|
|
|
127
138
|
FEATURE_FLAG_PROVIDER_NAME => 'LaunchDarkly'
|
|
128
139
|
}
|
|
129
140
|
|
|
130
|
-
|
|
131
|
-
if context
|
|
132
|
-
event_attributes[FEATURE_FLAG_CONTEXT_ID] = context.fully_qualified_key
|
|
133
|
-
end
|
|
141
|
+
event_attributes[FEATURE_FLAG_CONTEXT_ID] = context_id_for(series_context)
|
|
134
142
|
|
|
135
143
|
if detail.variation_index
|
|
136
144
|
event_attributes[FEATURE_FLAG_RESULT_VARIANT] = detail.variation_index.to_s
|
|
@@ -146,7 +154,9 @@ module LaunchDarklyObservability
|
|
|
146
154
|
add_reason_event_details(event_attributes, reason)
|
|
147
155
|
end
|
|
148
156
|
|
|
149
|
-
|
|
157
|
+
# See build_before_attributes: drop nil values so a missing context id (or
|
|
158
|
+
# any future optional attribute) cannot emit a nil-attribute OTel error.
|
|
159
|
+
span.add_event(FEATURE_FLAG_EVENT_NAME, attributes: event_attributes.compact)
|
|
150
160
|
end
|
|
151
161
|
|
|
152
162
|
def add_reason_event_details(event_attributes, reason)
|
|
@@ -2,6 +2,15 @@
|
|
|
2
2
|
|
|
3
3
|
require 'launchdarkly-server-sdk'
|
|
4
4
|
|
|
5
|
+
# Plugin support (LaunchDarkly::Interfaces::Plugins) was added in launchdarkly-server-sdk 8.11.0.
|
|
6
|
+
# Surface an actionable error instead of a bare "uninitialized constant" if an older SDK is loaded.
|
|
7
|
+
unless defined?(LaunchDarkly::Interfaces::Plugins::Plugin)
|
|
8
|
+
raise LoadError, 'launchdarkly-observability requires launchdarkly-server-sdk >= 8.11.0 ' \
|
|
9
|
+
'(plugin support was added in 8.11.0). Your installed launchdarkly-server-sdk ' \
|
|
10
|
+
"version is #{defined?(LaunchDarkly::VERSION) ? LaunchDarkly::VERSION : 'unknown'}. " \
|
|
11
|
+
'Please upgrade: bundle update launchdarkly-server-sdk'
|
|
12
|
+
end
|
|
13
|
+
|
|
5
14
|
module LaunchDarklyObservability
|
|
6
15
|
# LaunchDarkly SDK Plugin that provides observability instrumentation.
|
|
7
16
|
#
|
|
@@ -4,56 +4,16 @@ require_relative 'middleware'
|
|
|
4
4
|
|
|
5
5
|
module LaunchDarklyObservability
|
|
6
6
|
if defined?(::Rails::Railtie)
|
|
7
|
-
#
|
|
7
|
+
# Controller and view helper modules are defined BEFORE the Railtie on purpose.
|
|
8
8
|
#
|
|
9
|
-
#
|
|
10
|
-
#
|
|
11
|
-
#
|
|
12
|
-
#
|
|
13
|
-
#
|
|
14
|
-
#
|
|
15
|
-
#
|
|
16
|
-
#
|
|
17
|
-
#
|
|
18
|
-
class Railtie < ::Rails::Railtie
|
|
19
|
-
initializer 'launchdarkly_observability.configure_rails' do |app|
|
|
20
|
-
app.middleware.insert_before(0, LaunchDarklyObservability::Middleware)
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
config.after_initialize do
|
|
24
|
-
if defined?(ActionController::Base)
|
|
25
|
-
ActionController::Base.include(LaunchDarklyObservability::ControllerHelpers)
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
if defined?(ActionController::API)
|
|
29
|
-
ActionController::API.include(LaunchDarklyObservability::ControllerHelpers)
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
attach_otel_log_bridge
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
class << self
|
|
36
|
-
private
|
|
37
|
-
|
|
38
|
-
def attach_otel_log_bridge
|
|
39
|
-
return unless otel_logger_provider_available?
|
|
40
|
-
|
|
41
|
-
bridge = LaunchDarklyObservability::OtelLogBridge.new(OpenTelemetry.logger_provider)
|
|
42
|
-
|
|
43
|
-
if ::Rails.logger.respond_to?(:broadcast_to)
|
|
44
|
-
::Rails.logger.broadcast_to(bridge)
|
|
45
|
-
elsif defined?(ActiveSupport::Logger) && ActiveSupport::Logger.respond_to?(:broadcast)
|
|
46
|
-
::Rails.logger.extend(ActiveSupport::Logger.broadcast(bridge))
|
|
47
|
-
end
|
|
48
|
-
rescue StandardError => e
|
|
49
|
-
warn "[LaunchDarklyObservability] Could not attach log bridge to Rails.logger: #{e.message}"
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
def otel_logger_provider_available?
|
|
53
|
-
LaunchDarklyObservability.send(:otel_logger_provider_available?)
|
|
54
|
-
end
|
|
55
|
-
end
|
|
56
|
-
end
|
|
9
|
+
# The Railtie's `config.after_initialize` hook references ControllerHelpers. That
|
|
10
|
+
# hook is registered via ActiveSupport's lazy load hooks, which run immediately if
|
|
11
|
+
# the :after_initialize event has already fired. When the gem is required lazily
|
|
12
|
+
# *after* Rails has booted (e.g. from an autoloaded model during a request), the
|
|
13
|
+
# block executes synchronously while this file is still loading. If the helper
|
|
14
|
+
# modules were defined further down the file, they would not exist yet and the
|
|
15
|
+
# require would raise "uninitialized constant LaunchDarklyObservability::ControllerHelpers".
|
|
16
|
+
# Defining them first makes the require order-independent.
|
|
57
17
|
|
|
58
18
|
# Controller helper methods for Rails
|
|
59
19
|
#
|
|
@@ -134,6 +94,61 @@ module LaunchDarklyObservability
|
|
|
134
94
|
end
|
|
135
95
|
end
|
|
136
96
|
|
|
97
|
+
# Rails Railtie for automatic integration
|
|
98
|
+
#
|
|
99
|
+
# This Railtie automatically:
|
|
100
|
+
# - Inserts the LaunchDarkly middleware into the Rails middleware stack
|
|
101
|
+
# - Bridges Rails.logger to the OpenTelemetry Logs pipeline (if logger provider is available)
|
|
102
|
+
# - Provides helper methods for controllers and views
|
|
103
|
+
#
|
|
104
|
+
# @example The Railtie is automatically loaded when Rails is detected
|
|
105
|
+
# # In config/initializers/launchdarkly.rb
|
|
106
|
+
# LaunchDarklyObservability.init(project_id: ENV['LD_PROJECT_ID'])
|
|
107
|
+
#
|
|
108
|
+
class Railtie < ::Rails::Railtie
|
|
109
|
+
# Private helpers are defined before `config.after_initialize` references them.
|
|
110
|
+
# The after_initialize hook can run synchronously while this class body is still
|
|
111
|
+
# evaluating (lazy require after Rails has booted — see the note above), so any
|
|
112
|
+
# method it calls must already be defined at that point.
|
|
113
|
+
class << self
|
|
114
|
+
private
|
|
115
|
+
|
|
116
|
+
def attach_otel_log_bridge
|
|
117
|
+
return unless otel_logger_provider_available?
|
|
118
|
+
|
|
119
|
+
bridge = LaunchDarklyObservability::OtelLogBridge.new(OpenTelemetry.logger_provider)
|
|
120
|
+
|
|
121
|
+
if ::Rails.logger.respond_to?(:broadcast_to)
|
|
122
|
+
::Rails.logger.broadcast_to(bridge)
|
|
123
|
+
elsif defined?(ActiveSupport::Logger) && ActiveSupport::Logger.respond_to?(:broadcast)
|
|
124
|
+
::Rails.logger.extend(ActiveSupport::Logger.broadcast(bridge))
|
|
125
|
+
end
|
|
126
|
+
rescue StandardError => e
|
|
127
|
+
warn "[LaunchDarklyObservability] Could not attach log bridge to Rails.logger: #{e.message}"
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
def otel_logger_provider_available?
|
|
131
|
+
LaunchDarklyObservability.send(:otel_logger_provider_available?)
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
initializer 'launchdarkly_observability.configure_rails' do |app|
|
|
136
|
+
app.middleware.insert_before(0, LaunchDarklyObservability::Middleware)
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
config.after_initialize do
|
|
140
|
+
if defined?(ActionController::Base)
|
|
141
|
+
ActionController::Base.include(LaunchDarklyObservability::ControllerHelpers)
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
if defined?(ActionController::API)
|
|
145
|
+
ActionController::API.include(LaunchDarklyObservability::ControllerHelpers)
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
attach_otel_log_bridge
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
|
|
137
152
|
if defined?(ActionView::Base)
|
|
138
153
|
ActionView::Base.include(ViewHelpers)
|
|
139
154
|
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: launchdarkly-observability
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.2.
|
|
4
|
+
version: 0.2.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- LaunchDarkly
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-
|
|
11
|
+
date: 2026-06-22 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: launchdarkly-server-sdk
|
|
@@ -16,14 +16,14 @@ dependencies:
|
|
|
16
16
|
requirements:
|
|
17
17
|
- - ">="
|
|
18
18
|
- !ruby/object:Gem::Version
|
|
19
|
-
version:
|
|
19
|
+
version: 8.11.0
|
|
20
20
|
type: :runtime
|
|
21
21
|
prerelease: false
|
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
|
23
23
|
requirements:
|
|
24
24
|
- - ">="
|
|
25
25
|
- !ruby/object:Gem::Version
|
|
26
|
-
version:
|
|
26
|
+
version: 8.11.0
|
|
27
27
|
- !ruby/object:Gem::Dependency
|
|
28
28
|
name: opentelemetry-exporter-otlp
|
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|