lapsoss 0.4.0 → 0.4.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/README.md +66 -7
- data/lib/lapsoss/client.rb +1 -3
- data/lib/lapsoss/configuration.rb +8 -17
- data/lib/lapsoss/fingerprinter.rb +52 -47
- data/lib/lapsoss/middleware/release_tracker.rb +11 -98
- data/lib/lapsoss/pipeline_builder.rb +2 -2
- data/lib/lapsoss/rails_middleware.rb +2 -2
- data/lib/lapsoss/railtie.rb +13 -2
- data/lib/lapsoss/registry.rb +7 -7
- data/lib/lapsoss/router.rb +1 -3
- data/lib/lapsoss/scrubber.rb +15 -152
- data/lib/lapsoss/validators.rb +48 -112
- data/lib/lapsoss/version.rb +1 -1
- metadata +1 -21
- data/lib/lapsoss/exclusion_configuration.rb +0 -30
- data/lib/lapsoss/exclusion_presets.rb +0 -249
- data/lib/lapsoss/middleware/sample_filter.rb +0 -23
- data/lib/lapsoss/middleware/sampling_middleware.rb +0 -18
- data/lib/lapsoss/middleware/user_context_enhancer.rb +0 -46
- data/lib/lapsoss/release_providers.rb +0 -110
- data/lib/lapsoss/sampling/adaptive_sampler.rb +0 -46
- data/lib/lapsoss/sampling/composite_sampler.rb +0 -26
- data/lib/lapsoss/sampling/consistent_hash_sampler.rb +0 -30
- data/lib/lapsoss/sampling/exception_type_sampler.rb +0 -44
- data/lib/lapsoss/sampling/health_based_sampler.rb +0 -19
- data/lib/lapsoss/sampling/sampling_factory.rb +0 -69
- data/lib/lapsoss/sampling/time_based_sampler.rb +0 -44
- data/lib/lapsoss/sampling/user_based_sampler.rb +0 -42
- data/lib/lapsoss/user_context.rb +0 -185
- data/lib/lapsoss/user_context_integrations.rb +0 -39
- data/lib/lapsoss/user_context_middleware.rb +0 -50
- data/lib/lapsoss/user_context_provider.rb +0 -93
- data/lib/lapsoss/utils.rb +0 -11
- data/lib/tasks/cassettes.rake +0 -50
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 93ff41a78372ad8d5080a5b7d87c2783a1f5834020df285e2db5eb28f0a54d61
|
4
|
+
data.tar.gz: 1cbceab257813d8e7659d9a31abd2cfba0a33a6f5585776ed426c984c32a61e4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: da64a5b1ec01779137189432e8dfba438e3768a1af44f71de44f3827c6ef3f2eb27b49d1b6d88479a23c51218e328f4068a86b4e210a2f73b869d2ff7167bb30
|
7
|
+
data.tar.gz: 126e54769b4f4ad8dad6617c27b5a80aeba5ae073879b462c8c6e01346fbc6a78029aca8589b028b6eccf9900fd1cc24e8072d119098190dbb86ac0b88521eba
|
data/README.md
CHANGED
@@ -196,23 +196,82 @@ Lapsoss.configure do |config|
|
|
196
196
|
# Data scrubbing (uses Rails filter_parameters automatically)
|
197
197
|
config.scrub_fields = %w[password credit_card ssn] # Or leave nil to use Rails defaults
|
198
198
|
|
199
|
-
#
|
199
|
+
# Performance
|
200
|
+
config.async = true # Send errors in background
|
201
|
+
|
202
|
+
# Sampling (see docs/sampling_strategies.md for advanced examples)
|
203
|
+
config.sample_rate = Rails.env.production? ? 0.25 : 1.0
|
204
|
+
|
205
|
+
# Transport settings
|
206
|
+
config.transport_timeout = 10 # seconds
|
207
|
+
config.transport_max_retries = 3
|
208
|
+
end
|
209
|
+
```
|
210
|
+
|
211
|
+
### Filtering Errors
|
212
|
+
|
213
|
+
You decide what errors to track. Lapsoss doesn't make assumptions:
|
214
|
+
|
215
|
+
```ruby
|
216
|
+
Lapsoss.configure do |config|
|
217
|
+
# Use the before_send callback for simple filtering
|
200
218
|
config.before_send = lambda do |event|
|
201
219
|
# Return nil to prevent sending
|
202
220
|
return nil if event.exception.is_a?(ActiveRecord::RecordNotFound)
|
203
221
|
event
|
204
222
|
end
|
223
|
+
|
224
|
+
# Or use the exclusion filter for more complex rules
|
225
|
+
config.exclusion_filter = Lapsoss::ExclusionFilter.new(
|
226
|
+
# Exclude specific exception types
|
227
|
+
excluded_exceptions: [
|
228
|
+
"ActionController::RoutingError", # Your choice
|
229
|
+
"ActiveRecord::RecordNotFound" # Your decision
|
230
|
+
],
|
231
|
+
|
232
|
+
# Exclude by pattern matching
|
233
|
+
excluded_patterns: [
|
234
|
+
/timeout/i, # If timeouts are expected in your app
|
235
|
+
/user not found/i # If these are normal in your workflow
|
236
|
+
],
|
237
|
+
|
238
|
+
# Exclude specific error messages
|
239
|
+
excluded_messages: [
|
240
|
+
"No route matches",
|
241
|
+
"Invalid authenticity token"
|
242
|
+
]
|
243
|
+
)
|
244
|
+
|
245
|
+
# Add custom exclusion logic
|
246
|
+
config.exclusion_filter.add_exclusion(:custom, lambda do |event|
|
247
|
+
# Your business logic here
|
248
|
+
event.context[:request]&.dig(:user_agent)&.match?(/bot/i)
|
249
|
+
end)
|
250
|
+
end
|
251
|
+
```
|
205
252
|
|
206
|
-
|
207
|
-
config.sample_rate = Rails.env.production? ? 0.25 : 1.0
|
253
|
+
#### Common Patterns (Your Choice)
|
208
254
|
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
config.
|
255
|
+
```ruby
|
256
|
+
# Development/Test exclusions
|
257
|
+
if Rails.env.development?
|
258
|
+
config.exclusion_filter.add_exclusion(:exception, "RSpec::Expectations::ExpectationNotMetError")
|
259
|
+
config.exclusion_filter.add_exclusion(:exception, "Minitest::Assertion")
|
213
260
|
end
|
261
|
+
|
262
|
+
# User input errors (if you don't want to track them)
|
263
|
+
config.exclusion_filter.add_exclusion(:exception, "ActiveRecord::RecordInvalid")
|
264
|
+
config.exclusion_filter.add_exclusion(:exception, "ActionController::ParameterMissing")
|
265
|
+
|
266
|
+
# Bot traffic (if you want to exclude it)
|
267
|
+
config.exclusion_filter.add_exclusion(:custom, lambda do |event|
|
268
|
+
request = event.context[:request]
|
269
|
+
request && request[:user_agent]&.match?(/googlebot|bingbot/i)
|
270
|
+
end)
|
214
271
|
```
|
215
272
|
|
273
|
+
Your app, your rules. Lapsoss just provides the mechanism.
|
274
|
+
|
216
275
|
### Data Protection
|
217
276
|
|
218
277
|
Lapsoss automatically integrates with Rails' parameter filtering:
|
data/lib/lapsoss/client.rb
CHANGED
@@ -103,9 +103,7 @@ module Lapsoss
|
|
103
103
|
end
|
104
104
|
|
105
105
|
def handle_capture_error(error)
|
106
|
-
|
107
|
-
|
108
|
-
@configuration.logger.error("[Lapsoss] Failed to capture event: #{error.message}")
|
106
|
+
@configuration.logger.error("Failed to capture event: #{error.message}")
|
109
107
|
end
|
110
108
|
end
|
111
109
|
end
|
@@ -21,7 +21,7 @@ module Lapsoss
|
|
21
21
|
def initialize
|
22
22
|
@adapter_configs = {}
|
23
23
|
@async = true
|
24
|
-
@logger = nil
|
24
|
+
@logger = Logger.new(nil) # Default null logger
|
25
25
|
@environment = nil
|
26
26
|
@enabled = true
|
27
27
|
@release = nil
|
@@ -193,17 +193,8 @@ module Lapsoss
|
|
193
193
|
|
194
194
|
def create_sampling_strategy
|
195
195
|
case @sampling_strategy
|
196
|
-
when
|
197
|
-
|
198
|
-
when :production
|
199
|
-
Sampling::SamplingFactory.create_production_sampling
|
200
|
-
when :development
|
201
|
-
Sampling::SamplingFactory.create_development_sampling
|
202
|
-
when :user_focused
|
203
|
-
Sampling::SamplingFactory.create_user_focused_sampling
|
204
|
-
else
|
205
|
-
Sampling::UniformSampler.new(@sample_rate)
|
206
|
-
end
|
196
|
+
when Numeric
|
197
|
+
Sampling::UniformSampler.new(@sampling_strategy)
|
207
198
|
when Proc
|
208
199
|
@sampling_strategy
|
209
200
|
when nil
|
@@ -276,7 +267,7 @@ module Lapsoss
|
|
276
267
|
def validate!
|
277
268
|
# Check sample rate is between 0 and 1
|
278
269
|
if @sample_rate && (@sample_rate < 0 || @sample_rate > 1)
|
279
|
-
logger
|
270
|
+
logger.warn "sample_rate should be between 0 and 1, got #{@sample_rate}"
|
280
271
|
end
|
281
272
|
|
282
273
|
# Check callables
|
@@ -289,21 +280,21 @@ module Lapsoss
|
|
289
280
|
|
290
281
|
# Just log if transport settings look unusual
|
291
282
|
if @transport_timeout && @transport_timeout <= 0
|
292
|
-
logger
|
283
|
+
logger.warn "transport_timeout should be positive, got #{@transport_timeout}"
|
293
284
|
end
|
294
285
|
|
295
286
|
if @transport_max_retries && @transport_max_retries < 0
|
296
|
-
logger
|
287
|
+
logger.warn "transport_max_retries should be non-negative, got #{@transport_max_retries}"
|
297
288
|
end
|
298
289
|
|
299
290
|
if @transport_initial_backoff && @transport_max_backoff && @transport_initial_backoff > @transport_max_backoff
|
300
|
-
logger
|
291
|
+
logger.warn "transport_initial_backoff (#{@transport_initial_backoff}) should be less than transport_max_backoff (#{@transport_max_backoff})"
|
301
292
|
end
|
302
293
|
|
303
294
|
# Validate adapter configurations exist
|
304
295
|
@adapter_configs.each do |name, config|
|
305
296
|
if config[:type].blank?
|
306
|
-
logger
|
297
|
+
logger.warn "Adapter '#{name}' has no type specified"
|
307
298
|
end
|
308
299
|
end
|
309
300
|
|
@@ -4,8 +4,9 @@ require "digest"
|
|
4
4
|
|
5
5
|
module Lapsoss
|
6
6
|
class Fingerprinter
|
7
|
-
|
8
|
-
|
7
|
+
# Base patterns that are always available
|
8
|
+
BASE_PATTERNS = [
|
9
|
+
# Generic error message normalization
|
9
10
|
{
|
10
11
|
pattern: /User \d+ (not found|invalid|missing)/i,
|
11
12
|
fingerprint: "user-lookup-error"
|
@@ -15,21 +16,25 @@ module Lapsoss
|
|
15
16
|
fingerprint: "record-lookup-error"
|
16
17
|
},
|
17
18
|
|
18
|
-
#
|
19
|
+
# Network error patterns
|
19
20
|
{
|
20
|
-
pattern:
|
21
|
-
fingerprint: "
|
21
|
+
pattern: /Net::(TimeoutError|ReadTimeout|OpenTimeout)/,
|
22
|
+
fingerprint: "network-timeout"
|
22
23
|
},
|
23
24
|
{
|
24
|
-
pattern:
|
25
|
-
fingerprint: "
|
25
|
+
pattern: /Errno::(ECONNREFUSED|ECONNRESET|EHOSTUNREACH)/,
|
26
|
+
fingerprint: "network-connection-error"
|
26
27
|
},
|
27
28
|
|
28
|
-
#
|
29
|
+
# Memory/Resource patterns
|
29
30
|
{
|
30
|
-
pattern: /
|
31
|
-
fingerprint: "
|
32
|
-
}
|
31
|
+
pattern: /NoMemoryError|SystemStackError/,
|
32
|
+
fingerprint: "memory-resource-error"
|
33
|
+
}
|
34
|
+
].freeze
|
35
|
+
|
36
|
+
# ActiveRecord-specific patterns (only loaded if ActiveRecord is defined)
|
37
|
+
ACTIVERECORD_PATTERNS = [
|
33
38
|
{
|
34
39
|
pattern: /ActiveRecord::RecordNotFound/,
|
35
40
|
fingerprint: "record-not-found"
|
@@ -38,38 +43,34 @@ module Lapsoss
|
|
38
43
|
pattern: /ActiveRecord::StatementInvalid.*timeout/i,
|
39
44
|
fingerprint: "database-timeout"
|
40
45
|
},
|
41
|
-
|
42
|
-
# Network error patterns
|
43
|
-
{
|
44
|
-
pattern: /Net::(TimeoutError|ReadTimeout|OpenTimeout)/,
|
45
|
-
fingerprint: "network-timeout"
|
46
|
-
},
|
47
46
|
{
|
48
|
-
pattern: /
|
49
|
-
fingerprint: "
|
50
|
-
}
|
47
|
+
pattern: /ActiveRecord::ConnectionTimeoutError/,
|
48
|
+
fingerprint: "database-connection-timeout"
|
49
|
+
}
|
50
|
+
].freeze
|
51
51
|
|
52
|
-
|
52
|
+
# Database adapter patterns (only loaded if adapters are defined)
|
53
|
+
DATABASE_PATTERNS = [
|
53
54
|
{
|
54
|
-
pattern:
|
55
|
-
fingerprint: "
|
55
|
+
pattern: /PG::ConnectionBad/,
|
56
|
+
fingerprint: "postgres-connection-error",
|
57
|
+
condition: -> { defined?(PG) }
|
56
58
|
},
|
57
59
|
{
|
58
|
-
pattern: /
|
59
|
-
fingerprint: "
|
60
|
+
pattern: /Mysql2::Error/,
|
61
|
+
fingerprint: "mysql-connection-error",
|
62
|
+
condition: -> { defined?(Mysql2) }
|
60
63
|
},
|
61
|
-
|
62
|
-
# Memory/Resource patterns
|
63
64
|
{
|
64
|
-
pattern: /
|
65
|
-
fingerprint: "
|
65
|
+
pattern: /SQLite3::BusyException/,
|
66
|
+
fingerprint: "sqlite-busy-error",
|
67
|
+
condition: -> { defined?(SQLite3) }
|
66
68
|
}
|
67
69
|
].freeze
|
68
70
|
|
69
71
|
def initialize(config = {})
|
70
72
|
@custom_callback = config[:custom_callback]
|
71
|
-
@patterns = config[:patterns]
|
72
|
-
@normalize_paths = config.fetch(:normalize_paths, true)
|
73
|
+
@patterns = build_patterns(config[:patterns])
|
73
74
|
@normalize_ids = config.fetch(:normalize_ids, true)
|
74
75
|
@include_environment = config.fetch(:include_environment, false)
|
75
76
|
end
|
@@ -91,6 +92,23 @@ module Lapsoss
|
|
91
92
|
|
92
93
|
private
|
93
94
|
|
95
|
+
def build_patterns(custom_patterns)
|
96
|
+
return custom_patterns if custom_patterns
|
97
|
+
|
98
|
+
patterns = BASE_PATTERNS.dup
|
99
|
+
|
100
|
+
# Always include ActiveRecord patterns - they match on string names
|
101
|
+
patterns.concat(ACTIVERECORD_PATTERNS)
|
102
|
+
|
103
|
+
# Add database-specific patterns - they also match on string names
|
104
|
+
DATABASE_PATTERNS.each do |pattern_config|
|
105
|
+
# Skip the condition check - just match on error names
|
106
|
+
patterns << pattern_config.except(:condition)
|
107
|
+
end
|
108
|
+
|
109
|
+
patterns
|
110
|
+
end
|
111
|
+
|
94
112
|
def match_patterns(event)
|
95
113
|
full_error_text = build_error_text(event)
|
96
114
|
|
@@ -170,18 +188,9 @@ module Lapsoss
|
|
170
188
|
|
171
189
|
# Replace numeric IDs with placeholder (after UUIDs and hashes)
|
172
190
|
normalized.gsub!(/\b\d{3,}\b/, ":id")
|
173
|
-
end
|
174
|
-
|
175
|
-
if @normalize_paths
|
176
|
-
# Replace absolute file paths with placeholder
|
177
|
-
normalized.gsub!(%r{/[^/\s]+(?:/[^/\s]+)*\.[a-zA-Z0-9]+}, ":filepath")
|
178
|
-
normalized.gsub!(%r{/[^/\s]+(?:/[^/\s]+)+(?:/)?}, ":dirpath")
|
179
191
|
|
180
192
|
# Replace timestamps
|
181
193
|
normalized.gsub!(/\b\d{4}-\d{2}-\d{2}[T\s]\d{2}:\d{2}:\d{2}/, ":timestamp")
|
182
|
-
|
183
|
-
# Replace URLs with placeholder
|
184
|
-
normalized.gsub!(%r{https?://[^\s]+}, ":url")
|
185
194
|
end
|
186
195
|
|
187
196
|
# Clean up extra whitespace
|
@@ -201,13 +210,9 @@ module Lapsoss
|
|
201
210
|
|
202
211
|
line_to_use = app_line || backtrace.first
|
203
212
|
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
"#{::Regexp.last_match(1)}:#{::Regexp.last_match(2)}"
|
208
|
-
else
|
209
|
-
line_to_use
|
210
|
-
end
|
213
|
+
# Extract just filename:line_number
|
214
|
+
if line_to_use =~ %r{([^/]+):(\d+)}
|
215
|
+
"#{::Regexp.last_match(1)}:#{::Regexp.last_match(2)}"
|
211
216
|
else
|
212
217
|
line_to_use
|
213
218
|
end
|
@@ -3,114 +3,27 @@
|
|
3
3
|
module Lapsoss
|
4
4
|
module Middleware
|
5
5
|
class ReleaseTracker < Base
|
6
|
-
def initialize(app,
|
6
|
+
def initialize(app, release: nil)
|
7
7
|
super(app)
|
8
|
-
@
|
8
|
+
@release = release
|
9
9
|
end
|
10
10
|
|
11
11
|
def call(event, hint = {})
|
12
|
-
|
12
|
+
if release = detect_release
|
13
|
+
event.context[:release] = release
|
14
|
+
end
|
13
15
|
@app.call(event, hint)
|
14
16
|
end
|
15
17
|
|
16
18
|
private
|
17
19
|
|
18
|
-
def
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
end
|
23
|
-
|
24
|
-
def auto_detect_release
|
25
|
-
release_info = {}
|
26
|
-
|
27
|
-
# Try to detect Git information
|
28
|
-
if git_info = detect_git_info
|
29
|
-
release_info.merge!(git_info)
|
30
|
-
end
|
31
|
-
|
32
|
-
# Try to detect deployment info
|
33
|
-
if deployment_info = detect_deployment_info
|
34
|
-
release_info.merge!(deployment_info)
|
35
|
-
end
|
36
|
-
|
37
|
-
release_info.empty? ? nil : release_info
|
38
|
-
end
|
39
|
-
|
40
|
-
def detect_git_info
|
41
|
-
return nil unless File.exist?(".git")
|
42
|
-
|
43
|
-
begin
|
44
|
-
# Get current commit SHA
|
45
|
-
commit_sha = `git rev-parse HEAD`.strip
|
46
|
-
return nil if commit_sha.empty?
|
47
|
-
|
48
|
-
# Get branch name
|
49
|
-
branch = `git rev-parse --abbrev-ref HEAD`.strip
|
50
|
-
branch = nil if branch.empty? || branch == "HEAD"
|
51
|
-
|
52
|
-
# Get commit timestamp
|
53
|
-
commit_time = `git log -1 --format=%ct`.strip
|
54
|
-
commit_timestamp = commit_time.empty? ? nil : Time.zone.at(commit_time.to_i)
|
55
|
-
|
56
|
-
# Get tag if on a tag
|
57
|
-
tag = `git describe --exact-match --tags HEAD 2>/dev/null`.strip
|
58
|
-
tag = nil if tag.empty?
|
59
|
-
|
60
|
-
{
|
61
|
-
commit_sha: commit_sha,
|
62
|
-
branch: branch,
|
63
|
-
tag: tag,
|
64
|
-
commit_timestamp: commit_timestamp
|
65
|
-
}.compact
|
66
|
-
rescue StandardError
|
67
|
-
nil
|
68
|
-
end
|
69
|
-
end
|
70
|
-
|
71
|
-
def detect_deployment_info
|
72
|
-
info = {}
|
73
|
-
|
74
|
-
# Check common deployment environment variables
|
75
|
-
info[:deployment_id] = ENV["DEPLOYMENT_ID"] if ENV["DEPLOYMENT_ID"]
|
76
|
-
info[:build_number] = ENV["BUILD_NUMBER"] if ENV["BUILD_NUMBER"]
|
77
|
-
info[:deployment_time] = parse_deployment_time(ENV["DEPLOYMENT_TIME"]) if ENV["DEPLOYMENT_TIME"]
|
78
|
-
|
79
|
-
# Check Heroku
|
80
|
-
if ENV["HEROKU_APP_NAME"]
|
81
|
-
info[:platform] = "heroku"
|
82
|
-
info[:app_name] = ENV["HEROKU_APP_NAME"]
|
83
|
-
info[:dyno] = ENV.fetch("DYNO", nil)
|
84
|
-
info[:slug_commit] = ENV.fetch("HEROKU_SLUG_COMMIT", nil)
|
85
|
-
end
|
86
|
-
|
87
|
-
# Check AWS
|
88
|
-
if ENV["AWS_EXECUTION_ENV"]
|
89
|
-
info[:platform] = "aws"
|
90
|
-
info[:execution_env] = ENV["AWS_EXECUTION_ENV"]
|
91
|
-
info[:region] = ENV.fetch("AWS_REGION", nil)
|
92
|
-
end
|
93
|
-
|
94
|
-
# Check Docker
|
95
|
-
if ENV["DOCKER_CONTAINER_ID"] || File.exist?("/.dockerenv")
|
96
|
-
info[:platform] = "docker"
|
97
|
-
info[:container_id] = ENV["DOCKER_CONTAINER_ID"]
|
98
|
-
end
|
99
|
-
|
100
|
-
# Check Kubernetes
|
101
|
-
if ENV["KUBERNETES_SERVICE_HOST"]
|
102
|
-
info[:platform] = "kubernetes"
|
103
|
-
info[:namespace] = ENV.fetch("KUBERNETES_NAMESPACE", nil)
|
104
|
-
info[:pod_name] = ENV.fetch("HOSTNAME", nil)
|
105
|
-
end
|
106
|
-
|
107
|
-
info.empty? ? nil : info
|
108
|
-
end
|
20
|
+
def detect_release
|
21
|
+
# Use configured release
|
22
|
+
return @release.call if @release.respond_to?(:call)
|
23
|
+
return @release if @release.present?
|
109
24
|
|
110
|
-
|
111
|
-
|
112
|
-
rescue StandardError
|
113
|
-
nil
|
25
|
+
# Use rails_app_version gem if available
|
26
|
+
Rails.application.version.to_s if defined?(Rails) && Rails.application.respond_to?(:version)
|
114
27
|
end
|
115
28
|
end
|
116
29
|
end
|
@@ -25,8 +25,8 @@ module Lapsoss
|
|
25
25
|
self
|
26
26
|
end
|
27
27
|
|
28
|
-
def track_releases(
|
29
|
-
@pipeline.use(Middleware::ReleaseTracker,
|
28
|
+
def track_releases(release: nil)
|
29
|
+
@pipeline.use(Middleware::ReleaseTracker, release: release)
|
30
30
|
self
|
31
31
|
end
|
32
32
|
|
@@ -10,14 +10,14 @@ module Lapsoss
|
|
10
10
|
Lapsoss::Current.with_clean_scope do
|
11
11
|
# Add request context to current scope
|
12
12
|
if Lapsoss.configuration.capture_request_context
|
13
|
-
Rails.logger.debug "
|
13
|
+
Rails.logger.tagged("Lapsoss") { Rails.logger.debug "Adding request context" } if Rails.env.test?
|
14
14
|
add_request_context(env)
|
15
15
|
end
|
16
16
|
|
17
17
|
begin
|
18
18
|
@app.call(env)
|
19
19
|
rescue Exception => e
|
20
|
-
Rails.logger.
|
20
|
+
Rails.logger.tagged("Lapsoss") { Rails.logger.debug "Capturing exception: #{e.class} - #{e.message}" } if Rails.env.test?
|
21
21
|
# Capture the exception
|
22
22
|
Lapsoss.capture_exception(e)
|
23
23
|
# Re-raise the exception to maintain Rails error handling
|
data/lib/lapsoss/railtie.rb
CHANGED
@@ -2,7 +2,13 @@
|
|
2
2
|
|
3
3
|
module Lapsoss
|
4
4
|
class Railtie < Rails::Railtie
|
5
|
-
|
5
|
+
if ENV["DEBUG_LAPSOSS"]
|
6
|
+
if Rails.logger.respond_to?(:tagged)
|
7
|
+
Rails.logger.tagged("Lapsoss") { Rails.logger.debug "Railtie loaded" }
|
8
|
+
else
|
9
|
+
Rails.logger.debug "[Lapsoss] Railtie loaded"
|
10
|
+
end
|
11
|
+
end
|
6
12
|
config.lapsoss = ActiveSupport::OrderedOptions.new
|
7
13
|
|
8
14
|
initializer "lapsoss.configure" do |_app|
|
@@ -14,7 +20,12 @@ module Lapsoss
|
|
14
20
|
Rails.env
|
15
21
|
end
|
16
22
|
|
17
|
-
|
23
|
+
# Use tagged logger for all Lapsoss logs
|
24
|
+
config.logger ||= if Rails.logger.respond_to?(:tagged)
|
25
|
+
Rails.logger.tagged("Lapsoss")
|
26
|
+
else
|
27
|
+
ActiveSupport::TaggedLogging.new(Rails.logger).tagged("Lapsoss")
|
28
|
+
end
|
18
29
|
|
19
30
|
config.release ||= if Rails.application.respond_to?(:version)
|
20
31
|
Rails.application.version.to_s
|
data/lib/lapsoss/registry.rb
CHANGED
@@ -2,6 +2,7 @@
|
|
2
2
|
|
3
3
|
require "singleton"
|
4
4
|
require "concurrent"
|
5
|
+
require "active_support/core_ext/string/inflections"
|
5
6
|
|
6
7
|
module Lapsoss
|
7
8
|
class Registry
|
@@ -42,7 +43,7 @@ module Lapsoss
|
|
42
43
|
name = if adapter.respond_to?(:name) && adapter.name
|
43
44
|
adapter.name.to_sym
|
44
45
|
elsif adapter.class.name
|
45
|
-
adapter.class.name.
|
46
|
+
adapter.class.name.demodulize.underscore.to_sym
|
46
47
|
else
|
47
48
|
# Generate a unique name if class name is nil (anonymous class)
|
48
49
|
:"adapter_#{adapter.object_id}"
|
@@ -116,13 +117,12 @@ module Lapsoss
|
|
116
117
|
# Resolve adapter type to class
|
117
118
|
def resolve_adapter_class(type)
|
118
119
|
# Try to get the class by convention: Adapters::{Type}Adapter
|
119
|
-
class_name = "#{type.to_s.
|
120
|
+
class_name = "#{type.to_s.camelize}Adapter"
|
121
|
+
full_class_name = "Lapsoss::Adapters::#{class_name}"
|
120
122
|
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
raise AdapterNotFoundError, "Unknown adapter type: #{type}. Expected class: Lapsoss::Adapters::#{class_name}"
|
125
|
-
end
|
123
|
+
full_class_name.constantize
|
124
|
+
rescue NameError
|
125
|
+
raise AdapterNotFoundError, "Unknown adapter type: #{type}. Expected class: #{full_class_name}"
|
126
126
|
end
|
127
127
|
end
|
128
128
|
end
|
data/lib/lapsoss/router.rb
CHANGED
@@ -19,10 +19,8 @@ module Lapsoss
|
|
19
19
|
|
20
20
|
# Handle adapter errors gracefully
|
21
21
|
def handle_adapter_error(adapter, event, error)
|
22
|
-
return unless Lapsoss.configuration.logger
|
23
|
-
|
24
22
|
Lapsoss.configuration.logger.error(
|
25
|
-
"
|
23
|
+
"Adapter '#{adapter.name}' failed to capture event (type: #{event.type}): #{error.message}"
|
26
24
|
)
|
27
25
|
|
28
26
|
# Call error handler if configured
|