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
data/CONTRIBUTING.md ADDED
@@ -0,0 +1,640 @@
1
+ # Contributing to e11y
2
+
3
+ Thank you for your interest in contributing to e11y! This document provides guidelines and best practices for contributing.
4
+
5
+ ## Table of Contents
6
+
7
+ - [Code of Conduct](#code-of-conduct)
8
+ - [Getting Started](#getting-started)
9
+ - [Development Workflow](#development-workflow)
10
+ - [Commit Message Guidelines](#commit-message-guidelines)
11
+ - [Pull Request Process](#pull-request-process)
12
+ - [Testing Guidelines](#testing-guidelines)
13
+ - [Code Style](#code-style)
14
+
15
+ ---
16
+
17
+ ## Code of Conduct
18
+
19
+ This project follows the [Contributor Covenant Code of Conduct](CODE_OF_CONDUCT.md). By participating, you are expected to uphold this code.
20
+
21
+ ---
22
+
23
+ ## Getting Started
24
+
25
+ ### Prerequisites
26
+
27
+ - Ruby 3.2 or 3.3
28
+ - Bundler 2.x
29
+ - Git
30
+
31
+ ### Setup
32
+
33
+ ```bash
34
+ # Clone the repository (fork first on GitHub)
35
+ git clone https://github.com/YOUR_USERNAME/e11y.git
36
+ cd e11y
37
+
38
+ # Run setup script (configures bundle, installs dependencies)
39
+ bin/setup
40
+
41
+ # Run tests
42
+ bundle exec rake spec:unit
43
+ bundle exec rake spec:integration
44
+ bundle exec rake spec:railtie
45
+
46
+ # Check code style
47
+ bundle exec rubocop
48
+ ```
49
+
50
+ ### Integration Dependencies (Optional)
51
+
52
+ For integration tests, Rails adapter, or OpenTelemetry:
53
+
54
+ ```bash
55
+ bundle install --with integration
56
+ ```
57
+
58
+ For Loki/OTel integration tests, start services first:
59
+
60
+ ```bash
61
+ docker compose up -d loki otel-collector
62
+ INTEGRATION=true bundle exec rspec spec/integration/
63
+ ```
64
+
65
+ ---
66
+
67
+ ## Development Workflow
68
+
69
+ ### 1. Create a Feature Branch
70
+
71
+ ```bash
72
+ git checkout -b feature/your-feature-name
73
+ # or
74
+ git checkout -b fix/your-bug-fix
75
+ ```
76
+
77
+ **Branch Naming Convention:**
78
+ - `feature/` - New features
79
+ - `fix/` - Bug fixes
80
+ - `refactor/` - Code refactoring
81
+ - `test/` - Test improvements
82
+ - `docs/` - Documentation updates
83
+ - `chore/` - Maintenance tasks
84
+
85
+ ### 2. Make Your Changes
86
+
87
+ - Write tests first (TDD approach)
88
+ - Ensure all tests pass
89
+ - Follow Ruby style guide (enforced by RuboCop)
90
+ - Add documentation for new features
91
+ - Update CHANGELOG.md
92
+
93
+ ### 3. Commit Your Changes
94
+
95
+ Follow [Conventional Commits](#commit-message-guidelines) format:
96
+
97
+ ```bash
98
+ git add .
99
+ git commit -m "feat(adapters): add OpenTelemetry logs adapter"
100
+ ```
101
+
102
+ ### 4. Push and Create PR
103
+
104
+ ```bash
105
+ git push origin feature/your-feature-name
106
+ ```
107
+
108
+ Then create a Pull Request on GitHub.
109
+
110
+ ---
111
+
112
+ ## Commit Message Guidelines
113
+
114
+ We use [Conventional Commits](https://www.conventionalcommits.org/) for clear and structured commit messages.
115
+
116
+ ### Format
117
+
118
+ ```
119
+ <type>(<scope>): <subject>
120
+
121
+ <body>
122
+
123
+ <footer>
124
+ ```
125
+
126
+ ### Type
127
+
128
+ - `feat` - New feature
129
+ - `fix` - Bug fix
130
+ - `docs` - Documentation only
131
+ - `style` - Formatting (no code change)
132
+ - `refactor` - Code refactoring
133
+ - `perf` - Performance improvements
134
+ - `test` - Adding/updating tests
135
+ - `chore` - Maintenance tasks
136
+ - `ci` - CI/CD changes
137
+
138
+ ### Scope
139
+
140
+ Component affected (optional but recommended):
141
+
142
+ - `adapters` - Adapters (Loki, Sentry, etc)
143
+ - `buffers` - Buffer implementations
144
+ - `events` - Event classes
145
+ - `instruments` - ActiveJob, Sidekiq, Rails
146
+ - `middleware` - Middleware stack
147
+ - `metrics` - Metrics and cardinality
148
+ - `pipeline` - Event pipeline
149
+ - `reliability` - Circuit breaker, DLQ, retry
150
+ - `sampling` - Sampling strategies
151
+ - `slo` - SLO tracking
152
+ - `rails` - Rails integration
153
+ - `ci` - CI/CD
154
+ - `deps` - Dependencies
155
+ - `docs` - Documentation
156
+ - `test` - Test infrastructure
157
+ - `config` - Configuration
158
+
159
+ ### Subject
160
+
161
+ - Use imperative mood: "add" not "added"
162
+ - Don't capitalize first letter
163
+ - No period at the end
164
+ - Maximum 72 characters
165
+
166
+ ### Examples
167
+
168
+ **Good Commit Messages:**
169
+
170
+ ```
171
+ feat(adapters): add OpenTelemetry logs adapter
172
+
173
+ Implement OTelLogs adapter with:
174
+ - Severity mapping (Ruby Logger → OpenTelemetry)
175
+ - Attribute conversion (tags → log attributes)
176
+ - Trace context propagation
177
+
178
+ Closes #42
179
+
180
+ ---
181
+
182
+ fix(buffers): prevent memory leak in ring buffer
183
+
184
+ Ring buffer was not releasing old events when capacity reached.
185
+ Added proper cleanup in #push method.
186
+
187
+ Performance impact: minimal (< 1% overhead)
188
+
189
+ ---
190
+
191
+ refactor(middleware): extract routing logic to separate class
192
+
193
+ Routing logic was embedded in Middleware::Base making it hard to test.
194
+ Extracted to Middleware::Routing for better separation of concerns.
195
+
196
+ ---
197
+
198
+ test(integration): add Rails 8.0 compatibility tests
199
+
200
+ Added test matrix for Ruby 3.2/3.3 × Rails 7.0/7.1/8.0
201
+ All combinations pass except Rails 8.0 exception handling (known issue)
202
+
203
+ ---
204
+
205
+ docs(readme): update installation instructions
206
+
207
+ Added section on Rails 8.0 compatibility
208
+ Updated gem version requirement to ~> 0.1.1
209
+ ```
210
+
211
+ **Bad Commit Messages:**
212
+
213
+ ```
214
+ Fix # Too vague, no scope, no description
215
+ Update # Not descriptive
216
+ WIP # Work in progress should not be committed
217
+ Changes # Too generic
218
+ fix: Fix bug # Redundant, should be: fix(scope): describe the bug
219
+ Fixed the thing # Not imperative mood, no scope
220
+ feat: added new feature. # Should be lowercase, no period
221
+ ```
222
+
223
+ ### Commit Message Linting
224
+
225
+ We use commitlint to enforce these rules:
226
+
227
+ ```bash
228
+ # Install commitlint (one-time setup)
229
+ npm install -g @commitlint/cli @commitlint/config-conventional
230
+
231
+ # Check last commit
232
+ commitlint --from HEAD~1 --to HEAD --verbose
233
+
234
+ # Check all commits in branch
235
+ commitlint --from main --to HEAD --verbose
236
+ ```
237
+
238
+ ---
239
+
240
+ ## Pull Request Process
241
+
242
+ ### Before Creating PR
243
+
244
+ 1. **Ensure your branch is up to date:**
245
+ ```bash
246
+ git checkout main
247
+ git pull origin main
248
+ git checkout your-branch
249
+ git rebase main
250
+ ```
251
+
252
+ 2. **Run all tests:**
253
+ ```bash
254
+ bundle exec rake spec:unit
255
+ bundle exec rake spec:integration
256
+ bundle exec rake spec:railtie
257
+ ```
258
+
259
+ 3. **Check code style:**
260
+ ```bash
261
+ bundle exec rubocop
262
+ ```
263
+
264
+ 4. **Verify coverage:**
265
+ ```bash
266
+ bundle exec rake spec:coverage
267
+ # Coverage should be ≥95%
268
+ ```
269
+
270
+ 5. **Update documentation:**
271
+ - Update README.md if needed
272
+ - Add/update CHANGELOG.md
273
+ - Create ADR if making architectural decision
274
+
275
+ ### PR Guidelines
276
+
277
+ - **Keep PRs small:** \<500 lines of code
278
+ - **One logical change per PR:** Don't mix refactoring with features
279
+ - **Write descriptive PR title:** Follow Conventional Commits format
280
+ - **Fill out PR template:** Don't skip sections
281
+ - **Self-review:** Read your own PR before requesting review
282
+ - **Add tests:** PRs without tests will not be merged
283
+ - **Update docs:** Update relevant documentation
284
+
285
+ ### PR Title Format
286
+
287
+ Same as commit messages:
288
+
289
+ ```
290
+ feat(adapters): add OpenTelemetry logs adapter
291
+ fix(buffers): prevent memory leak in ring buffer
292
+ docs(readme): update installation instructions
293
+ ```
294
+
295
+ ### PR Size Guidelines
296
+
297
+ | Lines Changed | Review Time | Merge Probability |
298
+ |---------------|-------------|-------------------|
299
+ | \<100 | 30 min | 95% |
300
+ | 100-300 | 1-2 hours | 85% |
301
+ | 300-500 | 2-4 hours | 70% |
302
+ | \>500 | 4+ hours | 50% |
303
+
304
+ **Recommendation:** Break large PRs into smaller, logical units.
305
+
306
+ ### Stacked PRs
307
+
308
+ For large features, use stacked PRs:
309
+
310
+ ```
311
+ PR #1: feat(adapters): add OTel base adapter
312
+ └── PR #2: feat(adapters): add OTel logs adapter
313
+ └── PR #3: feat(adapters): add OTel metrics adapter
314
+ ```
315
+
316
+ Each PR builds on the previous one and can be reviewed independently.
317
+
318
+ ---
319
+
320
+ ## Testing Guidelines
321
+
322
+ ### Test Organization
323
+
324
+ ```
325
+ spec/
326
+ ├── e11y/ # Unit tests (fast, isolated)
327
+ ├── integration/ # Integration tests (Rails app, adapters)
328
+ └── support/ # Shared test helpers
329
+ ```
330
+
331
+ ### Test Types
332
+
333
+ **Unit Tests** (`spec/e11y/`):
334
+ - Fast (\<10ms each)
335
+ - No external dependencies
336
+ - Test single class/module
337
+ - Use mocks/stubs liberally
338
+
339
+ **Integration Tests** (`spec/integration/`):
340
+ - Slower (50-500ms each)
341
+ - Full Rails app
342
+ - Test component interactions
343
+ - Minimal mocking
344
+
345
+ ### Running Tests
346
+
347
+ ```bash
348
+ # All tests
349
+ bundle exec rspec
350
+
351
+ # Unit tests only
352
+ bundle exec rake spec:unit
353
+
354
+ # Integration tests only
355
+ bundle exec rake spec:integration
356
+
357
+ # Specific file
358
+ bundle exec rspec spec/e11y/buffers/ring_buffer_spec.rb
359
+
360
+ # Specific example
361
+ bundle exec rspec spec/e11y/buffers/ring_buffer_spec.rb:42
362
+ ```
363
+
364
+ ### Test Coverage
365
+
366
+ We maintain ≥95% test coverage:
367
+
368
+ ```bash
369
+ # Generate coverage report
370
+ bundle exec rake spec:coverage
371
+
372
+ # View report
373
+ open coverage/index.html
374
+ ```
375
+
376
+ **Coverage Requirements:**
377
+ - New code: 100% coverage
378
+ - Modified code: Maintain or improve coverage
379
+ - Exceptions: Document in PR why coverage is lower
380
+
381
+ ### Writing Good Tests
382
+
383
+ ```ruby
384
+ # Good test structure
385
+ RSpec.describe E11y::Buffers::RingBuffer do
386
+ subject(:buffer) { described_class.new(capacity: 3) }
387
+
388
+ describe '#push' do
389
+ context 'when buffer is not full' do
390
+ it 'adds event to buffer' do
391
+ buffer.push(event)
392
+ expect(buffer.size).to eq(1)
393
+ end
394
+ end
395
+
396
+ context 'when buffer is full' do
397
+ before do
398
+ 3.times { buffer.push(create_event) }
399
+ end
400
+
401
+ it 'evicts oldest event' do
402
+ oldest_event = buffer.first
403
+ buffer.push(new_event)
404
+ expect(buffer).not_to include(oldest_event)
405
+ end
406
+ end
407
+ end
408
+ end
409
+ ```
410
+
411
+ **Test Best Practices:**
412
+ - One assertion per test (when possible)
413
+ - Use descriptive test names
414
+ - Use `let` for shared setup
415
+ - Use `subject` for the object under test
416
+ - Use `before` for common setup
417
+ - Use `context` for different scenarios
418
+ - Test edge cases and error paths
419
+
420
+ ---
421
+
422
+ ## Code Style
423
+
424
+ ### Ruby Style Guide
425
+
426
+ We follow the [Ruby Style Guide](https://rubystyle.guide/) enforced by RuboCop.
427
+
428
+ ### Key Conventions
429
+
430
+ **Naming:**
431
+ ```ruby
432
+ # Classes: PascalCase
433
+ class EventProcessor
434
+ end
435
+
436
+ # Methods: snake_case
437
+ def process_event(event)
438
+ end
439
+
440
+ # Constants: SCREAMING_SNAKE_CASE
441
+ MAX_BUFFER_SIZE = 1000
442
+
443
+ # Files: snake_case.rb
444
+ lib/e11y/buffers/ring_buffer.rb
445
+ ```
446
+
447
+ **Code Organization:**
448
+ ```ruby
449
+ # Order: constants, attributes, initializer, public, protected, private
450
+ class Adapter
451
+ MAX_RETRIES = 3
452
+
453
+ attr_reader :config
454
+
455
+ def initialize(config)
456
+ @config = config
457
+ end
458
+
459
+ def emit(event)
460
+ # public method
461
+ end
462
+
463
+ protected
464
+
465
+ def validate(event)
466
+ # protected method
467
+ end
468
+
469
+ private
470
+
471
+ def internal_method
472
+ # private method
473
+ end
474
+ end
475
+ ```
476
+
477
+ **Performance:**
478
+ ```ruby
479
+ # Use #each instead of #map when not using return value
480
+ events.each { |event| process(event) }
481
+
482
+ # Use #select instead of #map + #compact
483
+ events.select { |event| event.valid? }
484
+
485
+ # Use ||= for memoization
486
+ def expensive_calculation
487
+ @result ||= perform_calculation
488
+ end
489
+ ```
490
+
491
+ ### RuboCop
492
+
493
+ ```bash
494
+ # Check violations
495
+ bundle exec rubocop
496
+
497
+ # Auto-fix (safe corrections only)
498
+ bundle exec rubocop --auto-correct
499
+
500
+ # Auto-fix (including unsafe corrections)
501
+ bundle exec rubocop --auto-correct-all
502
+
503
+ # Check specific file
504
+ bundle exec rubocop lib/e11y/buffers/ring_buffer.rb
505
+ ```
506
+
507
+ ### RuboCop Configuration
508
+
509
+ Our RuboCop config (`.rubocop.yml`) enforces:
510
+ - Ruby 3.2+ syntax
511
+ - Max line length: 120 characters
512
+ - Max method length: 25 lines
513
+ - Max class length: 250 lines
514
+ - Max cyclomatic complexity: 10
515
+
516
+ ---
517
+
518
+ ## Documentation
519
+
520
+ ### Project Documentation
521
+
522
+ - [Architecture Decisions (ADRs)](docs/architecture/ADR-INDEX.md)
523
+ - [Quick Start](docs/QUICK-START.md)
524
+
525
+ ### Code Documentation
526
+
527
+ Use YARD for documentation:
528
+
529
+ ```ruby
530
+ # @param event [E11y::Event::Base] Event to emit
531
+ # @param options [Hash] Additional options
532
+ # @option options [Boolean] :async (false) Emit asynchronously
533
+ # @return [Boolean] true if successful
534
+ # @raise [ArgumentError] if event is invalid
535
+ #
536
+ # @example Emit event synchronously
537
+ # adapter.emit(event)
538
+ #
539
+ # @example Emit event asynchronously
540
+ # adapter.emit(event, async: true)
541
+ def emit(event, options = {})
542
+ # implementation
543
+ end
544
+ ```
545
+
546
+ ### Inline Comments
547
+
548
+ ```ruby
549
+ # Good: Explain WHY, not WHAT
550
+ # Buffer uses ring structure to prevent unbounded growth
551
+ # while maintaining insertion performance O(1)
552
+ buffer = RingBuffer.new(capacity: 1000)
553
+
554
+ # Bad: Obvious comment (don't do this)
555
+ # Create new buffer
556
+ buffer = RingBuffer.new
557
+ ```
558
+
559
+ ---
560
+
561
+ ## Architecture Decision Records (ADRs)
562
+
563
+ For significant architectural decisions, create an ADR in `docs/`:
564
+
565
+ ```bash
566
+ # Create new ADR (see docs/architecture/ADR-INDEX.md for numbering)
567
+ # Follow format of existing ADRs (docs/architecture/ADR-001-architecture.md, etc.)
568
+ ```
569
+
570
+ **When to create ADR:**
571
+ - Changing core architecture
572
+ - Adding/removing major dependencies
573
+ - Breaking API changes
574
+ - Performance vs maintainability tradeoffs
575
+
576
+ **ADR Template:**
577
+ ```markdown
578
+ # ADR-018: Title
579
+
580
+ ## Status
581
+ Proposed | Accepted | Deprecated | Superseded by ADR-XXX
582
+
583
+ ## Context
584
+ What is the problem we're solving?
585
+
586
+ ## Decision
587
+ What did we decide to do?
588
+
589
+ ## Consequences
590
+ What are the positive and negative outcomes?
591
+
592
+ ## Alternatives Considered
593
+ What other options did we consider?
594
+ ```
595
+
596
+ ---
597
+
598
+ ## Security
599
+
600
+ ```bash
601
+ # Check for vulnerable dependencies
602
+ bundle exec bundler-audit check --update
603
+
604
+ # Static security analysis (if Brakeman installed)
605
+ bundle exec brakeman
606
+ ```
607
+
608
+ ## Reporting Bugs
609
+
610
+ **Before reporting:** Search existing issues, verify bug exists in main.
611
+
612
+ **Bug report template:**
613
+ - Describe the bug
614
+ - Steps to reproduce
615
+ - Expected vs actual behavior
616
+ - Environment (Ruby, E11y, Rails, OS versions)
617
+
618
+ ## Suggesting Features
619
+
620
+ **Feature request template:**
621
+ - Problem being solved
622
+ - Proposed solution
623
+ - Alternatives considered
624
+ - Additional context
625
+
626
+ ## Getting Help
627
+
628
+ - **Questions:** Open a GitHub Discussion
629
+ - **Bugs:** Open a GitHub Issue
630
+ - **Security:** Private disclosure via GitHub Security Advisories
631
+
632
+ ---
633
+
634
+ ## License
635
+
636
+ By contributing, you agree that your contributions will be licensed under the MIT License.
637
+
638
+ ---
639
+
640
+ Thank you for contributing to e11y! 🎉