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
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
- ✅ §4.3: Loki Adapter - Implemented (34 tests)
|
|
13
13
|
- ✅ §4.4: Sentry Adapter - Implemented (39 tests)
|
|
14
14
|
- ❌ §4.5: Elasticsearch Adapter - Cancelled (not needed now)
|
|
15
|
-
- ✅ §5: Adapter
|
|
15
|
+
- ✅ §5: Adapter storage (config.adapters)
|
|
16
16
|
- ✅ §9.1: InMemory Test Adapter - Implemented (51 tests)
|
|
17
17
|
- ✅ AuditEncrypted Adapter - Updated to new contract (13 tests)
|
|
18
18
|
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
- 4.3. [Loki Adapter](#43-loki-adapter)
|
|
32
32
|
- 4.4. [Sentry Adapter](#44-sentry-adapter)
|
|
33
33
|
- 4.5. [Elasticsearch Adapter](#45-elasticsearch-adapter)
|
|
34
|
-
5. [Adapter
|
|
34
|
+
5. [Adapter Storage (config.adapters)](#5-adapter-storage-configadapters)
|
|
35
35
|
6. [Connection Management](#6-connection-management)
|
|
36
36
|
7. [Error Handling & Retry](#7-error-handling--retry)
|
|
37
37
|
8. [Performance & Batching](#8-performance--batching)
|
|
@@ -1064,17 +1064,17 @@ end
|
|
|
1064
1064
|
|
|
1065
1065
|
---
|
|
1066
1066
|
|
|
1067
|
-
## 5. Adapter
|
|
1067
|
+
## 5. Adapter Storage (config.adapters)
|
|
1068
1068
|
|
|
1069
|
-
### 5.1.
|
|
1069
|
+
### 5.1. Architecture
|
|
1070
1070
|
|
|
1071
1071
|
```mermaid
|
|
1072
1072
|
graph TB
|
|
1073
1073
|
subgraph "Configuration Phase (Boot Time)"
|
|
1074
|
-
Config[Configuration] -->
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1074
|
+
Config[Configuration] --> Adapters[config.adapters]
|
|
1075
|
+
Adapters --> Instance1[Loki Instance]
|
|
1076
|
+
Adapters --> Instance2[Sentry Instance]
|
|
1077
|
+
Adapters --> Instance3[File Instance]
|
|
1078
1078
|
|
|
1079
1079
|
Instance1 --> Pool1[Connection Pool]
|
|
1080
1080
|
Instance2 --> Pool2[Connection Pool]
|
|
@@ -1082,79 +1082,33 @@ graph TB
|
|
|
1082
1082
|
end
|
|
1083
1083
|
|
|
1084
1084
|
subgraph "Runtime Phase"
|
|
1085
|
-
Event[Event.track] --> Resolve[
|
|
1085
|
+
Event[Event.track] --> Resolve[config.adapters[name]]
|
|
1086
1086
|
Resolve -->|:loki| Instance1
|
|
1087
1087
|
Resolve -->|:sentry| Instance2
|
|
1088
1088
|
Resolve -->|:file| Instance3
|
|
1089
1089
|
end
|
|
1090
1090
|
|
|
1091
|
-
style
|
|
1091
|
+
style Adapters fill:#d1ecf1
|
|
1092
1092
|
style Resolve fill:#fff3cd
|
|
1093
1093
|
style Pool1 fill:#d4edda
|
|
1094
1094
|
style Pool2 fill:#d4edda
|
|
1095
1095
|
style Pool3 fill:#d4edda
|
|
1096
1096
|
```
|
|
1097
1097
|
|
|
1098
|
-
### 5.2.
|
|
1098
|
+
### 5.2. config.adapters (Adapter Storage)
|
|
1099
|
+
|
|
1100
|
+
Adapters are stored in `E11y.configuration.adapters` (Hash). Routing middleware resolves by name: `config.adapters[adapter_name]`.
|
|
1099
1101
|
|
|
1100
1102
|
```ruby
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
def register(name, adapter_instance)
|
|
1106
|
-
validate_adapter!(adapter_instance)
|
|
1107
|
-
|
|
1108
|
-
adapters[name] = adapter_instance
|
|
1109
|
-
|
|
1110
|
-
# Register cleanup hook
|
|
1111
|
-
at_exit { adapter_instance.close }
|
|
1112
|
-
end
|
|
1113
|
-
|
|
1114
|
-
def resolve(name)
|
|
1115
|
-
adapters.fetch(name) do
|
|
1116
|
-
raise AdapterNotFoundError, "Adapter not found: #{name}"
|
|
1117
|
-
end
|
|
1118
|
-
end
|
|
1119
|
-
|
|
1120
|
-
def resolve_all(names)
|
|
1121
|
-
names.map { |name| resolve(name) }
|
|
1122
|
-
end
|
|
1123
|
-
|
|
1124
|
-
def all
|
|
1125
|
-
adapters.values
|
|
1126
|
-
end
|
|
1127
|
-
|
|
1128
|
-
def names
|
|
1129
|
-
adapters.keys
|
|
1130
|
-
end
|
|
1131
|
-
|
|
1132
|
-
def clear!
|
|
1133
|
-
adapters.each_value(&:close)
|
|
1134
|
-
adapters.clear
|
|
1135
|
-
end
|
|
1136
|
-
|
|
1137
|
-
private
|
|
1138
|
-
|
|
1139
|
-
def adapters
|
|
1140
|
-
@adapters ||= {}
|
|
1141
|
-
end
|
|
1142
|
-
|
|
1143
|
-
def validate_adapter!(adapter)
|
|
1144
|
-
unless adapter.respond_to?(:write)
|
|
1145
|
-
raise ArgumentError, "Adapter must respond to #write"
|
|
1146
|
-
end
|
|
1147
|
-
|
|
1148
|
-
unless adapter.respond_to?(:write_batch)
|
|
1149
|
-
raise ArgumentError, "Adapter must respond to #write_batch"
|
|
1150
|
-
end
|
|
1151
|
-
end
|
|
1152
|
-
end
|
|
1153
|
-
end
|
|
1154
|
-
|
|
1155
|
-
class AdapterNotFoundError < StandardError; end
|
|
1156
|
-
end
|
|
1103
|
+
# Registration (config phase)
|
|
1104
|
+
E11y.configure do |config|
|
|
1105
|
+
config.adapters[:loki] = E11y::Adapters::Loki.new(url: ENV["LOKI_URL"])
|
|
1106
|
+
config.adapters[:sentry] = E11y::Adapters::Sentry.new(dsn: ENV["SENTRY_DSN"])
|
|
1157
1107
|
end
|
|
1108
|
+
|
|
1109
|
+
# Resolution (runtime, in Routing middleware)
|
|
1110
|
+
adapter = E11y.configuration.adapters[:loki]
|
|
1111
|
+
adapter.write(event_data)
|
|
1158
1112
|
```
|
|
1159
1113
|
|
|
1160
1114
|
### 5.3. Usage in Events
|
|
@@ -1714,20 +1668,20 @@ E11y.configure do |config|
|
|
|
1714
1668
|
# Register adapters (infrastructure)
|
|
1715
1669
|
config.register_adapter :loki, Loki.new(url: ENV['LOKI_URL'])
|
|
1716
1670
|
config.register_adapter :sentry, Sentry.new(dsn: ENV['SENTRY_DSN'])
|
|
1717
|
-
|
|
1671
|
+
# Archival: external jobs filter by retention_until
|
|
1718
1672
|
config.register_adapter :audit_encrypted, AuditAdapter.new(...)
|
|
1719
1673
|
|
|
1720
1674
|
# ❌ PROBLEM: Routing for EVERY event in global config
|
|
1721
1675
|
config.events do
|
|
1722
1676
|
# Payment events → multiple adapters
|
|
1723
1677
|
event 'Events::PaymentSucceeded' do
|
|
1724
|
-
adapters [:loki, :sentry
|
|
1678
|
+
adapters [:loki, :sentry]
|
|
1725
1679
|
end
|
|
1726
1680
|
event 'Events::PaymentFailed' do
|
|
1727
|
-
adapters [:loki, :sentry
|
|
1681
|
+
adapters [:loki, :sentry]
|
|
1728
1682
|
end
|
|
1729
1683
|
event 'Events::PaymentRefunded' do
|
|
1730
|
-
adapters [:loki, :sentry
|
|
1684
|
+
adapters [:loki, :sentry]
|
|
1731
1685
|
end
|
|
1732
1686
|
|
|
1733
1687
|
# Audit events → encrypted adapter
|
|
@@ -1764,7 +1718,7 @@ E11y.configure do |config|
|
|
|
1764
1718
|
# ONLY infrastructure (adapter registration)
|
|
1765
1719
|
config.register_adapter :loki, Loki.new(url: ENV['LOKI_URL'])
|
|
1766
1720
|
config.register_adapter :sentry, Sentry.new(dsn: ENV['SENTRY_DSN'])
|
|
1767
|
-
|
|
1721
|
+
# Archival: external jobs filter by retention_until
|
|
1768
1722
|
config.register_adapter :audit_encrypted, AuditAdapter.new(...)
|
|
1769
1723
|
|
|
1770
1724
|
# Optional: default adapters (convention)
|
|
@@ -1777,7 +1731,7 @@ module Events
|
|
|
1777
1731
|
schema do; required(:transaction_id).filled(:string); end
|
|
1778
1732
|
|
|
1779
1733
|
# ✅ Adapters right next to schema!
|
|
1780
|
-
adapters [:loki, :sentry
|
|
1734
|
+
adapters [:loki, :sentry]
|
|
1781
1735
|
end
|
|
1782
1736
|
end
|
|
1783
1737
|
|
|
@@ -1817,7 +1771,7 @@ end
|
|
|
1817
1771
|
module Events
|
|
1818
1772
|
class BasePaymentEvent < E11y::Event::Base
|
|
1819
1773
|
# Common adapters for ALL payment events
|
|
1820
|
-
adapters [:loki, :sentry
|
|
1774
|
+
adapters [:loki, :sentry]
|
|
1821
1775
|
|
|
1822
1776
|
# Common config
|
|
1823
1777
|
severity :success
|
|
@@ -1829,18 +1783,18 @@ end
|
|
|
1829
1783
|
# Inherit from base (1-2 lines per event!)
|
|
1830
1784
|
class Events::PaymentSucceeded < Events::BasePaymentEvent
|
|
1831
1785
|
schema do; required(:transaction_id).filled(:string); end
|
|
1832
|
-
# ← Inherits: adapters [:loki, :sentry
|
|
1786
|
+
# ← Inherits: adapters [:loki, :sentry]
|
|
1833
1787
|
end
|
|
1834
1788
|
|
|
1835
1789
|
class Events::PaymentFailed < Events::BasePaymentEvent
|
|
1836
1790
|
severity :error # ← Override severity
|
|
1837
1791
|
schema do; required(:error_code).filled(:string); end
|
|
1838
|
-
# ← Inherits: adapters [:loki, :sentry
|
|
1792
|
+
# ← Inherits: adapters [:loki, :sentry]
|
|
1839
1793
|
end
|
|
1840
1794
|
|
|
1841
1795
|
class Events::PaymentRefunded < Events::BasePaymentEvent
|
|
1842
1796
|
schema do; required(:refund_id).filled(:string); end
|
|
1843
|
-
# ← Inherits: adapters [:loki, :sentry
|
|
1797
|
+
# ← Inherits: adapters [:loki, :sentry]
|
|
1844
1798
|
end
|
|
1845
1799
|
```
|
|
1846
1800
|
|
|
@@ -1882,7 +1836,7 @@ module E11y
|
|
|
1882
1836
|
module HighValueEvent
|
|
1883
1837
|
extend ActiveSupport::Concern
|
|
1884
1838
|
included do
|
|
1885
|
-
adapters [:loki, :sentry
|
|
1839
|
+
adapters [:loki, :sentry]
|
|
1886
1840
|
sample_rate 1.0
|
|
1887
1841
|
retention 7.years
|
|
1888
1842
|
end
|
|
@@ -1936,7 +1890,7 @@ end
|
|
|
1936
1890
|
# Override convention:
|
|
1937
1891
|
class Events::OrderCreated < E11y::Event::Base
|
|
1938
1892
|
severity :success
|
|
1939
|
-
adapters [:loki, :elasticsearch
|
|
1893
|
+
adapters [:loki, :elasticsearch] # ← Override
|
|
1940
1894
|
schema do; required(:order_id).filled(:string); end
|
|
1941
1895
|
end
|
|
1942
1896
|
```
|
|
@@ -1946,13 +1900,13 @@ end
|
|
|
1946
1900
|
```ruby
|
|
1947
1901
|
# Replace strategy (default): Override parent/convention
|
|
1948
1902
|
class Events::PaymentSucceeded < Events::BasePaymentEvent
|
|
1949
|
-
adapters [:loki, :sentry] # ← Replaces base
|
|
1903
|
+
adapters [:loki, :sentry] # ← Replaces base
|
|
1950
1904
|
end
|
|
1951
1905
|
|
|
1952
1906
|
# Append strategy: Add to parent/convention
|
|
1953
1907
|
class Events::PaymentSucceeded < Events::BasePaymentEvent
|
|
1954
1908
|
adapters_strategy :append
|
|
1955
|
-
adapters [:slack_business] # ← Adds to base (result: [:loki, :sentry, :
|
|
1909
|
+
adapters [:slack_business] # ← Adds to base (result: [:loki, :sentry, :slack_business])
|
|
1956
1910
|
end
|
|
1957
1911
|
```
|
|
1958
1912
|
|
|
@@ -1976,7 +1930,7 @@ class Events::BasePaymentEvent < E11y::Event::Base
|
|
|
1976
1930
|
end
|
|
1977
1931
|
|
|
1978
1932
|
class Events::PaymentSucceeded < Events::BasePaymentEvent
|
|
1979
|
-
include E11y::Presets::HighValueEvent # 2. Preset
|
|
1933
|
+
include E11y::Presets::HighValueEvent # 2. Preset
|
|
1980
1934
|
adapters [:loki, :sentry, :pagerduty] # 1. Event-level (WINS!)
|
|
1981
1935
|
end
|
|
1982
1936
|
|
|
@@ -2009,7 +1963,7 @@ end
|
|
|
2009
1963
|
```ruby
|
|
2010
1964
|
# Migrate high-value events first:
|
|
2011
1965
|
class Events::PaymentSucceeded < E11y::Event::Base
|
|
2012
|
-
adapters [:loki, :sentry
|
|
1966
|
+
adapters [:loki, :sentry] # ← Migrated
|
|
2013
1967
|
end
|
|
2014
1968
|
|
|
2015
1969
|
# Keep others in global config (temporary):
|
|
@@ -2124,7 +2078,7 @@ class Events::PaymentFailed < E11y::Event::Base
|
|
|
2124
2078
|
|
|
2125
2079
|
# Multi-environment routing
|
|
2126
2080
|
adapters case Rails.env
|
|
2127
|
-
when 'production' then [:loki, :sentry
|
|
2081
|
+
when 'production' then [:loki, :sentry]
|
|
2128
2082
|
when 'staging' then [:loki, :sentry]
|
|
2129
2083
|
else [:file]
|
|
2130
2084
|
end
|
|
@@ -2164,7 +2118,7 @@ end
|
|
|
2164
2118
|
module E11y::Presets::HighValueEvent
|
|
2165
2119
|
extend ActiveSupport::Concern
|
|
2166
2120
|
included do
|
|
2167
|
-
adapters [:loki, :sentry
|
|
2121
|
+
adapters [:loki, :sentry]
|
|
2168
2122
|
end
|
|
2169
2123
|
end
|
|
2170
2124
|
|
|
@@ -2172,9 +2126,9 @@ end
|
|
|
2172
2126
|
class Events::CriticalPayment < Events::BasePaymentEvent
|
|
2173
2127
|
include E11y::Presets::HighValueEvent
|
|
2174
2128
|
|
|
2175
|
-
adapters [:loki, :sentry, :
|
|
2129
|
+
adapters [:loki, :sentry, :datadog]
|
|
2176
2130
|
|
|
2177
|
-
# Final: [:loki, :sentry, :
|
|
2131
|
+
# Final: [:loki, :sentry, :datadog] (event-level wins)
|
|
2178
2132
|
end
|
|
2179
2133
|
```
|
|
2180
2134
|
|
|
@@ -2189,64 +2143,40 @@ end
|
|
|
2189
2143
|
require 'e11y'
|
|
2190
2144
|
|
|
2191
2145
|
E11y.configure do |config|
|
|
2192
|
-
#
|
|
2193
|
-
E11y::Adapters::
|
|
2194
|
-
:loki,
|
|
2195
|
-
|
|
2196
|
-
|
|
2197
|
-
|
|
2198
|
-
|
|
2199
|
-
|
|
2200
|
-
host: Socket.gethostname
|
|
2201
|
-
},
|
|
2202
|
-
batch_size: 100,
|
|
2203
|
-
batch_timeout: 5,
|
|
2204
|
-
compress: true,
|
|
2205
|
-
tenant_id: ENV['LOKI_TENANT_ID']
|
|
2206
|
-
)
|
|
2146
|
+
# Loki for centralized logging
|
|
2147
|
+
config.adapters[:loki] = E11y::Adapters::Loki.new(
|
|
2148
|
+
url: ENV['LOKI_URL'] || 'http://loki:3100',
|
|
2149
|
+
labels: { app: 'my_app', env: Rails.env, host: Socket.gethostname },
|
|
2150
|
+
batch_size: 100,
|
|
2151
|
+
batch_timeout: 5,
|
|
2152
|
+
compress: true,
|
|
2153
|
+
tenant_id: ENV['LOKI_TENANT_ID']
|
|
2207
2154
|
)
|
|
2208
2155
|
|
|
2209
|
-
#
|
|
2210
|
-
E11y::Adapters::
|
|
2211
|
-
:
|
|
2212
|
-
|
|
2213
|
-
|
|
2214
|
-
|
|
2215
|
-
severity_threshold: :warn,
|
|
2216
|
-
breadcrumbs: true
|
|
2217
|
-
)
|
|
2156
|
+
# Sentry for error tracking
|
|
2157
|
+
config.adapters[:sentry] = E11y::Adapters::Sentry.new(
|
|
2158
|
+
dsn: ENV['SENTRY_DSN'],
|
|
2159
|
+
environment: Rails.env,
|
|
2160
|
+
severity_threshold: :warn,
|
|
2161
|
+
breadcrumbs: true
|
|
2218
2162
|
)
|
|
2219
2163
|
|
|
2220
|
-
#
|
|
2221
|
-
E11y::Adapters::
|
|
2222
|
-
:
|
|
2223
|
-
|
|
2224
|
-
|
|
2225
|
-
|
|
2226
|
-
max_size: 100 * 1024 * 1024, # 100MB
|
|
2227
|
-
compress: true
|
|
2228
|
-
)
|
|
2164
|
+
# File adapter for local development
|
|
2165
|
+
config.adapters[:file] = E11y::Adapters::File.new(
|
|
2166
|
+
path: Rails.root.join('log', 'e11y.log'),
|
|
2167
|
+
rotation: :daily,
|
|
2168
|
+
max_size: 100 * 1024 * 1024,
|
|
2169
|
+
compress: true
|
|
2229
2170
|
)
|
|
2230
2171
|
|
|
2231
|
-
#
|
|
2232
|
-
E11y::Adapters::
|
|
2233
|
-
:
|
|
2234
|
-
|
|
2235
|
-
pretty: Rails.env.development?,
|
|
2236
|
-
colorize: true
|
|
2237
|
-
)
|
|
2172
|
+
# Stdout for console output
|
|
2173
|
+
config.adapters[:stdout] = E11y::Adapters::Stdout.new(
|
|
2174
|
+
pretty: Rails.env.development?,
|
|
2175
|
+
colorize: true
|
|
2238
2176
|
)
|
|
2239
2177
|
|
|
2240
|
-
#
|
|
2241
|
-
if Rails.env.test?
|
|
2242
|
-
E11y::Adapters::Registry.register(
|
|
2243
|
-
:test,
|
|
2244
|
-
E11y::Adapters::InMemory.new(
|
|
2245
|
-
max_events: 1000,
|
|
2246
|
-
max_batches: 100
|
|
2247
|
-
)
|
|
2248
|
-
)
|
|
2249
|
-
end
|
|
2178
|
+
# InMemory for testing
|
|
2179
|
+
config.adapters[:test] = E11y::Adapters::InMemory.new(max_events: 1000, max_batches: 100) if Rails.env.test?
|
|
2250
2180
|
end
|
|
2251
2181
|
```
|
|
2252
2182
|
|
|
@@ -2307,7 +2237,7 @@ Events::PaymentFailed.track(
|
|
|
2307
2237
|
```ruby
|
|
2308
2238
|
# spec/events/order_placed_spec.rb
|
|
2309
2239
|
RSpec.describe Events::OrderPlaced do
|
|
2310
|
-
let(:adapter) { E11y
|
|
2240
|
+
let(:adapter) { E11y.config.adapters[:test] }
|
|
2311
2241
|
|
|
2312
2242
|
before do
|
|
2313
2243
|
adapter.clear!
|
|
@@ -2342,7 +2272,7 @@ end
|
|
|
2342
2272
|
|
|
2343
2273
|
```ruby
|
|
2344
2274
|
# Check adapter capabilities before using
|
|
2345
|
-
loki = E11y
|
|
2275
|
+
loki = E11y.config.adapters[:loki]
|
|
2346
2276
|
puts loki.capabilities
|
|
2347
2277
|
# => {
|
|
2348
2278
|
# batching: true,
|
|
@@ -2366,8 +2296,8 @@ end
|
|
|
2366
2296
|
# config/initializers/health_check.rb
|
|
2367
2297
|
HealthCheck.setup do |config|
|
|
2368
2298
|
config.add_custom_check('e11y_adapters') do
|
|
2369
|
-
adapters = E11y
|
|
2370
|
-
unhealthy = adapters.
|
|
2299
|
+
adapters = E11y.config.adapters
|
|
2300
|
+
unhealthy = adapters.select { |_name, adapter| !adapter.respond_to?(:healthy?) || !adapter.healthy? }
|
|
2371
2301
|
|
|
2372
2302
|
if unhealthy.any?
|
|
2373
2303
|
"Unhealthy adapters: #{unhealthy.keys.join(', ')}"
|
|
@@ -2416,7 +2346,7 @@ E11y.configure do |config|
|
|
|
2416
2346
|
->(event) { :audit_encrypted if event[:audit_event] },
|
|
2417
2347
|
->(event) {
|
|
2418
2348
|
days = (Time.parse(event[:retention_until]) - Time.now) / 86400
|
|
2419
|
-
days > 90 ? :
|
|
2349
|
+
days > 90 ? :archive : :loki
|
|
2420
2350
|
}
|
|
2421
2351
|
]
|
|
2422
2352
|
end
|
|
@@ -2495,6 +2425,93 @@ module E11y
|
|
|
2495
2425
|
end
|
|
2496
2426
|
```
|
|
2497
2427
|
|
|
2428
|
+
### 14.4.1. Routing Decision Matrix
|
|
2429
|
+
|
|
2430
|
+
What happens to an event based on its type and configuration:
|
|
2431
|
+
|
|
2432
|
+
```mermaid
|
|
2433
|
+
flowchart TD
|
|
2434
|
+
Start{What type of event?}
|
|
2435
|
+
|
|
2436
|
+
Start -->|Regular Event| R1{Has explicit adapters?}
|
|
2437
|
+
Start -->|Audit Event| A1{Has explicit adapters?}
|
|
2438
|
+
|
|
2439
|
+
R1 -->|YES| R2[Use explicit adapters]
|
|
2440
|
+
R1 -->|NO| R3[Use severity mapping]
|
|
2441
|
+
|
|
2442
|
+
R3 --> R4[info → logs]
|
|
2443
|
+
R3 --> R5[error → logs + errors_tracker]
|
|
2444
|
+
|
|
2445
|
+
R2 --> R6[Write to adapters]
|
|
2446
|
+
R4 --> R6
|
|
2447
|
+
R5 --> R6
|
|
2448
|
+
R6 --> R7[SUCCESS]
|
|
2449
|
+
|
|
2450
|
+
A1 -->|YES| A2[Use explicit adapters]
|
|
2451
|
+
A1 -->|NO| A3[Return empty array]
|
|
2452
|
+
|
|
2453
|
+
A3 --> A4{Routing rule matches?}
|
|
2454
|
+
A4 -->|YES| A5[Use rule result]
|
|
2455
|
+
A4 -->|NO| A6[Would use fallback]
|
|
2456
|
+
|
|
2457
|
+
A2 --> A7[Validation: PASS explicit]
|
|
2458
|
+
A5 --> A8[Validation: PASS rule matched]
|
|
2459
|
+
A6 --> A9[Validation: FAIL]
|
|
2460
|
+
|
|
2461
|
+
A7 --> A10[Write to adapters]
|
|
2462
|
+
A8 --> A10
|
|
2463
|
+
A9 --> A11[RAISE ERROR]
|
|
2464
|
+
|
|
2465
|
+
A10 --> A12[SUCCESS encrypted + signed]
|
|
2466
|
+
A11 --> A13[FAILURE event not stored]
|
|
2467
|
+
|
|
2468
|
+
style R7 fill:#c8e6c9
|
|
2469
|
+
style A12 fill:#c8e6c9
|
|
2470
|
+
style A13 fill:#ffcdd2
|
|
2471
|
+
style A11 fill:#ef5350
|
|
2472
|
+
```
|
|
2473
|
+
|
|
2474
|
+
**Note:** Audit events without explicit adapters return `[]` so routing rules are evaluated. If no rule matches, fallback is used — but `validate_audit_routing!` raises (audit events MUST NOT use fallback).
|
|
2475
|
+
|
|
2476
|
+
### 14.4.2. Adapter Resolution Logic
|
|
2477
|
+
|
|
2478
|
+
How `Event::Base#adapters` resolves target adapters:
|
|
2479
|
+
|
|
2480
|
+
```mermaid
|
|
2481
|
+
flowchart TD
|
|
2482
|
+
A[Event.track called] --> B[Event::Base#adapters method]
|
|
2483
|
+
|
|
2484
|
+
B --> C{Check @adapters instance variable}
|
|
2485
|
+
C -->|SET| D[Return @adapters]
|
|
2486
|
+
C -->|NIL| E{Check parent class @adapters}
|
|
2487
|
+
|
|
2488
|
+
E -->|SET| F[Return parent.adapters]
|
|
2489
|
+
E -->|NIL| G{Call resolved_adapters}
|
|
2490
|
+
|
|
2491
|
+
G --> H{Is audit_event?}
|
|
2492
|
+
H -->|YES| I[Return empty array]
|
|
2493
|
+
H -->|NO| J[Call adapters_for_severity]
|
|
2494
|
+
|
|
2495
|
+
J --> K[Check severity level]
|
|
2496
|
+
K --> L[severity :info → logs]
|
|
2497
|
+
K --> M[severity :error → logs + errors_tracker]
|
|
2498
|
+
K --> N[severity :fatal → logs + errors_tracker]
|
|
2499
|
+
K --> O[default → logs]
|
|
2500
|
+
|
|
2501
|
+
D --> P[Result: adapters array]
|
|
2502
|
+
F --> P
|
|
2503
|
+
I --> P
|
|
2504
|
+
L --> P
|
|
2505
|
+
M --> P
|
|
2506
|
+
N --> P
|
|
2507
|
+
O --> P
|
|
2508
|
+
|
|
2509
|
+
style I fill:#fff9c4
|
|
2510
|
+
style P fill:#e0e0e0
|
|
2511
|
+
```
|
|
2512
|
+
|
|
2513
|
+
**Key:** Audit events without explicit adapters return `[]` — routing middleware then applies `routing_rules` (e.g. `->(e) { :audit_encrypted if e[:audit_event] }`).
|
|
2514
|
+
|
|
2498
2515
|
### 14.5. Configuration
|
|
2499
2516
|
|
|
2500
2517
|
```ruby
|
|
@@ -2508,13 +2525,13 @@ E11y.configure do |config|
|
|
|
2508
2525
|
# Rule 2: Long retention → cold storage
|
|
2509
2526
|
->(event) {
|
|
2510
2527
|
days = (Time.parse(event[:retention_until]) - Time.now) / 86400
|
|
2511
|
-
:
|
|
2528
|
+
:archive if days > 90
|
|
2512
2529
|
},
|
|
2513
2530
|
|
|
2514
2531
|
# Rule 3: Medium retention → warm storage
|
|
2515
2532
|
->(event) {
|
|
2516
2533
|
days = (Time.parse(event[:retention_until]) - Time.now) / 86400
|
|
2517
|
-
:
|
|
2534
|
+
:warm if days.between?(30, 90)
|
|
2518
2535
|
},
|
|
2519
2536
|
|
|
2520
2537
|
# Rule 4: Short retention → hot storage
|
|
@@ -2566,7 +2583,7 @@ end
|
|
|
2566
2583
|
**After:** Automatic routing
|
|
2567
2584
|
- Debug logs (7 days) → stdout: $0/month
|
|
2568
2585
|
- Business (30 days) → Loki: $100/month
|
|
2569
|
-
- Audit (7 years) →
|
|
2586
|
+
- Audit (7 years) → cold tier: $5/month
|
|
2570
2587
|
- **Total: $105/month (80% savings!)**
|
|
2571
2588
|
|
|
2572
2589
|
### 14.8. Advantages vs TieredStorage
|
|
@@ -2619,7 +2636,7 @@ RSpec.describe E11y::Middleware::Routing do
|
|
|
2619
2636
|
it 'respects explicit adapters' do
|
|
2620
2637
|
event = { adapters: [:sentry], retention_until: 1.year.from_now.iso8601 }
|
|
2621
2638
|
expect(adapters[:sentry]).to receive(:write)
|
|
2622
|
-
expect(adapters[:
|
|
2639
|
+
expect(adapters[:archive]).not_to receive(:write)
|
|
2623
2640
|
routing.call(event)
|
|
2624
2641
|
end
|
|
2625
2642
|
end
|
|
@@ -682,11 +682,11 @@ Already implemented in ADR-008, but here's the core logic:
|
|
|
682
682
|
module E11y
|
|
683
683
|
module TraceContext
|
|
684
684
|
class JobPropagator
|
|
685
|
-
# Inject trace
|
|
685
|
+
# C17 Hybrid: Inject parent trace into job metadata (job will create NEW trace_id)
|
|
686
686
|
def self.inject(job_metadata = {})
|
|
687
687
|
return job_metadata unless E11y::Current.traced?
|
|
688
688
|
|
|
689
|
-
job_metadata['
|
|
689
|
+
job_metadata['e11y_parent_trace_id'] = E11y::Current.trace_id
|
|
690
690
|
job_metadata['e11y_span_id'] = E11y::Current.span_id
|
|
691
691
|
job_metadata['e11y_sampled'] = E11y::Current.sampled
|
|
692
692
|
|
|
@@ -702,14 +702,15 @@ module E11y
|
|
|
702
702
|
job_metadata
|
|
703
703
|
end
|
|
704
704
|
|
|
705
|
-
# Extract
|
|
705
|
+
# C17 Hybrid: Extract parent context; job gets NEW trace_id, links via parent_trace_id
|
|
706
706
|
def self.extract(job_metadata)
|
|
707
|
-
return {} unless job_metadata['
|
|
707
|
+
return {} unless job_metadata['e11y_parent_trace_id']
|
|
708
708
|
|
|
709
709
|
{
|
|
710
|
-
trace_id:
|
|
710
|
+
trace_id: IDGenerator.generate_trace_id, # NEW trace per job
|
|
711
|
+
parent_trace_id: job_metadata['e11y_parent_trace_id'],
|
|
711
712
|
parent_span_id: job_metadata['e11y_span_id'],
|
|
712
|
-
span_id: IDGenerator.generate_span_id,
|
|
713
|
+
span_id: IDGenerator.generate_span_id,
|
|
713
714
|
sampled: job_metadata['e11y_sampled'],
|
|
714
715
|
baggage: job_metadata['e11y_baggage'],
|
|
715
716
|
user_id: job_metadata['e11y_user_id'],
|
|
@@ -1055,7 +1056,7 @@ module E11y
|
|
|
1055
1056
|
|
|
1056
1057
|
def extract_parent_context(job)
|
|
1057
1058
|
{
|
|
1058
|
-
trace_id: job['
|
|
1059
|
+
trace_id: job['e11y_parent_trace_id'],
|
|
1059
1060
|
span_id: job['e11y_span_id'],
|
|
1060
1061
|
sampled: job['e11y_sampled'],
|
|
1061
1062
|
baggage: job['e11y_baggage'],
|
|
@@ -1085,7 +1086,7 @@ module E11y
|
|
|
1085
1086
|
def call(worker_class, job, queue, redis_pool)
|
|
1086
1087
|
# Inject current trace context into job metadata
|
|
1087
1088
|
if E11y::Current.traced?
|
|
1088
|
-
job['
|
|
1089
|
+
job['e11y_parent_trace_id'] = E11y::Current.trace_id
|
|
1089
1090
|
job['e11y_span_id'] = E11y::Current.span_id
|
|
1090
1091
|
job['e11y_sampled'] = E11y::Current.sampled
|
|
1091
1092
|
job['e11y_baggage'] = E11y::Current.baggage if E11y::Current.baggage&.any?
|
|
@@ -1184,7 +1185,7 @@ ORDER BY created_at;
|
|
|
1184
1185
|
# 1. Web request (trace_id: abc-123)
|
|
1185
1186
|
POST /orders
|
|
1186
1187
|
→ Events::OrderCreated (trace_id: abc-123, span_id: span-001)
|
|
1187
|
-
→ Enqueue SendOrderEmailJob (metadata: {
|
|
1188
|
+
→ Enqueue SendOrderEmailJob (metadata: {e11y_parent_trace_id: 'abc-123'})
|
|
1188
1189
|
|
|
1189
1190
|
# 2. Sidekiq job execution (NEW trace_id: xyz-789)
|
|
1190
1191
|
SendOrderEmailJob#perform
|