lapsoss 0.2.0 → 0.3.1
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/README.md +153 -733
- data/lib/lapsoss/adapters/appsignal_adapter.rb +22 -22
- data/lib/lapsoss/adapters/base.rb +0 -3
- data/lib/lapsoss/adapters/insight_hub_adapter.rb +108 -104
- data/lib/lapsoss/adapters/logger_adapter.rb +1 -1
- data/lib/lapsoss/adapters/rollbar_adapter.rb +108 -68
- data/lib/lapsoss/adapters/sentry_adapter.rb +24 -24
- data/lib/lapsoss/backtrace_frame.rb +37 -206
- data/lib/lapsoss/backtrace_frame_factory.rb +228 -0
- data/lib/lapsoss/backtrace_processor.rb +27 -23
- data/lib/lapsoss/client.rb +2 -4
- data/lib/lapsoss/configuration.rb +28 -32
- data/lib/lapsoss/current.rb +10 -2
- data/lib/lapsoss/event.rb +28 -5
- data/lib/lapsoss/exception_backtrace_frame.rb +39 -0
- data/lib/lapsoss/exclusion_configuration.rb +30 -0
- data/lib/lapsoss/exclusion_filter.rb +0 -273
- data/lib/lapsoss/exclusion_presets.rb +249 -0
- data/lib/lapsoss/fingerprinter.rb +28 -28
- data/lib/lapsoss/http_client.rb +8 -8
- data/lib/lapsoss/merged_scope.rb +63 -0
- data/lib/lapsoss/middleware/base.rb +15 -0
- data/lib/lapsoss/middleware/conditional_filter.rb +18 -0
- data/lib/lapsoss/middleware/event_enricher.rb +19 -0
- data/lib/lapsoss/middleware/event_transformer.rb +19 -0
- data/lib/lapsoss/middleware/exception_filter.rb +43 -0
- data/lib/lapsoss/middleware/metrics_collector.rb +44 -0
- data/lib/lapsoss/middleware/rate_limiter.rb +31 -0
- data/lib/lapsoss/middleware/release_tracker.rb +117 -0
- data/lib/lapsoss/middleware/sample_filter.rb +23 -0
- data/lib/lapsoss/middleware/sampling_middleware.rb +18 -0
- data/lib/lapsoss/middleware/user_context_enhancer.rb +46 -0
- data/lib/lapsoss/pipeline.rb +0 -68
- data/lib/lapsoss/pipeline_builder.rb +69 -0
- data/lib/lapsoss/rails_error_subscriber.rb +42 -0
- data/lib/lapsoss/rails_middleware.rb +78 -0
- data/lib/lapsoss/railtie.rb +22 -50
- data/lib/lapsoss/registry.rb +18 -5
- data/lib/lapsoss/release_providers.rb +110 -0
- data/lib/lapsoss/release_tracker.rb +159 -232
- data/lib/lapsoss/sampling/adaptive_sampler.rb +46 -0
- data/lib/lapsoss/sampling/base.rb +11 -0
- data/lib/lapsoss/sampling/composite_sampler.rb +26 -0
- data/lib/lapsoss/sampling/consistent_hash_sampler.rb +30 -0
- data/lib/lapsoss/sampling/exception_type_sampler.rb +44 -0
- data/lib/lapsoss/sampling/health_based_sampler.rb +19 -0
- data/lib/lapsoss/sampling/rate_limiter.rb +32 -0
- data/lib/lapsoss/sampling/sampling_factory.rb +69 -0
- data/lib/lapsoss/sampling/time_based_sampler.rb +44 -0
- data/lib/lapsoss/sampling/uniform_sampler.rb +15 -0
- data/lib/lapsoss/sampling/user_based_sampler.rb +42 -0
- data/lib/lapsoss/scope.rb +12 -48
- data/lib/lapsoss/scrubber.rb +7 -7
- data/lib/lapsoss/user_context.rb +30 -203
- data/lib/lapsoss/user_context_integrations.rb +39 -0
- data/lib/lapsoss/user_context_middleware.rb +50 -0
- data/lib/lapsoss/user_context_provider.rb +93 -0
- data/lib/lapsoss/utils.rb +13 -0
- data/lib/lapsoss/validators.rb +15 -15
- data/lib/lapsoss/version.rb +1 -1
- data/lib/lapsoss.rb +3 -3
- metadata +60 -7
- data/lib/lapsoss/middleware.rb +0 -345
- data/lib/lapsoss/sampling.rb +0 -328
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: lapsoss
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Abdelkader Boudih
|
@@ -16,6 +16,9 @@ dependencies:
|
|
16
16
|
- - ">="
|
17
17
|
- !ruby/object:Gem::Version
|
18
18
|
version: '7.2'
|
19
|
+
- - "<"
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '9.0'
|
19
22
|
type: :runtime
|
20
23
|
prerelease: false
|
21
24
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -23,20 +26,23 @@ dependencies:
|
|
23
26
|
- - ">="
|
24
27
|
- !ruby/object:Gem::Version
|
25
28
|
version: '7.2'
|
29
|
+
- - "<"
|
30
|
+
- !ruby/object:Gem::Version
|
31
|
+
version: '9.0'
|
26
32
|
- !ruby/object:Gem::Dependency
|
27
33
|
name: concurrent-ruby
|
28
34
|
requirement: !ruby/object:Gem::Requirement
|
29
35
|
requirements:
|
30
|
-
- - "
|
36
|
+
- - ">="
|
31
37
|
- !ruby/object:Gem::Version
|
32
|
-
version:
|
38
|
+
version: 1.3.1
|
33
39
|
type: :runtime
|
34
40
|
prerelease: false
|
35
41
|
version_requirements: !ruby/object:Gem::Requirement
|
36
42
|
requirements:
|
37
|
-
- - "
|
43
|
+
- - ">="
|
38
44
|
- !ruby/object:Gem::Version
|
39
|
-
version:
|
45
|
+
version: 1.3.1
|
40
46
|
- !ruby/object:Gem::Dependency
|
41
47
|
name: faraday
|
42
48
|
requirement: !ruby/object:Gem::Requirement
|
@@ -141,6 +147,20 @@ dependencies:
|
|
141
147
|
- - "~>"
|
142
148
|
- !ruby/object:Gem::Version
|
143
149
|
version: '1.0'
|
150
|
+
- !ruby/object:Gem::Dependency
|
151
|
+
name: rubocop-rails-omakase
|
152
|
+
requirement: !ruby/object:Gem::Requirement
|
153
|
+
requirements:
|
154
|
+
- - "~>"
|
155
|
+
- !ruby/object:Gem::Version
|
156
|
+
version: '1.0'
|
157
|
+
type: :development
|
158
|
+
prerelease: false
|
159
|
+
version_requirements: !ruby/object:Gem::Requirement
|
160
|
+
requirements:
|
161
|
+
- - "~>"
|
162
|
+
- !ruby/object:Gem::Version
|
163
|
+
version: '1.0'
|
144
164
|
- !ruby/object:Gem::Dependency
|
145
165
|
name: steep
|
146
166
|
requirement: !ruby/object:Gem::Requirement
|
@@ -204,24 +224,57 @@ files:
|
|
204
224
|
- lib/lapsoss/adapters/rollbar_adapter.rb
|
205
225
|
- lib/lapsoss/adapters/sentry_adapter.rb
|
206
226
|
- lib/lapsoss/backtrace_frame.rb
|
227
|
+
- lib/lapsoss/backtrace_frame_factory.rb
|
207
228
|
- lib/lapsoss/backtrace_processor.rb
|
208
229
|
- lib/lapsoss/client.rb
|
209
230
|
- lib/lapsoss/configuration.rb
|
210
231
|
- lib/lapsoss/current.rb
|
211
232
|
- lib/lapsoss/event.rb
|
233
|
+
- lib/lapsoss/exception_backtrace_frame.rb
|
234
|
+
- lib/lapsoss/exclusion_configuration.rb
|
212
235
|
- lib/lapsoss/exclusion_filter.rb
|
236
|
+
- lib/lapsoss/exclusion_presets.rb
|
213
237
|
- lib/lapsoss/fingerprinter.rb
|
214
238
|
- lib/lapsoss/http_client.rb
|
215
|
-
- lib/lapsoss/
|
239
|
+
- lib/lapsoss/merged_scope.rb
|
240
|
+
- lib/lapsoss/middleware/base.rb
|
241
|
+
- lib/lapsoss/middleware/conditional_filter.rb
|
242
|
+
- lib/lapsoss/middleware/event_enricher.rb
|
243
|
+
- lib/lapsoss/middleware/event_transformer.rb
|
244
|
+
- lib/lapsoss/middleware/exception_filter.rb
|
245
|
+
- lib/lapsoss/middleware/metrics_collector.rb
|
246
|
+
- lib/lapsoss/middleware/rate_limiter.rb
|
247
|
+
- lib/lapsoss/middleware/release_tracker.rb
|
248
|
+
- lib/lapsoss/middleware/sample_filter.rb
|
249
|
+
- lib/lapsoss/middleware/sampling_middleware.rb
|
250
|
+
- lib/lapsoss/middleware/user_context_enhancer.rb
|
216
251
|
- lib/lapsoss/pipeline.rb
|
252
|
+
- lib/lapsoss/pipeline_builder.rb
|
253
|
+
- lib/lapsoss/rails_error_subscriber.rb
|
254
|
+
- lib/lapsoss/rails_middleware.rb
|
217
255
|
- lib/lapsoss/railtie.rb
|
218
256
|
- lib/lapsoss/registry.rb
|
257
|
+
- lib/lapsoss/release_providers.rb
|
219
258
|
- lib/lapsoss/release_tracker.rb
|
220
259
|
- lib/lapsoss/router.rb
|
221
|
-
- lib/lapsoss/sampling.rb
|
260
|
+
- lib/lapsoss/sampling/adaptive_sampler.rb
|
261
|
+
- lib/lapsoss/sampling/base.rb
|
262
|
+
- lib/lapsoss/sampling/composite_sampler.rb
|
263
|
+
- lib/lapsoss/sampling/consistent_hash_sampler.rb
|
264
|
+
- lib/lapsoss/sampling/exception_type_sampler.rb
|
265
|
+
- lib/lapsoss/sampling/health_based_sampler.rb
|
266
|
+
- lib/lapsoss/sampling/rate_limiter.rb
|
267
|
+
- lib/lapsoss/sampling/sampling_factory.rb
|
268
|
+
- lib/lapsoss/sampling/time_based_sampler.rb
|
269
|
+
- lib/lapsoss/sampling/uniform_sampler.rb
|
270
|
+
- lib/lapsoss/sampling/user_based_sampler.rb
|
222
271
|
- lib/lapsoss/scope.rb
|
223
272
|
- lib/lapsoss/scrubber.rb
|
224
273
|
- lib/lapsoss/user_context.rb
|
274
|
+
- lib/lapsoss/user_context_integrations.rb
|
275
|
+
- lib/lapsoss/user_context_middleware.rb
|
276
|
+
- lib/lapsoss/user_context_provider.rb
|
277
|
+
- lib/lapsoss/utils.rb
|
225
278
|
- lib/lapsoss/validators.rb
|
226
279
|
- lib/lapsoss/version.rb
|
227
280
|
homepage: https://github.com/seuros/lapsoss
|
data/lib/lapsoss/middleware.rb
DELETED
@@ -1,345 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Lapsoss
|
4
|
-
module Middleware
|
5
|
-
class Base
|
6
|
-
def initialize(app)
|
7
|
-
@app = app
|
8
|
-
end
|
9
|
-
|
10
|
-
def call(event, hint = {})
|
11
|
-
@app.call(event, hint)
|
12
|
-
end
|
13
|
-
end
|
14
|
-
|
15
|
-
# Built-in middleware for common functionality
|
16
|
-
class SampleFilter < Base
|
17
|
-
def initialize(app, sample_rate: 1.0, sample_callback: nil)
|
18
|
-
super(app)
|
19
|
-
@sample_rate = sample_rate
|
20
|
-
@sample_callback = sample_callback
|
21
|
-
end
|
22
|
-
|
23
|
-
def call(event, hint = {})
|
24
|
-
# Apply custom sampling logic first
|
25
|
-
return nil if @sample_callback && !@sample_callback.call(event, hint)
|
26
|
-
|
27
|
-
# Apply rate-based sampling
|
28
|
-
return nil if (@sample_rate < 1.0) && (rand > @sample_rate)
|
29
|
-
|
30
|
-
@app.call(event, hint)
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
class ExceptionFilter < Base
|
35
|
-
def initialize(app, excluded_exceptions: [], excluded_patterns: [])
|
36
|
-
super(app)
|
37
|
-
@excluded_exceptions = Array(excluded_exceptions)
|
38
|
-
@excluded_patterns = Array(excluded_patterns)
|
39
|
-
end
|
40
|
-
|
41
|
-
def call(event, hint = {})
|
42
|
-
return nil if should_exclude?(event)
|
43
|
-
|
44
|
-
@app.call(event, hint)
|
45
|
-
end
|
46
|
-
|
47
|
-
private
|
48
|
-
|
49
|
-
def should_exclude?(event)
|
50
|
-
return false unless event.exception
|
51
|
-
|
52
|
-
exception_class = event.exception.class
|
53
|
-
exception_message = event.exception.message
|
54
|
-
|
55
|
-
# Check exact class matches
|
56
|
-
return true if @excluded_exceptions.any? { |klass| exception_class <= klass }
|
57
|
-
|
58
|
-
# Check pattern matches
|
59
|
-
@excluded_patterns.any? do |pattern|
|
60
|
-
case pattern
|
61
|
-
when Regexp
|
62
|
-
exception_message&.match?(pattern) || exception_class.name.match?(pattern)
|
63
|
-
when String
|
64
|
-
exception_message&.include?(pattern) || exception_class.name.include?(pattern)
|
65
|
-
else
|
66
|
-
false
|
67
|
-
end
|
68
|
-
end
|
69
|
-
end
|
70
|
-
end
|
71
|
-
|
72
|
-
class UserContextEnhancer < Base
|
73
|
-
def initialize(app, user_provider: nil, privacy_mode: false)
|
74
|
-
super(app)
|
75
|
-
@user_provider = user_provider
|
76
|
-
@privacy_mode = privacy_mode
|
77
|
-
end
|
78
|
-
|
79
|
-
def call(event, hint = {})
|
80
|
-
enhance_user_context(event, hint)
|
81
|
-
@app.call(event, hint)
|
82
|
-
end
|
83
|
-
|
84
|
-
private
|
85
|
-
|
86
|
-
def enhance_user_context(event, hint)
|
87
|
-
# Get user from provider if available
|
88
|
-
user_data = @user_provider&.call(event, hint) || {}
|
89
|
-
|
90
|
-
# Merge with existing user context
|
91
|
-
existing_user = event.context[:user] || {}
|
92
|
-
enhanced_user = existing_user.merge(user_data)
|
93
|
-
|
94
|
-
# Apply privacy filtering if enabled
|
95
|
-
enhanced_user = apply_privacy_filtering(enhanced_user) if @privacy_mode
|
96
|
-
|
97
|
-
event.context[:user] = enhanced_user unless enhanced_user.empty?
|
98
|
-
end
|
99
|
-
|
100
|
-
def apply_privacy_filtering(user_data)
|
101
|
-
# Remove sensitive fields in privacy mode
|
102
|
-
sensitive_fields = %i[email phone address ssn credit_card]
|
103
|
-
filtered = user_data.dup
|
104
|
-
|
105
|
-
sensitive_fields.each do |field|
|
106
|
-
filtered[field] = '[FILTERED]' if filtered.key?(field)
|
107
|
-
end
|
108
|
-
|
109
|
-
filtered
|
110
|
-
end
|
111
|
-
end
|
112
|
-
|
113
|
-
class ReleaseTracker < Base
|
114
|
-
def initialize(app, release_provider: nil)
|
115
|
-
super(app)
|
116
|
-
@release_provider = release_provider
|
117
|
-
end
|
118
|
-
|
119
|
-
def call(event, hint = {})
|
120
|
-
add_release_info(event, hint)
|
121
|
-
@app.call(event, hint)
|
122
|
-
end
|
123
|
-
|
124
|
-
private
|
125
|
-
|
126
|
-
def add_release_info(event, hint)
|
127
|
-
release_info = @release_provider&.call(event, hint) || auto_detect_release
|
128
|
-
|
129
|
-
event.context[:release] = release_info if release_info
|
130
|
-
end
|
131
|
-
|
132
|
-
def auto_detect_release
|
133
|
-
release_info = {}
|
134
|
-
|
135
|
-
# Try to detect Git information
|
136
|
-
if git_info = detect_git_info
|
137
|
-
release_info.merge!(git_info)
|
138
|
-
end
|
139
|
-
|
140
|
-
# Try to detect deployment info
|
141
|
-
if deployment_info = detect_deployment_info
|
142
|
-
release_info.merge!(deployment_info)
|
143
|
-
end
|
144
|
-
|
145
|
-
release_info.empty? ? nil : release_info
|
146
|
-
end
|
147
|
-
|
148
|
-
def detect_git_info
|
149
|
-
return nil unless File.exist?('.git')
|
150
|
-
|
151
|
-
begin
|
152
|
-
# Get current commit SHA
|
153
|
-
commit_sha = `git rev-parse HEAD`.strip
|
154
|
-
return nil if commit_sha.empty?
|
155
|
-
|
156
|
-
# Get branch name
|
157
|
-
branch = `git rev-parse --abbrev-ref HEAD`.strip
|
158
|
-
branch = nil if branch.empty? || branch == 'HEAD'
|
159
|
-
|
160
|
-
# Get commit timestamp
|
161
|
-
commit_time = `git log -1 --format=%ct`.strip
|
162
|
-
commit_timestamp = commit_time.empty? ? nil : Time.zone.at(commit_time.to_i)
|
163
|
-
|
164
|
-
# Get tag if on a tag
|
165
|
-
tag = `git describe --exact-match --tags HEAD 2>/dev/null`.strip
|
166
|
-
tag = nil if tag.empty?
|
167
|
-
|
168
|
-
{
|
169
|
-
commit_sha: commit_sha,
|
170
|
-
branch: branch,
|
171
|
-
tag: tag,
|
172
|
-
commit_timestamp: commit_timestamp
|
173
|
-
}.compact
|
174
|
-
rescue StandardError
|
175
|
-
nil
|
176
|
-
end
|
177
|
-
end
|
178
|
-
|
179
|
-
def detect_deployment_info
|
180
|
-
info = {}
|
181
|
-
|
182
|
-
# Check common deployment environment variables
|
183
|
-
info[:deployment_id] = ENV['DEPLOYMENT_ID'] if ENV['DEPLOYMENT_ID']
|
184
|
-
info[:build_number] = ENV['BUILD_NUMBER'] if ENV['BUILD_NUMBER']
|
185
|
-
info[:deployment_time] = parse_deployment_time(ENV['DEPLOYMENT_TIME']) if ENV['DEPLOYMENT_TIME']
|
186
|
-
|
187
|
-
# Check Heroku
|
188
|
-
if ENV['HEROKU_APP_NAME']
|
189
|
-
info[:platform] = 'heroku'
|
190
|
-
info[:app_name] = ENV['HEROKU_APP_NAME']
|
191
|
-
info[:dyno] = ENV.fetch('DYNO', nil)
|
192
|
-
info[:slug_commit] = ENV.fetch('HEROKU_SLUG_COMMIT', nil)
|
193
|
-
end
|
194
|
-
|
195
|
-
# Check AWS
|
196
|
-
if ENV['AWS_EXECUTION_ENV']
|
197
|
-
info[:platform] = 'aws'
|
198
|
-
info[:execution_env] = ENV['AWS_EXECUTION_ENV']
|
199
|
-
info[:region] = ENV.fetch('AWS_REGION', nil)
|
200
|
-
end
|
201
|
-
|
202
|
-
# Check Docker
|
203
|
-
if ENV['DOCKER_CONTAINER_ID'] || File.exist?('/.dockerenv')
|
204
|
-
info[:platform] = 'docker'
|
205
|
-
info[:container_id] = ENV['DOCKER_CONTAINER_ID']
|
206
|
-
end
|
207
|
-
|
208
|
-
# Check Kubernetes
|
209
|
-
if ENV['KUBERNETES_SERVICE_HOST']
|
210
|
-
info[:platform] = 'kubernetes'
|
211
|
-
info[:namespace] = ENV.fetch('KUBERNETES_NAMESPACE', nil)
|
212
|
-
info[:pod_name] = ENV.fetch('HOSTNAME', nil)
|
213
|
-
end
|
214
|
-
|
215
|
-
info.empty? ? nil : info
|
216
|
-
end
|
217
|
-
|
218
|
-
def parse_deployment_time(time_str)
|
219
|
-
Time.zone.parse(time_str)
|
220
|
-
rescue StandardError
|
221
|
-
nil
|
222
|
-
end
|
223
|
-
end
|
224
|
-
|
225
|
-
class EventEnricher < Base
|
226
|
-
def initialize(app, enrichers: [])
|
227
|
-
super(app)
|
228
|
-
@enrichers = enrichers
|
229
|
-
end
|
230
|
-
|
231
|
-
def call(event, hint = {})
|
232
|
-
@enrichers.each do |enricher|
|
233
|
-
enricher.call(event, hint)
|
234
|
-
end
|
235
|
-
@app.call(event, hint)
|
236
|
-
end
|
237
|
-
end
|
238
|
-
|
239
|
-
class ConditionalFilter < Base
|
240
|
-
def initialize(app, condition)
|
241
|
-
super(app)
|
242
|
-
@condition = condition
|
243
|
-
end
|
244
|
-
|
245
|
-
def call(event, hint = {})
|
246
|
-
return nil unless @condition.call(event, hint)
|
247
|
-
|
248
|
-
@app.call(event, hint)
|
249
|
-
end
|
250
|
-
end
|
251
|
-
|
252
|
-
class EventTransformer < Base
|
253
|
-
def initialize(app, transformer)
|
254
|
-
super(app)
|
255
|
-
@transformer = transformer
|
256
|
-
end
|
257
|
-
|
258
|
-
def call(event, hint = {})
|
259
|
-
transformed_event = @transformer.call(event, hint)
|
260
|
-
return nil unless transformed_event
|
261
|
-
|
262
|
-
@app.call(transformed_event, hint)
|
263
|
-
end
|
264
|
-
end
|
265
|
-
|
266
|
-
class RateLimiter < Base
|
267
|
-
def initialize(app, max_events: 100, time_window: 60)
|
268
|
-
super(app)
|
269
|
-
@max_events = max_events
|
270
|
-
@time_window = time_window
|
271
|
-
@events = []
|
272
|
-
@mutex = Mutex.new
|
273
|
-
end
|
274
|
-
|
275
|
-
def call(event, hint = {})
|
276
|
-
@mutex.synchronize do
|
277
|
-
now = Time.zone.now
|
278
|
-
# Remove old events outside time window
|
279
|
-
@events.reject! { |timestamp| now - timestamp > @time_window }
|
280
|
-
|
281
|
-
# Check if we're over the limit
|
282
|
-
return nil if @events.length >= @max_events
|
283
|
-
|
284
|
-
# Add current event
|
285
|
-
@events << now
|
286
|
-
end
|
287
|
-
|
288
|
-
@app.call(event, hint)
|
289
|
-
end
|
290
|
-
end
|
291
|
-
|
292
|
-
class MetricsCollector < Base
|
293
|
-
def initialize(app, collector: nil)
|
294
|
-
super(app)
|
295
|
-
@collector = collector
|
296
|
-
@metrics = {
|
297
|
-
events_processed: 0,
|
298
|
-
events_dropped: 0,
|
299
|
-
events_by_type: Hash.new(0),
|
300
|
-
events_by_level: Hash.new(0)
|
301
|
-
}
|
302
|
-
@mutex = Mutex.new
|
303
|
-
end
|
304
|
-
|
305
|
-
def call(event, hint = {})
|
306
|
-
@mutex.synchronize do
|
307
|
-
@metrics[:events_processed] += 1
|
308
|
-
@metrics[:events_by_type][event.type] += 1
|
309
|
-
@metrics[:events_by_level][event.level] += 1
|
310
|
-
end
|
311
|
-
|
312
|
-
result = @app.call(event, hint)
|
313
|
-
|
314
|
-
if result.nil?
|
315
|
-
@mutex.synchronize do
|
316
|
-
@metrics[:events_dropped] += 1
|
317
|
-
end
|
318
|
-
end
|
319
|
-
|
320
|
-
# Send to external collector if provided
|
321
|
-
@collector&.call(@metrics.dup, event, hint)
|
322
|
-
|
323
|
-
result
|
324
|
-
end
|
325
|
-
|
326
|
-
def metrics
|
327
|
-
@mutex.synchronize { @metrics.dup }
|
328
|
-
end
|
329
|
-
end
|
330
|
-
|
331
|
-
# Middleware wrapper for sampling strategies
|
332
|
-
class SamplingMiddleware < Base
|
333
|
-
def initialize(app, sampler)
|
334
|
-
super(app)
|
335
|
-
@sampler = sampler
|
336
|
-
end
|
337
|
-
|
338
|
-
def call(event, hint = {})
|
339
|
-
return nil unless @sampler.sample?(event, hint)
|
340
|
-
|
341
|
-
@app.call(event, hint)
|
342
|
-
end
|
343
|
-
end
|
344
|
-
end
|
345
|
-
end
|