e11y 0.2.0 → 1.0.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/.rubocop.yml +130 -10
- data/CHANGELOG.md +56 -1
- data/CLAUDE.md +168 -0
- data/CONTRIBUTING.md +640 -0
- data/README.md +134 -702
- data/RELEASE.md +18 -3
- data/Rakefile +108 -29
- data/config/README.md +1 -1
- data/config/loki-local-config.yaml +12 -0
- data/config/otel-collector-config.yaml +44 -0
- data/cucumber.yml +1 -0
- data/docker-compose.yml +18 -2
- data/docs/ADAPTERS.md +76 -0
- data/docs/ADAPTIVE_SAMPLING.md +59 -0
- data/docs/COMPARISON.md +104 -0
- data/docs/CONFIGURATION.md +52 -0
- data/docs/DISTRIBUTED_TRACING.md +44 -0
- data/docs/LIMITATIONS.md +13 -0
- data/docs/METRICS_DSL.md +84 -0
- data/docs/PERFORMANCE.md +60 -0
- data/docs/PII_FILTERING.md +40 -0
- data/docs/PRESETS.md +65 -0
- data/docs/QUICK-START.md +546 -587
- data/docs/RAILS_INTEGRATION.md +29 -0
- data/docs/SCHEMA_VALIDATION.md +63 -0
- data/docs/SLO-PROMQL-ALERTS.md +161 -0
- data/docs/TESTING.md +69 -0
- data/docs/{ADR-001-architecture.md → architecture/ADR-001-architecture.md} +35 -64
- data/docs/{ADR-002-metrics-yabeda.md → architecture/ADR-002-metrics-yabeda.md} +62 -236
- data/docs/{ADR-003-slo-observability.md → architecture/ADR-003-slo-observability.md} +27 -466
- data/docs/{ADR-004-adapter-architecture.md → architecture/ADR-004-adapter-architecture.md} +163 -146
- data/docs/{ADR-005-tracing-context.md → architecture/ADR-005-tracing-context.md} +10 -9
- data/docs/{ADR-006-security-compliance.md → architecture/ADR-006-security-compliance.md} +184 -191
- data/docs/{ADR-007-opentelemetry-integration.md → architecture/ADR-007-opentelemetry-integration.md} +3 -21
- data/docs/{ADR-008-rails-integration.md → architecture/ADR-008-rails-integration.md} +209 -339
- data/docs/{ADR-009-cost-optimization.md → architecture/ADR-009-cost-optimization.md} +45 -54
- data/docs/architecture/ADR-010-developer-experience.md +522 -0
- data/docs/{ADR-011-testing-strategy.md → architecture/ADR-011-testing-strategy.md} +41 -83
- data/docs/{ADR-013-reliability-error-handling.md → architecture/ADR-013-reliability-error-handling.md} +37 -12
- data/docs/{ADR-014-event-driven-slo.md → architecture/ADR-014-event-driven-slo.md} +12 -24
- data/docs/{ADR-015-middleware-order.md → architecture/ADR-015-middleware-order.md} +23 -41
- data/docs/{ADR-016-self-monitoring-slo.md → architecture/ADR-016-self-monitoring-slo.md} +52 -349
- data/docs/{ADR-017-multi-rails-compatibility.md → architecture/ADR-017-multi-rails-compatibility.md} +4 -11
- data/docs/architecture/ADR-018-memory-optimization.md +366 -0
- data/docs/{ADR-INDEX.md → architecture/ADR-INDEX.md} +11 -6
- data/docs/{00-ICP-AND-TIMELINE.md → prd/00-ICP-AND-TIMELINE.md} +6 -6
- data/docs/{01-SCALE-REQUIREMENTS.md → prd/01-SCALE-REQUIREMENTS.md} +6 -6
- data/docs/prd/01-overview-vision.md +19 -14
- data/docs/use_cases/README.md +22 -23
- data/docs/use_cases/UC-001-request-scoped-debug-buffering.md +50 -44
- data/docs/use_cases/UC-002-business-event-tracking.md +26 -95
- data/docs/use_cases/UC-003-event-metrics.md +66 -0
- data/docs/use_cases/UC-004-zero-config-slo-tracking.md +42 -101
- data/docs/use_cases/UC-005-sentry-integration.md +13 -15
- data/docs/use_cases/UC-006-trace-context-management.md +30 -28
- data/docs/use_cases/UC-007-pii-filtering.md +35 -87
- data/docs/use_cases/UC-008-opentelemetry-integration.md +51 -89
- data/docs/use_cases/UC-009-multi-service-tracing.md +4 -4
- data/docs/use_cases/UC-010-background-job-tracking.md +5 -5
- data/docs/use_cases/UC-011-rate-limiting.md +95 -168
- data/docs/use_cases/UC-012-audit-trail.md +21 -46
- data/docs/use_cases/UC-013-high-cardinality-protection.md +29 -167
- data/docs/use_cases/UC-014-adaptive-sampling.md +2 -2
- data/docs/use_cases/UC-015-cost-optimization.md +46 -99
- data/docs/use_cases/UC-016-rails-logger-migration.md +39 -213
- data/docs/use_cases/UC-017-local-development.md +203 -777
- data/docs/use_cases/UC-018-testing-events.md +3 -3
- data/docs/use_cases/UC-019-retention-based-routing.md +53 -106
- data/docs/use_cases/UC-020-event-versioning.md +8 -9
- data/docs/use_cases/UC-021-error-handling-retry-dlq.md +18 -22
- data/docs/use_cases/UC-022-event-registry.md +15 -21
- data/docs/use_cases/backlog.md +119 -87
- data/e11y.gemspec +2 -2
- data/gems/e11y-devtools/README.md +136 -0
- data/gems/e11y-devtools/config/routes.rb +8 -0
- data/gems/e11y-devtools/e11y-devtools.gemspec +25 -0
- data/gems/e11y-devtools/exe/e11y +34 -0
- data/gems/e11y-devtools/lib/e11y/devtools/mcp/server.rb +96 -0
- data/gems/e11y-devtools/lib/e11y/devtools/mcp/tool_base.rb +25 -0
- data/gems/e11y-devtools/lib/e11y/devtools/mcp/tools/clear.rb +31 -0
- data/gems/e11y-devtools/lib/e11y/devtools/mcp/tools/errors.rb +35 -0
- data/gems/e11y-devtools/lib/e11y/devtools/mcp/tools/event_detail.rb +33 -0
- data/gems/e11y-devtools/lib/e11y/devtools/mcp/tools/events_by_trace.rb +33 -0
- data/gems/e11y-devtools/lib/e11y/devtools/mcp/tools/interactions.rb +40 -0
- data/gems/e11y-devtools/lib/e11y/devtools/mcp/tools/recent_events.rb +34 -0
- data/gems/e11y-devtools/lib/e11y/devtools/mcp/tools/search.rb +34 -0
- data/gems/e11y-devtools/lib/e11y/devtools/mcp/tools/stats.rb +30 -0
- data/gems/e11y-devtools/lib/e11y/devtools/overlay/assets/overlay.js +115 -0
- data/gems/e11y-devtools/lib/e11y/devtools/overlay/controller.rb +54 -0
- data/gems/e11y-devtools/lib/e11y/devtools/overlay/engine.rb +26 -0
- data/gems/e11y-devtools/lib/e11y/devtools/overlay/middleware.rb +80 -0
- data/gems/e11y-devtools/lib/e11y/devtools/overlay/rails_controller.rb +42 -0
- data/gems/e11y-devtools/lib/e11y/devtools/tui/app.rb +262 -0
- data/gems/e11y-devtools/lib/e11y/devtools/tui/grouping.rb +66 -0
- data/gems/e11y-devtools/lib/e11y/devtools/tui/widgets/event_detail.rb +62 -0
- data/gems/e11y-devtools/lib/e11y/devtools/tui/widgets/event_list.rb +70 -0
- data/gems/e11y-devtools/lib/e11y/devtools/tui/widgets/interaction_list.rb +47 -0
- data/gems/e11y-devtools/lib/e11y/devtools/version.rb +8 -0
- data/gems/e11y-devtools/lib/e11y/devtools.rb +13 -0
- data/gems/e11y-devtools/spec/e11y/devtools/mcp/tools_spec.rb +107 -0
- data/gems/e11y-devtools/spec/e11y/devtools/overlay/controller_spec.rb +58 -0
- data/gems/e11y-devtools/spec/e11y/devtools/overlay/middleware_spec.rb +46 -0
- data/gems/e11y-devtools/spec/e11y/devtools/tui/app_spec.rb +85 -0
- data/gems/e11y-devtools/spec/e11y/devtools/tui/grouping_spec.rb +64 -0
- data/gems/e11y-devtools/spec/spec_helper.rb +5 -0
- data/gems/e11y-devtools/spec/tui/widgets/event_list_spec.rb +44 -0
- data/gems/e11y-devtools/spec/tui/widgets/interaction_list_spec.rb +62 -0
- data/lib/e11y/adapters/audit_encrypted.rb +53 -11
- data/lib/e11y/adapters/base.rb +33 -34
- data/lib/e11y/adapters/dev_log/file_store.rb +143 -0
- data/lib/e11y/adapters/dev_log/query.rb +219 -0
- data/lib/e11y/adapters/dev_log.rb +118 -0
- data/lib/e11y/adapters/file.rb +3 -6
- data/lib/e11y/adapters/in_memory.rb +52 -5
- data/lib/e11y/adapters/in_memory_test.rb +29 -0
- data/lib/e11y/adapters/loki.rb +58 -23
- data/lib/e11y/adapters/null.rb +82 -0
- data/lib/e11y/adapters/opentelemetry_collector.rb +183 -0
- data/lib/e11y/adapters/otel_logs.rb +136 -23
- data/lib/e11y/adapters/sentry.rb +4 -7
- data/lib/e11y/adapters/stdout.rb +73 -7
- data/lib/e11y/adapters/yabeda.rb +153 -29
- data/lib/e11y/buffers/adaptive_buffer.rb +3 -17
- data/lib/e11y/buffers/{request_scoped_buffer.rb → ephemeral_buffer.rb} +72 -58
- data/lib/e11y/buffers/ring_buffer.rb +3 -16
- data/lib/e11y/configuration.rb +272 -0
- data/lib/e11y/console.rb +10 -17
- data/lib/e11y/current.rb +53 -1
- data/lib/e11y/debug/pipeline_inspector.rb +96 -0
- data/lib/e11y/documentation/generator.rb +48 -0
- data/lib/e11y/event/base.rb +176 -82
- data/lib/e11y/event/value_sampling_config.rb +1 -5
- data/lib/e11y/events/rails/database/query.rb +1 -4
- data/lib/e11y/events/rails/job/failed.rb +2 -0
- data/lib/e11y/instruments/active_job.rb +46 -12
- data/lib/e11y/instruments/rails_instrumentation.rb +49 -24
- data/lib/e11y/instruments/sidekiq.rb +137 -31
- data/lib/e11y/linters/base.rb +11 -0
- data/lib/e11y/linters/pii/pii_declaration_linter.rb +120 -0
- data/lib/e11y/linters/slo/config_consistency_linter.rb +76 -0
- data/lib/e11y/linters/slo/explicit_declaration_linter.rb +36 -0
- data/lib/e11y/linters/slo/slo_status_from_linter.rb +41 -0
- data/lib/e11y/logger/bridge.rb +26 -7
- data/lib/e11y/metrics/cardinality_protection.rb +10 -15
- data/lib/e11y/metrics/cardinality_tracker.rb +16 -6
- data/lib/e11y/metrics/registry.rb +3 -5
- data/lib/e11y/metrics/test_backend.rb +62 -0
- data/lib/e11y/metrics.rb +56 -10
- data/lib/e11y/middleware/adapter_resolver.rb +40 -0
- data/lib/e11y/middleware/audit_signing.rb +43 -6
- data/lib/e11y/middleware/baggage_protection.rb +75 -0
- data/lib/e11y/middleware/dev_log_source.rb +24 -0
- data/lib/e11y/middleware/event_slo.rb +23 -9
- data/lib/e11y/middleware/otel_span.rb +23 -0
- data/lib/e11y/middleware/pii_filter.rb +104 -75
- data/lib/e11y/middleware/rate_limiting.rb +54 -27
- data/lib/e11y/middleware/request.rb +70 -23
- data/lib/e11y/middleware/routing.rb +78 -21
- data/lib/e11y/middleware/sampling.rb +66 -17
- data/lib/e11y/middleware/self_monitoring_emit.rb +39 -0
- data/lib/e11y/middleware/trace_context.rb +45 -10
- data/lib/e11y/middleware/track_latency.rb +34 -0
- data/lib/e11y/middleware/validation.rb +7 -16
- data/lib/e11y/middleware/versioning.rb +26 -22
- data/lib/e11y/opentelemetry/semantic_conventions.rb +109 -0
- data/lib/e11y/opentelemetry/span_creator.rb +142 -0
- data/lib/e11y/pii/patterns.rb +12 -1
- data/lib/e11y/pipeline/builder.rb +1 -1
- data/lib/e11y/presets/audit_event.rb +13 -2
- data/lib/e11y/railtie.rb +52 -15
- data/lib/e11y/registry.rb +306 -0
- data/lib/e11y/reliability/circuit_breaker.rb +19 -21
- data/lib/e11y/reliability/dlq/base.rb +71 -0
- data/lib/e11y/reliability/dlq/file_adapter.rb +301 -0
- data/lib/e11y/reliability/dlq/file_storage.rb +63 -34
- data/lib/e11y/reliability/dlq/filter.rb +37 -54
- data/lib/e11y/reliability/retry_handler.rb +26 -29
- data/lib/e11y/reliability/retry_rate_limiter.rb +3 -11
- data/lib/e11y/sampling/error_spike_detector.rb +0 -2
- data/lib/e11y/sampling/load_monitor.rb +5 -9
- data/lib/e11y/sampling/stratified_tracker.rb +18 -0
- data/lib/e11y/self_monitoring/buffer_monitor.rb +2 -0
- data/lib/e11y/self_monitoring/performance_monitor.rb +19 -61
- data/lib/e11y/self_monitoring/reliability_monitor.rb +4 -74
- data/lib/e11y/slo/config_loader.rb +40 -0
- data/lib/e11y/slo/config_validator.rb +58 -0
- data/lib/e11y/slo/dashboard_generator.rb +122 -0
- data/lib/e11y/slo/event_driven.rb +8 -0
- data/lib/e11y/slo/tracker.rb +31 -4
- data/lib/e11y/testing/have_tracked_event_matcher.rb +190 -0
- data/lib/e11y/testing/rspec_matchers.rb +21 -0
- data/lib/e11y/testing/snapshot_matcher.rb +86 -0
- data/lib/e11y/trace_context/sampler.rb +35 -0
- data/lib/e11y/tracing/faraday_middleware.rb +31 -0
- data/lib/e11y/tracing/net_http_patch.rb +33 -0
- data/lib/e11y/tracing/propagator.rb +116 -0
- data/lib/e11y/tracing.rb +47 -0
- data/lib/e11y/version.rb +1 -1
- data/lib/e11y/versioning/version_extractor.rb +32 -0
- data/lib/e11y.rb +141 -265
- data/lib/generators/e11y/event/event_generator.rb +22 -0
- data/lib/generators/e11y/event/templates/event.rb.tt +16 -0
- data/lib/generators/e11y/grafana_dashboard/grafana_dashboard_generator.rb +30 -0
- data/lib/generators/e11y/grafana_dashboard/templates/e11y_dashboard.json +81 -0
- data/lib/generators/e11y/install/install_generator.rb +34 -0
- data/lib/generators/e11y/install/templates/e11y.rb +239 -0
- data/lib/generators/e11y/prometheus_alerts/prometheus_alerts_generator.rb +29 -0
- data/lib/generators/e11y/prometheus_alerts/templates/e11y_alerts.yml +28 -0
- data/lib/tasks/e11y_docs.rake +30 -0
- data/lib/tasks/e11y_events.rake +71 -0
- data/lib/tasks/e11y_lint.rake +91 -0
- data/lib/tasks/e11y_slo.rake +29 -0
- metadata +129 -39
- data/docs/ADR-010-developer-experience.md +0 -2166
- data/docs/API-REFERENCE-L28.md +0 -914
- data/docs/COMPREHENSIVE-CONFIGURATION.md +0 -2366
- data/docs/CONTRIBUTING.md +0 -312
- data/docs/IMPLEMENTATION_NOTES.md +0 -2804
- data/docs/IMPLEMENTATION_PLAN.md +0 -1971
- data/docs/IMPLEMENTATION_PLAN_ARCHITECTURE.md +0 -586
- data/docs/PLAN.md +0 -148
- data/docs/README.md +0 -296
- data/docs/design/00-memory-optimization.md +0 -593
- data/docs/guides/MIGRATION-L27-L28.md +0 -692
- data/docs/guides/PERFORMANCE-BENCHMARKS.md +0 -434
- data/docs/guides/README.md +0 -44
- data/docs/use_cases/UC-003-pattern-based-metrics.md +0 -1627
- data/lib/e11y/adapters/registry.rb +0 -141
- /data/docs/{ADR-012-event-evolution.md → architecture/ADR-012-event-evolution.md} +0 -0
data/RELEASE.md
CHANGED
|
@@ -20,14 +20,29 @@ For more control, see [Step-by-Step Release](#step-by-step-release) below.
|
|
|
20
20
|
|
|
21
21
|
## Pre-Release Checklist
|
|
22
22
|
|
|
23
|
+
### Core
|
|
23
24
|
- [ ] All changes documented in CHANGELOG.md under `[Unreleased]`
|
|
24
25
|
- [ ] Version bumped: `rake release:bump`
|
|
25
|
-
- [ ] All tests passing: `rake spec`
|
|
26
|
+
- [ ] All tests passing: `rake spec:all` (unit + integration)
|
|
27
|
+
- [ ] RuboCop clean: `bundle exec rubocop`
|
|
26
28
|
- [ ] Changes committed
|
|
27
29
|
- [ ] Git tag created
|
|
28
30
|
- [ ] Published to RubyGems.org
|
|
29
31
|
- [ ] GitHub release created
|
|
30
32
|
|
|
33
|
+
### Documentation & Links
|
|
34
|
+
- [ ] All doc links valid (ADRs in `docs/architecture/`, use cases in `docs/use_cases/`)
|
|
35
|
+
- [ ] No broken references to deleted files (e.g. `docs/analysis/`, `docs/IMPLEMENTATION_PLAN.md`)
|
|
36
|
+
- [ ] README, CONTRIBUTING, CLAUDE.md reference correct paths
|
|
37
|
+
- [ ] All user-facing text in English (no Russian in docs/code comments)
|
|
38
|
+
|
|
39
|
+
### Production Readiness
|
|
40
|
+
- [ ] SECURITY.md present (if handling sensitive data)
|
|
41
|
+
- [ ] LICENSE file present and correct
|
|
42
|
+
- [ ] No TODO/FIXME in critical paths
|
|
43
|
+
- [ ] Deprecation warnings documented (if any)
|
|
44
|
+
- [ ] Breaking changes clearly called out in CHANGELOG
|
|
45
|
+
|
|
31
46
|
## Step-by-Step Release
|
|
32
47
|
|
|
33
48
|
### Step 0: Bump Version
|
|
@@ -181,7 +196,7 @@ bundle install
|
|
|
181
196
|
## 📚 Documentation
|
|
182
197
|
|
|
183
198
|
- **Quick Start**: [README.md](https://github.com/arturseletskiy/e11y#quick-start)
|
|
184
|
-
- **Architecture**: [docs/ADR-INDEX.md](https://github.com/arturseletskiy/e11y/blob/main/docs/ADR-INDEX.md)
|
|
199
|
+
- **Architecture**: [docs/architecture/ADR-INDEX.md](https://github.com/arturseletskiy/e11y/blob/main/docs/architecture/ADR-INDEX.md)
|
|
185
200
|
- **Benchmarks**: [benchmarks/README.md](https://github.com/arturseletskiy/e11y/blob/main/benchmarks/README.md)
|
|
186
201
|
|
|
187
202
|
## 🔥 What's New
|
|
@@ -192,7 +207,7 @@ See [CHANGELOG.md](https://github.com/arturseletskiy/e11y/blob/main/CHANGELOG.md
|
|
|
192
207
|
- Event System with dry-schema validation
|
|
193
208
|
- Pipeline Architecture (middleware-based)
|
|
194
209
|
- 7 Adapters: Stdout, File, InMemory, Loki, Sentry, OpenTelemetry, Yabeda
|
|
195
|
-
- 3 Buffer Types: RingBuffer,
|
|
210
|
+
- 3 Buffer Types: RingBuffer, EphemeralBuffer, AdaptiveBuffer
|
|
196
211
|
- Reliability: Retry, Circuit Breaker, Dead Letter Queue
|
|
197
212
|
|
|
198
213
|
### SLO Tracking (Phase 3)
|
data/Rakefile
CHANGED
|
@@ -20,6 +20,12 @@ require "bundler/gem_tasks"
|
|
|
20
20
|
require "rspec/core/rake_task"
|
|
21
21
|
require "rubocop/rake_task"
|
|
22
22
|
|
|
23
|
+
def e11y_devtools_specs_available?
|
|
24
|
+
# Devtools specs live in monorepo; run them when the directory exists
|
|
25
|
+
# (no need for gem in bundle — spec_helper loads lib via path)
|
|
26
|
+
File.directory?(File.join(__dir__, "gems/e11y-devtools/spec"))
|
|
27
|
+
end
|
|
28
|
+
|
|
23
29
|
RSpec::Core::RakeTask.new(:spec)
|
|
24
30
|
|
|
25
31
|
RuboCop::RakeTask.new
|
|
@@ -36,7 +42,6 @@ namespace :spec do
|
|
|
36
42
|
desc "Run integration tests (requires Rails, bundle install --with integration)"
|
|
37
43
|
task :integration do
|
|
38
44
|
# Run integration tests with explicit file patterns to avoid loading all specs
|
|
39
|
-
# This prevents test pollution from unit test files
|
|
40
45
|
sh "INTEGRATION=true bundle exec rspec " \
|
|
41
46
|
"spec/integration/*.rb " \
|
|
42
47
|
"spec/e11y/adapters/*_spec.rb " \
|
|
@@ -49,13 +54,27 @@ namespace :spec do
|
|
|
49
54
|
sh "bundle exec rspec spec/e11y/railtie_integration_spec.rb --tag railtie_integration"
|
|
50
55
|
end
|
|
51
56
|
|
|
52
|
-
desc "Run all tests (unit + integration + railtie
|
|
57
|
+
desc "Run all tests (unit + memory + integration + railtie + cucumber)"
|
|
53
58
|
task :all do
|
|
54
59
|
puts "\n#{'=' * 80}"
|
|
55
60
|
puts "Running UNIT tests (spec/e11y + top-level specs)..."
|
|
56
61
|
puts "#{'=' * 80}\n"
|
|
57
62
|
Rake::Task["spec:unit"].invoke
|
|
58
63
|
|
|
64
|
+
if e11y_devtools_specs_available?
|
|
65
|
+
puts "\n#{'=' * 80}"
|
|
66
|
+
puts "Running E11Y-DEVTOOLS unit tests (gems/e11y-devtools/spec/)..."
|
|
67
|
+
puts "#{'=' * 80}\n"
|
|
68
|
+
Rake::Task["spec:devtools"].invoke
|
|
69
|
+
else
|
|
70
|
+
puts "\n⏭️ Skipping e11y-devtools specs (gems/e11y-devtools/spec/ not found)"
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
puts "\n#{'=' * 80}"
|
|
74
|
+
puts "Running MEMORY tests (allocations, leaks, consumption)..."
|
|
75
|
+
puts "#{'=' * 80}\n"
|
|
76
|
+
Rake::Task["spec:memory"].invoke
|
|
77
|
+
|
|
59
78
|
puts "\n#{'=' * 80}"
|
|
60
79
|
puts "Running INTEGRATION tests (spec/integration)..."
|
|
61
80
|
puts "#{'=' * 80}\n"
|
|
@@ -66,6 +85,15 @@ namespace :spec do
|
|
|
66
85
|
puts "#{'=' * 80}\n"
|
|
67
86
|
Rake::Task["spec:railtie"].invoke
|
|
68
87
|
|
|
88
|
+
if Rake::Task.task_defined?("cucumber:passing")
|
|
89
|
+
puts "\n#{'=' * 80}"
|
|
90
|
+
puts "Running CUCUMBER tests (features/, exclude @wip)..."
|
|
91
|
+
puts "#{'=' * 80}\n"
|
|
92
|
+
Rake::Task["cucumber:passing"].invoke
|
|
93
|
+
else
|
|
94
|
+
puts "\n⚠️ Skipping Cucumber (bundle install --with development)"
|
|
95
|
+
end
|
|
96
|
+
|
|
69
97
|
puts "\n#{'=' * 80}"
|
|
70
98
|
puts "✅ All test suites completed!"
|
|
71
99
|
puts "#{'=' * 80}\n"
|
|
@@ -86,15 +114,31 @@ namespace :spec do
|
|
|
86
114
|
sh "bundle exec rspec spec/e11y --tag benchmark"
|
|
87
115
|
end
|
|
88
116
|
|
|
89
|
-
desc "Run
|
|
117
|
+
desc "Run memory profiling specs (allocations, leaks, consumption)"
|
|
118
|
+
task :memory do
|
|
119
|
+
sh "bundle exec rspec " \
|
|
120
|
+
"spec/e11y/memory_spec.rb " \
|
|
121
|
+
"spec/e11y/event/base_benchmark_spec.rb " \
|
|
122
|
+
"--tag memory --format documentation"
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
desc "Run e11y-devtools unit tests (gems/e11y-devtools/spec/)"
|
|
126
|
+
task :devtools do
|
|
127
|
+
sh "bundle exec rspec gems/e11y-devtools/spec/ --tag ~integration --format progress"
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
desc "Run ALL tests including benchmarks and cucumber (very slow)"
|
|
90
131
|
task :everything do
|
|
91
132
|
puts "\n#{'=' * 80}"
|
|
92
|
-
puts "Running ALL tests (unit + integration + railtie + benchmarks)"
|
|
133
|
+
puts "Running ALL tests (unit + integration + railtie + cucumber + benchmarks)"
|
|
93
134
|
puts "#{'=' * 80}\n"
|
|
94
135
|
Rake::Task["spec:unit"].invoke
|
|
136
|
+
Rake::Task["spec:devtools"].invoke if e11y_devtools_specs_available?
|
|
95
137
|
Rake::Task["spec:integration"].invoke
|
|
96
138
|
Rake::Task["spec:railtie"].invoke
|
|
139
|
+
Rake::Task["cucumber:passing"].invoke if Rake::Task.task_defined?("cucumber:passing")
|
|
97
140
|
Rake::Task["spec:benchmark"].invoke
|
|
141
|
+
Rake::Task["spec:memory"].invoke
|
|
98
142
|
|
|
99
143
|
puts "\n#{'=' * 80}"
|
|
100
144
|
puts "✅ All test suites including benchmarks completed!"
|
|
@@ -136,32 +180,32 @@ namespace :release do
|
|
|
136
180
|
task :bump do
|
|
137
181
|
require_relative "lib/e11y/version"
|
|
138
182
|
current_version = E11y::VERSION
|
|
139
|
-
|
|
183
|
+
|
|
140
184
|
puts "\n#{'=' * 80}"
|
|
141
185
|
puts "📝 Version Bump"
|
|
142
186
|
puts "#{'=' * 80}\n"
|
|
143
187
|
puts "Current version: #{current_version}"
|
|
144
188
|
puts "\nEnter new version (e.g., 0.2.0, 1.0.0):"
|
|
145
|
-
|
|
189
|
+
|
|
146
190
|
new_version = $stdin.gets.chomp.strip
|
|
147
|
-
|
|
191
|
+
|
|
148
192
|
if new_version.empty?
|
|
149
193
|
puts "❌ Error: Version cannot be empty"
|
|
150
194
|
exit 1
|
|
151
195
|
end
|
|
152
|
-
|
|
196
|
+
|
|
153
197
|
unless new_version.match?(/^\d+\.\d+\.\d+$/)
|
|
154
198
|
puts "❌ Error: Invalid version format. Use semantic versioning (e.g., 0.2.0)"
|
|
155
199
|
exit 1
|
|
156
200
|
end
|
|
157
|
-
|
|
201
|
+
|
|
158
202
|
if new_version == current_version
|
|
159
203
|
puts "⚠️ Warning: New version is the same as current version"
|
|
160
204
|
puts "Continue anyway? (y/N)"
|
|
161
205
|
response = $stdin.gets.chomp.downcase
|
|
162
|
-
exit 0 unless
|
|
206
|
+
exit 0 unless %w[y yes].include?(response)
|
|
163
207
|
end
|
|
164
|
-
|
|
208
|
+
|
|
165
209
|
puts "\n[1/3] Updating lib/e11y/version.rb..."
|
|
166
210
|
version_file = "lib/e11y/version.rb"
|
|
167
211
|
version_content = File.read(version_file)
|
|
@@ -171,58 +215,60 @@ namespace :release do
|
|
|
171
215
|
)
|
|
172
216
|
File.write(version_file, updated_version_content)
|
|
173
217
|
puts "✅ Updated: #{current_version} → #{new_version}"
|
|
174
|
-
|
|
218
|
+
|
|
175
219
|
puts "\n[2/3] Updating CHANGELOG.md..."
|
|
176
220
|
changelog_file = "CHANGELOG.md"
|
|
177
221
|
changelog_content = File.read(changelog_file)
|
|
178
|
-
|
|
222
|
+
|
|
179
223
|
# Check if there's an [Unreleased] section
|
|
224
|
+
today = Time.now.strftime("%Y-%m-%d")
|
|
180
225
|
if changelog_content.include?("## [Unreleased]")
|
|
181
226
|
# Replace [Unreleased] with version and date
|
|
182
|
-
today = Time.now.strftime("%Y-%m-%d")
|
|
183
227
|
updated_changelog = changelog_content.sub(
|
|
184
|
-
|
|
228
|
+
"## [Unreleased]",
|
|
185
229
|
"## [#{new_version}] - #{today}"
|
|
186
230
|
)
|
|
187
|
-
|
|
231
|
+
|
|
188
232
|
# Add new [Unreleased] section at the top
|
|
233
|
+
unreleased = "## [Unreleased]\n\n### Added\n\n### Changed\n\n### Fixed\n\n"
|
|
234
|
+
unreleased += "### Deprecated\n\n### Removed\n\n### Security\n\n\\1"
|
|
189
235
|
updated_changelog = updated_changelog.sub(
|
|
190
236
|
/(## \[#{Regexp.escape(new_version)}\] - #{today})/,
|
|
191
|
-
|
|
237
|
+
unreleased
|
|
192
238
|
)
|
|
193
|
-
|
|
239
|
+
|
|
194
240
|
File.write(changelog_file, updated_changelog)
|
|
195
241
|
puts "✅ Updated CHANGELOG.md:"
|
|
196
242
|
puts " - [Unreleased] → [#{new_version}] - #{today}"
|
|
197
243
|
puts " - Added new [Unreleased] section"
|
|
198
244
|
else
|
|
199
245
|
# No [Unreleased] section, just add version entry
|
|
200
|
-
|
|
201
|
-
|
|
246
|
+
|
|
202
247
|
# Find where to insert (after the header, before first version)
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
248
|
+
|
|
249
|
+
if /(## \[\d+\.\d+\.\d+\])/.match?(changelog_content)
|
|
250
|
+
new_section = "## [Unreleased]\n\n### Added\n\n### Changed\n\n### Fixed\n\n"
|
|
251
|
+
new_section += "### Deprecated\n\n### Removed\n\n### Security\n\n"
|
|
252
|
+
new_section += "## [#{new_version}] - #{today}\n\n### Added\n- Version bump\n\n\\1"
|
|
253
|
+
updated_changelog = changelog_content.sub(/(## \[\d+\.\d+\.\d+\])/, new_section)
|
|
208
254
|
else
|
|
209
255
|
# No previous versions, add after header
|
|
210
256
|
header_end = changelog_content.index("\n\n") || 0
|
|
211
257
|
header = changelog_content[0..header_end]
|
|
212
|
-
rest = changelog_content[header_end + 1
|
|
258
|
+
rest = changelog_content[(header_end + 1)..] || ""
|
|
213
259
|
updated_changelog = "#{header}\n## [#{new_version}] - #{today}\n\n### Added\n- Initial release\n\n#{rest}"
|
|
214
260
|
end
|
|
215
|
-
|
|
261
|
+
|
|
216
262
|
File.write(changelog_file, updated_changelog)
|
|
217
263
|
puts "✅ Added version [#{new_version}] - #{today} to CHANGELOG.md"
|
|
218
264
|
end
|
|
219
|
-
|
|
265
|
+
|
|
220
266
|
puts "\n[3/3] Summary"
|
|
221
267
|
puts "✅ Version bumped: #{current_version} → #{new_version}"
|
|
222
268
|
puts "✅ Files updated:"
|
|
223
269
|
puts " - lib/e11y/version.rb"
|
|
224
270
|
puts " - CHANGELOG.md"
|
|
225
|
-
|
|
271
|
+
|
|
226
272
|
puts "\n#{'=' * 80}"
|
|
227
273
|
puts "Next steps:"
|
|
228
274
|
puts " 1. Review changes: git diff"
|
|
@@ -412,3 +458,36 @@ namespace :release do
|
|
|
412
458
|
puts "✅ Clean complete"
|
|
413
459
|
end
|
|
414
460
|
end
|
|
461
|
+
|
|
462
|
+
# ---------------------------------------------------------------------------
|
|
463
|
+
# Cucumber acceptance tests
|
|
464
|
+
# ---------------------------------------------------------------------------
|
|
465
|
+
begin
|
|
466
|
+
require "cucumber/rake/task"
|
|
467
|
+
|
|
468
|
+
namespace :cucumber do
|
|
469
|
+
desc "Run all Cucumber acceptance tests"
|
|
470
|
+
Cucumber::Rake::Task.new(:all) do |t|
|
|
471
|
+
t.cucumber_opts = ["--format", "progress", "features/"]
|
|
472
|
+
end
|
|
473
|
+
|
|
474
|
+
desc "Run only @wip (known-bug) Cucumber scenarios"
|
|
475
|
+
Cucumber::Rake::Task.new(:wip) do |t|
|
|
476
|
+
t.cucumber_opts = ["--tags", "@wip", "--format", "progress", "features/"]
|
|
477
|
+
end
|
|
478
|
+
|
|
479
|
+
desc "Run passing Cucumber scenarios (exclude @wip)"
|
|
480
|
+
Cucumber::Rake::Task.new(:passing) do |t|
|
|
481
|
+
# Quote tag expression so shell keeps "not @wip" as one arg (Cucumber::Rake::Task uses cmd.join(' '))
|
|
482
|
+
t.cucumber_opts = ["--tags", '"not @wip"', "--format", "progress", "features/"]
|
|
483
|
+
end
|
|
484
|
+
end
|
|
485
|
+
|
|
486
|
+
desc "Run all Cucumber acceptance tests (alias for cucumber:all)"
|
|
487
|
+
task cucumber: "cucumber:all"
|
|
488
|
+
rescue LoadError
|
|
489
|
+
desc "Cucumber not available — install with: bundle install --with development"
|
|
490
|
+
task :cucumber do
|
|
491
|
+
warn "Cucumber gem is not available. Run: bundle install --with development"
|
|
492
|
+
end
|
|
493
|
+
end
|
data/config/README.md
CHANGED
|
@@ -80,4 +80,4 @@ Edit `docker-compose.yml` and change port mappings.
|
|
|
80
80
|
|
|
81
81
|
⚠️ **This is for TESTING ONLY!** Do not use these configurations in production.
|
|
82
82
|
|
|
83
|
-
For production setup, see
|
|
83
|
+
For production setup, see [QUICK-START](../docs/QUICK-START.md) and [CONFIGURATION](../docs/CONFIGURATION.md).
|
|
@@ -26,6 +26,18 @@ schema_config:
|
|
|
26
26
|
prefix: index_
|
|
27
27
|
period: 24h
|
|
28
28
|
|
|
29
|
+
# Fast flush for integration tests
|
|
30
|
+
ingester:
|
|
31
|
+
chunk_idle_period: 1s # Flush chunks after 1 second of inactivity
|
|
32
|
+
chunk_retain_period: 1s # Keep chunks in memory for 1 second before flush
|
|
33
|
+
max_chunk_age: 2s # Force flush after 2 seconds
|
|
34
|
+
chunk_target_size: 0 # Disable size-based flush delay
|
|
35
|
+
chunk_encoding: snappy
|
|
36
|
+
wal:
|
|
37
|
+
enabled: true
|
|
38
|
+
dir: /tmp/loki/wal
|
|
39
|
+
replay_memory_ceiling: 100MB
|
|
40
|
+
|
|
29
41
|
ruler:
|
|
30
42
|
alertmanager_url: http://localhost:9093
|
|
31
43
|
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# OpenTelemetry Collector config for E11y integration tests
|
|
2
|
+
# Receives OTLP (logs, traces, metrics) and exports to debug + Loki
|
|
3
|
+
#
|
|
4
|
+
# Usage: docker compose up -d otel-collector
|
|
5
|
+
# App sends to: http://localhost:4318 (HTTP) or localhost:4317 (gRPC)
|
|
6
|
+
|
|
7
|
+
receivers:
|
|
8
|
+
otlp:
|
|
9
|
+
protocols:
|
|
10
|
+
grpc:
|
|
11
|
+
endpoint: 0.0.0.0:4317
|
|
12
|
+
http:
|
|
13
|
+
endpoint: 0.0.0.0:4318
|
|
14
|
+
|
|
15
|
+
processors:
|
|
16
|
+
batch:
|
|
17
|
+
timeout: 5s
|
|
18
|
+
send_batch_size: 1024
|
|
19
|
+
|
|
20
|
+
exporters:
|
|
21
|
+
debug:
|
|
22
|
+
verbosity: detailed
|
|
23
|
+
sampling_initial: 5
|
|
24
|
+
sampling_thereafter: 200
|
|
25
|
+
|
|
26
|
+
# Forward logs to Loki (same backend as direct Loki adapter)
|
|
27
|
+
# Requires contrib image: otel/opentelemetry-collector-contrib
|
|
28
|
+
loki:
|
|
29
|
+
endpoint: http://loki:3100/loki/api/v1/push
|
|
30
|
+
|
|
31
|
+
service:
|
|
32
|
+
pipelines:
|
|
33
|
+
logs:
|
|
34
|
+
receivers: [otlp]
|
|
35
|
+
processors: [batch]
|
|
36
|
+
exporters: [debug, loki]
|
|
37
|
+
traces:
|
|
38
|
+
receivers: [otlp]
|
|
39
|
+
processors: [batch]
|
|
40
|
+
exporters: [debug]
|
|
41
|
+
metrics:
|
|
42
|
+
receivers: [otlp]
|
|
43
|
+
processors: [batch]
|
|
44
|
+
exporters: [debug]
|
data/cucumber.yml
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
default: --publish-quiet
|
data/docker-compose.yml
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
version: '3.8'
|
|
2
|
-
|
|
3
1
|
services:
|
|
4
2
|
loki:
|
|
5
3
|
image: grafana/loki:2.9.0
|
|
@@ -69,6 +67,24 @@ services:
|
|
|
69
67
|
networks:
|
|
70
68
|
- e11y_network
|
|
71
69
|
|
|
70
|
+
# OpenTelemetry Collector - receives OTLP, exports to debug + Loki
|
|
71
|
+
# HTTP: localhost:4318, gRPC: localhost:4317
|
|
72
|
+
# Usage: docker compose up -d loki otel-collector
|
|
73
|
+
otel-collector:
|
|
74
|
+
image: otel/opentelemetry-collector-contrib:0.104.0
|
|
75
|
+
container_name: e11y_otel_collector
|
|
76
|
+
ports:
|
|
77
|
+
- "4317:4317" # OTLP gRPC
|
|
78
|
+
- "4318:4318" # OTLP HTTP
|
|
79
|
+
volumes:
|
|
80
|
+
- ./config/otel-collector-config.yaml:/etc/otelcol-contrib/config.yaml
|
|
81
|
+
command: ["--config=/etc/otelcol-contrib/config.yaml"]
|
|
82
|
+
depends_on:
|
|
83
|
+
loki:
|
|
84
|
+
condition: service_healthy
|
|
85
|
+
networks:
|
|
86
|
+
- e11y_network
|
|
87
|
+
|
|
72
88
|
networks:
|
|
73
89
|
e11y_network:
|
|
74
90
|
driver: bridge
|
data/docs/ADAPTERS.md
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# Adapters
|
|
2
|
+
|
|
3
|
+
> Back to [README](../README.md#documentation)
|
|
4
|
+
|
|
5
|
+
E11y supports multiple adapters for different backends.
|
|
6
|
+
|
|
7
|
+
| Adapter | Purpose | Batching | Use Case |
|
|
8
|
+
|---------|---------|----------|----------|
|
|
9
|
+
| **Loki** | Log aggregation (Grafana) | Yes | Production logs |
|
|
10
|
+
| **Sentry** | Error tracking | Via SDK | Error monitoring |
|
|
11
|
+
| **OpenTelemetry** | OTLP export (OTelLogs, OpenTelemetryCollector) | Varies | Distributed tracing, logs |
|
|
12
|
+
| **Yabeda** | Prometheus metrics | N/A | Metrics export |
|
|
13
|
+
| **File** | Local logs | Yes | Development, CI |
|
|
14
|
+
| **Stdout** | Console output | No | Development |
|
|
15
|
+
| **InMemory** | Test buffer | No | Testing |
|
|
16
|
+
|
|
17
|
+
## Configuration
|
|
18
|
+
|
|
19
|
+
```ruby
|
|
20
|
+
# config/initializers/e11y.rb
|
|
21
|
+
E11y.configure do |config|
|
|
22
|
+
# Configure adapters
|
|
23
|
+
config.adapters[:logs] = E11y::Adapters::Loki.new(
|
|
24
|
+
url: ENV["LOKI_URL"],
|
|
25
|
+
batch_size: 100,
|
|
26
|
+
batch_timeout: 5,
|
|
27
|
+
compress: true
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
config.adapters[:errors_tracker] = E11y::Adapters::Sentry.new(
|
|
31
|
+
dsn: ENV["SENTRY_DSN"]
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
config.adapters[:stdout] = E11y::Adapters::Stdout.new(
|
|
35
|
+
format: :pretty
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
# OpenTelemetry Collector (compress: true default, requires Faraday)
|
|
39
|
+
# config.adapters[:otel] = E11y::Adapters::OpenTelemetryCollector.new(
|
|
40
|
+
# endpoint: ENV["OTEL_EXPORTER_OTLP_ENDPOINT"],
|
|
41
|
+
# service_name: "my-app"
|
|
42
|
+
# )
|
|
43
|
+
end
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Adapter Routing by Severity
|
|
47
|
+
|
|
48
|
+
Events are routed to adapters based on severity. The default mapping:
|
|
49
|
+
|
|
50
|
+
- `error`, `fatal` → `[:logs, :errors_tracker]`
|
|
51
|
+
- Other severities → `[:logs]`
|
|
52
|
+
|
|
53
|
+
Override routing explicitly:
|
|
54
|
+
|
|
55
|
+
```ruby
|
|
56
|
+
class CustomEvent < E11y::Event::Base
|
|
57
|
+
adapters :logs, :stdout # Explicit routing
|
|
58
|
+
end
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Custom Adapters
|
|
62
|
+
|
|
63
|
+
Implement the `write` method:
|
|
64
|
+
|
|
65
|
+
```ruby
|
|
66
|
+
class MyBackendAdapter < E11y::Adapters::Base
|
|
67
|
+
def write(event_data)
|
|
68
|
+
# event_data contains event_name, payload, severity, timestamp, etc.
|
|
69
|
+
MyBackend.send_event(event_data)
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
E11y.configure do |config|
|
|
74
|
+
config.adapters[:my_backend] = MyBackendAdapter.new
|
|
75
|
+
end
|
|
76
|
+
```
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# Adaptive Sampling
|
|
2
|
+
|
|
3
|
+
> Back to [README](../README.md#documentation)
|
|
4
|
+
|
|
5
|
+
E11y supports adaptive sampling to reduce event volume during high load.
|
|
6
|
+
|
|
7
|
+
Sampling strategies:
|
|
8
|
+
|
|
9
|
+
1. **Error-based** - Increase sampling during error spikes
|
|
10
|
+
2. **Load-based** - Reduce sampling under high throughput
|
|
11
|
+
3. **Value-based** - Always sample high-value events
|
|
12
|
+
|
|
13
|
+
> **Note:** Rate limiting (`E11y::Middleware::RateLimiting`) is **not included in the default
|
|
14
|
+
> pipeline**. To enable it, add it manually:
|
|
15
|
+
>
|
|
16
|
+
> ```ruby
|
|
17
|
+
> config.pipeline.use E11y::Middleware::RateLimiting
|
|
18
|
+
> ```
|
|
19
|
+
> Enabling `config.rate_limiting_enabled = true` alone has no effect without this step.
|
|
20
|
+
|
|
21
|
+
## Configuration
|
|
22
|
+
|
|
23
|
+
```ruby
|
|
24
|
+
E11y.configure do |config|
|
|
25
|
+
config.pipeline.use E11y::Middleware::Sampling,
|
|
26
|
+
default_sample_rate: 0.1,
|
|
27
|
+
|
|
28
|
+
# Error-based sampling
|
|
29
|
+
error_based_adaptive: true,
|
|
30
|
+
error_spike_config: {
|
|
31
|
+
window: 60,
|
|
32
|
+
absolute_threshold: 100,
|
|
33
|
+
relative_threshold: 3.0,
|
|
34
|
+
spike_duration: 300
|
|
35
|
+
},
|
|
36
|
+
|
|
37
|
+
# Load-based sampling
|
|
38
|
+
load_based_adaptive: true,
|
|
39
|
+
load_monitor_config: {
|
|
40
|
+
window: 60,
|
|
41
|
+
thresholds: {
|
|
42
|
+
normal: 1_000,
|
|
43
|
+
high: 10_000,
|
|
44
|
+
very_high: 50_000,
|
|
45
|
+
overload: 100_000
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
end
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Value-Based Sampling
|
|
52
|
+
|
|
53
|
+
Sample events based on payload values:
|
|
54
|
+
|
|
55
|
+
```ruby
|
|
56
|
+
class PaymentEvent < E11y::Event::Base
|
|
57
|
+
sample_by_value :amount, greater_than: 1000 # Always sample large payments
|
|
58
|
+
end
|
|
59
|
+
```
|
data/docs/COMPARISON.md
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
# E11y vs. Alternatives — Detailed Comparison
|
|
2
|
+
|
|
3
|
+
> For a quick overview, see the [comparison table in README](../README.md#what-makes-e11y-different).
|
|
4
|
+
|
|
5
|
+
### Detailed Comparisons
|
|
6
|
+
|
|
7
|
+
#### vs. SaaS APM (Datadog, New Relic, Dynatrace)
|
|
8
|
+
|
|
9
|
+
**Datadog / New Relic:**
|
|
10
|
+
- ✅ **Pros:** Full-stack visibility, mature dashboards, auto-instrumentation
|
|
11
|
+
- ❌ **Cons:** $500-5k/month, vendor lock-in, no debug buffering, no schema validation
|
|
12
|
+
- **E11y advantage:** 10x cheaper, request-scoped buffering (unique), type-safe events, own your data
|
|
13
|
+
|
|
14
|
+
**When to use Datadog/New Relic instead:**
|
|
15
|
+
- You need frontend RUM (Real User Monitoring)
|
|
16
|
+
- You have polyglot microservices (not just Rails)
|
|
17
|
+
- Budget is unlimited, prefer turnkey solution
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
#### vs. Open-Source Logging (Semantic Logger, Lograge)
|
|
22
|
+
|
|
23
|
+
**Semantic Logger:**
|
|
24
|
+
- ✅ **Pros:** Structured logs (JSON), async writes, Rails integration
|
|
25
|
+
- ❌ **Cons:** No debug buffering, no schema validation, no auto-metrics, logs-only
|
|
26
|
+
- **E11y advantage:** Request-scoped buffering (unique), schema validation, auto-metrics, unified events
|
|
27
|
+
|
|
28
|
+
**Lograge:**
|
|
29
|
+
- ✅ **Pros:** Reduces Rails log noise (single-line requests)
|
|
30
|
+
- ❌ **Cons:** Filtering only, no buffering, no validation, no metrics
|
|
31
|
+
- **E11y advantage:** Request-scoped buffering (selective, not filtering), schema validation, auto-metrics
|
|
32
|
+
|
|
33
|
+
**When to use Semantic Logger instead:**
|
|
34
|
+
- You only need structured JSON logs (no events/metrics)
|
|
35
|
+
- You don't need debug buffering or schema validation
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
#### vs. OpenTelemetry
|
|
40
|
+
|
|
41
|
+
**OpenTelemetry:**
|
|
42
|
+
- ✅ **Pros:** Industry standard, polyglot, vendor-neutral, mature ecosystem
|
|
43
|
+
- ❌ **Cons:** Complex setup (1-2 weeks), no debug buffering, no schema validation, overkill for Rails monolith
|
|
44
|
+
- **E11y advantage:** Fast setup, Rails-first, request-scoped buffering, schema validation
|
|
45
|
+
|
|
46
|
+
**When to use OpenTelemetry instead:**
|
|
47
|
+
- You have microservices in multiple languages (Go, Java, Python, etc.)
|
|
48
|
+
- You need distributed tracing across services
|
|
49
|
+
- You have a platform team to manage complexity
|
|
50
|
+
|
|
51
|
+
**Use both:** E11y events can be sent to OpenTelemetry via `E11y::Adapters::OtelLogs`
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
#### vs. Grafana + Loki + Prometheus
|
|
56
|
+
|
|
57
|
+
**Grafana Stack:**
|
|
58
|
+
- ✅ **Pros:** Open-source, powerful visualizations, mature, self-hosted
|
|
59
|
+
- ❌ **Cons:** Complex setup (2-3 days), requires DevOps, no Rails integration, no schema validation
|
|
60
|
+
- **E11y advantage:** Fast setup, Rails-native, schema validation, no DevOps required
|
|
61
|
+
|
|
62
|
+
**When to use Grafana Stack instead:**
|
|
63
|
+
- You already have Grafana/Loki infrastructure
|
|
64
|
+
- You have a dedicated DevOps team
|
|
65
|
+
- You need custom dashboards across multiple systems
|
|
66
|
+
|
|
67
|
+
**Use both:** E11y can send events to Loki via `E11y::Adapters::Loki`
|
|
68
|
+
|
|
69
|
+
---
|
|
70
|
+
|
|
71
|
+
#### vs. Error Tracking (Sentry, Honeybadger, Rollbar)
|
|
72
|
+
|
|
73
|
+
**Sentry:**
|
|
74
|
+
- ✅ **Pros:** Excellent error tracking, stack traces, breadcrumbs, release tracking
|
|
75
|
+
- ❌ **Cons:** Errors-only, no debug buffering, no schema validation, $26-80/mo
|
|
76
|
+
- **E11y advantage:** Events + errors + metrics unified, request-scoped buffering, schema validation
|
|
77
|
+
|
|
78
|
+
**When to use Sentry instead:**
|
|
79
|
+
- You only need error tracking (not general observability)
|
|
80
|
+
- You need frontend JavaScript error tracking
|
|
81
|
+
|
|
82
|
+
**Use both:** E11y can send error events to Sentry via `E11y::Adapters::Sentry`
|
|
83
|
+
|
|
84
|
+
---
|
|
85
|
+
|
|
86
|
+
#### vs. Rails-First APM (AppSignal, Skylight)
|
|
87
|
+
|
|
88
|
+
**AppSignal:**
|
|
89
|
+
- ✅ **Pros:** Rails-native, beautiful UI, performance monitoring, $23/mo entry
|
|
90
|
+
- ❌ **Cons:** SaaS lock-in, no debug buffering, no schema validation, limited to supported languages
|
|
91
|
+
- **E11y advantage:** Request-scoped buffering (unique), schema validation, own your data
|
|
92
|
+
|
|
93
|
+
**Skylight:**
|
|
94
|
+
- ✅ **Pros:** Rails performance profiling, SQL query analysis
|
|
95
|
+
- ❌ **Cons:** Performance-only (no logs/events), SaaS lock-in, $20+/mo
|
|
96
|
+
- **E11y advantage:** Unified events/logs/metrics, request-scoped buffering, own your data
|
|
97
|
+
|
|
98
|
+
**When to use AppSignal/Skylight instead:**
|
|
99
|
+
- You want zero-config turnkey solution
|
|
100
|
+
- You prefer paying for hosted service over self-hosting
|
|
101
|
+
|
|
102
|
+
**Use both:** E11y for events/logs/metrics, AppSignal for performance profiling
|
|
103
|
+
|
|
104
|
+
---
|