lapsoss 0.1.0 → 0.3.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 +4 -4
- data/README.md +153 -733
- data/lib/lapsoss/adapters/appsignal_adapter.rb +7 -8
- data/lib/lapsoss/adapters/base.rb +0 -3
- data/lib/lapsoss/adapters/bugsnag_adapter.rb +12 -0
- data/lib/lapsoss/adapters/insight_hub_adapter.rb +102 -101
- data/lib/lapsoss/adapters/logger_adapter.rb +7 -7
- data/lib/lapsoss/adapters/rollbar_adapter.rb +93 -54
- data/lib/lapsoss/adapters/sentry_adapter.rb +11 -17
- data/lib/lapsoss/backtrace_frame.rb +35 -214
- data/lib/lapsoss/backtrace_frame_factory.rb +228 -0
- data/lib/lapsoss/backtrace_processor.rb +37 -37
- data/lib/lapsoss/client.rb +2 -6
- data/lib/lapsoss/configuration.rb +25 -22
- data/lib/lapsoss/current.rb +9 -1
- data/lib/lapsoss/event.rb +30 -6
- data/lib/lapsoss/exception_backtrace_frame.rb +39 -0
- data/lib/lapsoss/exclusion_configuration.rb +30 -0
- data/lib/lapsoss/exclusion_filter.rb +156 -0
- data/lib/lapsoss/{exclusions.rb → exclusion_presets.rb} +1 -181
- data/lib/lapsoss/fingerprinter.rb +9 -13
- data/lib/lapsoss/http_client.rb +42 -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/middleware.rb +0 -347
- data/lib/lapsoss/pipeline.rb +1 -73
- 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 +34 -20
- data/lib/lapsoss/release_providers.rb +110 -0
- data/lib/lapsoss/release_tracker.rb +112 -207
- data/lib/lapsoss/router.rb +3 -5
- 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/sampling.rb +0 -326
- data/lib/lapsoss/scope.rb +17 -57
- data/lib/lapsoss/scrubber.rb +16 -18
- data/lib/lapsoss/user_context.rb +18 -198
- 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 +14 -27
- data/lib/lapsoss/version.rb +1 -1
- data/lib/lapsoss.rb +12 -25
- metadata +106 -21
data/README.md
CHANGED
@@ -1,855 +1,275 @@
|
|
1
|
-
# Lapsoss
|
1
|
+
# Lapsoss - Vendor-Neutral Error Reporting for Rails
|
2
2
|
|
3
|
-
|
3
|
+
## The Problem We All Face
|
4
4
|
|
5
|
-
|
5
|
+
You're 6 months into production with Bugsnag. The CFO says "costs are too high, switch to Sentry."
|
6
6
|
|
7
|
-
|
7
|
+
The migration estimate? 3 months. Why? Because your entire codebase is littered with:
|
8
|
+
- `Bugsnag.notify(exception)`
|
9
|
+
- `Bugsnag.leave_breadcrumb("User clicked checkout")`
|
10
|
+
- Bugsnag-specific configuration
|
11
|
+
- Custom Bugsnag metadata patterns
|
8
12
|
|
9
|
-
|
13
|
+
**This is vendor lock-in through API pollution.**
|
10
14
|
|
11
|
-
|
12
|
-
- **Zero Monkey-Patching**: Your application's core behavior remains untouched.
|
13
|
-
- **Complete Control**: You dictate how errors are processed and sent, without hidden telemetry or unwanted features.
|
14
|
-
- **True Vendor Agnosticism**: Switch or combine error tracking services seamlessly, without changing your application's code.
|
15
|
-
|
16
|
-
## Rails-First Architecture
|
17
|
-
|
18
|
-
Lapsoss is designed **primarily for Rails applications** and modern Ruby projects. This architectural choice provides clear benefits:
|
19
|
-
|
20
|
-
### Why ActiveSupport?
|
21
|
-
|
22
|
-
Lapsoss depends on ActiveSupport (Rails 7.2+) as a deliberate design decision:
|
23
|
-
|
24
|
-
- **Rails Integration**: Seamless integration with Rails' parameter filtering, configuration patterns, and error reporting API
|
25
|
-
- **Essential Utilities**: ActiveSupport provides utilities we need anyway: `concurrent-ruby`, `zeitwerk`, inflection, configuration handling
|
26
|
-
- **No Namespace Pollution**: Unlike vendor SDKs that bring Redis, Elasticsearch, and other external namespaces, ActiveSupport provides clean Ruby utilities
|
27
|
-
- **Your Choice**: Use Lapsoss with ActiveSupport, or use official vendor SDKs that monkey-patch your entire application
|
28
|
-
|
29
|
-
### The Real Bloat Problem
|
30
|
-
|
31
|
-
The issue isn't dependency count - it's **namespace pollution** and **monkey-patching**:
|
32
|
-
|
33
|
-
- **Vendor SDKs**: Force Redis, Elasticsearch, proprietary gems, and monkey-patch core Ruby classes
|
34
|
-
- **Lapsoss + ActiveSupport**: Clean utilities that enhance Ruby without breaking your application's behavior
|
35
|
-
|
36
|
-
### Ruby Implementation Support
|
37
|
-
|
38
|
-
Lapsoss is built and tested exclusively for **CRuby (MRI) 3.2+**. Other Ruby implementations (JRuby, TruffleRuby) are not supported. This focused approach allows us to:
|
39
|
-
|
40
|
-
- Optimize for the most common Ruby implementation
|
41
|
-
- Avoid complexity of cross-implementation compatibility
|
42
|
-
- Provide reliable backtrace processing and code context extraction
|
43
|
-
|
44
|
-
### Rails Version Support
|
45
|
-
|
46
|
-
Lapsoss targets **Rails 7.2+** applications. If you're running an older Rails version, upgrade first. We follow Rails' release support policy and focus on modern Rails applications.
|
47
|
-
|
48
|
-
### What Lapsoss Is (and Isn't)
|
49
|
-
|
50
|
-
**Lapsoss is not a full replacement for vendor SDKs.** It focuses on core error tracking functionality, providing a Rails-optimized alternative for teams that:
|
51
|
-
|
52
|
-
- Want clean, vendor-neutral error reporting without external namespace pollution
|
53
|
-
- Need to use multiple error tracking services simultaneously
|
54
|
-
- Are tired of vendor SDKs that monkey-patch core Ruby classes
|
55
|
-
- Want to avoid the complexity of legacy support and premium features you don't use
|
56
|
-
|
57
|
-
**What's included:**
|
58
|
-
- ✅ Exception and error message capture
|
59
|
-
- ✅ Contextual data (user, tags, extra data)
|
60
|
-
- ✅ Breadcrumbs and error grouping
|
61
|
-
- ✅ Deploy markers and release tracking
|
62
|
-
- ✅ Basic health checks/heartbeats
|
63
|
-
- ✅ **Custom fingerprinting for intelligent error grouping**
|
64
|
-
- ✅ **Automatic data scrubbing with Rails parameter filtering**
|
65
|
-
- ✅ **Transport reliability with retry logic and client-side rate limiting**
|
66
|
-
- ✅ **Configuration validation for all adapter settings**
|
67
|
-
- ✅ **Advanced backtrace processing with code context extraction**
|
68
|
-
- ✅ **Intelligent frame filtering and normalization**
|
69
|
-
- ✅ **Performance-optimized file caching for backtrace processing**
|
70
|
-
|
71
|
-
**What's NOT included:**
|
72
|
-
- ❌ Application Performance Monitoring (APM)
|
73
|
-
- ❌ Distributed tracing
|
74
|
-
- ❌ Host metrics and system monitoring
|
75
|
-
- ❌ Advanced profiling
|
76
|
-
- ❌ Database query analysis
|
77
|
-
|
78
|
-
Most vendor SDKs contain significant boilerplate to support legacy Ruby versions, deprecated features, and premium functionality that requires additional subscriptions. Lapsoss strips away this complexity, focusing on what most applications actually need: reliable error tracking.
|
79
|
-
|
80
|
-
> 📖 **Want the full story?** Read [STORY.md](STORY.md) for detailed research on SDK bloat, including actual gem sizes and feature creep analysis across 25+ releases of major error tracking libraries.
|
81
|
-
|
82
|
-
## Core Principles (COSS-Compliant)
|
83
|
-
|
84
|
-
Lapsoss adheres strictly to the [Contriboss (COSS) standard](https://www.contriboss.com), ensuring software neutrality and freedom from vendor lock-in.
|
85
|
-
|
86
|
-
- 🔓 **Absolute Vendor Neutrality**: Lapsoss provides its own pure Ruby implementations for error reporting, eliminating the need for any external vendor SDKs.
|
87
|
-
- 🔌 **Pluggable Adapters**: Configure and use one or multiple built-in or custom adapters simultaneously.
|
88
|
-
- 🚀 **Rails 7.2+ Native Integration**: Seamlessly integrates with Rails' native error reporting API, without any monkey-patching.
|
89
|
-
- 🧬 **Adaptive Trait Selection**: I've carefully selected and implemented the most valuable error reporting features directly within Lapsoss, providing a unified, best-of-breed solution.
|
90
|
-
|
91
|
-
## Installation
|
15
|
+
## The Solution: Write Once, Deploy Anywhere
|
92
16
|
|
93
17
|
```ruby
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
## Quick Start
|
18
|
+
# Your code never changes:
|
19
|
+
Lapsoss.capture_exception(e)
|
98
20
|
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
- **Insight Hub** (formerly Bugsnag) - Error tracking with breadcrumbs and session support
|
21
|
+
# Switch vendors in config, not code:
|
22
|
+
Lapsoss.configure do |config|
|
23
|
+
# Monday: Using Bugsnag
|
24
|
+
config.use_bugsnag(api_key: ENV['BUGSNAG_KEY'])
|
104
25
|
|
105
|
-
|
26
|
+
# Tuesday: Add Sentry for comparison
|
27
|
+
config.use_sentry(dsn: ENV['SENTRY_DSN'])
|
106
28
|
|
107
|
-
|
108
|
-
|
109
|
-
# config/initializers/lapsoss.rb
|
110
|
-
Lapsoss.configure do |config|
|
111
|
-
# Configure the built-in Sentry adapter
|
112
|
-
config.use_sentry(dsn: ENV["SENTRY_DSN"])
|
29
|
+
# Wednesday: Drop Bugsnag, keep Sentry
|
30
|
+
# Just remove the line. Zero code changes.
|
113
31
|
end
|
114
32
|
```
|
115
33
|
|
116
|
-
|
117
|
-
```ruby
|
118
|
-
# config/initializers/lapsoss.rb
|
119
|
-
Lapsoss.configure do |config|
|
120
|
-
# Run multiple built-in adapters simultaneously!
|
121
|
-
config.use_sentry(name: :sentry_us, dsn: ENV['SENTRY_US_DSN'])
|
122
|
-
config.use_sentry(name: :sentry_eu, dsn: ENV['SENTRY_EU_DSN'])
|
123
|
-
config.use_appsignal(name: :appsignal, api_key: ENV['APPSIGNAL_API_KEY'])
|
124
|
-
config.use_rollbar(name: :rollbar, access_token: ENV['ROLLBAR_ACCESS_TOKEN'])
|
125
|
-
config.use_insight_hub(name: :insight_hub, api_key: ENV['INSIGHT_HUB_API_KEY'])
|
126
|
-
config.use_logger(name: :local_backup) # Example: log errors to a local file
|
127
|
-
end
|
34
|
+
## Installation
|
128
35
|
|
129
|
-
|
130
|
-
|
36
|
+
```ruby
|
37
|
+
gem 'lapsoss'
|
131
38
|
```
|
132
39
|
|
133
40
|
## Usage
|
134
41
|
|
135
|
-
### Core API
|
136
|
-
|
137
|
-
Lapsoss provides a simple, intuitive API for error tracking:
|
138
|
-
|
139
42
|
```ruby
|
140
43
|
# Capture exceptions
|
141
|
-
Lapsoss.capture_exception(
|
44
|
+
Lapsoss.capture_exception(e)
|
142
45
|
|
143
46
|
# Capture messages
|
144
|
-
Lapsoss.capture_message(
|
47
|
+
Lapsoss.capture_message("Payment processed", level: :info)
|
145
48
|
|
146
|
-
# Add
|
147
|
-
Lapsoss.
|
148
|
-
|
149
|
-
# Work with scoped context
|
150
|
-
Lapsoss.with_scope(context = {}, &block)
|
151
|
-
Lapsoss.current_scope
|
152
|
-
```
|
153
|
-
|
154
|
-
### Rails Integration
|
155
|
-
|
156
|
-
For Rails applications, errors are automatically captured:
|
157
|
-
|
158
|
-
```ruby
|
159
|
-
# config/initializers/lapsoss.rb
|
160
|
-
Lapsoss.configure do |config|
|
161
|
-
config.use_sentry(dsn: ENV["SENTRY_DSN"])
|
49
|
+
# Add context
|
50
|
+
Lapsoss.with_scope(user_id: current_user.id) do
|
51
|
+
process_payment
|
162
52
|
end
|
163
53
|
|
164
|
-
#
|
165
|
-
|
54
|
+
# Add breadcrumbs
|
55
|
+
Lapsoss.add_breadcrumb("User clicked checkout", type: :navigation)
|
166
56
|
```
|
167
57
|
|
168
|
-
|
58
|
+
That's it. No 500-line examples needed.
|
59
|
+
|
60
|
+
## Built for Rails, Not Around It
|
169
61
|
|
170
|
-
|
62
|
+
Lapsoss integrates with Rails' native error reporting API introduced in Rails 7. No monkey-patching, no middleware gymnastics:
|
171
63
|
|
172
64
|
```ruby
|
173
|
-
#
|
174
|
-
|
65
|
+
# It just works with Rails.error:
|
66
|
+
Rails.error.handle(context: {user_id: current_user.id}) do
|
175
67
|
risky_operation
|
176
|
-
rescue => e
|
177
|
-
Lapsoss.capture_exception(e)
|
178
|
-
end
|
179
|
-
|
180
|
-
# With additional context
|
181
|
-
begin
|
182
|
-
process_payment(user, amount)
|
183
|
-
rescue PaymentError => e
|
184
|
-
Lapsoss.capture_exception(e,
|
185
|
-
user: { id: user.id, email: user.email },
|
186
|
-
tags: { payment_method: "credit_card", amount: amount },
|
187
|
-
extra: { order_id: order.id, retry_count: 3 }
|
188
|
-
)
|
189
68
|
end
|
69
|
+
# Automatically captured by whatever service you configured
|
190
70
|
```
|
191
71
|
|
192
|
-
|
193
|
-
|
194
|
-
For important events or custom alerts:
|
72
|
+
## Zero-Downtime Vendor Migration
|
195
73
|
|
196
74
|
```ruby
|
197
|
-
#
|
198
|
-
|
199
|
-
|
200
|
-
# With context
|
201
|
-
Lapsoss.capture_message("High CPU usage detected",
|
202
|
-
level: :warning,
|
203
|
-
tags: { server: "web-01", cpu_usage: "85%" },
|
204
|
-
extra: { pid: Process.pid, memory_usage: "2.1GB" }
|
205
|
-
)
|
206
|
-
```
|
75
|
+
# Step 1: Add Lapsoss alongside your current setup
|
76
|
+
gem 'lapsoss'
|
77
|
+
gem 'bugsnag' # Keep your existing gem for now
|
207
78
|
|
208
|
-
|
79
|
+
# Step 2: Configure dual reporting
|
80
|
+
Lapsoss.configure do |config|
|
81
|
+
config.use_bugsnag(api_key: ENV['BUGSNAG_KEY'])
|
82
|
+
config.use_sentry(dsn: ENV['SENTRY_DSN'])
|
83
|
+
end
|
209
84
|
|
210
|
-
|
85
|
+
# Step 3: Gradually replace Bugsnag calls
|
86
|
+
# Old: Bugsnag.notify(e)
|
87
|
+
# New: Lapsoss.capture_exception(e)
|
211
88
|
|
212
|
-
|
213
|
-
#
|
214
|
-
Lapsoss.add_breadcrumb("User logged in",
|
215
|
-
type: :user,
|
216
|
-
user_id: user.id,
|
217
|
-
ip: request.remote_ip
|
218
|
-
)
|
219
|
-
|
220
|
-
# System events
|
221
|
-
Lapsoss.add_breadcrumb("Database connection established",
|
222
|
-
type: :system,
|
223
|
-
host: "db-primary",
|
224
|
-
latency: "45ms"
|
225
|
-
)
|
226
|
-
|
227
|
-
# Navigation
|
228
|
-
Lapsoss.add_breadcrumb("User visited checkout",
|
229
|
-
type: :navigation,
|
230
|
-
url: "/checkout",
|
231
|
-
referrer: "/cart"
|
232
|
-
)
|
233
|
-
|
234
|
-
# When an error occurs, all breadcrumbs are included automatically
|
235
|
-
begin
|
236
|
-
complete_checkout
|
237
|
-
rescue => e
|
238
|
-
Lapsoss.capture_exception(e) # Includes all breadcrumbs above
|
239
|
-
end
|
89
|
+
# Step 4: Remove bugsnag gem when ready
|
90
|
+
# Your app keeps running, now on Sentry
|
240
91
|
```
|
241
92
|
|
242
|
-
|
93
|
+
## Why Not Just Use Vendor SDKs?
|
243
94
|
|
244
|
-
|
95
|
+
**Vendor SDKs monkey-patch your application:**
|
96
|
+
- Sentry patches Net::HTTP, Redis, and 20+ other gems
|
97
|
+
- Each vendor races to patch the same methods
|
98
|
+
- Multiple SDKs = multiple layers of patches
|
99
|
+
- Your app behavior changes based on load order
|
245
100
|
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
) do
|
252
|
-
|
253
|
-
# Any errors in this block will include the scope context
|
254
|
-
process_payment
|
255
|
-
update_inventory
|
256
|
-
send_confirmation_email
|
257
|
-
|
258
|
-
end
|
259
|
-
|
260
|
-
# Background job context
|
261
|
-
Lapsoss.with_scope(
|
262
|
-
tags: { job: "invoice_generator", queue: "high_priority" },
|
263
|
-
extra: { batch_size: invoices.count }
|
264
|
-
) do
|
265
|
-
|
266
|
-
invoices.each do |invoice|
|
267
|
-
Lapsoss.add_breadcrumb("Processing invoice #{invoice.id}")
|
268
|
-
generate_invoice(invoice)
|
269
|
-
end
|
270
|
-
|
271
|
-
end
|
272
|
-
```
|
101
|
+
**Lapsoss doesn't patch anything:**
|
102
|
+
- Pure Ruby implementation
|
103
|
+
- Uses Rails' error API
|
104
|
+
- Your app behavior remains unchanged
|
105
|
+
- No competing instrumentation
|
273
106
|
|
274
|
-
|
107
|
+
## Real-World Use Cases
|
275
108
|
|
276
|
-
|
109
|
+
### GDPR Compliance
|
277
110
|
```ruby
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
user: { id: current_user.id, email: current_user.email },
|
282
|
-
tags: { controller: "checkout", action: "create" },
|
283
|
-
extra: { cart_total: cart.total, item_count: cart.items.count }
|
284
|
-
) do
|
285
|
-
|
286
|
-
Lapsoss.add_breadcrumb("Checkout initiated", type: :user)
|
287
|
-
|
288
|
-
begin
|
289
|
-
payment = process_payment(cart.total)
|
290
|
-
Lapsoss.add_breadcrumb("Payment processed", type: :system,
|
291
|
-
payment_id: payment.id, method: payment.method)
|
292
|
-
|
293
|
-
order = create_order(cart, payment)
|
294
|
-
Lapsoss.add_breadcrumb("Order created", type: :system, order_id: order.id)
|
295
|
-
|
296
|
-
redirect_to order_path(order)
|
297
|
-
|
298
|
-
rescue PaymentError => e
|
299
|
-
Lapsoss.capture_exception(e,
|
300
|
-
tags: { error_type: "payment_failure" },
|
301
|
-
extra: { payment_method: params[:payment_method] }
|
302
|
-
)
|
303
|
-
redirect_to checkout_path, alert: "Payment failed"
|
304
|
-
|
305
|
-
rescue InventoryError => e
|
306
|
-
Lapsoss.capture_exception(e,
|
307
|
-
tags: { error_type: "inventory_failure" },
|
308
|
-
extra: { requested_items: cart.items.pluck(:id) }
|
309
|
-
)
|
310
|
-
redirect_to cart_path, alert: "Item no longer available"
|
311
|
-
end
|
312
|
-
|
313
|
-
end
|
314
|
-
end
|
315
|
-
end
|
111
|
+
# Route EU data to EU servers, US data to US servers
|
112
|
+
config.use_sentry(name: :us, dsn: ENV['US_DSN'])
|
113
|
+
config.use_sentry(name: :eu, dsn: ENV['EU_DSN'])
|
316
114
|
```
|
317
115
|
|
318
|
-
|
116
|
+
### A/B Testing Error Services
|
319
117
|
```ruby
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
tags: { job: "invoice_generator", batch_id: batch_id },
|
324
|
-
extra: { queue: queue_name, priority: priority }
|
325
|
-
) do
|
326
|
-
|
327
|
-
invoices = Invoice.where(batch_id: batch_id)
|
328
|
-
|
329
|
-
invoices.each_with_index do |invoice, index|
|
330
|
-
Lapsoss.add_breadcrumb("Processing invoice #{invoice.id}",
|
331
|
-
type: :system,
|
332
|
-
progress: "#{index + 1}/#{invoices.count}"
|
333
|
-
)
|
334
|
-
|
335
|
-
begin
|
336
|
-
generate_pdf(invoice)
|
337
|
-
send_email(invoice)
|
338
|
-
invoice.update!(status: :sent)
|
339
|
-
|
340
|
-
rescue => e
|
341
|
-
Lapsoss.capture_exception(e,
|
342
|
-
tags: { error_type: "invoice_generation_failure" },
|
343
|
-
extra: { invoice_id: invoice.id, customer_id: invoice.customer_id }
|
344
|
-
)
|
345
|
-
|
346
|
-
invoice.update!(status: :failed)
|
347
|
-
end
|
348
|
-
end
|
349
|
-
|
350
|
-
end
|
351
|
-
end
|
352
|
-
end
|
118
|
+
# Run both services, compare effectiveness
|
119
|
+
config.use_rollbar(name: :current, access_token: ENV['ROLLBAR_TOKEN'])
|
120
|
+
config.use_sentry(name: :candidate, dsn: ENV['SENTRY_DSN'])
|
353
121
|
```
|
354
122
|
|
355
|
-
|
123
|
+
### High Availability
|
356
124
|
```ruby
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
private
|
361
|
-
|
362
|
-
def track_api_errors
|
363
|
-
Lapsoss.with_scope(
|
364
|
-
tags: {
|
365
|
-
api_version: request.headers["API-Version"],
|
366
|
-
endpoint: "#{params[:controller]}##{params[:action]}"
|
367
|
-
},
|
368
|
-
extra: {
|
369
|
-
user_agent: request.user_agent,
|
370
|
-
ip_address: request.remote_ip
|
371
|
-
}
|
372
|
-
) do
|
373
|
-
|
374
|
-
Lapsoss.add_breadcrumb("API request started",
|
375
|
-
type: :http,
|
376
|
-
url: request.path,
|
377
|
-
method: request.method
|
378
|
-
)
|
379
|
-
|
380
|
-
begin
|
381
|
-
yield
|
382
|
-
|
383
|
-
rescue RateLimitError => e
|
384
|
-
Lapsoss.capture_exception(e,
|
385
|
-
tags: { error_type: "rate_limit_exceeded" },
|
386
|
-
extra: { limit: e.limit, reset_time: e.reset_time }
|
387
|
-
)
|
388
|
-
render json: { error: "Rate limit exceeded" }, status: 429
|
389
|
-
|
390
|
-
rescue AuthenticationError => e
|
391
|
-
Lapsoss.capture_exception(e,
|
392
|
-
tags: { error_type: "authentication_failure" },
|
393
|
-
extra: { auth_method: request.headers["Authorization"]&.split(" ")&.first }
|
394
|
-
)
|
395
|
-
render json: { error: "Authentication required" }, status: 401
|
396
|
-
|
397
|
-
rescue => e
|
398
|
-
Lapsoss.capture_exception(e,
|
399
|
-
tags: { error_type: "unexpected_api_error" }
|
400
|
-
)
|
401
|
-
render json: { error: "Internal server error" }, status: 500
|
402
|
-
end
|
403
|
-
|
404
|
-
end
|
405
|
-
end
|
406
|
-
end
|
125
|
+
# Multiple providers for redundancy
|
126
|
+
config.use_sentry(name: :primary, dsn: ENV['PRIMARY_DSN'])
|
127
|
+
config.use_rollbar(name: :backup, access_token: ENV['BACKUP_TOKEN'])
|
407
128
|
```
|
408
129
|
|
409
|
-
|
130
|
+
## Yes, We Require ActiveSupport
|
410
131
|
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
# With Lapsoss:
|
417
|
-
config.use_rollbar(
|
418
|
-
name: :rollbar,
|
419
|
-
access_token: ENV['ROLLBAR_ACCESS_TOKEN'] # or your token directly
|
420
|
-
)
|
421
|
-
```
|
132
|
+
This is a Rails gem for Rails applications. We use ActiveSupport because:
|
133
|
+
- You already have it (you're using Rails)
|
134
|
+
- It provides the exact utilities we need
|
135
|
+
- It's better than reimplementing Rails patterns poorly
|
422
136
|
|
423
|
-
|
424
|
-
```ruby
|
425
|
-
config.use_insight_hub(
|
426
|
-
name: :insight_hub,
|
427
|
-
api_key: ENV['INSIGHT_HUB_API_KEY'],
|
428
|
-
release_stage: Rails.env,
|
429
|
-
app_version: '1.0.0'
|
430
|
-
)
|
431
|
-
|
432
|
-
# For backwards compatibility, you can still use:
|
433
|
-
# config.use_bugsnag(...) which maps to Insight Hub
|
434
|
-
```
|
137
|
+
If you need pure Ruby error tracking, use the vendor SDKs directly for now.
|
435
138
|
|
436
|
-
##
|
139
|
+
## Who This Is For
|
437
140
|
|
438
|
-
|
141
|
+
- Teams that have been burned by vendor lock-in
|
142
|
+
- Apps that need regional data compliance (GDPR)
|
143
|
+
- Developers who value clean, maintainable code
|
144
|
+
- Rails applications that embrace change
|
439
145
|
|
440
|
-
|
146
|
+
## Who This Is NOT For
|
441
147
|
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
"User 456 not found" }
|
148
|
+
- Pure Ruby libraries (use vendor SDKs)
|
149
|
+
- Teams happy with their current vendor forever
|
150
|
+
- Applications that need APM features
|
151
|
+
- Non-Rails applications
|
447
152
|
|
448
|
-
|
449
|
-
"Payment failed for card ending in 4567" }
|
153
|
+
## Supported Adapters
|
450
154
|
|
451
|
-
|
452
|
-
"PG::ConnectionBad: timeout" }
|
453
|
-
```
|
155
|
+
All adapters are pure Ruby implementations with no external SDK dependencies:
|
454
156
|
|
455
|
-
|
456
|
-
|
457
|
-
|
458
|
-
|
459
|
-
case event.exception&.class&.name
|
460
|
-
when "ActiveRecord::RecordNotFound"
|
461
|
-
# Group all record not found errors
|
462
|
-
"database-record-error"
|
463
|
-
when /Net::/
|
464
|
-
# Group all network errors
|
465
|
-
"network-error"
|
466
|
-
when "Redis::ConnectionError", "Redis::TimeoutError"
|
467
|
-
# Group Redis issues
|
468
|
-
"redis-error"
|
469
|
-
else
|
470
|
-
nil # Use default fingerprinting
|
471
|
-
end
|
472
|
-
end
|
473
|
-
end
|
474
|
-
```
|
157
|
+
- **Sentry** - Full error tracking support
|
158
|
+
- **Rollbar** - Complete error tracking with grouping
|
159
|
+
- **AppSignal** - Error tracking and deploy markers
|
160
|
+
- **Insight Hub** (formerly Bugsnag) - Error tracking with breadcrumbs
|
475
161
|
|
476
|
-
|
477
|
-
```ruby
|
478
|
-
Lapsoss.configure do |config|
|
479
|
-
config.fingerprint_patterns = [
|
480
|
-
# E-commerce patterns
|
481
|
-
{
|
482
|
-
pattern: /Payment.*failed/i,
|
483
|
-
fingerprint: "payment-failure"
|
484
|
-
},
|
485
|
-
{
|
486
|
-
pattern: /Order \d+ (invalid|missing|not found)/i,
|
487
|
-
fingerprint: "order-lookup-error"
|
488
|
-
},
|
489
|
-
|
490
|
-
# API patterns
|
491
|
-
{
|
492
|
-
pattern: %r{/api/v\d+/users/\d+},
|
493
|
-
fingerprint: "api-user-endpoint-error"
|
494
|
-
},
|
495
|
-
{
|
496
|
-
pattern: /Rate limit exceeded/i,
|
497
|
-
fingerprint: "rate-limit-exceeded"
|
498
|
-
}
|
499
|
-
]
|
500
|
-
end
|
501
|
-
```
|
162
|
+
## Configuration
|
502
163
|
|
503
|
-
|
504
|
-
```ruby
|
505
|
-
Lapsoss.configure do |config|
|
506
|
-
# Normalize IDs: "User 12345 not found" → "User :id not found"
|
507
|
-
config.normalize_fingerprint_ids = true
|
508
|
-
|
509
|
-
# Normalize paths: "/home/user/file.txt" → ":filepath"
|
510
|
-
config.normalize_fingerprint_paths = true
|
511
|
-
|
512
|
-
# Include environment in fingerprint (useful for staging vs production)
|
513
|
-
config.fingerprint_include_environment = false
|
514
|
-
end
|
515
|
-
```
|
164
|
+
### Basic Setup
|
516
165
|
|
517
|
-
#### Advanced Use Cases
|
518
166
|
```ruby
|
519
|
-
#
|
520
|
-
|
521
|
-
|
522
|
-
# More detailed fingerprints for debugging
|
523
|
-
"#{event.exception.class.name}-#{event.exception.backtrace&.first}"
|
524
|
-
else
|
525
|
-
# Simpler fingerprints for production
|
526
|
-
case event.exception&.class&.name
|
527
|
-
when /ActiveRecord/ then "database-error"
|
528
|
-
when /Net::/ then "network-error"
|
529
|
-
else nil
|
530
|
-
end
|
531
|
-
end
|
532
|
-
end
|
533
|
-
|
534
|
-
# Group by controller/model for Rails apps
|
535
|
-
config.fingerprint_callback = lambda do |event|
|
536
|
-
backtrace = event.exception&.backtrace || []
|
537
|
-
|
538
|
-
if controller_line = backtrace.find { |line| line.include?("app/controllers/") }
|
539
|
-
controller = controller_line.match(%r{app/controllers/(\w+)_controller\.rb})[1]
|
540
|
-
"controller-#{controller}-error"
|
541
|
-
elsif model_line = backtrace.find { |line| line.include?("app/models/") }
|
542
|
-
model = model_line.match(%r{app/models/(\w+)\.rb})[1]
|
543
|
-
"model-#{model}-error"
|
544
|
-
else
|
545
|
-
nil
|
546
|
-
end
|
167
|
+
# config/initializers/lapsoss.rb
|
168
|
+
Lapsoss.configure do |config|
|
169
|
+
config.use_sentry(dsn: ENV["SENTRY_DSN"])
|
547
170
|
end
|
548
171
|
```
|
549
172
|
|
550
|
-
###
|
551
|
-
|
552
|
-
Lapsoss includes built-in transport reliability to ensure your errors reach their destination even under adverse conditions.
|
173
|
+
### Multi-Adapter Setup
|
553
174
|
|
554
175
|
```ruby
|
555
176
|
Lapsoss.configure do |config|
|
556
|
-
#
|
557
|
-
config.
|
558
|
-
config.
|
559
|
-
config.
|
560
|
-
config.transport_max_backoff = 64.0 # Maximum backoff delay
|
561
|
-
config.transport_backoff_multiplier = 2.0 # Exponential backoff multiplier
|
562
|
-
config.transport_jitter = true # Add random jitter to prevent thundering herd
|
177
|
+
# Named adapters for different purposes
|
178
|
+
config.use_sentry(name: :errors, dsn: ENV['SENTRY_DSN'])
|
179
|
+
config.use_rollbar(name: :business_events, access_token: ENV['ROLLBAR_TOKEN'])
|
180
|
+
config.use_logger(name: :local_backup) # Local file backup
|
563
181
|
end
|
564
182
|
```
|
565
183
|
|
566
|
-
|
567
|
-
- **Exponential Backoff**: Intelligent retry timing to avoid overwhelming services (transport layer)
|
568
|
-
- **Rate Limiting**: Pipeline middleware with time-window and token bucket algorithms
|
569
|
-
- **Jitter**: Random delays to prevent synchronized retry storms (transport layer)
|
570
|
-
- **Circuit Breaking**: Automatic failure detection and recovery (transport layer)
|
571
|
-
|
572
|
-
### Backtrace Processing
|
573
|
-
|
574
|
-
Lapsoss includes advanced backtrace processing that enhances error reports across all adapters:
|
184
|
+
### Advanced Configuration
|
575
185
|
|
576
186
|
```ruby
|
577
187
|
Lapsoss.configure do |config|
|
578
|
-
#
|
579
|
-
config.
|
580
|
-
config.backtrace_enable_code_context = true # Enable/disable context extraction
|
581
|
-
|
582
|
-
# Path normalization
|
583
|
-
config.backtrace_strip_load_path = true # Strip Ruby load paths for cleaner traces
|
584
|
-
|
585
|
-
# Frame limiting (for deep stack traces)
|
586
|
-
config.backtrace_max_frames = 100 # Prevent memory issues with stack overflows
|
587
|
-
|
588
|
-
# Application code detection
|
589
|
-
config.backtrace_in_app_patterns = [
|
590
|
-
%r{^/app/}, # Rails app directory
|
591
|
-
%r{^lib/}, # Custom libraries
|
592
|
-
%r{/my_company/} # Company code
|
593
|
-
]
|
594
|
-
|
595
|
-
# Noise filtering
|
596
|
-
config.backtrace_exclude_patterns = [
|
597
|
-
%r{/ruby/gems/.*/rack-}, # Rack internals
|
598
|
-
%r{/activesupport-.*/notifications}, # AS internals
|
599
|
-
%r{/newrelic_rpm/} # Monitoring gems
|
600
|
-
]
|
601
|
-
end
|
602
|
-
```
|
188
|
+
# Adapter setup
|
189
|
+
config.use_sentry(dsn: ENV['SENTRY_DSN'])
|
603
190
|
|
604
|
-
|
605
|
-
|
606
|
-
- **Smart Filtering**: Remove framework noise, focus on your code
|
607
|
-
- **In-App Detection**: Automatically identify application vs library code
|
608
|
-
- **Performance Optimized**: LRU file caching for efficient processing
|
609
|
-
- **Format Agnostic**: Consistent processing across all adapters
|
191
|
+
# Data scrubbing (uses Rails filter_parameters automatically)
|
192
|
+
config.scrub_fields = %w[password credit_card ssn] # Or leave nil to use Rails defaults
|
610
193
|
|
611
|
-
|
194
|
+
# Error filtering
|
195
|
+
config.before_send = lambda do |event|
|
196
|
+
# Return nil to prevent sending
|
197
|
+
return nil if event.exception.is_a?(ActiveRecord::RecordNotFound)
|
198
|
+
event
|
199
|
+
end
|
612
200
|
|
613
|
-
|
201
|
+
# Sampling
|
202
|
+
config.sample_rate = Rails.env.production? ? 0.25 : 1.0
|
614
203
|
|
615
|
-
|
616
|
-
#
|
617
|
-
config.
|
618
|
-
config.
|
619
|
-
|
620
|
-
|
621
|
-
# ❌ Invalid configurations (caught at startup)
|
622
|
-
config.use_sentry(dsn: "invalid-dsn") # ValidationError: DSN scheme is required
|
623
|
-
config.use_rollbar(access_token: "invalid@token") # ValidationError: must be alphanumeric
|
624
|
-
config.use_appsignal(push_api_key: "not-a-uuid") # ValidationError: must be valid UUID
|
204
|
+
# Performance
|
205
|
+
config.async = true # Send errors in background
|
206
|
+
config.transport_timeout = 10 # seconds
|
207
|
+
config.transport_max_retries = 3
|
208
|
+
end
|
625
209
|
```
|
626
210
|
|
627
|
-
|
211
|
+
### Data Protection
|
628
212
|
|
629
|
-
Lapsoss automatically
|
213
|
+
Lapsoss automatically integrates with Rails' parameter filtering:
|
630
214
|
|
631
|
-
### Automatic Rails Integration
|
632
215
|
```ruby
|
633
|
-
# config/initializers/filter_parameter_logging.rb
|
634
|
-
Rails.application.config.filter_parameters += [
|
635
|
-
:passw, :secret, :token, :_key, :crypt, :salt, :certificate, :otp, :ssn
|
636
|
-
]
|
216
|
+
# config/initializers/filter_parameter_logging.rb
|
217
|
+
Rails.application.config.filter_parameters += [:password, :token]
|
637
218
|
|
638
219
|
# Lapsoss automatically uses these filters - no additional configuration needed!
|
639
|
-
Lapsoss.configure do |config|
|
640
|
-
config.use_sentry(dsn: ENV['SENTRY_DSN'])
|
641
|
-
# Sensitive fields are automatically scrubbed using Rails filter_parameters
|
642
|
-
end
|
643
|
-
```
|
644
|
-
|
645
|
-
### Custom Data Scrubbing
|
646
|
-
```ruby
|
647
|
-
Lapsoss.configure do |config|
|
648
|
-
# Add custom fields to scrub (in addition to Rails filters)
|
649
|
-
config.scrub_fields = %w[internal_token custom_secret]
|
650
|
-
|
651
|
-
# Override Rails filters completely
|
652
|
-
config.scrub_fields = %w[password api_key credit_card] # Ignores Rails config
|
653
|
-
|
654
|
-
# Scrub everything except whitelisted fields
|
655
|
-
config.scrub_all = true
|
656
|
-
config.whitelist_fields = %w[debug_info safe_field]
|
657
|
-
|
658
|
-
# Randomize scrubbed value lengths (security through obscurity)
|
659
|
-
config.randomize_scrub_length = true # "******" to "*********"
|
660
|
-
end
|
661
220
|
```
|
662
221
|
|
663
|
-
###
|
664
|
-
- **Passwords**: `password`, `passwd`, `pwd`
|
665
|
-
- **Tokens**: `token`, `access_token`, `auth_token`, `csrf_token`
|
666
|
-
- **Keys**: `key`, `api_key`, `secret_key`
|
667
|
-
- **PII**: `ssn`, `social_security_number`, `credit_card`, `phone`
|
668
|
-
- **File Uploads**: Metadata extracted, content scrubbed
|
669
|
-
- **Rails filter_parameters**: Automatically respected
|
670
|
-
|
671
|
-
## Adaptive Traits We've Selected
|
672
|
-
|
673
|
-
### From Sentry 🔍
|
674
|
-
- **Custom fingerprinting** for intelligent error grouping
|
675
|
-
- Robust error capture with context
|
676
|
-
- Release tracking and environment awareness
|
677
|
-
|
678
|
-
### From Rollbar 🎲
|
679
|
-
- **Advanced data scrubbing** with Rails parameter filter integration
|
680
|
-
- **Transport reliability** with exponential backoff and retry logic
|
681
|
-
- Person tracking and user context
|
222
|
+
### Custom Fingerprinting
|
682
223
|
|
683
|
-
|
684
|
-
- **Configuration validation** to catch setup errors early
|
685
|
-
- Check-in monitoring for cron jobs
|
686
|
-
- Deploy markers and health checks
|
224
|
+
Control how errors are grouped:
|
687
225
|
|
688
|
-
### From Insight Hub (formerly Bugsnag) 🐛
|
689
|
-
- Feature flag correlation with errors
|
690
|
-
- Session tracking for crash-free rates
|
691
|
-
- Typed breadcrumbs for debugging context
|
692
|
-
|
693
|
-
|
694
|
-
### Lapsoss Innovations 🧬
|
695
|
-
- **Pure Ruby implementations** - no external SDK dependencies
|
696
|
-
- **Multi-adapter architecture** - use multiple services simultaneously
|
697
|
-
- **Vendor-neutral configuration** - switch providers without code changes
|
698
|
-
- **Zero monkey-patching** - your application remains untouched
|
699
|
-
|
700
|
-
## Usage Examples
|
701
|
-
|
702
|
-
### Basic Error Capture
|
703
226
|
```ruby
|
704
|
-
|
705
|
-
|
706
|
-
|
707
|
-
|
227
|
+
config.fingerprint_callback = lambda do |event|
|
228
|
+
case event.exception&.class&.name
|
229
|
+
when "ActiveRecord::RecordNotFound"
|
230
|
+
"record-not-found" # Group all together
|
231
|
+
when "Stripe::CardError"
|
232
|
+
"payment-failure"
|
233
|
+
else
|
234
|
+
nil # Use default fingerprinting
|
235
|
+
end
|
708
236
|
end
|
709
237
|
```
|
710
238
|
|
711
|
-
###
|
712
|
-
```ruby
|
713
|
-
# These errors will be automatically grouped:
|
714
|
-
begin
|
715
|
-
User.find(123) # → "user-lookup-error"
|
716
|
-
rescue ActiveRecord::RecordNotFound => e
|
717
|
-
Lapsoss.capture_exception(e)
|
718
|
-
end
|
239
|
+
### Transport Reliability
|
719
240
|
|
720
|
-
|
721
|
-
User.find(456) # → Same "user-lookup-error" group
|
722
|
-
rescue ActiveRecord::RecordNotFound => e
|
723
|
-
Lapsoss.capture_exception(e)
|
724
|
-
end
|
725
|
-
```
|
241
|
+
Built-in retry logic with exponential backoff:
|
726
242
|
|
727
|
-
### Advanced Configuration Example
|
728
243
|
```ruby
|
729
|
-
|
730
|
-
|
731
|
-
|
732
|
-
config.use_rollbar(name: :rollbar, access_token: ENV['ROLLBAR_TOKEN'])
|
733
|
-
|
734
|
-
# Custom fingerprinting for your domain
|
735
|
-
config.fingerprint_callback = lambda do |event|
|
736
|
-
case event.exception&.message
|
737
|
-
when /payment.*failed/i
|
738
|
-
"payment-processing-error"
|
739
|
-
when /user.*not.*found/i
|
740
|
-
"user-lookup-error"
|
741
|
-
else
|
742
|
-
nil # Use built-in patterns and defaults
|
743
|
-
end
|
744
|
-
end
|
745
|
-
|
746
|
-
# Enhanced data protection
|
747
|
-
config.scrub_fields = %w[credit_card_number api_token internal_id]
|
748
|
-
config.randomize_scrub_length = true
|
749
|
-
|
750
|
-
# Reliable transport
|
751
|
-
config.transport_max_retries = 5
|
752
|
-
config.transport_timeout = 15
|
753
|
-
end
|
244
|
+
config.transport_max_retries = 3
|
245
|
+
config.transport_timeout = 10
|
246
|
+
config.transport_jitter = true # Prevent thundering herd
|
754
247
|
```
|
755
248
|
|
756
|
-
|
757
249
|
## Creating Custom Adapters
|
758
250
|
|
759
251
|
```ruby
|
760
|
-
class
|
252
|
+
class MyAdapter < Lapsoss::Adapters::Base
|
761
253
|
def capture(event)
|
762
254
|
# Send to your service
|
255
|
+
HttpClient.post("/errors", event.to_h)
|
763
256
|
end
|
764
257
|
end
|
765
258
|
|
766
|
-
Lapsoss::Registry.register(:
|
767
|
-
```
|
768
|
-
|
769
|
-
## Multi-Adapter Use Cases
|
770
|
-
|
771
|
-
### GDPR Region Migration
|
772
|
-
```ruby
|
773
|
-
# Step 1: Start with US
|
774
|
-
config.use_sentry(name: :sentry_us, dsn: ENV['SENTRY_US_DSN'])
|
775
|
-
|
776
|
-
# Step 2: Add EU, run both
|
777
|
-
config.use_sentry(name: :sentry_us, dsn: ENV['SENTRY_US_DSN'])
|
778
|
-
config.use_sentry(name: :sentry_eu, dsn: ENV['SENTRY_EU_DSN'])
|
779
|
-
|
780
|
-
# Step 3: Complete migration
|
781
|
-
config.use_sentry(name: :sentry_eu, dsn: ENV['SENTRY_EU_DSN'])
|
782
|
-
```
|
783
|
-
|
784
|
-
### Vendor Migration
|
785
|
-
```ruby
|
786
|
-
# Gradual migration with zero downtime
|
787
|
-
config.use_bugsnag(name: :old_vendor, api_key: ENV['BUGSNAG_KEY'])
|
788
|
-
config.use_sentry(name: :new_vendor, dsn: ENV['SENTRY_DSN'])
|
789
|
-
# Remove old vendor when ready
|
259
|
+
Lapsoss::Registry.register(:my_service, MyAdapter)
|
790
260
|
```
|
791
261
|
|
792
|
-
### AppSignal Integration
|
793
|
-
```ruby
|
794
|
-
# config/initializers/lapsoss.rb
|
795
|
-
config.use_appsignal(
|
796
|
-
name: :appsignal,
|
797
|
-
push_api_key: ENV['APPSIGNAL_PUSH_API_KEY'], # For markers & check-ins
|
798
|
-
frontend_api_key: ENV['APPSIGNAL_FRONTEND_API_KEY'], # For error tracking
|
799
|
-
app_name: 'my-app'
|
800
|
-
)
|
801
|
-
```
|
802
|
-
|
803
|
-
**AppSignal API Keys**: AppSignal uses two different API keys:
|
804
|
-
- **Push API Key**: For deploy markers and check-ins (found in Push & Deploy settings)
|
805
|
-
- **Frontend API Key**: For error tracking via public API (found in App settings > "Front-end error monitoring")
|
806
|
-
|
807
|
-
The Lapsoss AppSignal adapter provides:
|
808
|
-
- ✅ Error tracking (via public `/errors` endpoint with frontend key)
|
809
|
-
- ✅ Deploy markers (via `/markers` endpoint with push key)
|
810
|
-
- ✅ Check-ins/Heartbeats (via `/heartbeats` endpoint with push key)
|
811
|
-
- ✅ Breadcrumbs (included with errors)
|
812
|
-
- ❌ Performance monitoring (requires native extension)
|
813
|
-
- ❌ Host metrics (requires native extension)
|
814
|
-
|
815
|
-
### High Availability
|
816
|
-
```ruby
|
817
|
-
# Multiple regions + vendors for redundancy
|
818
|
-
config.use_sentry(name: :primary, dsn: ENV['PRIMARY_DSN'])
|
819
|
-
config.use_sentry(name: :backup, dsn: ENV['BACKUP_DSN'])
|
820
|
-
config.use_rollbar(name: :backup_service, access_token: ENV['ROLLBAR_TOKEN'])
|
821
|
-
```
|
822
|
-
|
823
|
-
## Why "Adaptive Trait Selection"?
|
824
|
-
|
825
|
-
Traditional error tracking gems lock you into their ecosystem. Lapsoss applies evolutionary principles:
|
826
|
-
|
827
|
-
1. **Observation**: Each vendor evolved unique strengths
|
828
|
-
2. **Selection**: I identify the most beneficial traits
|
829
|
-
3. **Adaptation**: I create vendor-neutral interfaces
|
830
|
-
4. **Evolution**: Your app gains the best of all worlds
|
831
|
-
|
832
|
-
### The Multi-Adapter Advantage
|
833
|
-
|
834
|
-
- **Zero-downtime migrations** between providers
|
835
|
-
- **Regional compliance** (GDPR, data residency)
|
836
|
-
- **Vendor independence** - never locked in
|
837
|
-
- **Cost optimization** - route by importance
|
838
|
-
- **A/B testing** different services
|
839
|
-
|
840
262
|
## Contributing
|
841
263
|
|
842
|
-
|
843
|
-
|
844
|
-
1. Fork the repo
|
264
|
+
1. Fork it
|
845
265
|
2. Create your feature branch
|
846
|
-
3. Add your
|
847
|
-
4. Submit a
|
266
|
+
3. Add tests for your changes
|
267
|
+
4. Submit a pull request
|
848
268
|
|
849
269
|
## License
|
850
270
|
|
851
|
-
MIT License - Because good
|
271
|
+
MIT License - Because good code should be free
|
852
272
|
|
853
273
|
---
|
854
274
|
|
855
|
-
Built
|
275
|
+
Built for Rails developers who refuse to be locked in.
|