e11y 0.2.0 → 1.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 +4 -4
- data/.rubocop.yml +130 -10
- data/CHANGELOG.md +80 -1
- data/CLAUDE.md +168 -0
- data/CONTRIBUTING.md +640 -0
- data/README.md +165 -701
- data/RELEASE.md +41 -12
- data/Rakefile +249 -57
- 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 +79 -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} +36 -65
- data/docs/{ADR-002-metrics-yabeda.md → architecture/ADR-002-metrics-yabeda.md} +62 -236
- data/docs/architecture/ADR-003-slo-observability.md +1402 -0
- 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} +182 -743
- 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} +44 -86
- data/docs/{ADR-012-event-evolution.md → architecture/ADR-012-event-evolution.md} +11 -11
- 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} +43 -59
- data/docs/{ADR-016-self-monitoring-slo.md → architecture/ADR-016-self-monitoring-slo.md} +58 -355
- 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/plans/2026-03-20-browser-overlay-svelte.md +281 -0
- 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 +33 -684
- 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 +30 -178
- data/docs/use_cases/UC-010-background-job-tracking.md +24 -91
- 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 +158 -0
- data/gems/e11y-devtools/config/routes.rb +15 -0
- data/gems/e11y-devtools/e11y-devtools.gemspec +25 -0
- data/gems/e11y-devtools/exe/e11y +34 -0
- data/gems/e11y-devtools/frontend/.gitignore +24 -0
- data/gems/e11y-devtools/frontend/README.md +51 -0
- data/gems/e11y-devtools/frontend/index.html +14 -0
- data/gems/e11y-devtools/frontend/package-lock.json +3707 -0
- data/gems/e11y-devtools/frontend/package.json +28 -0
- data/gems/e11y-devtools/frontend/public/mocks/v1/events/recent.json +4205 -0
- data/gems/e11y-devtools/frontend/public/mocks/v1/interactions.json +194 -0
- data/gems/e11y-devtools/frontend/public/mocks/v1/traces/0a2e04027cfa22d014bc22e8b27cd913/events.json +86 -0
- data/gems/e11y-devtools/frontend/public/mocks/v1/traces/0e1543af6a630fb3af6b52283154b3e0/events.json +169 -0
- data/gems/e11y-devtools/frontend/public/mocks/v1/traces/1838b691faa49564f97db8592ff3978d/events.json +78 -0
- data/gems/e11y-devtools/frontend/public/mocks/v1/traces/29f198f6588dacffb687777eb5f8f118/events.json +197 -0
- data/gems/e11y-devtools/frontend/public/mocks/v1/traces/34bc3c9c0097de28a7a6f99b90a8e7bc/events.json +194 -0
- data/gems/e11y-devtools/frontend/public/mocks/v1/traces/3ba6c20d068ab9cee00e51b180e66444/events.json +184 -0
- data/gems/e11y-devtools/frontend/public/mocks/v1/traces/435bfd8f17b9009146a79812d7c3726d/events.json +144 -0
- data/gems/e11y-devtools/frontend/public/mocks/v1/traces/4c7676e3fe668e99edb2b94d7d5678a9/events.json +222 -0
- data/gems/e11y-devtools/frontend/public/mocks/v1/traces/6daf0d47974bedfc55d5de7004a3ea9f/events.json +194 -0
- data/gems/e11y-devtools/frontend/public/mocks/v1/traces/8a81ada42834d15f287bb40010043605/events.json +194 -0
- data/gems/e11y-devtools/frontend/public/mocks/v1/traces/8c0a98900edaae105469df8daedccf02/events.json +198 -0
- data/gems/e11y-devtools/frontend/public/mocks/v1/traces/8e4f645180f8a7d1dce426b07380466b/events.json +222 -0
- data/gems/e11y-devtools/frontend/public/mocks/v1/traces/93db346fa5d44a032605a13b627f4b80/events.json +128 -0
- data/gems/e11y-devtools/frontend/public/mocks/v1/traces/98ff6146faf7bd9be8bd03a8275817ba/events.json +223 -0
- data/gems/e11y-devtools/frontend/public/mocks/v1/traces/9997ddd0247bc7e25f2ca7a5c415c93d/events.json +197 -0
- data/gems/e11y-devtools/frontend/public/mocks/v1/traces/99e35f8ef3baedd798cc4fd085980ad9/events.json +194 -0
- data/gems/e11y-devtools/frontend/public/mocks/v1/traces/b4f3095c1909924cbc98889a86c83d6d/events.json +131 -0
- data/gems/e11y-devtools/frontend/public/mocks/v1/traces/b54b7fc32b7575a7110de809d11ccda0/events.json +128 -0
- data/gems/e11y-devtools/frontend/public/mocks/v1/traces/c0b48033fa06746bcc5886745e053cff/events.json +169 -0
- data/gems/e11y-devtools/frontend/public/mocks/v1/traces/c44649ac76701b4558927cd2305ab535/events.json +169 -0
- data/gems/e11y-devtools/frontend/public/mocks/v1/traces/d601ae3320057580a39dbdac2edfdf4a/events.json +248 -0
- data/gems/e11y-devtools/frontend/public/mocks/v1/traces/e67e724bab422d2b52eeb49635e512e1/events.json +194 -0
- data/gems/e11y-devtools/frontend/public/mocks/v1/traces/e6c72765a28f158a8485b35fa63f73da/events.json +194 -0
- data/gems/e11y-devtools/frontend/public/mocks/v1/traces/f541b87405c9a54819b18ebe529f6419/events.json +194 -0
- data/gems/e11y-devtools/frontend/scripts/generate_mocks.rb +397 -0
- data/gems/e11y-devtools/frontend/src/App.svelte +827 -0
- data/gems/e11y-devtools/frontend/src/components/Fab.svelte +19 -0
- data/gems/e11y-devtools/frontend/src/components/FilterBar.svelte +38 -0
- data/gems/e11y-devtools/frontend/src/components/FullscreenPanel.svelte +82 -0
- data/gems/e11y-devtools/frontend/src/components/InteractionsTimeline.svelte +264 -0
- data/gems/e11y-devtools/frontend/src/components/RecentHistogram.svelte +354 -0
- data/gems/e11y-devtools/frontend/src/lib/api.ts +37 -0
- data/gems/e11y-devtools/frontend/src/lib/eventIdentity.ts +12 -0
- data/gems/e11y-devtools/frontend/src/lib/format.ts +37 -0
- data/gems/e11y-devtools/frontend/src/lib/listFilter.ts +43 -0
- data/gems/e11y-devtools/frontend/src/lib/recentVolume.ts +80 -0
- data/gems/e11y-devtools/frontend/src/lib/router.ts +12 -0
- data/gems/e11y-devtools/frontend/src/lib/transitions.ts +34 -0
- data/gems/e11y-devtools/frontend/src/lib/viewportOrigin.ts +25 -0
- data/gems/e11y-devtools/frontend/src/main.ts +8 -0
- data/gems/e11y-devtools/frontend/src/overlay-entry.ts +24 -0
- data/gems/e11y-devtools/frontend/src/overlay.css +1080 -0
- data/gems/e11y-devtools/frontend/svelte.config.js +2 -0
- data/gems/e11y-devtools/frontend/test_puppeteer.js +41 -0
- data/gems/e11y-devtools/frontend/test_scale.js +3 -0
- data/gems/e11y-devtools/frontend/tsconfig.app.json +21 -0
- data/gems/e11y-devtools/frontend/tsconfig.json +7 -0
- data/gems/e11y-devtools/frontend/tsconfig.node.json +26 -0
- data/gems/e11y-devtools/frontend/vite.config.ts +36 -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 +20 -0
- data/gems/e11y-devtools/lib/e11y/devtools/overlay/controller.rb +94 -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 +67 -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 +91 -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 +44 -12
- data/lib/e11y/instruments/rails_instrumentation.rb +49 -24
- data/lib/e11y/instruments/sidekiq.rb +135 -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 +4 -4
- data/lib/e11y/presets/audit_event.rb +13 -2
- data/lib/e11y/railtie.rb +52 -14
- 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 +144 -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 +123 -266
- 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 +186 -39
- data/docs/ADR-003-slo-observability.md +0 -3337
- 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/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
|
+
---
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# Configuration
|
|
2
|
+
|
|
3
|
+
> Back to [README](../README.md#documentation)
|
|
4
|
+
|
|
5
|
+
## Basic Configuration
|
|
6
|
+
|
|
7
|
+
```ruby
|
|
8
|
+
# config/initializers/e11y.rb
|
|
9
|
+
E11y.configure do |config|
|
|
10
|
+
# Service identification
|
|
11
|
+
config.service_name = "myapp"
|
|
12
|
+
config.environment = Rails.env
|
|
13
|
+
|
|
14
|
+
# Configure adapters
|
|
15
|
+
config.adapters[:logs] = E11y::Adapters::Loki.new(
|
|
16
|
+
url: ENV["LOKI_URL"],
|
|
17
|
+
batch_size: 100,
|
|
18
|
+
batch_timeout: 5,
|
|
19
|
+
compress: true
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
config.adapters[:errors_tracker] = E11y::Adapters::Sentry.new(
|
|
23
|
+
dsn: ENV["SENTRY_DSN"]
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
# Default retention period
|
|
27
|
+
config.default_retention_period = 30.days
|
|
28
|
+
end
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Middleware Pipeline
|
|
32
|
+
|
|
33
|
+
Configure middleware for sampling, PII filtering, and more. Add `TrackLatency` first for self-monitoring (Event.track() latency):
|
|
34
|
+
|
|
35
|
+
```ruby
|
|
36
|
+
E11y.configure do |config|
|
|
37
|
+
# Self-monitoring: track latency (must be first)
|
|
38
|
+
config.pipeline.use E11y::Middleware::TrackLatency
|
|
39
|
+
|
|
40
|
+
# Sampling middleware
|
|
41
|
+
config.pipeline.use E11y::Middleware::Sampling,
|
|
42
|
+
default_sample_rate: 0.1,
|
|
43
|
+
error_based_adaptive: true,
|
|
44
|
+
load_based_adaptive: true
|
|
45
|
+
|
|
46
|
+
# PII filtering middleware
|
|
47
|
+
config.pipeline.use E11y::Middleware::PIIFilter
|
|
48
|
+
|
|
49
|
+
# Trace context middleware
|
|
50
|
+
config.pipeline.use E11y::Middleware::TraceContext
|
|
51
|
+
end
|
|
52
|
+
```
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# Distributed Tracing
|
|
2
|
+
|
|
3
|
+
> Back to [README](../README.md#documentation)
|
|
4
|
+
|
|
5
|
+
E11y automatically attaches W3C Trace Context headers to incoming requests via the `TraceContext` middleware and propagates trace/span IDs through the event pipeline.
|
|
6
|
+
|
|
7
|
+
## Incoming Trace Context
|
|
8
|
+
|
|
9
|
+
Incoming `traceparent` / `tracestate` headers are extracted automatically:
|
|
10
|
+
|
|
11
|
+
```ruby
|
|
12
|
+
E11y.configure do |config|
|
|
13
|
+
config.pipeline.use E11y::Middleware::TraceContext
|
|
14
|
+
end
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Events tracked during a request will include `trace_id` and `span_id` from the incoming context.
|
|
18
|
+
|
|
19
|
+
## Outgoing HTTP Trace Propagation (Manual — v1.0)
|
|
20
|
+
|
|
21
|
+
> **Note:** Automatic outgoing trace context injection (Faraday / Net::HTTP middleware) is planned for v1.1.
|
|
22
|
+
> Until then, use the helper below to propagate W3C Trace Context manually:
|
|
23
|
+
|
|
24
|
+
```ruby
|
|
25
|
+
# Helper: build W3C traceparent header from current context
|
|
26
|
+
def traceparent_header
|
|
27
|
+
return {} unless E11y::Current.trace_id
|
|
28
|
+
|
|
29
|
+
span_id = E11y::Current.span_id || SecureRandom.hex(8)
|
|
30
|
+
{ "traceparent" => "00-#{E11y::Current.trace_id}-#{span_id}-01" }
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Faraday — inject on each connection
|
|
34
|
+
conn = Faraday.new(url: "https://api.example.com") do |f|
|
|
35
|
+
f.headers.merge!(traceparent_header)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# Net::HTTP — inject per request
|
|
39
|
+
request = Net::HTTP::Post.new("/events")
|
|
40
|
+
traceparent_header.each { |k, v| request[k] = v }
|
|
41
|
+
http.request(request)
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
This ensures downstream services receive a valid `traceparent` header and can correlate logs/traces back to the originating request.
|
data/docs/LIMITATIONS.md
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# Limitations & Tradeoffs
|
|
2
|
+
|
|
3
|
+
> Back to [README](../README.md#documentation)
|
|
4
|
+
|
|
5
|
+
E11y trades generality for Rails-specific ergonomics. Know what you're getting:
|
|
6
|
+
|
|
7
|
+
| Limitation | Detail |
|
|
8
|
+
|------------|--------|
|
|
9
|
+
| **Rails only** | No Sinatra, Hanami, or pure-Ruby support. Railtie is required. |
|
|
10
|
+
| **Ruby 3.2+** | Older projects can't use it without upgrading Ruby. |
|
|
11
|
+
| **Rails 7.0–8.0** | Rails 8.1 excluded (sqlite3 bug in test environment). |
|
|
12
|
+
| **Memory overhead** | Debug buffer holds events in RAM per request. Under heavy load with large payloads, monitor heap usage. |
|
|
13
|
+
| **No distributed tracing UI** | OTel adapter emits spans, but e11y has no built-in trace visualization. Use Grafana Tempo or Jaeger. |
|
data/docs/METRICS_DSL.md
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# Metrics DSL
|
|
2
|
+
|
|
3
|
+
> Back to [README](../README.md#documentation)
|
|
4
|
+
|
|
5
|
+
Define Prometheus metrics alongside events.
|
|
6
|
+
|
|
7
|
+
## Basic Example
|
|
8
|
+
|
|
9
|
+
```ruby
|
|
10
|
+
class OrderPaidEvent < E11y::Event::Base
|
|
11
|
+
schema do
|
|
12
|
+
required(:order_id).filled(:string)
|
|
13
|
+
required(:amount).filled(:float)
|
|
14
|
+
required(:currency).filled(:string)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
metrics do
|
|
18
|
+
# Counter: Track number of paid orders
|
|
19
|
+
counter :orders_total, tags: [:currency]
|
|
20
|
+
|
|
21
|
+
# Histogram: Track order amount distribution
|
|
22
|
+
histogram :order_amount,
|
|
23
|
+
value: :amount,
|
|
24
|
+
tags: [:currency],
|
|
25
|
+
buckets: [10, 50, 100, 500, 1000]
|
|
26
|
+
|
|
27
|
+
# Gauge: Track active orders
|
|
28
|
+
gauge :active_orders, value: :active_count
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# One track() call = event + metrics
|
|
33
|
+
OrderPaidEvent.track(order_id: "123", amount: 99.99, currency: "USD")
|
|
34
|
+
# => orders_total{currency="USD"} +1
|
|
35
|
+
# => order_amount{currency="USD"} observe 99.99
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Metric Types
|
|
39
|
+
|
|
40
|
+
**Counter** - Monotonically increasing value:
|
|
41
|
+
|
|
42
|
+
```ruby
|
|
43
|
+
metrics do
|
|
44
|
+
counter :orders_total, tags: [:currency, :status]
|
|
45
|
+
end
|
|
46
|
+
# => orders_total{currency="USD", status="paid"} 42
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
**Histogram** - Distribution of values:
|
|
50
|
+
|
|
51
|
+
```ruby
|
|
52
|
+
metrics do
|
|
53
|
+
histogram :order_amount,
|
|
54
|
+
value: :amount,
|
|
55
|
+
tags: [:currency],
|
|
56
|
+
buckets: [10, 50, 100, 500, 1000]
|
|
57
|
+
end
|
|
58
|
+
# => order_amount_bucket{currency="USD", le="100"} 15
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
**Gauge** - Arbitrary value that can go up or down:
|
|
62
|
+
|
|
63
|
+
```ruby
|
|
64
|
+
metrics do
|
|
65
|
+
gauge :queue_depth, value: :size, tags: [:queue_name]
|
|
66
|
+
end
|
|
67
|
+
# => queue_depth{queue_name="emails"} 37
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## How It Works
|
|
71
|
+
|
|
72
|
+
1. Define metrics in event class
|
|
73
|
+
2. Metrics registered in `E11y::Metrics::Registry` at boot time
|
|
74
|
+
3. When `track()` is called, metrics are automatically updated **if the Yabeda adapter is configured and routed to**
|
|
75
|
+
4. Metrics exported via Yabeda adapter (Prometheus format)
|
|
76
|
+
|
|
77
|
+
> **Note:** The `metrics do` DSL only registers metric definitions. Metrics are actually updated
|
|
78
|
+
> when an event is written to the `E11y::Adapters::Yabeda` adapter. If you omit the Yabeda adapter
|
|
79
|
+
> from your configuration, `track()` will send events to Loki/Sentry but metric counters will not
|
|
80
|
+
> be incremented. Make sure to add:
|
|
81
|
+
>
|
|
82
|
+
> ```ruby
|
|
83
|
+
> config.adapters[:metrics] = E11y::Adapters::Yabeda.new
|
|
84
|
+
> ```
|
data/docs/PERFORMANCE.md
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# Performance
|
|
2
|
+
|
|
3
|
+
> Back to [README](../README.md#documentation)
|
|
4
|
+
|
|
5
|
+
## Design Principles
|
|
6
|
+
|
|
7
|
+
E11y is designed for performance:
|
|
8
|
+
|
|
9
|
+
- **Hash-based events** - Events are Hashes, not objects, minimizing allocations
|
|
10
|
+
- **Configurable validation** - Choose validation mode based on performance needs
|
|
11
|
+
- **Batching** - Loki and other adapters support batching to reduce network overhead
|
|
12
|
+
- **Sampling** - Adaptive sampling reduces event volume under high load
|
|
13
|
+
|
|
14
|
+
## Benchmarks (Ruby 3.3, measured via `rake spec:benchmark` and `rake spec:memory`)
|
|
15
|
+
|
|
16
|
+
| Metric | Value | Notes |
|
|
17
|
+
|--------|-------|-------|
|
|
18
|
+
| Event tracking latency (p99, `:always`) | <70µs | Full dry-schema validation per event |
|
|
19
|
+
| Event tracking latency (p99, `:sampled` 1%) | <10µs | Schema runs ~1% of events |
|
|
20
|
+
| Event tracking latency (p99, `:never`) | <50µs | Pipeline overhead, no validation |
|
|
21
|
+
| Memory allocations (`:always` mode) | ~47 objects/event | Baseline; threshold ≤72 |
|
|
22
|
+
| Memory allocations (`:never` mode) | ~33 objects/event | Baseline; threshold ≤50 |
|
|
23
|
+
| Memory retained after 10K events | 0 objects | No leaks detected |
|
|
24
|
+
| Memory consumption (1K events) | <100 MB allocated | Small-scale benchmark target |
|
|
25
|
+
|
|
26
|
+
## Validation Mode Trade-offs
|
|
27
|
+
|
|
28
|
+
```ruby
|
|
29
|
+
# Fastest — skip schema checks in production hot paths
|
|
30
|
+
validation_mode :never # ~33 allocs/event, <50µs p99
|
|
31
|
+
|
|
32
|
+
# Balanced — validate 1% of traffic for regression detection
|
|
33
|
+
validation_mode :sampled, sample_rate: 0.01 # <10µs p99
|
|
34
|
+
|
|
35
|
+
# Safest — validate every event (default, recommended for dev/staging)
|
|
36
|
+
validation_mode :always # ~47 allocs/event, <70µs p99
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Running Benchmarks
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
rake spec:benchmark # latency benchmarks (~44 examples)
|
|
43
|
+
rake spec:memory # allocation and leak checks
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
See `spec/e11y/event/base_benchmark_spec.rb` and `spec/e11y/memory_spec.rb` for the full test suite.
|
|
47
|
+
|
|
48
|
+
## Cardinality Protection
|
|
49
|
+
|
|
50
|
+
Optional cardinality protection prevents high-cardinality labels from overwhelming metrics systems:
|
|
51
|
+
|
|
52
|
+
```ruby
|
|
53
|
+
E11y::Adapters::Loki.new(
|
|
54
|
+
url: "http://loki:3100",
|
|
55
|
+
enable_cardinality_protection: true, # default
|
|
56
|
+
max_label_cardinality: 1000 # ~1000 event types
|
|
57
|
+
)
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Labels = `event_name` + `severity` only. Payload (user_uuid, etc.) stays in log line — filter via LogQL: `| json | user_uuid="xxx"`.
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# PII Filtering
|
|
2
|
+
|
|
3
|
+
> Back to [README](../README.md#documentation)
|
|
4
|
+
|
|
5
|
+
E11y provides PII filtering capabilities for sensitive data.
|
|
6
|
+
|
|
7
|
+
## Rails Integration
|
|
8
|
+
|
|
9
|
+
E11y can respect `Rails.application.config.filter_parameters` when configured:
|
|
10
|
+
|
|
11
|
+
```ruby
|
|
12
|
+
# config/application.rb
|
|
13
|
+
config.filter_parameters += [:password, :email, :ssn, :credit_card]
|
|
14
|
+
|
|
15
|
+
# E11y will filter these fields when PII filtering middleware is enabled
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Explicit PII Strategies
|
|
19
|
+
|
|
20
|
+
Configure PII filtering per event:
|
|
21
|
+
|
|
22
|
+
```ruby
|
|
23
|
+
class PaymentEvent < E11y::Event::Base
|
|
24
|
+
contains_pii true
|
|
25
|
+
|
|
26
|
+
pii_filtering do
|
|
27
|
+
masks :card_number # Replace with "[FILTERED]"
|
|
28
|
+
hashes :user_email # SHA256 hash (searchable)
|
|
29
|
+
allows :amount # No filtering
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Available strategies:
|
|
35
|
+
|
|
36
|
+
- `masks` - Replace with "[FILTERED]"
|
|
37
|
+
- `hashes` - SHA256 hash (preserves searchability)
|
|
38
|
+
- `partials` - Show first/last characters
|
|
39
|
+
- `redacts` - Remove completely
|
|
40
|
+
- `allows` - No filtering
|
data/docs/PRESETS.md
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# Presets
|
|
2
|
+
|
|
3
|
+
> Back to [README](../README.md#documentation)
|
|
4
|
+
|
|
5
|
+
E11y provides presets for common event types.
|
|
6
|
+
|
|
7
|
+
## HighValueEvent
|
|
8
|
+
|
|
9
|
+
For financial transactions and critical business events:
|
|
10
|
+
|
|
11
|
+
```ruby
|
|
12
|
+
class PaymentProcessedEvent < E11y::Event::Base
|
|
13
|
+
include E11y::Presets::HighValueEvent
|
|
14
|
+
|
|
15
|
+
schema do
|
|
16
|
+
required(:transaction_id).filled(:string)
|
|
17
|
+
required(:amount).filled(:decimal)
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# Configured with:
|
|
22
|
+
# - severity: :success
|
|
23
|
+
# - sample_rate: 1.0 (always sampled)
|
|
24
|
+
# - adapters: [:logs, :errors_tracker]
|
|
25
|
+
# - rate_limit: unlimited
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## AuditEvent
|
|
29
|
+
|
|
30
|
+
For compliance and audit trails:
|
|
31
|
+
|
|
32
|
+
```ruby
|
|
33
|
+
class UserDeletedEvent < E11y::Event::Base
|
|
34
|
+
include E11y::Presets::AuditEvent
|
|
35
|
+
|
|
36
|
+
schema do
|
|
37
|
+
required(:user_id).filled(:string)
|
|
38
|
+
required(:deleted_by).filled(:string)
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# Configured with:
|
|
43
|
+
# - sample_rate: 1.0 (never sampled)
|
|
44
|
+
# - rate_limit: unlimited
|
|
45
|
+
# Note: Set severity based on event criticality
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## DebugEvent
|
|
49
|
+
|
|
50
|
+
For development and troubleshooting:
|
|
51
|
+
|
|
52
|
+
```ruby
|
|
53
|
+
class SlowQueryEvent < E11y::Event::Base
|
|
54
|
+
include E11y::Presets::DebugEvent
|
|
55
|
+
|
|
56
|
+
schema do
|
|
57
|
+
required(:query).filled(:string)
|
|
58
|
+
required(:duration_ms).filled(:integer)
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# Configured with:
|
|
63
|
+
# - severity: :debug
|
|
64
|
+
# - adapters: [:logs]
|
|
65
|
+
```
|