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.
Files changed (288) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +130 -10
  3. data/CHANGELOG.md +80 -1
  4. data/CLAUDE.md +168 -0
  5. data/CONTRIBUTING.md +640 -0
  6. data/README.md +165 -701
  7. data/RELEASE.md +41 -12
  8. data/Rakefile +249 -57
  9. data/config/README.md +1 -1
  10. data/config/loki-local-config.yaml +12 -0
  11. data/config/otel-collector-config.yaml +44 -0
  12. data/cucumber.yml +1 -0
  13. data/docker-compose.yml +18 -2
  14. data/docs/ADAPTERS.md +76 -0
  15. data/docs/ADAPTIVE_SAMPLING.md +59 -0
  16. data/docs/COMPARISON.md +104 -0
  17. data/docs/CONFIGURATION.md +52 -0
  18. data/docs/DISTRIBUTED_TRACING.md +44 -0
  19. data/docs/LIMITATIONS.md +13 -0
  20. data/docs/METRICS_DSL.md +84 -0
  21. data/docs/PERFORMANCE.md +60 -0
  22. data/docs/PII_FILTERING.md +40 -0
  23. data/docs/PRESETS.md +65 -0
  24. data/docs/QUICK-START.md +546 -587
  25. data/docs/RAILS_INTEGRATION.md +79 -0
  26. data/docs/SCHEMA_VALIDATION.md +63 -0
  27. data/docs/SLO-PROMQL-ALERTS.md +161 -0
  28. data/docs/TESTING.md +69 -0
  29. data/docs/{ADR-001-architecture.md → architecture/ADR-001-architecture.md} +36 -65
  30. data/docs/{ADR-002-metrics-yabeda.md → architecture/ADR-002-metrics-yabeda.md} +62 -236
  31. data/docs/architecture/ADR-003-slo-observability.md +1402 -0
  32. data/docs/{ADR-004-adapter-architecture.md → architecture/ADR-004-adapter-architecture.md} +163 -146
  33. data/docs/{ADR-005-tracing-context.md → architecture/ADR-005-tracing-context.md} +10 -9
  34. data/docs/{ADR-006-security-compliance.md → architecture/ADR-006-security-compliance.md} +184 -191
  35. data/docs/{ADR-007-opentelemetry-integration.md → architecture/ADR-007-opentelemetry-integration.md} +3 -21
  36. data/docs/{ADR-008-rails-integration.md → architecture/ADR-008-rails-integration.md} +182 -743
  37. data/docs/{ADR-009-cost-optimization.md → architecture/ADR-009-cost-optimization.md} +45 -54
  38. data/docs/architecture/ADR-010-developer-experience.md +522 -0
  39. data/docs/{ADR-011-testing-strategy.md → architecture/ADR-011-testing-strategy.md} +44 -86
  40. data/docs/{ADR-012-event-evolution.md → architecture/ADR-012-event-evolution.md} +11 -11
  41. data/docs/{ADR-013-reliability-error-handling.md → architecture/ADR-013-reliability-error-handling.md} +37 -12
  42. data/docs/{ADR-014-event-driven-slo.md → architecture/ADR-014-event-driven-slo.md} +12 -24
  43. data/docs/{ADR-015-middleware-order.md → architecture/ADR-015-middleware-order.md} +43 -59
  44. data/docs/{ADR-016-self-monitoring-slo.md → architecture/ADR-016-self-monitoring-slo.md} +58 -355
  45. data/docs/{ADR-017-multi-rails-compatibility.md → architecture/ADR-017-multi-rails-compatibility.md} +4 -11
  46. data/docs/architecture/ADR-018-memory-optimization.md +366 -0
  47. data/docs/{ADR-INDEX.md → architecture/ADR-INDEX.md} +11 -6
  48. data/docs/plans/2026-03-20-browser-overlay-svelte.md +281 -0
  49. data/docs/{00-ICP-AND-TIMELINE.md → prd/00-ICP-AND-TIMELINE.md} +6 -6
  50. data/docs/{01-SCALE-REQUIREMENTS.md → prd/01-SCALE-REQUIREMENTS.md} +6 -6
  51. data/docs/prd/01-overview-vision.md +19 -14
  52. data/docs/use_cases/README.md +22 -23
  53. data/docs/use_cases/UC-001-request-scoped-debug-buffering.md +50 -44
  54. data/docs/use_cases/UC-002-business-event-tracking.md +26 -95
  55. data/docs/use_cases/UC-003-event-metrics.md +66 -0
  56. data/docs/use_cases/UC-004-zero-config-slo-tracking.md +33 -684
  57. data/docs/use_cases/UC-005-sentry-integration.md +13 -15
  58. data/docs/use_cases/UC-006-trace-context-management.md +30 -28
  59. data/docs/use_cases/UC-007-pii-filtering.md +35 -87
  60. data/docs/use_cases/UC-008-opentelemetry-integration.md +51 -89
  61. data/docs/use_cases/UC-009-multi-service-tracing.md +30 -178
  62. data/docs/use_cases/UC-010-background-job-tracking.md +24 -91
  63. data/docs/use_cases/UC-011-rate-limiting.md +95 -168
  64. data/docs/use_cases/UC-012-audit-trail.md +21 -46
  65. data/docs/use_cases/UC-013-high-cardinality-protection.md +29 -167
  66. data/docs/use_cases/UC-014-adaptive-sampling.md +2 -2
  67. data/docs/use_cases/UC-015-cost-optimization.md +46 -99
  68. data/docs/use_cases/UC-016-rails-logger-migration.md +39 -213
  69. data/docs/use_cases/UC-017-local-development.md +203 -777
  70. data/docs/use_cases/UC-018-testing-events.md +3 -3
  71. data/docs/use_cases/UC-019-retention-based-routing.md +53 -106
  72. data/docs/use_cases/UC-020-event-versioning.md +8 -9
  73. data/docs/use_cases/UC-021-error-handling-retry-dlq.md +18 -22
  74. data/docs/use_cases/UC-022-event-registry.md +15 -21
  75. data/docs/use_cases/backlog.md +119 -87
  76. data/e11y.gemspec +2 -2
  77. data/gems/e11y-devtools/README.md +158 -0
  78. data/gems/e11y-devtools/config/routes.rb +15 -0
  79. data/gems/e11y-devtools/e11y-devtools.gemspec +25 -0
  80. data/gems/e11y-devtools/exe/e11y +34 -0
  81. data/gems/e11y-devtools/frontend/.gitignore +24 -0
  82. data/gems/e11y-devtools/frontend/README.md +51 -0
  83. data/gems/e11y-devtools/frontend/index.html +14 -0
  84. data/gems/e11y-devtools/frontend/package-lock.json +3707 -0
  85. data/gems/e11y-devtools/frontend/package.json +28 -0
  86. data/gems/e11y-devtools/frontend/public/mocks/v1/events/recent.json +4205 -0
  87. data/gems/e11y-devtools/frontend/public/mocks/v1/interactions.json +194 -0
  88. data/gems/e11y-devtools/frontend/public/mocks/v1/traces/0a2e04027cfa22d014bc22e8b27cd913/events.json +86 -0
  89. data/gems/e11y-devtools/frontend/public/mocks/v1/traces/0e1543af6a630fb3af6b52283154b3e0/events.json +169 -0
  90. data/gems/e11y-devtools/frontend/public/mocks/v1/traces/1838b691faa49564f97db8592ff3978d/events.json +78 -0
  91. data/gems/e11y-devtools/frontend/public/mocks/v1/traces/29f198f6588dacffb687777eb5f8f118/events.json +197 -0
  92. data/gems/e11y-devtools/frontend/public/mocks/v1/traces/34bc3c9c0097de28a7a6f99b90a8e7bc/events.json +194 -0
  93. data/gems/e11y-devtools/frontend/public/mocks/v1/traces/3ba6c20d068ab9cee00e51b180e66444/events.json +184 -0
  94. data/gems/e11y-devtools/frontend/public/mocks/v1/traces/435bfd8f17b9009146a79812d7c3726d/events.json +144 -0
  95. data/gems/e11y-devtools/frontend/public/mocks/v1/traces/4c7676e3fe668e99edb2b94d7d5678a9/events.json +222 -0
  96. data/gems/e11y-devtools/frontend/public/mocks/v1/traces/6daf0d47974bedfc55d5de7004a3ea9f/events.json +194 -0
  97. data/gems/e11y-devtools/frontend/public/mocks/v1/traces/8a81ada42834d15f287bb40010043605/events.json +194 -0
  98. data/gems/e11y-devtools/frontend/public/mocks/v1/traces/8c0a98900edaae105469df8daedccf02/events.json +198 -0
  99. data/gems/e11y-devtools/frontend/public/mocks/v1/traces/8e4f645180f8a7d1dce426b07380466b/events.json +222 -0
  100. data/gems/e11y-devtools/frontend/public/mocks/v1/traces/93db346fa5d44a032605a13b627f4b80/events.json +128 -0
  101. data/gems/e11y-devtools/frontend/public/mocks/v1/traces/98ff6146faf7bd9be8bd03a8275817ba/events.json +223 -0
  102. data/gems/e11y-devtools/frontend/public/mocks/v1/traces/9997ddd0247bc7e25f2ca7a5c415c93d/events.json +197 -0
  103. data/gems/e11y-devtools/frontend/public/mocks/v1/traces/99e35f8ef3baedd798cc4fd085980ad9/events.json +194 -0
  104. data/gems/e11y-devtools/frontend/public/mocks/v1/traces/b4f3095c1909924cbc98889a86c83d6d/events.json +131 -0
  105. data/gems/e11y-devtools/frontend/public/mocks/v1/traces/b54b7fc32b7575a7110de809d11ccda0/events.json +128 -0
  106. data/gems/e11y-devtools/frontend/public/mocks/v1/traces/c0b48033fa06746bcc5886745e053cff/events.json +169 -0
  107. data/gems/e11y-devtools/frontend/public/mocks/v1/traces/c44649ac76701b4558927cd2305ab535/events.json +169 -0
  108. data/gems/e11y-devtools/frontend/public/mocks/v1/traces/d601ae3320057580a39dbdac2edfdf4a/events.json +248 -0
  109. data/gems/e11y-devtools/frontend/public/mocks/v1/traces/e67e724bab422d2b52eeb49635e512e1/events.json +194 -0
  110. data/gems/e11y-devtools/frontend/public/mocks/v1/traces/e6c72765a28f158a8485b35fa63f73da/events.json +194 -0
  111. data/gems/e11y-devtools/frontend/public/mocks/v1/traces/f541b87405c9a54819b18ebe529f6419/events.json +194 -0
  112. data/gems/e11y-devtools/frontend/scripts/generate_mocks.rb +397 -0
  113. data/gems/e11y-devtools/frontend/src/App.svelte +827 -0
  114. data/gems/e11y-devtools/frontend/src/components/Fab.svelte +19 -0
  115. data/gems/e11y-devtools/frontend/src/components/FilterBar.svelte +38 -0
  116. data/gems/e11y-devtools/frontend/src/components/FullscreenPanel.svelte +82 -0
  117. data/gems/e11y-devtools/frontend/src/components/InteractionsTimeline.svelte +264 -0
  118. data/gems/e11y-devtools/frontend/src/components/RecentHistogram.svelte +354 -0
  119. data/gems/e11y-devtools/frontend/src/lib/api.ts +37 -0
  120. data/gems/e11y-devtools/frontend/src/lib/eventIdentity.ts +12 -0
  121. data/gems/e11y-devtools/frontend/src/lib/format.ts +37 -0
  122. data/gems/e11y-devtools/frontend/src/lib/listFilter.ts +43 -0
  123. data/gems/e11y-devtools/frontend/src/lib/recentVolume.ts +80 -0
  124. data/gems/e11y-devtools/frontend/src/lib/router.ts +12 -0
  125. data/gems/e11y-devtools/frontend/src/lib/transitions.ts +34 -0
  126. data/gems/e11y-devtools/frontend/src/lib/viewportOrigin.ts +25 -0
  127. data/gems/e11y-devtools/frontend/src/main.ts +8 -0
  128. data/gems/e11y-devtools/frontend/src/overlay-entry.ts +24 -0
  129. data/gems/e11y-devtools/frontend/src/overlay.css +1080 -0
  130. data/gems/e11y-devtools/frontend/svelte.config.js +2 -0
  131. data/gems/e11y-devtools/frontend/test_puppeteer.js +41 -0
  132. data/gems/e11y-devtools/frontend/test_scale.js +3 -0
  133. data/gems/e11y-devtools/frontend/tsconfig.app.json +21 -0
  134. data/gems/e11y-devtools/frontend/tsconfig.json +7 -0
  135. data/gems/e11y-devtools/frontend/tsconfig.node.json +26 -0
  136. data/gems/e11y-devtools/frontend/vite.config.ts +36 -0
  137. data/gems/e11y-devtools/lib/e11y/devtools/mcp/server.rb +96 -0
  138. data/gems/e11y-devtools/lib/e11y/devtools/mcp/tool_base.rb +25 -0
  139. data/gems/e11y-devtools/lib/e11y/devtools/mcp/tools/clear.rb +31 -0
  140. data/gems/e11y-devtools/lib/e11y/devtools/mcp/tools/errors.rb +35 -0
  141. data/gems/e11y-devtools/lib/e11y/devtools/mcp/tools/event_detail.rb +33 -0
  142. data/gems/e11y-devtools/lib/e11y/devtools/mcp/tools/events_by_trace.rb +33 -0
  143. data/gems/e11y-devtools/lib/e11y/devtools/mcp/tools/interactions.rb +40 -0
  144. data/gems/e11y-devtools/lib/e11y/devtools/mcp/tools/recent_events.rb +34 -0
  145. data/gems/e11y-devtools/lib/e11y/devtools/mcp/tools/search.rb +34 -0
  146. data/gems/e11y-devtools/lib/e11y/devtools/mcp/tools/stats.rb +30 -0
  147. data/gems/e11y-devtools/lib/e11y/devtools/overlay/assets/overlay.js +20 -0
  148. data/gems/e11y-devtools/lib/e11y/devtools/overlay/controller.rb +94 -0
  149. data/gems/e11y-devtools/lib/e11y/devtools/overlay/engine.rb +26 -0
  150. data/gems/e11y-devtools/lib/e11y/devtools/overlay/middleware.rb +80 -0
  151. data/gems/e11y-devtools/lib/e11y/devtools/overlay/rails_controller.rb +67 -0
  152. data/gems/e11y-devtools/lib/e11y/devtools/tui/app.rb +262 -0
  153. data/gems/e11y-devtools/lib/e11y/devtools/tui/grouping.rb +66 -0
  154. data/gems/e11y-devtools/lib/e11y/devtools/tui/widgets/event_detail.rb +62 -0
  155. data/gems/e11y-devtools/lib/e11y/devtools/tui/widgets/event_list.rb +70 -0
  156. data/gems/e11y-devtools/lib/e11y/devtools/tui/widgets/interaction_list.rb +47 -0
  157. data/gems/e11y-devtools/lib/e11y/devtools/version.rb +8 -0
  158. data/gems/e11y-devtools/lib/e11y/devtools.rb +13 -0
  159. data/gems/e11y-devtools/spec/e11y/devtools/mcp/tools_spec.rb +107 -0
  160. data/gems/e11y-devtools/spec/e11y/devtools/overlay/controller_spec.rb +91 -0
  161. data/gems/e11y-devtools/spec/e11y/devtools/overlay/middleware_spec.rb +46 -0
  162. data/gems/e11y-devtools/spec/e11y/devtools/tui/app_spec.rb +85 -0
  163. data/gems/e11y-devtools/spec/e11y/devtools/tui/grouping_spec.rb +64 -0
  164. data/gems/e11y-devtools/spec/spec_helper.rb +5 -0
  165. data/gems/e11y-devtools/spec/tui/widgets/event_list_spec.rb +44 -0
  166. data/gems/e11y-devtools/spec/tui/widgets/interaction_list_spec.rb +62 -0
  167. data/lib/e11y/adapters/audit_encrypted.rb +53 -11
  168. data/lib/e11y/adapters/base.rb +33 -34
  169. data/lib/e11y/adapters/dev_log/file_store.rb +143 -0
  170. data/lib/e11y/adapters/dev_log/query.rb +219 -0
  171. data/lib/e11y/adapters/dev_log.rb +118 -0
  172. data/lib/e11y/adapters/file.rb +3 -6
  173. data/lib/e11y/adapters/in_memory.rb +52 -5
  174. data/lib/e11y/adapters/in_memory_test.rb +29 -0
  175. data/lib/e11y/adapters/loki.rb +58 -23
  176. data/lib/e11y/adapters/null.rb +82 -0
  177. data/lib/e11y/adapters/opentelemetry_collector.rb +183 -0
  178. data/lib/e11y/adapters/otel_logs.rb +136 -23
  179. data/lib/e11y/adapters/sentry.rb +4 -7
  180. data/lib/e11y/adapters/stdout.rb +73 -7
  181. data/lib/e11y/adapters/yabeda.rb +153 -29
  182. data/lib/e11y/buffers/adaptive_buffer.rb +3 -17
  183. data/lib/e11y/buffers/{request_scoped_buffer.rb → ephemeral_buffer.rb} +72 -58
  184. data/lib/e11y/buffers/ring_buffer.rb +3 -16
  185. data/lib/e11y/configuration.rb +272 -0
  186. data/lib/e11y/console.rb +10 -17
  187. data/lib/e11y/current.rb +53 -1
  188. data/lib/e11y/debug/pipeline_inspector.rb +96 -0
  189. data/lib/e11y/documentation/generator.rb +48 -0
  190. data/lib/e11y/event/base.rb +176 -82
  191. data/lib/e11y/event/value_sampling_config.rb +1 -5
  192. data/lib/e11y/events/rails/database/query.rb +1 -4
  193. data/lib/e11y/events/rails/job/failed.rb +2 -0
  194. data/lib/e11y/instruments/active_job.rb +44 -12
  195. data/lib/e11y/instruments/rails_instrumentation.rb +49 -24
  196. data/lib/e11y/instruments/sidekiq.rb +135 -31
  197. data/lib/e11y/linters/base.rb +11 -0
  198. data/lib/e11y/linters/pii/pii_declaration_linter.rb +120 -0
  199. data/lib/e11y/linters/slo/config_consistency_linter.rb +76 -0
  200. data/lib/e11y/linters/slo/explicit_declaration_linter.rb +36 -0
  201. data/lib/e11y/linters/slo/slo_status_from_linter.rb +41 -0
  202. data/lib/e11y/logger/bridge.rb +26 -7
  203. data/lib/e11y/metrics/cardinality_protection.rb +10 -15
  204. data/lib/e11y/metrics/cardinality_tracker.rb +16 -6
  205. data/lib/e11y/metrics/registry.rb +3 -5
  206. data/lib/e11y/metrics/test_backend.rb +62 -0
  207. data/lib/e11y/metrics.rb +56 -10
  208. data/lib/e11y/middleware/adapter_resolver.rb +40 -0
  209. data/lib/e11y/middleware/audit_signing.rb +43 -6
  210. data/lib/e11y/middleware/baggage_protection.rb +75 -0
  211. data/lib/e11y/middleware/dev_log_source.rb +24 -0
  212. data/lib/e11y/middleware/event_slo.rb +23 -9
  213. data/lib/e11y/middleware/otel_span.rb +23 -0
  214. data/lib/e11y/middleware/pii_filter.rb +104 -75
  215. data/lib/e11y/middleware/rate_limiting.rb +54 -27
  216. data/lib/e11y/middleware/request.rb +70 -23
  217. data/lib/e11y/middleware/routing.rb +78 -21
  218. data/lib/e11y/middleware/sampling.rb +66 -17
  219. data/lib/e11y/middleware/self_monitoring_emit.rb +39 -0
  220. data/lib/e11y/middleware/trace_context.rb +45 -10
  221. data/lib/e11y/middleware/track_latency.rb +34 -0
  222. data/lib/e11y/middleware/validation.rb +7 -16
  223. data/lib/e11y/middleware/versioning.rb +26 -22
  224. data/lib/e11y/opentelemetry/semantic_conventions.rb +109 -0
  225. data/lib/e11y/opentelemetry/span_creator.rb +142 -0
  226. data/lib/e11y/pii/patterns.rb +12 -1
  227. data/lib/e11y/pipeline/builder.rb +4 -4
  228. data/lib/e11y/presets/audit_event.rb +13 -2
  229. data/lib/e11y/railtie.rb +52 -14
  230. data/lib/e11y/registry.rb +306 -0
  231. data/lib/e11y/reliability/circuit_breaker.rb +19 -21
  232. data/lib/e11y/reliability/dlq/base.rb +71 -0
  233. data/lib/e11y/reliability/dlq/file_adapter.rb +301 -0
  234. data/lib/e11y/reliability/dlq/file_storage.rb +63 -34
  235. data/lib/e11y/reliability/dlq/filter.rb +37 -54
  236. data/lib/e11y/reliability/retry_handler.rb +26 -29
  237. data/lib/e11y/reliability/retry_rate_limiter.rb +3 -11
  238. data/lib/e11y/sampling/error_spike_detector.rb +0 -2
  239. data/lib/e11y/sampling/load_monitor.rb +5 -9
  240. data/lib/e11y/sampling/stratified_tracker.rb +18 -0
  241. data/lib/e11y/self_monitoring/buffer_monitor.rb +2 -0
  242. data/lib/e11y/self_monitoring/performance_monitor.rb +19 -61
  243. data/lib/e11y/self_monitoring/reliability_monitor.rb +4 -74
  244. data/lib/e11y/slo/config_loader.rb +40 -0
  245. data/lib/e11y/slo/config_validator.rb +58 -0
  246. data/lib/e11y/slo/dashboard_generator.rb +122 -0
  247. data/lib/e11y/slo/event_driven.rb +8 -0
  248. data/lib/e11y/slo/tracker.rb +31 -4
  249. data/lib/e11y/testing/have_tracked_event_matcher.rb +190 -0
  250. data/lib/e11y/testing/rspec_matchers.rb +21 -0
  251. data/lib/e11y/testing/snapshot_matcher.rb +86 -0
  252. data/lib/e11y/trace_context/sampler.rb +35 -0
  253. data/lib/e11y/tracing/faraday_middleware.rb +31 -0
  254. data/lib/e11y/tracing/net_http_patch.rb +33 -0
  255. data/lib/e11y/tracing/propagator.rb +144 -0
  256. data/lib/e11y/tracing.rb +47 -0
  257. data/lib/e11y/version.rb +1 -1
  258. data/lib/e11y/versioning/version_extractor.rb +32 -0
  259. data/lib/e11y.rb +123 -266
  260. data/lib/generators/e11y/event/event_generator.rb +22 -0
  261. data/lib/generators/e11y/event/templates/event.rb.tt +16 -0
  262. data/lib/generators/e11y/grafana_dashboard/grafana_dashboard_generator.rb +30 -0
  263. data/lib/generators/e11y/grafana_dashboard/templates/e11y_dashboard.json +81 -0
  264. data/lib/generators/e11y/install/install_generator.rb +34 -0
  265. data/lib/generators/e11y/install/templates/e11y.rb +239 -0
  266. data/lib/generators/e11y/prometheus_alerts/prometheus_alerts_generator.rb +29 -0
  267. data/lib/generators/e11y/prometheus_alerts/templates/e11y_alerts.yml +28 -0
  268. data/lib/tasks/e11y_docs.rake +30 -0
  269. data/lib/tasks/e11y_events.rake +71 -0
  270. data/lib/tasks/e11y_lint.rake +91 -0
  271. data/lib/tasks/e11y_slo.rake +29 -0
  272. metadata +186 -39
  273. data/docs/ADR-003-slo-observability.md +0 -3337
  274. data/docs/ADR-010-developer-experience.md +0 -2166
  275. data/docs/API-REFERENCE-L28.md +0 -914
  276. data/docs/COMPREHENSIVE-CONFIGURATION.md +0 -2366
  277. data/docs/CONTRIBUTING.md +0 -312
  278. data/docs/IMPLEMENTATION_NOTES.md +0 -2804
  279. data/docs/IMPLEMENTATION_PLAN.md +0 -1971
  280. data/docs/IMPLEMENTATION_PLAN_ARCHITECTURE.md +0 -586
  281. data/docs/PLAN.md +0 -148
  282. data/docs/README.md +0 -296
  283. data/docs/design/00-memory-optimization.md +0 -593
  284. data/docs/guides/MIGRATION-L27-L28.md +0 -692
  285. data/docs/guides/PERFORMANCE-BENCHMARKS.md +0 -434
  286. data/docs/guides/README.md +0 -44
  287. data/docs/use_cases/UC-003-pattern-based-metrics.md +0 -1627
  288. data/lib/e11y/adapters/registry.rb +0 -141
@@ -81,22 +81,38 @@ module E11y
81
81
  # - Auto-calculated retention_until from retention_period
82
82
  #
83
83
  # @param payload [Hash] Event data matching the schema
84
+ # @yield Optional block — measured for duration; adds :duration_ms to payload
84
85
  # @return [Hash] Event hash (includes metadata)
85
86
  #
86
- # @example
87
+ # @example Without block
87
88
  # UserSignupEvent.track(user_id: 123, email: "user@example.com")
88
89
  # # => { event_name: "UserSignupEvent", payload: {...}, severity: :info, adapters: [:logs], ... }
89
90
  #
91
+ # @example With block (duration measurement)
92
+ # Events::OrderPaid.track(order_id: '123') { ExternalPaymentService.charge! }
93
+ # # => payload includes duration_ms automatically
94
+ #
90
95
  # @raise [E11y::ValidationError] if payload doesn't match schema (when validation runs)
91
- def track(**payload)
96
+ def track(**payload, &block)
92
97
  return unless E11y.config.enabled
93
98
 
99
+ # Block form: execute block, measure duration, capture return value
100
+ block_result = nil
101
+ if block
102
+ start = Process.clock_gettime(Process::CLOCK_MONOTONIC, :millisecond)
103
+ block_result = yield
104
+ payload = payload.merge(duration_ms: Process.clock_gettime(Process::CLOCK_MONOTONIC, :millisecond) - start)
105
+ end
106
+
107
+ # Severity: payload override (e.g. exception → :error) or class default
108
+ resolved_severity = payload[:severity] || payload["severity"] || severity
109
+
94
110
  # Build event data hash for pipeline processing
95
111
  event_data = {
96
112
  event_class: self,
97
113
  event_name: event_name,
98
114
  payload: payload,
99
- severity: severity,
115
+ severity: resolved_severity,
100
116
  version: version,
101
117
  adapters: adapters,
102
118
  timestamp: Time.now.utc,
@@ -109,8 +125,8 @@ module E11y
109
125
  # Routing middleware is the LAST middleware and it writes to adapters directly
110
126
  E11y.config.built_pipeline.call(event_data)
111
127
 
112
- # Return event data for testing/debugging
113
- event_data
128
+ # With block: return block's result (caller cares about it); without: return event_data
129
+ block ? block_result : event_data
114
130
  end
115
131
 
116
132
  # Build event hash
@@ -240,9 +256,7 @@ module E11y
240
256
  # end
241
257
  def severity(value = nil)
242
258
  if value
243
- unless SEVERITIES.include?(value)
244
- raise ArgumentError, "Invalid severity: #{value}. Must be one of: #{SEVERITIES.join(', ')}"
245
- end
259
+ raise ArgumentError, "Invalid severity: #{value}. Must be one of: #{SEVERITIES.join(', ')}" unless SEVERITIES.include?(value)
246
260
 
247
261
  @severity = value
248
262
  end
@@ -263,13 +277,15 @@ module E11y
263
277
  # class OrderPaidEventV2 < E11y::Event::Base
264
278
  # version 2
265
279
  # end
280
+ VERSION_REGEX = /V(\d+)$/
281
+
266
282
  def version(value = nil)
267
283
  @version = value if value
268
- # Return explicitly set version OR inherit from parent (if set) OR default to 1
269
284
  return @version if @version
270
- return superclass.version if superclass != E11y::Event::Base && superclass.instance_variable_get(:@version)
271
285
 
272
- 1
286
+ # Auto-extract from class name (e.g. OrderPaidV2 → 2)
287
+ match = name&.match(VERSION_REGEX)
288
+ match ? match[1].to_i : 1
273
289
  end
274
290
 
275
291
  # Set or get retention period for this event
@@ -299,14 +315,15 @@ module E11y
299
315
  @retention_period = value if value
300
316
  # Return explicitly set retention_period OR inherit from parent (if set) OR config default OR final fallback
301
317
  return @retention_period if @retention_period
302
- if superclass != E11y::Event::Base && superclass.instance_variable_get(:@retention_period)
303
- return superclass.retention_period
304
- end
318
+ return superclass.retention_period if superclass != E11y::Event::Base && superclass.instance_variable_get(:@retention_period)
305
319
 
306
320
  # Fallback to configuration or 30 days
307
321
  E11y.configuration&.default_retention_period || 30.days
308
322
  end
309
323
 
324
+ # Convenience alias — matches Quick Start documentation.
325
+ alias retention retention_period
326
+
310
327
  # Set or get adapters for this event
311
328
  #
312
329
  # Adapters are referenced by NAME (e.g., :logs, :errors_tracker).
@@ -331,16 +348,42 @@ module E11y
331
348
  return @adapters if @adapters
332
349
  return superclass.adapters if superclass != E11y::Event::Base && superclass.instance_variable_get(:@adapters)
333
350
 
351
+ # No explicit adapters: inherit from parent or resolve from severity
352
+ # (audit events and regular events both use severity-based mapping)
334
353
  resolved_adapters
335
354
  end
336
355
 
337
- # Get event name (normalized)
356
+ # Get or set event name (normalized)
338
357
  #
339
- # @return [String] Event name without version suffix
358
+ # When called with a value, stores it and auto-registers the class in `E11y::Registry`.
359
+ # When called without a value, derives the name from the class name (stripping version suffix).
340
360
  #
341
- # @example
361
+ # @param value [String, Symbol, nil] Explicit event name to set, or nil to read
362
+ # @return [String] Event name
363
+ #
364
+ # @example Explicit name
365
+ # class OrderPaidEvent < E11y::Event::Base
366
+ # event_name "order.paid"
367
+ # end
368
+ #
369
+ # @example Auto-derived name
342
370
  # OrderPaidEventV2.event_name # => "OrderPaidEvent"
343
- def event_name
371
+ def event_name(value = nil)
372
+ if value
373
+ @event_name = value.to_s
374
+ @event_name_explicit = true
375
+ # Auto-register in E11y::Registry when an explicit name is set.
376
+ # Guard with defined? so that loading order does not matter.
377
+ # NOTE: call register AFTER setting @event_name_explicit so that any
378
+ # re-entrant call to event_name (from Registry#register) returns the
379
+ # correct value instead of falling through to the auto-derive path.
380
+ E11y::Registry.register(self) if defined?(E11y::Registry)
381
+ return @event_name
382
+ end
383
+
384
+ # Return explicitly-set name unconditionally (works for anonymous classes too)
385
+ return @event_name if @event_name_explicit
386
+
344
387
  # Don't cache for anonymous classes (name returns nil)
345
388
  return @event_name if @event_name && name
346
389
 
@@ -365,7 +408,6 @@ module E11y
365
408
  # class CriticalEvent < E11y::Event::Base
366
409
  # sample_rate 1.0 # 100% sampling
367
410
  # end
368
- # rubocop:disable Metrics/CyclomaticComplexity
369
411
  def sample_rate(value = nil)
370
412
  if value
371
413
  unless value.is_a?(Numeric) && value >= 0.0 && value <= 1.0
@@ -377,13 +419,10 @@ module E11y
377
419
 
378
420
  # Return explicitly set sample_rate OR inherit from parent (if set) OR nil (use resolve_sample_rate)
379
421
  return @sample_rate if @sample_rate
380
- if superclass != E11y::Event::Base && superclass.instance_variable_get(:@sample_rate)
381
- return superclass.sample_rate
382
- end
422
+ return superclass.sample_rate if superclass != E11y::Event::Base && superclass.instance_variable_get(:@sample_rate)
383
423
 
384
424
  nil
385
425
  end
386
- # rubocop:enable Metrics/CyclomaticComplexity
387
426
 
388
427
  # Configure value-based sampling (FEAT-4849)
389
428
  #
@@ -460,9 +499,7 @@ module E11y
460
499
 
461
500
  # Return explicitly set config OR inherit from parent (if set) OR nil
462
501
  return @adaptive_sampling if @adaptive_sampling
463
- if superclass != E11y::Event::Base && superclass.instance_variable_get(:@adaptive_sampling)
464
- return superclass.adaptive_sampling
465
- end
502
+ return superclass.adaptive_sampling if superclass != E11y::Event::Base && superclass.instance_variable_get(:@adaptive_sampling)
466
503
 
467
504
  nil
468
505
  end
@@ -476,12 +513,36 @@ module E11y
476
513
  def resolve_rate_limit
477
514
  case severity
478
515
  when :error, :fatal
479
- nil # Unlimited - не теряем ошибки
516
+ nil # Unlimited - never drop errors
480
517
  else
481
518
  1000 # 1000 events/sec
482
519
  end
483
520
  end
484
521
 
522
+ # Set a per-event-class rate limit for the RateLimiting middleware.
523
+ #
524
+ # Overrides the global rate limit for events of this class.
525
+ # error/fatal events are always exempt (never rate-limited).
526
+ #
527
+ # @param count [Integer] Max events allowed per window
528
+ # @param window [Numeric, ActiveSupport::Duration] Time window in seconds (default: 1.0)
529
+ #
530
+ # @example Strict limit for login failures (brute-force protection)
531
+ # class Events::UserLoginFailed < E11y::Event::Base
532
+ # rate_limit 100, window: 60
533
+ # end
534
+ def rate_limit(count, window: 1.0)
535
+ @rate_limit_count = count
536
+ @rate_limit_window = window.to_f
537
+ end
538
+
539
+ # Per-event rate limit configuration.
540
+ #
541
+ # @return [Hash] { count: Integer|nil, window: Float|nil }
542
+ def rate_limit_config
543
+ { count: @rate_limit_count, window: @rate_limit_window }
544
+ end
545
+
485
546
  private
486
547
 
487
548
  # Determine if validation should run for this event
@@ -581,21 +642,21 @@ module E11y
581
642
  # end
582
643
  def contains_pii(value = nil)
583
644
  if value.nil?
584
- # Getter
645
+ return superclass.contains_pii if !instance_variable_defined?(:@contains_pii) && superclass.respond_to?(:contains_pii)
646
+
585
647
  @contains_pii
586
648
  else
587
- # Setter
588
649
  @contains_pii = value
589
650
  end
590
651
  end
591
652
 
592
- # Determine the PII filtering tier for this event.
593
- # @return [Symbol] :tier1, :tier2, or :tier3
594
- def pii_tier
653
+ # PII filtering mode for this event.
654
+ # @return [Symbol] :no_pii, :rails_filters, or :explicit_pii
655
+ def pii_filtering_mode
595
656
  case contains_pii
596
- when false then :tier1
597
- when true then :tier3
598
- else :tier2 # Default if not explicitly declared
657
+ when false then :no_pii
658
+ when true then :explicit_pii
659
+ else :rails_filters # Default if not explicitly declared
599
660
  end
600
661
  end
601
662
 
@@ -610,15 +671,22 @@ module E11y
610
671
  # allows :user_id, :amount
611
672
  # end
612
673
  def pii_filtering(&)
613
- @pii_filtering_config ||= { fields: {} }
674
+ if @pii_filtering_config.nil?
675
+ parent_config = superclass.respond_to?(:pii_filtering_config) && superclass.pii_filtering_config
676
+ @pii_filtering_config = parent_config ? { fields: parent_config[:fields].dup } : { fields: {} }
677
+ end
614
678
  builder = PIIFilteringBuilder.new(@pii_filtering_config)
615
679
  builder.instance_eval(&)
616
680
  end
617
681
 
618
- # Get PII filtering configuration
682
+ # Get PII filtering configuration (inherits from superclass if not defined)
619
683
  #
620
- # @return [Hash] PII filtering config
621
- attr_reader :pii_filtering_config
684
+ # @return [Hash, nil] PII filtering config
685
+ def pii_filtering_config
686
+ return @pii_filtering_config if instance_variable_defined?(:@pii_filtering_config) && @pii_filtering_config
687
+
688
+ superclass.pii_filtering_config if superclass.respond_to?(:pii_filtering_config)
689
+ end
622
690
 
623
691
  # PII Filtering DSL Builder
624
692
  #
@@ -666,6 +734,30 @@ module E11y
666
734
  def allows(*fields)
667
735
  fields.each { |field| @config[:fields][field] = { strategy: :allow } }
668
736
  end
737
+
738
+ # Per-field config with exclude_adapters (Tier 3 per-adapter filtering).
739
+ #
740
+ # @param field [Symbol] Field name
741
+ # @yield Block with strategy, exclude_adapters
742
+ # @example
743
+ # field :email do
744
+ # strategy :hash
745
+ # exclude_adapters [:file_audit] # Audit gets original (GDPR)
746
+ # end
747
+ def field(field_name, &)
748
+ return unless block_given?
749
+
750
+ opts = { strategy: :allow }
751
+ dsl = Class.new do
752
+ attr_reader :opts
753
+
754
+ def initialize(opts) = @opts = opts
755
+ def strategy(val) = @opts.[]=(:strategy, val)
756
+ def exclude_adapters(adapters) = @opts.[]=(:exclude_adapters, Array(adapters).map(&:to_sym))
757
+ end.new(opts)
758
+ dsl.instance_eval(&)
759
+ @config[:fields][field_name] = opts
760
+ end
669
761
  end
670
762
 
671
763
  # === Audit Event DSL (ADR-006, UC-012) ===
@@ -705,6 +797,33 @@ module E11y
705
797
  @audit_event == true
706
798
  end
707
799
 
800
+ # === DLQ Filter DSL (ADR-013, UC-021) ===
801
+
802
+ # Declare whether this event should be saved to DLQ on failure.
803
+ #
804
+ # @param value [Boolean, nil] true = save, false = discard, nil = use severity + default
805
+ # @example
806
+ # class Events::PaymentFailed < E11y::Event::Base
807
+ # use_dlq true
808
+ # end
809
+ #
810
+ # class Events::DebugTrace < E11y::Event::Base
811
+ # use_dlq false
812
+ # end
813
+ def use_dlq(value = nil)
814
+ if value.nil?
815
+ return superclass.use_dlq if !instance_variable_defined?(:@use_dlq) && superclass.respond_to?(:use_dlq)
816
+
817
+ @use_dlq
818
+ else
819
+ @use_dlq = value
820
+ end
821
+ end
822
+
823
+ def use_dlq?
824
+ use_dlq == true
825
+ end
826
+
708
827
  # Configure cryptographic signing for audit event
709
828
  #
710
829
  # By default, all audit events are signed with HMAC-SHA256.
@@ -759,7 +878,7 @@ module E11y
759
878
  audit_event? && signing_enabled?
760
879
  end
761
880
 
762
- # === Metrics DSL (ADR-002, UC-003) ===
881
+ # === Metrics DSL (ADR-002, UC-003 Event Metrics) ===
763
882
 
764
883
  # Define metrics for this event
765
884
  #
@@ -810,6 +929,23 @@ module E11y
810
929
  register_metrics_in_registry!
811
930
  end
812
931
 
932
+ # Single-call metric shorthand — equivalent to a one-metric `metrics` block.
933
+ #
934
+ # @param type [Symbol] :counter, :histogram, or :gauge
935
+ # @param name [Symbol] Metric name
936
+ # @param opts [Hash] Options: tags:, value: (histogram/gauge), buckets: (histogram)
937
+ #
938
+ # @example
939
+ # metric :counter, name: :orders_total, tags: [:currency]
940
+ # metric :histogram, name: :order_amount, value: :amount, tags: [:currency]
941
+ def metric(type, name:, **opts)
942
+ raise ArgumentError, "Unknown metric type: #{type}. Use :counter, :histogram, or :gauge" unless %i[counter histogram gauge].include?(type)
943
+
944
+ @metrics_config ||= []
945
+ @metrics_config << { type: type, name: name }.merge(opts).compact
946
+ register_metrics_in_registry!
947
+ end
948
+
813
949
  # Get metrics configuration
814
950
  #
815
951
  # @return [Array<Hash>] Metrics configuration
@@ -911,48 +1047,6 @@ module E11y
911
1047
  end
912
1048
  end
913
1049
  end
914
-
915
- # Builder for PII filtering DSL
916
- class PIIFilteringBuilder
917
- def initialize(config)
918
- @config = config
919
- end
920
-
921
- # Mask fields (strategy: :mask)
922
- def masks(*fields)
923
- fields.each do |field|
924
- @config[:fields][field] = { strategy: :mask }
925
- end
926
- end
927
-
928
- # Hash fields (strategy: :hash)
929
- def hashes(*fields)
930
- fields.each do |field|
931
- @config[:fields][field] = { strategy: :hash }
932
- end
933
- end
934
-
935
- # Allow fields (strategy: :allow)
936
- def allows(*fields)
937
- fields.each do |field|
938
- @config[:fields][field] = { strategy: :allow }
939
- end
940
- end
941
-
942
- # Partial mask fields (strategy: :partial)
943
- def partials(*fields)
944
- fields.each do |field|
945
- @config[:fields][field] = { strategy: :partial }
946
- end
947
- end
948
-
949
- # Redact fields (strategy: :redact)
950
- def redacts(*fields)
951
- fields.each do |field|
952
- @config[:fields][field] = { strategy: :redact }
953
- end
954
- end
955
- end
956
1050
  end
957
1051
  # rubocop:enable Metrics/ClassLength
958
1052
  end
@@ -69,7 +69,6 @@ module E11y
69
69
 
70
70
  private
71
71
 
72
- # rubocop:disable Metrics/CyclomaticComplexity
73
72
  # Validation requires checking multiple comparison types and threshold types
74
73
  def validate_comparisons!
75
74
  raise ArgumentError, "At least one comparison required" if comparisons.empty?
@@ -79,12 +78,9 @@ module E11y
79
78
 
80
79
  raise ArgumentError, "in_range requires a Range" if type == :in_range && !threshold.is_a?(Range)
81
80
 
82
- if NUMERIC_COMPARISON_TYPES.include?(type) && !threshold.is_a?(Numeric)
83
- raise ArgumentError, "#{type} requires a Numeric threshold"
84
- end
81
+ raise ArgumentError, "#{type} requires a Numeric threshold" if NUMERIC_COMPARISON_TYPES.include?(type) && !threshold.is_a?(Numeric)
85
82
  end
86
83
  end
87
- # rubocop:enable Metrics/CyclomaticComplexity
88
84
  end
89
85
  end
90
86
  end
@@ -16,10 +16,7 @@ module E11y
16
16
  # @example Custom override
17
17
  # # config/initializers/e11y.rb
18
18
  # E11y.configure do |config|
19
- # config.rails_instrumentation.event_class_for(
20
- # 'sql.active_record',
21
- # MyApp::CustomDatabaseQuery
22
- # )
19
+ # config.rails_instrumentation_custom_mappings['sql.active_record'] = MyApp::CustomDatabaseQuery
23
20
  # end
24
21
  #
25
22
  # @see ADR-008 §4.3 (Built-in Event Classes)
@@ -12,6 +12,8 @@ module E11y
12
12
  optional(:job_class).maybe(:string)
13
13
  optional(:job_id).maybe(:string)
14
14
  optional(:queue).maybe(:string)
15
+ optional(:error_class).maybe(:string)
16
+ optional(:error_message).maybe(:string)
15
17
  end
16
18
 
17
19
  severity :error
@@ -29,13 +29,16 @@ module E11y
29
29
  # Store current trace as parent (job will create NEW trace)
30
30
  job.e11y_parent_trace_id = E11y::Current.trace_id if E11y::Current.trace_id
31
31
  job.e11y_parent_span_id = E11y::Current.span_id if E11y::Current.span_id
32
+ job.e11y_sampled = E11y::Current.sampled if E11y::Current.respond_to?(:sampled) && !E11y::Current.sampled.nil?
33
+ baggage = E11y::Tracing::Propagator.baggage_for_propagation_from_current
34
+ job.e11y_baggage = baggage if baggage.any?
32
35
  end
33
36
 
34
37
  # Set up job-scoped context around job execution (C17 Hybrid Tracing + C18 Non-Failing)
35
38
  around_perform do |job, block|
36
39
  # C18: Disable fail_on_error for jobs (observability should not block business logic)
37
- original_fail_on_error = E11y.config.error_handling.fail_on_error
38
- E11y.config.error_handling.fail_on_error = false
40
+ original_fail_on_error = E11y.config.error_handling_fail_on_error
41
+ E11y.config.error_handling_fail_on_error = false
39
42
 
40
43
  setup_job_context_active_job(job)
41
44
  setup_job_buffer_active_job
@@ -59,7 +62,7 @@ module E11y
59
62
  cleanup_job_context_active_job
60
63
 
61
64
  # Restore original setting
62
- E11y.config.error_handling.fail_on_error = original_fail_on_error
65
+ E11y.config.error_handling_fail_on_error = original_fail_on_error
63
66
  end
64
67
  end
65
68
 
@@ -79,13 +82,28 @@ module E11y
79
82
  E11y::Current.span_id = span_id
80
83
  E11y::Current.parent_trace_id = parent_trace_id
81
84
  E11y::Current.request_id = job.job_id
85
+ E11y::Tracing::Propagator.hydrate_current_from_job_baggage!(job.e11y_baggage) if job.respond_to?(:e11y_baggage)
86
+
87
+ # Restore or compute sampling decision (ADR-005 §7)
88
+ if job.respond_to?(:e11y_sampled) && !job.e11y_sampled.nil?
89
+ E11y::Current.sampled = job.e11y_sampled
90
+ else
91
+ require "e11y/trace_context/sampler"
92
+ ctx = E11y::Current.to_context.merge(
93
+ job_class: job.class.name,
94
+ queue: job.queue_name
95
+ ).compact
96
+ E11y::Current.sampled = E11y::TraceContext::Sampler.should_sample?(ctx)
97
+ end
82
98
  end
83
99
 
84
100
  # Setup job-scoped buffer
85
101
  def setup_job_buffer_active_job
86
- return unless E11y.config.request_buffer&.enabled
102
+ return unless E11y.config.ephemeral_buffer_enabled
87
103
 
88
- E11y::Buffers::RequestScopedBuffer.initialize!
104
+ limit = E11y.config.ephemeral_buffer_job_buffer_limit ||
105
+ E11y::Buffers::EphemeralBuffer::DEFAULT_BUFFER_LIMIT
106
+ E11y::Buffers::EphemeralBuffer.initialize!(buffer_limit: limit)
89
107
  rescue StandardError => e
90
108
  # C18: Don't fail job if buffer setup fails
91
109
  warn "[E11y] Failed to start job buffer: #{e.message}"
@@ -93,9 +111,9 @@ module E11y
93
111
 
94
112
  # Handle job error (C18: Non-Failing Event Tracking)
95
113
  def handle_job_error_active_job(_error)
96
- return unless E11y.config.request_buffer&.enabled
114
+ return unless E11y.config.ephemeral_buffer_enabled
97
115
 
98
- E11y::Buffers::RequestScopedBuffer.flush_on_error
116
+ E11y::Buffers::EphemeralBuffer.flush_on_error
99
117
  rescue StandardError => e
100
118
  # C18: Don't fail job if buffer flush fails
101
119
  warn "[E11y] Failed to flush job buffer on error: #{e.message}"
@@ -104,9 +122,9 @@ module E11y
104
122
  # Cleanup job-scoped context
105
123
  def cleanup_job_context_active_job
106
124
  # Flush buffer on success (not on error, already flushed in rescue)
107
- if !$ERROR_INFO && E11y.config.request_buffer&.enabled
125
+ if !$ERROR_INFO && E11y.config.ephemeral_buffer_enabled
108
126
  begin
109
- E11y::Buffers::RequestScopedBuffer.discard
127
+ E11y::Buffers::EphemeralBuffer.discard
110
128
  rescue StandardError => e
111
129
  # C18: Don't fail job if buffer flush fails
112
130
  warn "[E11y] Failed to flush job buffer: #{e.message}"
@@ -139,10 +157,9 @@ module E11y
139
157
  # @param start_time [Time] Job start time
140
158
  # @return [void]
141
159
  # @api private
142
- # rubocop:disable Metrics/AbcSize
143
160
  # SLO tracking requires config check, duration calculation, method call, and error handling
144
161
  def track_job_slo_active_job(job, status, start_time)
145
- return unless E11y.config.slo_tracking&.enabled
162
+ return unless E11y.config.slo_tracking_enabled
146
163
 
147
164
  duration_ms = ((Time.now - start_time) * 1000).round(2)
148
165
 
@@ -157,7 +174,6 @@ module E11y
157
174
  # C18: Don't fail if SLO tracking fails
158
175
  E11y.logger.warn("[E11y] SLO tracking error: #{e.message}", error: e.class.name)
159
176
  end
160
- # rubocop:enable Metrics/AbcSize
161
177
  end
162
178
 
163
179
  # Custom attribute accessors for trace context (C17 Hybrid Tracing)
@@ -195,6 +211,22 @@ module E11y
195
211
  def e11y_span_id=(value)
196
212
  @e11y_span_id = value
197
213
  end
214
+
215
+ def e11y_sampled
216
+ @e11y_sampled
217
+ end
218
+
219
+ def e11y_sampled=(value)
220
+ @e11y_sampled = value
221
+ end
222
+
223
+ def e11y_baggage
224
+ @e11y_baggage
225
+ end
226
+
227
+ def e11y_baggage=(value)
228
+ @e11y_baggage = value
229
+ end
198
230
  end
199
231
  end
200
232
  end