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/docs/use_cases/backlog.md
CHANGED
|
@@ -12,92 +12,20 @@ This document captures promising ideas for future versions of `e11y` that are no
|
|
|
12
12
|
|
|
13
13
|
---
|
|
14
14
|
|
|
15
|
-
##
|
|
15
|
+
## Status: What's Already Done (as of v0.2.0)
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
Provide pre-configured profiles for common scenarios:
|
|
24
|
-
|
|
25
|
-
```ruby
|
|
26
|
-
E11y.configure do |config|
|
|
27
|
-
# Option 1: Use a preset
|
|
28
|
-
config.use_preset :production_high_traffic
|
|
29
|
-
|
|
30
|
-
# Option 2: Use a preset with overrides
|
|
31
|
-
config.use_preset :production_high_traffic do |preset|
|
|
32
|
-
preset.sampling.max_events_per_sec = 5_000 # Override default
|
|
33
|
-
end
|
|
34
|
-
end
|
|
35
|
-
```
|
|
36
|
-
|
|
37
|
-
### Available Presets
|
|
38
|
-
|
|
39
|
-
| Preset | Description | Sample Rate | Compression | Retention |
|
|
40
|
-
|--------|-------------|-------------|-------------|-----------|
|
|
41
|
-
| `:development` | Local dev, no sampling | 100% | None | 1 day |
|
|
42
|
-
| `:staging` | Pre-prod testing | 50% | Gzip | 7 days |
|
|
43
|
-
| `:production_low_traffic` | < 1K events/sec | 80% | Gzip | 30 days |
|
|
44
|
-
| `:production_high_traffic` | > 10K events/sec | 10% | Zstd | 7 days hot, 90 days warm |
|
|
45
|
-
| `:production_cost_optimized` | Aggressive cost reduction | 5% | Zstd level 9 | 3 days hot, 30 days warm |
|
|
46
|
-
|
|
47
|
-
### Implementation Example
|
|
48
|
-
|
|
49
|
-
```ruby
|
|
50
|
-
module E11y
|
|
51
|
-
module Presets
|
|
52
|
-
PRODUCTION_HIGH_TRAFFIC = {
|
|
53
|
-
adaptive_sampling: {
|
|
54
|
-
enabled: true,
|
|
55
|
-
load_based: { max_events_per_sec: 10_000 },
|
|
56
|
-
error_based: { enabled: true },
|
|
57
|
-
value_based: {
|
|
58
|
-
high_value_patterns: [/^payment\./, /^order\./, /^error\./],
|
|
59
|
-
low_value_patterns: [/^debug\./, /^health_check/]
|
|
60
|
-
}
|
|
61
|
-
},
|
|
62
|
-
compression: {
|
|
63
|
-
enabled: true,
|
|
64
|
-
algorithm: :zstd,
|
|
65
|
-
level: 3
|
|
66
|
-
},
|
|
67
|
-
retention_tagging: {
|
|
68
|
-
enabled: true,
|
|
69
|
-
default_retention: 7.days,
|
|
70
|
-
retention_by_pattern: {
|
|
71
|
-
'audit.*' => 7.years,
|
|
72
|
-
'payment.*' => 1.year,
|
|
73
|
-
'debug.*' => 1.day
|
|
74
|
-
}
|
|
75
|
-
},
|
|
76
|
-
payload_minimization: {
|
|
77
|
-
enabled: true,
|
|
78
|
-
truncate_strings_at: 1000,
|
|
79
|
-
truncate_arrays_at: 100,
|
|
80
|
-
remove_null_fields: true
|
|
81
|
-
}
|
|
82
|
-
}.freeze
|
|
83
|
-
end
|
|
84
|
-
end
|
|
85
|
-
```
|
|
86
|
-
|
|
87
|
-
### Benefits
|
|
88
|
-
|
|
89
|
-
- ✅ Faster onboarding (< 5 minutes to production-ready config)
|
|
90
|
-
- ✅ Best practices baked in
|
|
91
|
-
- ✅ Easy to customize (override specific settings)
|
|
92
|
-
- ✅ Reduces configuration errors
|
|
93
|
-
|
|
94
|
-
### Priority
|
|
95
|
-
|
|
96
|
-
**Medium (v1.1)**
|
|
17
|
+
| Backlog Item | Status | Notes |
|
|
18
|
+
|--------------|--------|-------|
|
|
19
|
+
| **§1 Sampling Budget** | ❌ Not done | |
|
|
20
|
+
| **§2 Global Async** | ❌ Not done | |
|
|
21
|
+
| **§3 Ring Buffer** | ⚠️ Implemented, not integrated | `E11y::Buffers::RingBuffer` exists; Loki uses `[]` + Mutex |
|
|
22
|
+
| **§4 Multi-Tenant** | ⚠️ Partial | Loki adapter has `tenant_id` (X-Scope-OrgID); baggage allows `tenant` key. No full multi-tenant isolation |
|
|
97
23
|
|
|
98
24
|
---
|
|
99
25
|
|
|
100
|
-
##
|
|
26
|
+
## 1. Sampling Budget
|
|
27
|
+
|
|
28
|
+
> **Related (implemented):** Adaptive sampling (error-spike, load-based), value-based (`sample_by_value`), per-event `sample_rate`. No budget/cap, no Redis state.
|
|
101
29
|
|
|
102
30
|
### Problem
|
|
103
31
|
|
|
@@ -196,15 +124,113 @@ monthly_cost = $1,000 * 30 = $30,000/month
|
|
|
196
124
|
|
|
197
125
|
---
|
|
198
126
|
|
|
199
|
-
##
|
|
127
|
+
## 2. Global Async Mode and Queue
|
|
128
|
+
|
|
129
|
+
### Problem
|
|
130
|
+
|
|
131
|
+
Current pipeline is **synchronous**: `Event.track() → Pipeline → Routing → Adapter.write()`. Batching happens only inside individual adapters (Loki, OTel). There is no global async layer between `track()` and adapters.
|
|
132
|
+
|
|
133
|
+
The [01-SCALE-REQUIREMENTS.md](../prd/01-SCALE-REQUIREMENTS.md) document specifies a global async configuration that is **not implemented**:
|
|
134
|
+
|
|
135
|
+
```ruby
|
|
136
|
+
# Specified but NOT implemented
|
|
137
|
+
E11y.configure do |config|
|
|
138
|
+
config.async do
|
|
139
|
+
queue_size 10_000 # 10k events buffer
|
|
140
|
+
batch_size 500 # Moderate batching
|
|
141
|
+
flush_interval 200 # ms
|
|
142
|
+
worker_threads 1 # Single worker
|
|
143
|
+
end
|
|
144
|
+
end
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
### Missing Self-Monitoring Metrics
|
|
148
|
+
|
|
149
|
+
The scale requirements also specify metrics that are not wired:
|
|
150
|
+
|
|
151
|
+
- `E11y.stats.drops_total` — total dropped events
|
|
152
|
+
- `E11y.stats.events_processed_total` — total events processed
|
|
153
|
+
- `e11y_internal_queue_utilization_ratio` — buffer fill level (0–1)
|
|
154
|
+
- `e11y_internal_queue_size` / `e11y_internal_queue_capacity`
|
|
155
|
+
|
|
156
|
+
### Proposal
|
|
157
|
+
|
|
158
|
+
1. **Add global async config** — optional `config.async` block with `queue_size`, `batch_size`, `flush_interval`, `worker_threads`
|
|
159
|
+
2. **Use `RingBuffer`** — `E11y::Buffers::RingBuffer` exists but is unused; it could be the backing store for the global queue
|
|
160
|
+
3. **Worker thread(s)** — background consumer that pops from `RingBuffer` and writes to adapters in batches
|
|
161
|
+
4. **Self-monitoring** — expose `e11y_internal_*` metrics for queue health, drops, throughput
|
|
162
|
+
|
|
163
|
+
### Architecture Options
|
|
164
|
+
|
|
165
|
+
| Option | Description | Complexity |
|
|
166
|
+
|--------|-------------|------------|
|
|
167
|
+
| **A: Keep current** | Batching stays in adapters only | None |
|
|
168
|
+
| **B: Global queue** | Single RingBuffer before routing, worker threads | Medium |
|
|
169
|
+
| **C: Per-adapter queues** | Each adapter has its own RingBuffer + worker | High |
|
|
170
|
+
|
|
171
|
+
### Benefits
|
|
172
|
+
|
|
173
|
+
- ✅ Decouples `track()` from I/O (network, disk)
|
|
174
|
+
- ✅ Predictable latency under load (<1ms p99 for track)
|
|
175
|
+
- ✅ Backpressure handling (drop_oldest when full)
|
|
176
|
+
- ✅ Self-monitoring (queue utilization, drops)
|
|
177
|
+
|
|
178
|
+
### Trade-offs
|
|
179
|
+
|
|
180
|
+
- ⚠️ Complexity (thread management, shutdown)
|
|
181
|
+
- ⚠️ Data loss window (events in buffer on crash)
|
|
182
|
+
- ⚠️ Memory overhead (buffer capacity × avg event size)
|
|
183
|
+
|
|
184
|
+
### Priority
|
|
185
|
+
|
|
186
|
+
**Medium (v1.1)** — Required for small teams at scale; optional for MVP
|
|
187
|
+
|
|
188
|
+
---
|
|
189
|
+
|
|
190
|
+
## 3. In-Memory Ring Buffer (Integration)
|
|
191
|
+
|
|
192
|
+
### Problem
|
|
193
|
+
|
|
194
|
+
`E11y::Buffers::RingBuffer` is **fully implemented** (`lib/e11y/buffers/ring_buffer.rb`) but **not used** anywhere in the pipeline:
|
|
195
|
+
|
|
196
|
+
- **Loki adapter** uses `@buffer = []` + `Mutex` (not RingBuffer)
|
|
197
|
+
- **EphemeralBuffer** uses `Concurrent::Array` in `Thread.current`
|
|
198
|
+
- **RingBuffer** exists only in unit tests and benchmarks
|
|
199
|
+
|
|
200
|
+
PRD Phase 1 (00-ICP-AND-TIMELINE.md) specifies "In-memory ring buffer (SPSC)" as a Week 1–2 deliverable, but it was never integrated.
|
|
201
|
+
|
|
202
|
+
### RingBuffer Spec
|
|
203
|
+
|
|
204
|
+
- Lock-free SPSC (Single-Producer, Single-Consumer)
|
|
205
|
+
- 100K events capacity (default)
|
|
206
|
+
- Overflow strategies: `:drop_oldest`, `:drop_newest`, `:block`
|
|
207
|
+
- Target: 100K+ events/sec, <10μs p99 per push/pop
|
|
208
|
+
|
|
209
|
+
### Proposal
|
|
210
|
+
|
|
211
|
+
1. **Option A: Integrate into global async** — Use RingBuffer as the backing store when `config.async` is enabled (see §2)
|
|
212
|
+
2. **Option B: Replace Loki buffer** — Swap `[]` + Mutex for RingBuffer in Loki adapter for better throughput
|
|
213
|
+
3. **Option C: Remove from PRD** — Document that RingBuffer is "future-ready" for async mode; adapter-level batching is sufficient for MVP
|
|
214
|
+
|
|
215
|
+
### Recommendation
|
|
216
|
+
|
|
217
|
+
**Option A** — RingBuffer is the natural choice for global async queue. Integrate when implementing §2 (Global Async Mode).
|
|
218
|
+
|
|
219
|
+
### Priority
|
|
220
|
+
|
|
221
|
+
**Medium (v1.1)** — Depends on §2 (Global Async Mode)
|
|
222
|
+
|
|
223
|
+
---
|
|
224
|
+
|
|
225
|
+
## 4. Additional Ideas (Placeholder)
|
|
200
226
|
|
|
201
227
|
Future ideas to be added:
|
|
202
228
|
|
|
203
229
|
- **ML-Based Anomaly Detection:** Automatically detect unusual patterns in events
|
|
204
230
|
- **Event Replay from Storage:** Replay events from cold storage for debugging
|
|
205
|
-
- **Multi-Tenant Support:** Isolate events by tenant/customer
|
|
206
|
-
- **Event Transformation Rules:** Transform events before sending to adapters
|
|
207
|
-
- **Custom Retention Policies:** More granular control over data lifecycle
|
|
231
|
+
- **Multi-Tenant Support:** Isolate events by tenant/customer — *Loki has `tenant_id`; baggage allows `tenant`*
|
|
232
|
+
- **Event Transformation Rules:** Transform events before sending to adapters — *routing + PII filter exist*
|
|
233
|
+
- **Custom Retention Policies:** More granular control over data lifecycle — *`retention_period` per event exists*
|
|
208
234
|
|
|
209
235
|
---
|
|
210
236
|
|
|
@@ -217,7 +243,13 @@ Future ideas to be added:
|
|
|
217
243
|
|
|
218
244
|
## Related ADRs
|
|
219
245
|
|
|
220
|
-
- [ADR-009: Cost Optimization](../ADR-009-cost-optimization.md) - Current implementation
|
|
246
|
+
- [ADR-009: Cost Optimization](../architecture/ADR-009-cost-optimization.md) - Current implementation
|
|
247
|
+
- [ADR-001: Architecture](../architecture/ADR-001-architecture.md) - RingBuffer specification (§3.3.1)
|
|
248
|
+
|
|
249
|
+
## Related Documents
|
|
250
|
+
|
|
251
|
+
- [01-SCALE-REQUIREMENTS.md](../prd/01-SCALE-REQUIREMENTS.md) - Specifies `config.async`, self-monitoring metrics
|
|
252
|
+
- [00-ICP-AND-TIMELINE.md](../prd/00-ICP-AND-TIMELINE.md) - Phase 1 "In-memory ring buffer (SPSC)"
|
|
221
253
|
|
|
222
254
|
---
|
|
223
255
|
|
data/e11y.gemspec
CHANGED
|
@@ -17,7 +17,7 @@ Gem::Specification.new do |spec|
|
|
|
17
17
|
• Schema-validated events - catch bugs before production with dry-schema
|
|
18
18
|
|
|
19
19
|
DEVELOPER EXPERIENCE:
|
|
20
|
-
•
|
|
20
|
+
• Minimal setup — one config block, works with stdout out of the box
|
|
21
21
|
• Auto-metrics from events (no manual Yabeda.increment)
|
|
22
22
|
• Rails-first design (follows Rails conventions)
|
|
23
23
|
• Pluggable adapters (Loki, Sentry, OpenTelemetry, custom backends)
|
|
@@ -73,7 +73,7 @@ Gem::Specification.new do |spec|
|
|
|
73
73
|
spec.add_development_dependency "rspec", "~> 3.12"
|
|
74
74
|
spec.add_development_dependency "rubocop", "~> 1.50"
|
|
75
75
|
spec.add_development_dependency "rubocop-rake", "~> 0.6"
|
|
76
|
-
spec.add_development_dependency "rubocop-rspec", "~>
|
|
76
|
+
spec.add_development_dependency "rubocop-rspec", "~> 3.0"
|
|
77
77
|
spec.add_development_dependency "simplecov", "~> 0.22"
|
|
78
78
|
spec.add_development_dependency "webmock", "~> 3.19" # For HTTP adapter testing
|
|
79
79
|
spec.add_development_dependency "yard", "~> 0.9"
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
# e11y-devtools
|
|
2
|
+
|
|
3
|
+
Developer tools for [e11y](https://github.com/aseletskiy/e11y) — the Rails observability gem.
|
|
4
|
+
|
|
5
|
+
Three complementary viewers for the same JSONL log:
|
|
6
|
+
|
|
7
|
+
| Viewer | How to use |
|
|
8
|
+
|--------|-----------|
|
|
9
|
+
| **TUI** (terminal) | `bundle exec e11y` |
|
|
10
|
+
| **Browser Overlay** | Automatic in development — floating badge in bottom-right |
|
|
11
|
+
| **MCP Server** | `bundle exec e11y mcp` — AI integration for Cursor / Claude Code |
|
|
12
|
+
|
|
13
|
+
## Installation
|
|
14
|
+
|
|
15
|
+
Add to your Gemfile (development group only):
|
|
16
|
+
|
|
17
|
+
```ruby
|
|
18
|
+
# Gemfile
|
|
19
|
+
gem "e11y", "~> 1.0"
|
|
20
|
+
gem "e11y-devtools", "~> 0.1.0", group: :development
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Then run `bundle install`.
|
|
24
|
+
|
|
25
|
+
## TUI — Interactive Log Viewer
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
bundle exec e11y # Open TUI (default)
|
|
29
|
+
bundle exec e11y tui # Same as above
|
|
30
|
+
bundle exec e11y tail # Stream events to stdout
|
|
31
|
+
bundle exec e11y help # Show help
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### TUI Keyboard Shortcuts
|
|
35
|
+
|
|
36
|
+
| Key | Action |
|
|
37
|
+
|-----|--------|
|
|
38
|
+
| `↑` / `k` | Move up |
|
|
39
|
+
| `↓` / `j` | Move down |
|
|
40
|
+
| `Enter` | Drill in (interactions → events → detail) |
|
|
41
|
+
| `Esc` / `b` | Go back |
|
|
42
|
+
| `w` | Filter: web requests only |
|
|
43
|
+
| `j` | Filter: background jobs only |
|
|
44
|
+
| `a` | Filter: all sources |
|
|
45
|
+
| `r` | Reload manually |
|
|
46
|
+
| `c` | Copy event JSON to clipboard (in detail view) |
|
|
47
|
+
| `q` | Quit |
|
|
48
|
+
|
|
49
|
+
## Browser Overlay
|
|
50
|
+
|
|
51
|
+
When `gem "e11y-devtools"` is in your Gemfile, the overlay appears automatically in development (Rails mounts `E11y::Devtools::Overlay::Engine` at `/_e11y`).
|
|
52
|
+
|
|
53
|
+
The UI is a **Svelte** bundle (`overlay.js`) with:
|
|
54
|
+
|
|
55
|
+
- **FAB** (bottom-right): total events, warn/error counts; brief **pulse** when **new** `warn` or `error`/`fatal` rows appear (not on every poll).
|
|
56
|
+
- **Fullscreen panel**: tabs **Problems** (error/fatal from recent buffer, 1-click → JSON) and **Interactions** (grouped traces like TUI). If there are errors in the recent snapshot, the panel opens on **Problems** first.
|
|
57
|
+
- **Wide viewport** (~900px+): interactions use a **split view** (list left, events right); narrow screens keep the stacked flow.
|
|
58
|
+
- Source filter chips (web / job / all) apply to **Interactions** only.
|
|
59
|
+
- **JSON API** under `/_e11y/v1/`: `GET interactions`, `GET traces/:trace_id/events`, `GET events/recent`.
|
|
60
|
+
|
|
61
|
+
### Rebuild the overlay asset
|
|
62
|
+
|
|
63
|
+
After changing `gems/e11y-devtools/frontend/`:
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
cd gems/e11y-devtools/frontend && npm install && npm run build
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Output: `lib/e11y/devtools/overlay/assets/overlay.js` (served at `/_e11y/overlay.js`).
|
|
70
|
+
|
|
71
|
+
### Local UI prototype (mocks)
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
cd gems/e11y-devtools/frontend && npm run dev
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Uses `public/mocks/v1/*.json` — see `frontend/README.md`.
|
|
78
|
+
|
|
79
|
+
## MCP Server — AI Integration
|
|
80
|
+
|
|
81
|
+
Start the server:
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
# stdio (for Cursor / Claude Code)
|
|
85
|
+
bundle exec e11y mcp
|
|
86
|
+
|
|
87
|
+
# HTTP (for direct integration)
|
|
88
|
+
bundle exec e11y mcp --port 3099
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Add to `.cursor/mcp.json` or `~/.claude/mcp.json`:
|
|
92
|
+
|
|
93
|
+
```json
|
|
94
|
+
{
|
|
95
|
+
"mcpServers": {
|
|
96
|
+
"e11y": {
|
|
97
|
+
"command": "bundle",
|
|
98
|
+
"args": ["exec", "e11y", "mcp"],
|
|
99
|
+
"cwd": "/path/to/your/rails/app"
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### Available MCP Tools
|
|
106
|
+
|
|
107
|
+
| Tool | Description |
|
|
108
|
+
|------|-------------|
|
|
109
|
+
| `recent_events` | Get latest N events (filterable by severity) |
|
|
110
|
+
| `events_by_trace` | Get all events for a trace ID |
|
|
111
|
+
| `search` | Full-text search across event names and payloads |
|
|
112
|
+
| `stats` | Aggregate statistics (total, by severity, oldest/newest) |
|
|
113
|
+
| `interactions` | Time-grouped interactions (parallel requests) |
|
|
114
|
+
| `event_detail` | Full payload for a single event by ID |
|
|
115
|
+
| `errors` | Recent error/fatal events only — fastest way to see what went wrong |
|
|
116
|
+
| `clear` | Clear the dev log |
|
|
117
|
+
|
|
118
|
+
## Configuration
|
|
119
|
+
|
|
120
|
+
```ruby
|
|
121
|
+
# config/initializers/e11y.rb
|
|
122
|
+
E11y.configure do |config|
|
|
123
|
+
config.register_adapter :dev_log, E11y::Adapters::DevLog.new(
|
|
124
|
+
path: Rails.root.join("log", "e11y_dev.jsonl"),
|
|
125
|
+
max_size: ENV.fetch("E11Y_MAX_SIZE", 50).to_i * 1024 * 1024, # 50 MB
|
|
126
|
+
max_lines: ENV.fetch("E11Y_MAX_EVENTS", 10_000).to_i,
|
|
127
|
+
keep_rotated: ENV.fetch("E11Y_KEEP_ROTATED", 5).to_i
|
|
128
|
+
)
|
|
129
|
+
end
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
### Environment Variables
|
|
133
|
+
|
|
134
|
+
| Variable | Default | Description |
|
|
135
|
+
|----------|---------|-------------|
|
|
136
|
+
| `E11Y_MAX_EVENTS` | `10000` | Max lines before rotation |
|
|
137
|
+
| `E11Y_MAX_SIZE` | `50` | Max log size in MB before rotation |
|
|
138
|
+
| `E11Y_KEEP_ROTATED` | `5` | Number of compressed `.gz` files to keep |
|
|
139
|
+
|
|
140
|
+
## Log Format
|
|
141
|
+
|
|
142
|
+
Events are stored as JSONL (one JSON object per line) at `log/e11y_dev.jsonl`.
|
|
143
|
+
Rotated files are numbered and gzip-compressed: `e11y_dev.jsonl.1.gz`, `.2.gz`, etc.
|
|
144
|
+
|
|
145
|
+
## Architecture
|
|
146
|
+
|
|
147
|
+
```
|
|
148
|
+
log/e11y_dev.jsonl ← E11y::Adapters::DevLog (write)
|
|
149
|
+
↓
|
|
150
|
+
E11y::Adapters::DevLog::Query (read, cache, search, grouping)
|
|
151
|
+
↓
|
|
152
|
+
┌─────┴──────┬──────────────┬──────────────┐
|
|
153
|
+
TUI Browser MCP Server
|
|
154
|
+
(ratatui_ruby) Overlay (gem 'mcp')
|
|
155
|
+
(Rack)
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
The JSONL file is the single source of truth. All viewers are stateless readers — they never write.
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
E11y::Devtools::Overlay::Engine.routes.draw do
|
|
4
|
+
get "overlay.js", to: "e11y/devtools/overlay/rails#overlay_js"
|
|
5
|
+
get "events", to: "e11y/devtools/overlay/rails#events"
|
|
6
|
+
get "events/recent", to: "e11y/devtools/overlay/rails#recent"
|
|
7
|
+
delete "events", to: "e11y/devtools/overlay/rails#clear"
|
|
8
|
+
get "stats", to: "e11y/devtools/overlay/rails#stats"
|
|
9
|
+
|
|
10
|
+
scope "v1" do
|
|
11
|
+
get "interactions", to: "e11y/devtools/overlay/rails#v1_interactions"
|
|
12
|
+
get "traces/:trace_id/events", to: "e11y/devtools/overlay/rails#v1_trace_events"
|
|
13
|
+
get "events/recent", to: "e11y/devtools/overlay/rails#v1_events_recent"
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "lib/e11y/devtools/version"
|
|
4
|
+
|
|
5
|
+
Gem::Specification.new do |spec|
|
|
6
|
+
spec.name = "e11y-devtools"
|
|
7
|
+
spec.version = E11y::Devtools::VERSION
|
|
8
|
+
spec.authors = ["Artur Seletskiy"]
|
|
9
|
+
spec.summary = "Developer tools for E11y: TUI, Browser Overlay, MCP Server"
|
|
10
|
+
|
|
11
|
+
spec.required_ruby_version = ">= 3.2"
|
|
12
|
+
|
|
13
|
+
spec.files = Dir["lib/**/*.rb", "lib/**/*.js", "config/**/*.rb", "exe/*", "*.md"]
|
|
14
|
+
spec.bindir = "exe"
|
|
15
|
+
spec.executables = ["e11y"]
|
|
16
|
+
spec.require_paths = ["lib"]
|
|
17
|
+
|
|
18
|
+
spec.add_dependency "e11y", "~> #{E11y::Devtools::CORE_VERSION}"
|
|
19
|
+
spec.add_dependency "mcp", ">= 0.8"
|
|
20
|
+
spec.add_dependency "ratatui_ruby", "~> 1.4"
|
|
21
|
+
|
|
22
|
+
# Optional but recommended for performance
|
|
23
|
+
spec.add_development_dependency "oj"
|
|
24
|
+
spec.metadata["rubygems_mfa_required"] = "true"
|
|
25
|
+
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
require "e11y/devtools"
|
|
5
|
+
|
|
6
|
+
command = ARGV.shift || "tui"
|
|
7
|
+
|
|
8
|
+
case command
|
|
9
|
+
when "tui"
|
|
10
|
+
require "e11y/devtools/tui/app"
|
|
11
|
+
E11y::Devtools::Tui::App.new.run
|
|
12
|
+
when "mcp"
|
|
13
|
+
require "e11y/devtools/mcp/server"
|
|
14
|
+
E11y::Devtools::Mcp::Server.new.run(
|
|
15
|
+
transport: ARGV.include?("--port") ? :http : :stdio,
|
|
16
|
+
port: (ARGV[ARGV.index("--port") + 1] if ARGV.include?("--port"))&.to_i
|
|
17
|
+
)
|
|
18
|
+
when "tail"
|
|
19
|
+
require "e11y/devtools/tui/tail"
|
|
20
|
+
E11y::Devtools::Tui::Tail.new.run
|
|
21
|
+
when "help", "--help", "-h"
|
|
22
|
+
puts <<~HELP
|
|
23
|
+
bundle exec e11y [command]
|
|
24
|
+
|
|
25
|
+
Commands:
|
|
26
|
+
tui (default) Interactive TUI — browse events and traces
|
|
27
|
+
mcp MCP server for Cursor / Claude Code AI integration
|
|
28
|
+
tail Stream new events to stdout (pipe-friendly)
|
|
29
|
+
help Show this help
|
|
30
|
+
HELP
|
|
31
|
+
else
|
|
32
|
+
warn "Unknown command: #{command}. Run `bundle exec e11y help`."
|
|
33
|
+
exit 1
|
|
34
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# Logs
|
|
2
|
+
logs
|
|
3
|
+
*.log
|
|
4
|
+
npm-debug.log*
|
|
5
|
+
yarn-debug.log*
|
|
6
|
+
yarn-error.log*
|
|
7
|
+
pnpm-debug.log*
|
|
8
|
+
lerna-debug.log*
|
|
9
|
+
|
|
10
|
+
node_modules
|
|
11
|
+
dist
|
|
12
|
+
dist-ssr
|
|
13
|
+
*.local
|
|
14
|
+
|
|
15
|
+
# Editor directories and files
|
|
16
|
+
.vscode/*
|
|
17
|
+
!.vscode/extensions.json
|
|
18
|
+
.idea
|
|
19
|
+
.DS_Store
|
|
20
|
+
*.suo
|
|
21
|
+
*.ntvs*
|
|
22
|
+
*.njsproj
|
|
23
|
+
*.sln
|
|
24
|
+
*.sw?
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# e11y browser overlay — frontend (Svelte)
|
|
2
|
+
|
|
3
|
+
Prototype and production bundle for the dev-only overlay injected into Rails apps at `/_e11y/overlay.js`.
|
|
4
|
+
|
|
5
|
+
## API mocks (Phase 1)
|
|
6
|
+
|
|
7
|
+
Static JSON mirrors the target `/_e11y/v1/` contract:
|
|
8
|
+
|
|
9
|
+
| Path | File |
|
|
10
|
+
|------|------|
|
|
11
|
+
| `GET /v1/events/recent` | `public/mocks/v1/events/recent.json` |
|
|
12
|
+
| `GET /v1/interactions` | `public/mocks/v1/interactions.json` |
|
|
13
|
+
| `GET /v1/traces/:trace_id/events` | `public/mocks/v1/traces/<trace_id>/events.json` |
|
|
14
|
+
|
|
15
|
+
Trace ids are 32-char hex strings (like `DevLog` / OpenTelemetry). Files live under `public/mocks/v1/traces/<trace_id>/events.json`.
|
|
16
|
+
|
|
17
|
+
**Regenerate mocks** (deterministic `Random.new(42)`):
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npm run generate-mocks
|
|
21
|
+
# or: E11Y_MOCK_TRACES=52 ruby scripts/generate_mocks.rb # stress (~300+ events)
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Default is `E11Y_MOCK_TRACES=24` (~150 events). `interactions.json` is rebuilt using the same 500ms window grouping as `E11y::Adapters::DevLog::Query`.
|
|
25
|
+
|
|
26
|
+
**Overlay UX (dev):** Problems tab includes a stacked **volume bar** over `recent` (UTC time scale, drag to **brush** a range and narrow the error list, double-click or **Clear range** to reset), search, and expandable payload rows. Trace event lists support **severity + text filters**, inline **payload expand**, **±2 context** highlight after opening an event and going back, and detail **Copy trace_id / request_id** plus collapsible payload / metadata / full JSON.
|
|
27
|
+
|
|
28
|
+
## Setup
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
cd gems/e11y-devtools/frontend
|
|
32
|
+
npm install
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Dev server
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
npm run dev
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Open the URL Vite prints (default `http://localhost:5173`) to load `index.html` with a fake host page and the overlay.
|
|
42
|
+
|
|
43
|
+
## Production build
|
|
44
|
+
|
|
45
|
+
After the Svelte app is scaffolded (plan Task 2+):
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
npm run build
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Output is written to `../lib/e11y/devtools/overlay/assets/overlay.js` for the Rails engine to serve.
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
|
6
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
7
|
+
<title>e11y overlay (dev)</title>
|
|
8
|
+
</head>
|
|
9
|
+
<body>
|
|
10
|
+
<p style="padding: 1rem; font-family: system-ui">Demo host page — overlay FAB bottom-right.</p>
|
|
11
|
+
<div id="app" class="e11y-demo-host"></div>
|
|
12
|
+
<script type="module" src="/src/main.ts"></script>
|
|
13
|
+
</body>
|
|
14
|
+
</html>
|