lapsoss 0.1.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 +7 -0
- data/CHANGELOG.md +5 -0
- data/LICENSE.txt +21 -0
- data/README.md +855 -0
- data/lib/lapsoss/adapters/appsignal_adapter.rb +136 -0
- data/lib/lapsoss/adapters/base.rb +88 -0
- data/lib/lapsoss/adapters/insight_hub_adapter.rb +190 -0
- data/lib/lapsoss/adapters/logger_adapter.rb +67 -0
- data/lib/lapsoss/adapters/rollbar_adapter.rb +157 -0
- data/lib/lapsoss/adapters/sentry_adapter.rb +197 -0
- data/lib/lapsoss/backtrace_frame.rb +258 -0
- data/lib/lapsoss/backtrace_processor.rb +346 -0
- data/lib/lapsoss/client.rb +115 -0
- data/lib/lapsoss/configuration.rb +310 -0
- data/lib/lapsoss/current.rb +9 -0
- data/lib/lapsoss/event.rb +107 -0
- data/lib/lapsoss/exclusions.rb +429 -0
- data/lib/lapsoss/fingerprinter.rb +217 -0
- data/lib/lapsoss/http_client.rb +79 -0
- data/lib/lapsoss/middleware.rb +353 -0
- data/lib/lapsoss/pipeline.rb +131 -0
- data/lib/lapsoss/railtie.rb +72 -0
- data/lib/lapsoss/registry.rb +114 -0
- data/lib/lapsoss/release_tracker.rb +553 -0
- data/lib/lapsoss/router.rb +36 -0
- data/lib/lapsoss/sampling.rb +332 -0
- data/lib/lapsoss/scope.rb +110 -0
- data/lib/lapsoss/scrubber.rb +170 -0
- data/lib/lapsoss/user_context.rb +355 -0
- data/lib/lapsoss/validators.rb +142 -0
- data/lib/lapsoss/version.rb +5 -0
- data/lib/lapsoss.rb +76 -0
- metadata +217 -0
data/README.md
ADDED
|
@@ -0,0 +1,855 @@
|
|
|
1
|
+
# Lapsoss 🧬
|
|
2
|
+
|
|
3
|
+
**Adaptive Trait Selection for Error Tracking**
|
|
4
|
+
|
|
5
|
+
Lapsoss is a vendor-neutral error tracking library for Ruby that applies the principle of "Adaptive Trait Selection" - intelligently selecting the best features from each error tracking ecosystem to create a superior, unified solution.
|
|
6
|
+
|
|
7
|
+
## Philosophy
|
|
8
|
+
|
|
9
|
+
Lapsoss is built on the principle of absolute vendor neutrality and control. Unlike traditional error tracking libraries that often bundle proprietary SDKs, Lapsoss provides a pure Ruby implementation for error reporting. This ensures:
|
|
10
|
+
|
|
11
|
+
- **No External SDK Dependencies**: Lapsoss handles payload construction and transport directly, eliminating the need for any third-party error tracking gems.
|
|
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
|
|
92
|
+
|
|
93
|
+
```ruby
|
|
94
|
+
gem 'lapsoss'
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
## Quick Start
|
|
98
|
+
|
|
99
|
+
Lapsoss currently provides 4 built-in adapters:
|
|
100
|
+
- **Sentry** - Full error tracking support with pure Ruby implementation
|
|
101
|
+
- **AppSignal** - Error tracking, deploy markers, and check-ins support (messages limited to :error, :fatal, :critical levels)
|
|
102
|
+
- **Rollbar** - Complete error tracking with grouping and person tracking
|
|
103
|
+
- **Insight Hub** (formerly Bugsnag) - Error tracking with breadcrumbs and session support
|
|
104
|
+
|
|
105
|
+
All adapters are pure Ruby implementations with no external SDK dependencies or monkey-patching. Additional adapters can be easily added by the community or vendors.
|
|
106
|
+
|
|
107
|
+
### Single Adapter (Simple Mode)
|
|
108
|
+
```ruby
|
|
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"])
|
|
113
|
+
end
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### Multi-Adapter (Advanced Mode)
|
|
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
|
|
128
|
+
|
|
129
|
+
# For Rails applications, errors are automatically captured via the Rails error reporting API.
|
|
130
|
+
# For other Ruby applications, use Lapsoss.capture_exception or Lapsoss.capture_message.
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
## Usage
|
|
134
|
+
|
|
135
|
+
### Core API
|
|
136
|
+
|
|
137
|
+
Lapsoss provides a simple, intuitive API for error tracking:
|
|
138
|
+
|
|
139
|
+
```ruby
|
|
140
|
+
# Capture exceptions
|
|
141
|
+
Lapsoss.capture_exception(exception, **context)
|
|
142
|
+
|
|
143
|
+
# Capture messages
|
|
144
|
+
Lapsoss.capture_message(message, level: :info, **context)
|
|
145
|
+
|
|
146
|
+
# Add breadcrumbs for debugging context
|
|
147
|
+
Lapsoss.add_breadcrumb(message, type: :default, **metadata)
|
|
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"])
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
# That's it! All unhandled exceptions are automatically captured
|
|
165
|
+
# No need to modify your controllers or models
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
### Manual Error Capture
|
|
169
|
+
|
|
170
|
+
For non-Rails applications or custom error handling:
|
|
171
|
+
|
|
172
|
+
```ruby
|
|
173
|
+
# Basic exception capture
|
|
174
|
+
begin
|
|
175
|
+
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
|
+
end
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
### Message Logging
|
|
193
|
+
|
|
194
|
+
For important events or custom alerts:
|
|
195
|
+
|
|
196
|
+
```ruby
|
|
197
|
+
# Simple message
|
|
198
|
+
Lapsoss.capture_message("Payment processing started", level: :info)
|
|
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
|
+
```
|
|
207
|
+
|
|
208
|
+
### Breadcrumbs for Debugging
|
|
209
|
+
|
|
210
|
+
Track user actions and system events leading up to errors:
|
|
211
|
+
|
|
212
|
+
```ruby
|
|
213
|
+
# User actions
|
|
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
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
### Scoped Context
|
|
243
|
+
|
|
244
|
+
Use scoped context to apply data to multiple operations:
|
|
245
|
+
|
|
246
|
+
```ruby
|
|
247
|
+
# Request-scoped context
|
|
248
|
+
Lapsoss.with_scope(
|
|
249
|
+
user: { id: current_user.id, email: current_user.email },
|
|
250
|
+
tags: { request_id: request.id, controller: "checkout" }
|
|
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
|
+
```
|
|
273
|
+
|
|
274
|
+
### Real-World Examples
|
|
275
|
+
|
|
276
|
+
#### E-commerce Checkout Flow
|
|
277
|
+
```ruby
|
|
278
|
+
class CheckoutController < ApplicationController
|
|
279
|
+
def create
|
|
280
|
+
Lapsoss.with_scope(
|
|
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
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
#### Background Job Error Handling
|
|
319
|
+
```ruby
|
|
320
|
+
class InvoiceGeneratorJob < ApplicationJob
|
|
321
|
+
def perform(batch_id)
|
|
322
|
+
Lapsoss.with_scope(
|
|
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
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
#### API Error Tracking
|
|
356
|
+
```ruby
|
|
357
|
+
class ApiController < ApplicationController
|
|
358
|
+
around_action :track_api_errors
|
|
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
|
|
407
|
+
```
|
|
408
|
+
|
|
409
|
+
> 💡 **Pro Tip**: Check out the `/examples` directory for more comprehensive configuration examples and use cases.
|
|
410
|
+
|
|
411
|
+
### Rollbar Integration
|
|
412
|
+
```ruby
|
|
413
|
+
# Traditional Rollbar setup:
|
|
414
|
+
# rails generate rollbar YOUR_ACCESS_TOKEN
|
|
415
|
+
|
|
416
|
+
# With Lapsoss:
|
|
417
|
+
config.use_rollbar(
|
|
418
|
+
name: :rollbar,
|
|
419
|
+
access_token: ENV['ROLLBAR_ACCESS_TOKEN'] # or your token directly
|
|
420
|
+
)
|
|
421
|
+
```
|
|
422
|
+
|
|
423
|
+
### Insight Hub Integration
|
|
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
|
+
```
|
|
435
|
+
|
|
436
|
+
## Advanced Features
|
|
437
|
+
|
|
438
|
+
### Custom Fingerprinting for Intelligent Error Grouping
|
|
439
|
+
|
|
440
|
+
Lapsoss provides sophisticated error fingerprinting to group related errors together, reducing noise and improving debugging efficiency.
|
|
441
|
+
|
|
442
|
+
#### Built-in Smart Patterns
|
|
443
|
+
```ruby
|
|
444
|
+
# These errors get automatically grouped:
|
|
445
|
+
"User 123 not found" } → "user-lookup-error"
|
|
446
|
+
"User 456 not found" }
|
|
447
|
+
|
|
448
|
+
"Payment processing failed for order #123" } → "payment-failure"
|
|
449
|
+
"Payment failed for card ending in 4567" }
|
|
450
|
+
|
|
451
|
+
"Database connection lost" } → "database-connection-error"
|
|
452
|
+
"PG::ConnectionBad: timeout" }
|
|
453
|
+
```
|
|
454
|
+
|
|
455
|
+
#### Custom Fingerprint Callbacks
|
|
456
|
+
```ruby
|
|
457
|
+
Lapsoss.configure do |config|
|
|
458
|
+
config.fingerprint_callback = lambda do |event|
|
|
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
|
+
```
|
|
475
|
+
|
|
476
|
+
#### Pattern-Based Fingerprinting
|
|
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
|
+
```
|
|
502
|
+
|
|
503
|
+
#### Smart Normalization
|
|
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
|
+
```
|
|
516
|
+
|
|
517
|
+
#### Advanced Use Cases
|
|
518
|
+
```ruby
|
|
519
|
+
# Environment-specific fingerprinting
|
|
520
|
+
config.fingerprint_callback = lambda do |event|
|
|
521
|
+
if Rails.env.development?
|
|
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
|
|
547
|
+
end
|
|
548
|
+
```
|
|
549
|
+
|
|
550
|
+
### Transport Reliability & Rate Limiting
|
|
551
|
+
|
|
552
|
+
Lapsoss includes built-in transport reliability to ensure your errors reach their destination even under adverse conditions.
|
|
553
|
+
|
|
554
|
+
```ruby
|
|
555
|
+
Lapsoss.configure do |config|
|
|
556
|
+
# Transport reliability settings
|
|
557
|
+
config.transport_timeout = 10 # Request timeout in seconds
|
|
558
|
+
config.transport_max_retries = 3 # Number of retry attempts
|
|
559
|
+
config.transport_initial_backoff = 1.0 # Initial backoff delay
|
|
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
|
|
563
|
+
end
|
|
564
|
+
```
|
|
565
|
+
|
|
566
|
+
**Features:**
|
|
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:
|
|
575
|
+
|
|
576
|
+
```ruby
|
|
577
|
+
Lapsoss.configure do |config|
|
|
578
|
+
# Code context extraction
|
|
579
|
+
config.backtrace_context_lines = 3 # Lines of code context (before/after)
|
|
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
|
+
```
|
|
603
|
+
|
|
604
|
+
**Features:**
|
|
605
|
+
- **Code Context**: Include source code snippets around error locations
|
|
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
|
|
610
|
+
|
|
611
|
+
### Configuration Validation
|
|
612
|
+
|
|
613
|
+
All adapter settings are validated to catch configuration errors early:
|
|
614
|
+
|
|
615
|
+
```ruby
|
|
616
|
+
# ✅ Valid configurations
|
|
617
|
+
config.use_sentry(dsn: "https://public_key@sentry.io/project_id")
|
|
618
|
+
config.use_rollbar(access_token: "abc123def456")
|
|
619
|
+
config.use_appsignal(push_api_key: "12345678-1234-1234-1234-123456789abc")
|
|
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
|
|
625
|
+
```
|
|
626
|
+
|
|
627
|
+
## Data Security & Privacy
|
|
628
|
+
|
|
629
|
+
Lapsoss automatically protects sensitive data by integrating with Rails' parameter filtering system.
|
|
630
|
+
|
|
631
|
+
### Automatic Rails Integration
|
|
632
|
+
```ruby
|
|
633
|
+
# config/initializers/filter_parameter_logging.rb (Standard Rails)
|
|
634
|
+
Rails.application.config.filter_parameters += [
|
|
635
|
+
:passw, :secret, :token, :_key, :crypt, :salt, :certificate, :otp, :ssn
|
|
636
|
+
]
|
|
637
|
+
|
|
638
|
+
# 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
|
+
```
|
|
662
|
+
|
|
663
|
+
### What Gets Protected
|
|
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
|
|
682
|
+
|
|
683
|
+
### From AppSignal 📊
|
|
684
|
+
- **Configuration validation** to catch setup errors early
|
|
685
|
+
- Check-in monitoring for cron jobs
|
|
686
|
+
- Deploy markers and health checks
|
|
687
|
+
|
|
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
|
+
```ruby
|
|
704
|
+
begin
|
|
705
|
+
risky_operation
|
|
706
|
+
rescue => e
|
|
707
|
+
Lapsoss.capture_exception(e, user: current_user)
|
|
708
|
+
end
|
|
709
|
+
```
|
|
710
|
+
|
|
711
|
+
### Custom Fingerprinting in Action
|
|
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
|
|
719
|
+
|
|
720
|
+
begin
|
|
721
|
+
User.find(456) # → Same "user-lookup-error" group
|
|
722
|
+
rescue ActiveRecord::RecordNotFound => e
|
|
723
|
+
Lapsoss.capture_exception(e)
|
|
724
|
+
end
|
|
725
|
+
```
|
|
726
|
+
|
|
727
|
+
### Advanced Configuration Example
|
|
728
|
+
```ruby
|
|
729
|
+
Lapsoss.configure do |config|
|
|
730
|
+
# Multi-vendor setup with custom fingerprinting
|
|
731
|
+
config.use_sentry(name: :sentry, dsn: ENV['SENTRY_DSN'])
|
|
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
|
|
754
|
+
```
|
|
755
|
+
|
|
756
|
+
|
|
757
|
+
## Creating Custom Adapters
|
|
758
|
+
|
|
759
|
+
```ruby
|
|
760
|
+
class MyCustomAdapter < Lapsoss::Adapters::Base
|
|
761
|
+
def capture(event)
|
|
762
|
+
# Send to your service
|
|
763
|
+
end
|
|
764
|
+
end
|
|
765
|
+
|
|
766
|
+
Lapsoss::Registry.register(:custom, MyCustomAdapter)
|
|
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
|
|
790
|
+
```
|
|
791
|
+
|
|
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
|
+
## Contributing
|
|
841
|
+
|
|
842
|
+
Help me evolve! I'm actively selecting new adaptive traits:
|
|
843
|
+
|
|
844
|
+
1. Fork the repo
|
|
845
|
+
2. Create your feature branch
|
|
846
|
+
3. Add your trait selection
|
|
847
|
+
4. Submit a PR
|
|
848
|
+
|
|
849
|
+
## License
|
|
850
|
+
|
|
851
|
+
MIT License - Because good traits should spread freely
|
|
852
|
+
|
|
853
|
+
---
|
|
854
|
+
|
|
855
|
+
Built with ❤️ and evolutionary principles
|