foam-ruby 0.1.0.alpha7 → 0.1.0.alpha9

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: 6357c1e7accb580c8cec51b5ca55500a49c84964984f1037176dccd242240e82
4
- data.tar.gz: 85b970210911bc6bbacf876c25407f13ab1d8900a0466a83d92d267f065d1bb6
3
+ metadata.gz: 87d1563f7f755555866b2b250981864ab47631e4bd751bbc9b9c74cc039bcf3f
4
+ data.tar.gz: 12f4674411cdc386042fca764ec96b7e38c4c19a7632a913b8b940bc0cfa8df5
5
5
  SHA512:
6
- metadata.gz: 127fbcc2b2c88659c61d20404fb6361e090cdc2dc352221b87d123efeb3121e2727414f6b4f05ba4140b2748b330a137e2c8e1eda6205f27097ad2be592d896c
7
- data.tar.gz: 9d5718f4db88c948a6787632687cf9081c4c0a0425e5b45ae4c349e4b3e333aed3d075980bf54ece6fdea8427b95139a8cb7ddcd7faea59ac2bf5d7ec56053f3
6
+ metadata.gz: ae75e5573553e9e9dc3df56dfd474a80ea1aebdabf47868524ceed505d7cdfbdc7d8b20721dcf85c8d97a4711d802d7fe3a2678b2ca47651f39d37585426db21
7
+ data.tar.gz: c6f2ac7466bd9d53c2d434d43f0f8378a396ed859a1dae5af523d18ce7564a3242c87eea117bd07179b2f181b415204ba57997288b8b393d75223b1fd6b72baa
@@ -24,13 +24,14 @@ module Foam
24
24
  }.freeze
25
25
 
26
26
  def initialize
27
- @otel_logger = OpenTelemetry.logger_provider.logger(name: "foam-ruby")
27
+ @logger_name = "foam-ruby"
28
28
  end
29
29
 
30
30
  def emit(severity, message)
31
31
  return if message.nil? || (message.respond_to?(:empty?) && message.empty?)
32
32
 
33
- @otel_logger.on_emit(
33
+ otel_logger = OpenTelemetry.logger_provider.logger(name: @logger_name)
34
+ otel_logger.on_emit(
34
35
  body: message.to_s,
35
36
  severity_number: SEVERITY_MAP.fetch(severity, OpenTelemetry::Logs::SeverityNumber::SEVERITY_NUMBER_INFO),
36
37
  severity_text: SEVERITY_TEXT.fetch(severity, "INFO"),
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Foam
4
+ module Ruby
5
+ class Middleware
6
+ def initialize(app)
7
+ @app = app
8
+ end
9
+
10
+ def call(env)
11
+ Foam::Ruby.ensure_worker_setup!
12
+ @app.call(env)
13
+ end
14
+ end
15
+ end
16
+ end
@@ -17,37 +17,71 @@ module Foam
17
17
  end
18
18
 
19
19
  def configure_traces(config)
20
- OpenTelemetry::SDK.configure do |c|
21
- c.service_name = config.service_name
22
-
23
- c.add_span_processor(
24
- OpenTelemetry::SDK::Trace::Export::BatchSpanProcessor.new(
25
- OpenTelemetry::Exporter::OTLP::Exporter.new(
26
- endpoint: config.traces_endpoint,
27
- headers: config.otel_headers
28
- )
29
- )
20
+ @foam_span_processor = OpenTelemetry::SDK::Trace::Export::BatchSpanProcessor.new(
21
+ OpenTelemetry::Exporter::OTLP::Exporter.new(
22
+ endpoint: config.traces_endpoint,
23
+ headers: config.otel_headers
30
24
  )
25
+ )
31
26
 
32
- c.use_all
27
+ existing = OpenTelemetry.tracer_provider
28
+ if existing.is_a?(OpenTelemetry::SDK::Trace::TracerProvider)
29
+ existing.add_span_processor(@foam_span_processor)
30
+ else
31
+ OpenTelemetry::SDK.configure do |c|
32
+ c.service_name = config.service_name
33
+ c.add_span_processor(@foam_span_processor)
34
+ c.use_all
35
+ end
33
36
  end
37
+
38
+ @attached_provider = OpenTelemetry.tracer_provider
39
+ end
40
+
41
+ def ensure_processor_attached!
42
+ return unless @foam_span_processor
43
+
44
+ current = OpenTelemetry.tracer_provider
45
+ return if current.equal?(@attached_provider)
46
+ return unless current.is_a?(OpenTelemetry::SDK::Trace::TracerProvider)
47
+
48
+ current.add_span_processor(@foam_span_processor)
49
+ @attached_provider = current
34
50
  end
35
51
 
36
52
  def configure_logs(config)
37
- resource = OpenTelemetry::SDK::Resources::Resource.create(
38
- "service.name" => config.service_name,
39
- "deployment.environment" => ENV["RAILS_ENV"] || ENV["RACK_ENV"] || "production"
53
+ @foam_log_processor = OpenTelemetry::SDK::Logs::Export::BatchLogRecordProcessor.new(
54
+ OpenTelemetry::Exporter::OTLP::Logs::LogsExporter.new(
55
+ endpoint: config.logs_endpoint,
56
+ headers: config.otel_headers
57
+ )
40
58
  )
41
59
 
42
- exporter = OpenTelemetry::Exporter::OTLP::Logs::LogsExporter.new(
43
- endpoint: config.logs_endpoint,
44
- headers: config.otel_headers
45
- )
60
+ existing = OpenTelemetry.logger_provider
61
+ if existing.is_a?(OpenTelemetry::SDK::Logs::LoggerProvider)
62
+ existing.add_log_record_processor(@foam_log_processor)
63
+ else
64
+ resource = OpenTelemetry::SDK::Resources::Resource.create(
65
+ "service.name" => config.service_name,
66
+ "deployment.environment" => ENV["RAILS_ENV"] || ENV["RACK_ENV"] || "production"
67
+ )
68
+ provider = OpenTelemetry::SDK::Logs::LoggerProvider.new(resource: resource)
69
+ provider.add_log_record_processor(@foam_log_processor)
70
+ OpenTelemetry.logger_provider = provider
71
+ end
72
+
73
+ @attached_logger_provider = OpenTelemetry.logger_provider
74
+ end
75
+
76
+ def ensure_log_processor_attached!
77
+ return unless @foam_log_processor
78
+
79
+ current = OpenTelemetry.logger_provider
80
+ return if current.equal?(@attached_logger_provider)
81
+ return unless current.is_a?(OpenTelemetry::SDK::Logs::LoggerProvider)
46
82
 
47
- processor = OpenTelemetry::SDK::Logs::Export::BatchLogRecordProcessor.new(exporter)
48
- logger_provider = OpenTelemetry::SDK::Logs::LoggerProvider.new(resource: resource)
49
- logger_provider.add_log_record_processor(processor)
50
- OpenTelemetry.logger_provider = logger_provider
83
+ current.add_log_record_processor(@foam_log_processor)
84
+ @attached_logger_provider = current
51
85
  end
52
86
  end
53
87
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Foam
4
4
  module Ruby
5
- VERSION = "0.1.0.alpha7"
5
+ VERSION = "0.1.0.alpha9"
6
6
  end
7
7
  end
data/lib/foam/ruby.rb CHANGED
@@ -11,6 +11,7 @@ module Foam
11
11
  end
12
12
 
13
13
  def init(token: nil, service_name: nil)
14
+ return if initialized?
14
15
  return unless production?
15
16
 
16
17
  config = configuration
@@ -24,9 +25,10 @@ module Foam
24
25
 
25
26
  require_relative "ruby/otel_setup"
26
27
  require_relative "ruby/log_subscriber"
28
+ require_relative "ruby/middleware"
27
29
 
28
30
  OtelSetup.configure!(config)
29
- schedule_logger_attach!
31
+ insert_middleware!
30
32
  bridge_sentry!
31
33
  @initialized = true
32
34
  rescue Exception => e # rubocop:disable Lint/RescueException
@@ -34,6 +36,24 @@ module Foam
34
36
  @initialized = false
35
37
  end
36
38
 
39
+ # Ensures Foam's processors and logger broadcast are attached in the
40
+ # current process. Called by Middleware on the first request per worker
41
+ # PID — a single integer comparison on every subsequent request.
42
+ # Public so non-Rails apps can call it from custom fork hooks.
43
+ def ensure_worker_setup!
44
+ return unless initialized?
45
+
46
+ pid = Process.pid
47
+ return if @worker_pid == pid
48
+ @worker_pid = pid
49
+
50
+ OtelSetup.ensure_processor_attached!
51
+ OtelSetup.ensure_log_processor_attached!
52
+ attach_otel_logger!
53
+ rescue Exception # rubocop:disable Lint/RescueException
54
+ nil
55
+ end
56
+
37
57
  def capture_exception(error, attributes: {})
38
58
  return unless initialized?
39
59
 
@@ -71,14 +91,10 @@ module Foam
71
91
  false
72
92
  end
73
93
 
74
- def schedule_logger_attach!
75
- return unless defined?(::Rails)
94
+ def insert_middleware!
95
+ return unless defined?(::Rails) && ::Rails.respond_to?(:application) && ::Rails.application
76
96
 
77
- if ::Rails.respond_to?(:application) && ::Rails.application
78
- ::Rails.application.config.after_initialize { do_attach_otel_logger! }
79
- else
80
- do_attach_otel_logger!
81
- end
97
+ ::Rails.application.middleware.insert(0, Foam::Ruby::Middleware)
82
98
  rescue Exception # rubocop:disable Lint/RescueException
83
99
  nil
84
100
  end
@@ -100,20 +116,30 @@ module Foam
100
116
  nil
101
117
  end
102
118
 
103
- def do_attach_otel_logger!
104
- return unless ::Rails.respond_to?(:logger) && ::Rails.logger
119
+ def attach_otel_logger!
120
+ return unless defined?(::Rails) && ::Rails.respond_to?(:logger) && ::Rails.logger
105
121
 
106
122
  unless OpenTelemetry.logger_provider.is_a?(OpenTelemetry::SDK::Logs::LoggerProvider)
107
123
  return
108
124
  end
109
125
 
126
+ logger = ::Rails.logger
127
+
128
+ if logger.respond_to?(:broadcasts)
129
+ return if logger.broadcasts.any? { |l| l.is_a?(OtelLogger) }
130
+ else
131
+ return if logger.equal?(@attached_rails_logger)
132
+ end
133
+
110
134
  otel_logger = OtelLogger.new
111
135
 
112
- if ::Rails.logger.respond_to?(:broadcast_to)
113
- ::Rails.logger.broadcast_to(otel_logger)
136
+ if logger.respond_to?(:broadcast_to)
137
+ logger.broadcast_to(otel_logger)
114
138
  elsif defined?(::ActiveSupport::Logger) && ::ActiveSupport::Logger.respond_to?(:broadcast)
115
- ::Rails.logger.extend(::ActiveSupport::Logger.broadcast(otel_logger))
139
+ logger.extend(::ActiveSupport::Logger.broadcast(otel_logger))
116
140
  end
141
+
142
+ @attached_rails_logger = logger
117
143
  rescue Exception # rubocop:disable Lint/RescueException
118
144
  nil
119
145
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: foam-ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0.alpha7
4
+ version: 0.1.0.alpha9
5
5
  platform: ruby
6
6
  authors:
7
7
  - Foam
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-04-14 00:00:00.000000000 Z
11
+ date: 2026-04-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: opentelemetry-api
@@ -218,6 +218,7 @@ files:
218
218
  - lib/foam/ruby.rb
219
219
  - lib/foam/ruby/configuration.rb
220
220
  - lib/foam/ruby/log_subscriber.rb
221
+ - lib/foam/ruby/middleware.rb
221
222
  - lib/foam/ruby/otel_setup.rb
222
223
  - lib/foam/ruby/version.rb
223
224
  homepage: https://github.com/nicktesh/packages