e11y 1.0.0 โ 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +24 -0
- data/README.md +38 -6
- data/RELEASE.md +23 -9
- data/Rakefile +141 -28
- data/docs/QUICK-START.md +2 -2
- data/docs/RAILS_INTEGRATION.md +64 -14
- data/docs/architecture/ADR-001-architecture.md +1 -1
- data/docs/architecture/ADR-003-slo-observability.md +58 -1554
- data/docs/architecture/ADR-008-rails-integration.md +81 -512
- data/docs/architecture/ADR-011-testing-strategy.md +3 -3
- data/docs/architecture/ADR-012-event-evolution.md +11 -11
- data/docs/architecture/ADR-015-middleware-order.md +22 -20
- data/docs/architecture/ADR-016-self-monitoring-slo.md +6 -6
- data/docs/plans/2026-03-20-browser-overlay-svelte.md +281 -0
- data/docs/use_cases/UC-004-zero-config-slo-tracking.md +33 -625
- data/docs/use_cases/UC-009-multi-service-tracing.md +26 -174
- data/docs/use_cases/UC-010-background-job-tracking.md +19 -86
- data/gems/e11y-devtools/README.md +28 -6
- data/gems/e11y-devtools/config/routes.rb +7 -0
- data/gems/e11y-devtools/e11y-devtools.gemspec +1 -1
- data/gems/e11y-devtools/frontend/.gitignore +24 -0
- data/gems/e11y-devtools/frontend/README.md +51 -0
- data/gems/e11y-devtools/frontend/index.html +14 -0
- data/gems/e11y-devtools/frontend/package-lock.json +3707 -0
- data/gems/e11y-devtools/frontend/package.json +28 -0
- data/gems/e11y-devtools/frontend/public/mocks/v1/events/recent.json +4205 -0
- data/gems/e11y-devtools/frontend/public/mocks/v1/interactions.json +194 -0
- data/gems/e11y-devtools/frontend/public/mocks/v1/traces/0a2e04027cfa22d014bc22e8b27cd913/events.json +86 -0
- data/gems/e11y-devtools/frontend/public/mocks/v1/traces/0e1543af6a630fb3af6b52283154b3e0/events.json +169 -0
- data/gems/e11y-devtools/frontend/public/mocks/v1/traces/1838b691faa49564f97db8592ff3978d/events.json +78 -0
- data/gems/e11y-devtools/frontend/public/mocks/v1/traces/29f198f6588dacffb687777eb5f8f118/events.json +197 -0
- data/gems/e11y-devtools/frontend/public/mocks/v1/traces/34bc3c9c0097de28a7a6f99b90a8e7bc/events.json +194 -0
- data/gems/e11y-devtools/frontend/public/mocks/v1/traces/3ba6c20d068ab9cee00e51b180e66444/events.json +184 -0
- data/gems/e11y-devtools/frontend/public/mocks/v1/traces/435bfd8f17b9009146a79812d7c3726d/events.json +144 -0
- data/gems/e11y-devtools/frontend/public/mocks/v1/traces/4c7676e3fe668e99edb2b94d7d5678a9/events.json +222 -0
- data/gems/e11y-devtools/frontend/public/mocks/v1/traces/6daf0d47974bedfc55d5de7004a3ea9f/events.json +194 -0
- data/gems/e11y-devtools/frontend/public/mocks/v1/traces/8a81ada42834d15f287bb40010043605/events.json +194 -0
- data/gems/e11y-devtools/frontend/public/mocks/v1/traces/8c0a98900edaae105469df8daedccf02/events.json +198 -0
- data/gems/e11y-devtools/frontend/public/mocks/v1/traces/8e4f645180f8a7d1dce426b07380466b/events.json +222 -0
- data/gems/e11y-devtools/frontend/public/mocks/v1/traces/93db346fa5d44a032605a13b627f4b80/events.json +128 -0
- data/gems/e11y-devtools/frontend/public/mocks/v1/traces/98ff6146faf7bd9be8bd03a8275817ba/events.json +223 -0
- data/gems/e11y-devtools/frontend/public/mocks/v1/traces/9997ddd0247bc7e25f2ca7a5c415c93d/events.json +197 -0
- data/gems/e11y-devtools/frontend/public/mocks/v1/traces/99e35f8ef3baedd798cc4fd085980ad9/events.json +194 -0
- data/gems/e11y-devtools/frontend/public/mocks/v1/traces/b4f3095c1909924cbc98889a86c83d6d/events.json +131 -0
- data/gems/e11y-devtools/frontend/public/mocks/v1/traces/b54b7fc32b7575a7110de809d11ccda0/events.json +128 -0
- data/gems/e11y-devtools/frontend/public/mocks/v1/traces/c0b48033fa06746bcc5886745e053cff/events.json +169 -0
- data/gems/e11y-devtools/frontend/public/mocks/v1/traces/c44649ac76701b4558927cd2305ab535/events.json +169 -0
- data/gems/e11y-devtools/frontend/public/mocks/v1/traces/d601ae3320057580a39dbdac2edfdf4a/events.json +248 -0
- data/gems/e11y-devtools/frontend/public/mocks/v1/traces/e67e724bab422d2b52eeb49635e512e1/events.json +194 -0
- data/gems/e11y-devtools/frontend/public/mocks/v1/traces/e6c72765a28f158a8485b35fa63f73da/events.json +194 -0
- data/gems/e11y-devtools/frontend/public/mocks/v1/traces/f541b87405c9a54819b18ebe529f6419/events.json +194 -0
- data/gems/e11y-devtools/frontend/scripts/generate_mocks.rb +397 -0
- data/gems/e11y-devtools/frontend/src/App.svelte +827 -0
- data/gems/e11y-devtools/frontend/src/components/Fab.svelte +19 -0
- data/gems/e11y-devtools/frontend/src/components/FilterBar.svelte +38 -0
- data/gems/e11y-devtools/frontend/src/components/FullscreenPanel.svelte +82 -0
- data/gems/e11y-devtools/frontend/src/components/InteractionsTimeline.svelte +264 -0
- data/gems/e11y-devtools/frontend/src/components/RecentHistogram.svelte +354 -0
- data/gems/e11y-devtools/frontend/src/lib/api.ts +37 -0
- data/gems/e11y-devtools/frontend/src/lib/eventIdentity.ts +12 -0
- data/gems/e11y-devtools/frontend/src/lib/format.ts +37 -0
- data/gems/e11y-devtools/frontend/src/lib/listFilter.ts +43 -0
- data/gems/e11y-devtools/frontend/src/lib/recentVolume.ts +80 -0
- data/gems/e11y-devtools/frontend/src/lib/router.ts +12 -0
- data/gems/e11y-devtools/frontend/src/lib/transitions.ts +34 -0
- data/gems/e11y-devtools/frontend/src/lib/viewportOrigin.ts +25 -0
- data/gems/e11y-devtools/frontend/src/main.ts +8 -0
- data/gems/e11y-devtools/frontend/src/overlay-entry.ts +24 -0
- data/gems/e11y-devtools/frontend/src/overlay.css +1080 -0
- data/gems/e11y-devtools/frontend/svelte.config.js +2 -0
- data/gems/e11y-devtools/frontend/test_puppeteer.js +41 -0
- data/gems/e11y-devtools/frontend/test_scale.js +3 -0
- data/gems/e11y-devtools/frontend/tsconfig.app.json +21 -0
- data/gems/e11y-devtools/frontend/tsconfig.json +7 -0
- data/gems/e11y-devtools/frontend/tsconfig.node.json +26 -0
- data/gems/e11y-devtools/frontend/vite.config.ts +36 -0
- data/gems/e11y-devtools/lib/e11y/devtools/overlay/assets/overlay.js +20 -115
- data/gems/e11y-devtools/lib/e11y/devtools/overlay/controller.rb +40 -0
- data/gems/e11y-devtools/lib/e11y/devtools/overlay/rails_controller.rb +25 -0
- data/gems/e11y-devtools/lib/e11y/devtools/version.rb +2 -2
- data/gems/e11y-devtools/spec/e11y/devtools/overlay/controller_spec.rb +33 -0
- data/lib/e11y/adapters/file.rb +1 -1
- data/lib/e11y/instruments/active_job.rb +3 -5
- data/lib/e11y/instruments/sidekiq.rb +3 -5
- data/lib/e11y/pipeline/builder.rb +3 -3
- data/lib/e11y/railtie.rb +3 -2
- data/lib/e11y/tracing/propagator.rb +28 -0
- data/lib/e11y/version.rb +1 -1
- data/lib/e11y.rb +1 -20
- data/lib/generators/e11y/install/templates/e11y.rb +2 -2
- metadata +58 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 4cf2b7d2a17ee4e2474c6a286fe16e1c6dc3f3f6c62c687c21e6e19ff2326cff
|
|
4
|
+
data.tar.gz: cf70471e2647774b1ca4fa34c54cb731eed9adee5a6fb4e3b45203030a0c2843
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: f06a9a21e21cf3c287a0e5b271d15bbd1d8d453bf1168e9a1ef5a37eb3f1390f627b14801a02c668e6ae063ba12bcaf5854ba76ce4288ec4050b2a2e6eea18f1
|
|
7
|
+
data.tar.gz: c862108b20fc6c9da7ec1672baeb037dbbc4ac10fa06d713c8306c0ca1fd58c2e4bafec2b7a935fee2afc6bf7a1bd6741fb3a386b87edd024fa3c91e521c017d
|
data/CHANGELOG.md
CHANGED
|
@@ -19,6 +19,26 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
19
19
|
|
|
20
20
|
### Security
|
|
21
21
|
|
|
22
|
+
## [1.1.0] - 2026-03-23
|
|
23
|
+
|
|
24
|
+
### Added
|
|
25
|
+
|
|
26
|
+
- Sidekiq and Active Job: propagate **`user_id`** into **`e11y_baggage`** (and restore **`E11y::Current.user_id`** when the job runs). Key **`user_id`** is included in default baggage allowlist.
|
|
27
|
+
|
|
28
|
+
### Changed
|
|
29
|
+
|
|
30
|
+
### Fixed
|
|
31
|
+
|
|
32
|
+
- **Rails Railtie:** `config.enabled` is defaulted with `!Rails.env.test?` **only when still `nil`**, so an explicit `true`/`false` from `E11y.configure` in `config/application.rb` (or any code that runs before `before_initialize`) is no longer overwritten.
|
|
33
|
+
|
|
34
|
+
### Deprecated
|
|
35
|
+
|
|
36
|
+
### Removed
|
|
37
|
+
|
|
38
|
+
- **`E11y.track`** โ removed. Call **`YourEvent.track(...)`** on the event class only.
|
|
39
|
+
|
|
40
|
+
### Security
|
|
41
|
+
|
|
22
42
|
## [1.0.0] - 2026-03-20
|
|
23
43
|
|
|
24
44
|
### BREAKING: Configuration โ Flat config API
|
|
@@ -64,8 +84,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
64
84
|
|
|
65
85
|
### Added
|
|
66
86
|
|
|
87
|
+
- Monorepo release tooling: `rake release:build_gems` and `rake release:gem_push` build/publish **e11y** and **e11y-devtools**; optional `release:rubygems:push_core` / `push_devtools`; GitHub Release workflow attaches both `.gem` files.
|
|
88
|
+
|
|
67
89
|
### Changed
|
|
68
90
|
|
|
91
|
+
- **e11y-devtools** 0.1.1 โ depends on **e11y** `~> 1.0` (`CORE_VERSION`); README Gemfile example updated.
|
|
92
|
+
|
|
69
93
|
### Fixed
|
|
70
94
|
|
|
71
95
|
### Deprecated
|
data/README.md
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
|
|
11
11
|
[Quick Start](#quick-start) โข [How it works](#the-e11y-solution) โข [Docs](#documentation)
|
|
12
12
|
|
|
13
|
-
>
|
|
13
|
+
> v1.0.0 ยท Actively developed ยท Production feedback welcome โ [open an issue](https://github.com/arturseletskiy/e11y/issues)
|
|
14
14
|
|
|
15
15
|
</div>
|
|
16
16
|
|
|
@@ -93,8 +93,11 @@ end
|
|
|
93
93
|
|
|
94
94
|
# 3. Track it
|
|
95
95
|
OrderPaidEvent.track(order_id: "123", amount: 99.99, currency: "USD")
|
|
96
|
+
|
|
96
97
|
```
|
|
97
98
|
|
|
99
|
+
**Public API:** define events as subclasses of `E11y::Event::Base` and call **`.track(...)`** on the event class (for example `OrderPaidEvent.track(...)`). That is the only supported tracking entry point in application code.
|
|
100
|
+
|
|
98
101
|
โ [Full Quick Start guide (5 min)](#quick-start)
|
|
99
102
|
|
|
100
103
|
---
|
|
@@ -221,11 +224,19 @@ gem "e11y"
|
|
|
221
224
|
E11y.configure do |config|
|
|
222
225
|
config.adapters[:logs] = E11y::Adapters::Loki.new(url: ENV["LOKI_URL"])
|
|
223
226
|
config.adapters[:errors_tracker] = E11y::Adapters::Sentry.new(dsn: ENV["SENTRY_DSN"])
|
|
224
|
-
end
|
|
225
227
|
|
|
226
|
-
#
|
|
227
|
-
config.rails_instrumentation_enabled = true
|
|
228
|
-
|
|
228
|
+
# ActiveSupport::Notifications โ E11y (HTTP, DB, cache, job lifecycle, etc.)
|
|
229
|
+
config.rails_instrumentation_enabled = true
|
|
230
|
+
|
|
231
|
+
# Optional: Sidekiq client/server middleware (buffer + job events) โ enable if you use Sidekiq
|
|
232
|
+
config.sidekiq_enabled = true
|
|
233
|
+
|
|
234
|
+
# Optional: ActiveJob callbacks (buffer + context) โ enable if you use Active Job
|
|
235
|
+
config.active_job_enabled = true
|
|
236
|
+
|
|
237
|
+
# Optional: wrap Rails.logger and emit E11y::Events::Rails::Log::* โ opt-in
|
|
238
|
+
# config.logger_bridge_enabled = true
|
|
239
|
+
end
|
|
229
240
|
```
|
|
230
241
|
|
|
231
242
|
**vs. Traditional Observability:**
|
|
@@ -322,8 +333,17 @@ E11y.configure do |config|
|
|
|
322
333
|
dsn: ENV["SENTRY_DSN"]
|
|
323
334
|
)
|
|
324
335
|
|
|
325
|
-
#
|
|
336
|
+
# ActiveSupport::Notifications โ E11y (see docs/RAILS_INTEGRATION.md)
|
|
326
337
|
config.rails_instrumentation_enabled = true
|
|
338
|
+
|
|
339
|
+
# Optional: Sidekiq / ActiveJob (ephemeral buffer + instrumentation at job boundaries)
|
|
340
|
+
config.sidekiq_enabled = true # set if you use Sidekiq
|
|
341
|
+
config.active_job_enabled = true # set if you use Active Job (in addition or instead)
|
|
342
|
+
|
|
343
|
+
# Optional: send Rails.logger lines into E11y as structured events
|
|
344
|
+
# config.logger_bridge_enabled = true
|
|
345
|
+
# config.logger_bridge_track_severities = [:warn, :error, :fatal] # nil = all severities
|
|
346
|
+
# config.logger_bridge_ignore_patterns = [%r{\A\[ActiveJob\]}]
|
|
327
347
|
end
|
|
328
348
|
```
|
|
329
349
|
|
|
@@ -532,6 +552,18 @@ p99 latency <70ยตs (`:always`), <10ยตs (`:sampled`), <50ยตs (`:never`). Full ben
|
|
|
532
552
|
|
|
533
553
|
---
|
|
534
554
|
|
|
555
|
+
## Upgrading
|
|
556
|
+
|
|
557
|
+
Breaking renames and migration steps are listed in [CHANGELOG.md](CHANGELOG.md). Common ones:
|
|
558
|
+
|
|
559
|
+
- **`RequestScopedBuffer` โ `E11y::Buffers::EphemeralBuffer`** โ use `initialize!`, `flush_on_error`, and `discard` at request/job boundaries (middleware and instruments already do this).
|
|
560
|
+
- **Sidekiq / Active Job** โ enable with `config.sidekiq_enabled` and `config.active_job_enabled`; see [docs/RAILS_INTEGRATION.md](docs/RAILS_INTEGRATION.md).
|
|
561
|
+
- **Logger bridge** โ `config.logger_bridge_enabled` plus optional `logger_bridge_track_severities` and `logger_bridge_ignore_patterns` (same file).
|
|
562
|
+
|
|
563
|
+
Known tradeoffs and unfinished pieces: [docs/LIMITATIONS.md](docs/LIMITATIONS.md).
|
|
564
|
+
|
|
565
|
+
---
|
|
566
|
+
|
|
535
567
|
## Documentation
|
|
536
568
|
|
|
537
569
|
| Topic | Doc |
|
data/RELEASE.md
CHANGED
|
@@ -68,7 +68,7 @@ git commit -m "Bump version to 0.2.0"
|
|
|
68
68
|
|
|
69
69
|
### Step 1: Prepare Release
|
|
70
70
|
|
|
71
|
-
Run tests, build
|
|
71
|
+
Run tests, build both gems, create tag:
|
|
72
72
|
|
|
73
73
|
```bash
|
|
74
74
|
rake release:prep
|
|
@@ -77,8 +77,14 @@ rake release:prep
|
|
|
77
77
|
This will:
|
|
78
78
|
- โ
Check git status (fails if uncommitted changes)
|
|
79
79
|
- โ
Run full test suite
|
|
80
|
-
- โ
Build gem
|
|
81
|
-
- โ
Create annotated git tag
|
|
80
|
+
- โ
Build **e11y** and **e11y-devtools** `.gem` files (devtools is built under `gems/e11y-devtools/`)
|
|
81
|
+
- โ
Create annotated git tag `v<e11y-version>` (tag follows the core gem only)
|
|
82
|
+
|
|
83
|
+
Build gems without tests (e.g. after a failed spec run you already trust):
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
rake release:build_gems
|
|
87
|
+
```
|
|
82
88
|
|
|
83
89
|
Or manually:
|
|
84
90
|
|
|
@@ -86,8 +92,9 @@ Or manually:
|
|
|
86
92
|
# Run all tests
|
|
87
93
|
bundle exec rspec
|
|
88
94
|
|
|
89
|
-
# Build
|
|
95
|
+
# Build gems
|
|
90
96
|
gem build e11y.gemspec
|
|
97
|
+
(cd gems/e11y-devtools && gem build e11y-devtools.gemspec)
|
|
91
98
|
|
|
92
99
|
# Create and push tag
|
|
93
100
|
git tag -a v0.2.0 -m "Release v0.2.0"
|
|
@@ -114,10 +121,16 @@ rake release:gem_push
|
|
|
114
121
|
```
|
|
115
122
|
|
|
116
123
|
This will:
|
|
117
|
-
- โ
Verify gem
|
|
118
|
-
- โ
Prompt for confirmation
|
|
119
|
-
- โ
Push
|
|
120
|
-
|
|
124
|
+
- โ
Verify both `.gem` files exist (e11y in repo root, e11y-devtools under `gems/e11y-devtools/`)
|
|
125
|
+
- โ
Prompt once for confirmation
|
|
126
|
+
- โ
Push **e11y** first, then **e11y-devtools** (each `gem push` may ask for MFA)
|
|
127
|
+
|
|
128
|
+
Push only one gem if needed:
|
|
129
|
+
|
|
130
|
+
```bash
|
|
131
|
+
rake release:rubygems:push_core # e11y only
|
|
132
|
+
rake release:rubygems:push_devtools # e11y-devtools only
|
|
133
|
+
```
|
|
121
134
|
|
|
122
135
|
Or manually:
|
|
123
136
|
|
|
@@ -133,8 +146,9 @@ Or manually:
|
|
|
133
146
|
# Sign in to RubyGems (one-time setup)
|
|
134
147
|
gem signin
|
|
135
148
|
|
|
136
|
-
# Push the
|
|
149
|
+
# Push the gems (requires MFA; e11y first โ devtools depends on it)
|
|
137
150
|
gem push e11y-0.1.0.gem
|
|
151
|
+
gem push gems/e11y-devtools/e11y-devtools-0.1.0.gem
|
|
138
152
|
```
|
|
139
153
|
|
|
140
154
|
Expected output:
|
data/Rakefile
CHANGED
|
@@ -9,7 +9,8 @@
|
|
|
9
9
|
# rake release:full # Complete release workflow (prep + git_push + gem_push)
|
|
10
10
|
# rake release:prep # Run tests, build gem, create tag
|
|
11
11
|
# rake release:git_push # Push to GitHub
|
|
12
|
-
# rake release:gem_push # Publish to RubyGems
|
|
12
|
+
# rake release:gem_push # Publish e11y + e11y-devtools to RubyGems
|
|
13
|
+
# rake release:build_gems # Build both .gem packages (no tests)
|
|
13
14
|
# rake spec:all # Run all test suites
|
|
14
15
|
# rake spec:unit # Run unit tests only (fast)
|
|
15
16
|
# rake spec:integration # Run integration tests
|
|
@@ -26,6 +27,9 @@ def e11y_devtools_specs_available?
|
|
|
26
27
|
File.directory?(File.join(__dir__, "gems/e11y-devtools/spec"))
|
|
27
28
|
end
|
|
28
29
|
|
|
30
|
+
# Built with: (cd gems/e11y-devtools && gem build โฆ) โ .gem stays in this directory
|
|
31
|
+
E11Y_DEVTOOLS_GEM_DIR = File.expand_path("gems/e11y-devtools", __dir__).freeze
|
|
32
|
+
|
|
29
33
|
RSpec::Core::RakeTask.new(:spec)
|
|
30
34
|
|
|
31
35
|
RuboCop::RakeTask.new
|
|
@@ -277,6 +281,31 @@ namespace :release do
|
|
|
277
281
|
puts "#{'=' * 80}\n"
|
|
278
282
|
end
|
|
279
283
|
|
|
284
|
+
desc "Build e11y and e11y-devtools .gem files (no tests; devtools built in its directory)"
|
|
285
|
+
task :build_gems do
|
|
286
|
+
require_relative "lib/e11y/version"
|
|
287
|
+
require_relative "gems/e11y-devtools/lib/e11y/devtools/version"
|
|
288
|
+
|
|
289
|
+
puts "\n[build] e11y v#{E11y::VERSION}..."
|
|
290
|
+
unless system("gem build e11y.gemspec")
|
|
291
|
+
puts "โ Error: Failed to build e11y gem"
|
|
292
|
+
exit 1
|
|
293
|
+
end
|
|
294
|
+
|
|
295
|
+
puts "\n[build] e11y-devtools v#{E11y::Devtools::VERSION}..."
|
|
296
|
+
Dir.chdir(E11Y_DEVTOOLS_GEM_DIR) do
|
|
297
|
+
unless system("gem build e11y-devtools.gemspec")
|
|
298
|
+
puts "โ Error: Failed to build e11y-devtools gem"
|
|
299
|
+
exit 1
|
|
300
|
+
end
|
|
301
|
+
end
|
|
302
|
+
|
|
303
|
+
devtools_artifact = File.join(E11Y_DEVTOOLS_GEM_DIR, "e11y-devtools-#{E11y::Devtools::VERSION}.gem")
|
|
304
|
+
puts "\nโ
Built:"
|
|
305
|
+
puts " - e11y-#{E11y::VERSION}.gem"
|
|
306
|
+
puts " - #{devtools_artifact}"
|
|
307
|
+
end
|
|
308
|
+
|
|
280
309
|
desc "Prepare release: run tests, build gem, create git tag (safe)"
|
|
281
310
|
task :prep do
|
|
282
311
|
require_relative "lib/e11y/version"
|
|
@@ -302,13 +331,11 @@ namespace :release do
|
|
|
302
331
|
end
|
|
303
332
|
puts "โ
All tests passed"
|
|
304
333
|
|
|
305
|
-
# Step 3: Build
|
|
306
|
-
puts "\n[3/5] Building
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
end
|
|
311
|
-
puts "โ
Gem built: e11y-#{version}.gem"
|
|
334
|
+
# Step 3: Build gems (e11y + e11y-devtools)
|
|
335
|
+
puts "\n[3/5] Building gems..."
|
|
336
|
+
Rake::Task["release:build_gems"].invoke
|
|
337
|
+
require_relative "gems/e11y-devtools/lib/e11y/devtools/version"
|
|
338
|
+
puts "โ
Gems built: e11y-#{version}.gem + e11y-devtools-#{E11y::Devtools::VERSION}.gem"
|
|
312
339
|
|
|
313
340
|
# Step 4: Create git tag
|
|
314
341
|
puts "\n[4/5] Creating git tag..."
|
|
@@ -336,28 +363,108 @@ namespace :release do
|
|
|
336
363
|
puts " git push origin main"
|
|
337
364
|
puts " git push origin #{tag_name}"
|
|
338
365
|
puts " 3. Publish to RubyGems:"
|
|
339
|
-
puts " rake release:
|
|
366
|
+
puts " rake release:gem_push"
|
|
340
367
|
puts "\n"
|
|
341
368
|
end
|
|
342
369
|
|
|
343
|
-
|
|
370
|
+
namespace :rubygems do
|
|
371
|
+
desc "Publish e11y gem only"
|
|
372
|
+
task :push_core do
|
|
373
|
+
require_relative "lib/e11y/version"
|
|
374
|
+
gem_file = "e11y-#{E11y::VERSION}.gem"
|
|
375
|
+
|
|
376
|
+
puts "\n#{'=' * 80}"
|
|
377
|
+
puts "๐ค Publishing e11y v#{E11y::VERSION} to RubyGems.org"
|
|
378
|
+
puts "#{'=' * 80}\n"
|
|
379
|
+
|
|
380
|
+
unless File.exist?(gem_file)
|
|
381
|
+
puts "โ Error: Gem file not found: #{gem_file}"
|
|
382
|
+
puts "Run 'rake release:build_gems' or 'rake release:prep' first"
|
|
383
|
+
exit 1
|
|
384
|
+
end
|
|
385
|
+
|
|
386
|
+
puts "This will publish #{gem_file}"
|
|
387
|
+
puts "You may be prompted for RubyGems credentials and MFA."
|
|
388
|
+
puts "\nContinue? (y/N)"
|
|
389
|
+
|
|
390
|
+
response = $stdin.gets.chomp.downcase
|
|
391
|
+
unless %w[y yes].include?(response)
|
|
392
|
+
puts "โ Publication cancelled"
|
|
393
|
+
exit 0
|
|
394
|
+
end
|
|
395
|
+
|
|
396
|
+
unless system("gem push #{gem_file}")
|
|
397
|
+
puts "\nโ Error: Failed to publish e11y"
|
|
398
|
+
exit 1
|
|
399
|
+
end
|
|
400
|
+
|
|
401
|
+
puts "\nโ
Published e11y v#{E11y::VERSION}"
|
|
402
|
+
puts "Verify: https://rubygems.org/gems/e11y/versions/#{E11y::VERSION}"
|
|
403
|
+
end
|
|
404
|
+
|
|
405
|
+
desc "Publish e11y-devtools gem only"
|
|
406
|
+
task :push_devtools do
|
|
407
|
+
require_relative "gems/e11y-devtools/lib/e11y/devtools/version"
|
|
408
|
+
version = E11y::Devtools::VERSION
|
|
409
|
+
gem_file = File.join(E11Y_DEVTOOLS_GEM_DIR, "e11y-devtools-#{version}.gem")
|
|
410
|
+
|
|
411
|
+
puts "\n#{'=' * 80}"
|
|
412
|
+
puts "๐ค Publishing e11y-devtools v#{version} to RubyGems.org"
|
|
413
|
+
puts "#{'=' * 80}\n"
|
|
414
|
+
|
|
415
|
+
unless File.exist?(gem_file)
|
|
416
|
+
puts "โ Error: Gem file not found: #{gem_file}"
|
|
417
|
+
puts "Run 'rake release:build_gems' or 'rake release:prep' first"
|
|
418
|
+
exit 1
|
|
419
|
+
end
|
|
420
|
+
|
|
421
|
+
puts "This will publish #{gem_file}"
|
|
422
|
+
puts "You may be prompted for RubyGems credentials and MFA."
|
|
423
|
+
puts "\nContinue? (y/N)"
|
|
424
|
+
|
|
425
|
+
response = $stdin.gets.chomp.downcase
|
|
426
|
+
unless %w[y yes].include?(response)
|
|
427
|
+
puts "โ Publication cancelled"
|
|
428
|
+
exit 0
|
|
429
|
+
end
|
|
430
|
+
|
|
431
|
+
unless system("gem push #{gem_file}")
|
|
432
|
+
puts "\nโ Error: Failed to publish e11y-devtools"
|
|
433
|
+
exit 1
|
|
434
|
+
end
|
|
435
|
+
|
|
436
|
+
puts "\nโ
Published e11y-devtools v#{version}"
|
|
437
|
+
puts "Verify: https://rubygems.org/gems/e11y-devtools/versions/#{version}"
|
|
438
|
+
end
|
|
439
|
+
end
|
|
440
|
+
|
|
441
|
+
desc "Publish e11y then e11y-devtools to RubyGems.org (requires authentication, MFA)"
|
|
344
442
|
task :gem_push do
|
|
345
443
|
require_relative "lib/e11y/version"
|
|
346
|
-
version
|
|
347
|
-
|
|
444
|
+
require_relative "gems/e11y-devtools/lib/e11y/devtools/version"
|
|
445
|
+
|
|
446
|
+
core_gem = "e11y-#{E11y::VERSION}.gem"
|
|
447
|
+
devtools_gem = File.join(E11Y_DEVTOOLS_GEM_DIR, "e11y-devtools-#{E11y::Devtools::VERSION}.gem")
|
|
348
448
|
|
|
349
449
|
puts "\n#{'=' * 80}"
|
|
350
|
-
puts "๐ค Publishing
|
|
450
|
+
puts "๐ค Publishing to RubyGems.org"
|
|
351
451
|
puts "#{'=' * 80}\n"
|
|
352
452
|
|
|
353
|
-
unless File.exist?(
|
|
354
|
-
puts "โ Error: Gem file not found: #{
|
|
355
|
-
puts "Run 'rake release:prep' first"
|
|
453
|
+
unless File.exist?(core_gem)
|
|
454
|
+
puts "โ Error: Gem file not found: #{core_gem}"
|
|
455
|
+
puts "Run 'rake release:build_gems' or 'rake release:prep' first"
|
|
456
|
+
exit 1
|
|
457
|
+
end
|
|
458
|
+
unless File.exist?(devtools_gem)
|
|
459
|
+
puts "โ Error: Gem file not found: #{devtools_gem}"
|
|
460
|
+
puts "Run 'rake release:build_gems' or 'rake release:prep' first"
|
|
356
461
|
exit 1
|
|
357
462
|
end
|
|
358
463
|
|
|
359
|
-
puts "This will publish
|
|
360
|
-
puts "
|
|
464
|
+
puts "This will publish (e11y first, then e11y-devtools):"
|
|
465
|
+
puts " 1. #{core_gem}"
|
|
466
|
+
puts " 2. #{devtools_gem}"
|
|
467
|
+
puts "\nYou may be prompted for RubyGems credentials and MFA for each push."
|
|
361
468
|
puts "\nContinue? (y/N)"
|
|
362
469
|
|
|
363
470
|
response = $stdin.gets.chomp.downcase
|
|
@@ -366,17 +473,19 @@ namespace :release do
|
|
|
366
473
|
exit 0
|
|
367
474
|
end
|
|
368
475
|
|
|
369
|
-
unless system("gem push #{
|
|
370
|
-
puts "\nโ Error: Failed to publish
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
476
|
+
unless system("gem push #{core_gem}")
|
|
477
|
+
puts "\nโ Error: Failed to publish e11y"
|
|
478
|
+
exit 1
|
|
479
|
+
end
|
|
480
|
+
|
|
481
|
+
unless system("gem push #{devtools_gem}")
|
|
482
|
+
puts "\nโ Error: Failed to publish e11y-devtools (e11y may already be on RubyGems)"
|
|
375
483
|
exit 1
|
|
376
484
|
end
|
|
377
485
|
|
|
378
|
-
puts "\nโ
Successfully published
|
|
379
|
-
puts "
|
|
486
|
+
puts "\nโ
Successfully published both gems!"
|
|
487
|
+
puts " e11y: https://rubygems.org/gems/e11y/versions/#{E11y::VERSION}"
|
|
488
|
+
puts " e11y-devtools: https://rubygems.org/gems/e11y-devtools/versions/#{E11y::Devtools::VERSION}"
|
|
380
489
|
end
|
|
381
490
|
|
|
382
491
|
desc "Push git changes and tag to GitHub (safe)"
|
|
@@ -442,19 +551,23 @@ namespace :release do
|
|
|
442
551
|
puts "=" * 80
|
|
443
552
|
puts "\nPost-release tasks:"
|
|
444
553
|
puts " 1. Create GitHub release: https://github.com/arturseletskiy/e11y/releases/new"
|
|
445
|
-
puts " 2. Verify on RubyGems: https://rubygems.org/gems/e11y"
|
|
554
|
+
puts " 2. Verify on RubyGems: https://rubygems.org/gems/e11y and /gems/e11y-devtools"
|
|
446
555
|
puts " 3. Update README badges"
|
|
447
556
|
puts " 4. Announce on social media"
|
|
448
557
|
puts "\n"
|
|
449
558
|
end
|
|
450
559
|
|
|
451
|
-
desc "Clean up built gems"
|
|
560
|
+
desc "Clean up built gem files (repo root + gems/e11y-devtools)"
|
|
452
561
|
task :clean do
|
|
453
562
|
puts "๐งน Cleaning up gem files..."
|
|
454
563
|
FileList["*.gem"].each do |gem_file|
|
|
455
564
|
File.delete(gem_file)
|
|
456
565
|
puts " Deleted: #{gem_file}"
|
|
457
566
|
end
|
|
567
|
+
FileList[File.join(E11Y_DEVTOOLS_GEM_DIR, "*.gem")].each do |gem_file|
|
|
568
|
+
File.delete(gem_file)
|
|
569
|
+
puts " Deleted: #{gem_file}"
|
|
570
|
+
end
|
|
458
571
|
puts "โ
Clean complete"
|
|
459
572
|
end
|
|
460
573
|
end
|
data/docs/QUICK-START.md
CHANGED
|
@@ -860,7 +860,7 @@ E11y.config.adapters[:logs].healthy?
|
|
|
860
860
|
| OTelLogs payload attributes | All payload attributes now included in OTel log records |
|
|
861
861
|
| `config.slo_tracking = true` | Boolean coercion now accepted |
|
|
862
862
|
| `retention` / `retention_period` | Both work as aliases on event class |
|
|
863
|
-
| `
|
|
863
|
+
| `add_slo_controller` / `add_slo_job` | Helpers on `E11y::Configuration` (stored config; see UC-004) |
|
|
864
864
|
| `config.rate_limiting do` | Rate limiting block DSL |
|
|
865
865
|
| `config.cardinality_protection do` | Cardinality DSL block |
|
|
866
866
|
| `config.register_adapter` | Alias for `config.adapters[name] =` |
|
|
@@ -878,7 +878,7 @@ The following features are **documented in ADRs** but not yet implemented:
|
|
|
878
878
|
|---------|--------|
|
|
879
879
|
| `rails g e11y:grafana_dashboard` | ADR-003 |
|
|
880
880
|
| `rails g e11y:prometheus_alerts` | ADR-003 |
|
|
881
|
-
| `
|
|
881
|
+
| Wire `add_slo_controller` / `add_slo_job` into HTTP/job `Tracker` dimensions | UC-004, ADR-003 |
|
|
882
882
|
| Per-event rate limiting (`rate_limit` DSL on event class) | UC-011 |
|
|
883
883
|
| Tiered storage (archival) | UC-019 โ filter by `retention_until` |
|
|
884
884
|
| Cost Tracking / Budget Enforcement | ADR-009, UC-015 |
|
data/docs/RAILS_INTEGRATION.md
CHANGED
|
@@ -2,28 +2,78 @@
|
|
|
2
2
|
|
|
3
3
|
> Back to [README](../README.md#documentation)
|
|
4
4
|
|
|
5
|
-
E11y integrates with Rails via Railtie.
|
|
5
|
+
E11y integrates with Rails via `E11y::Railtie` (`lib/e11y/railtie.rb`). After `bundle install`, requiring the gem in a Rails app loads the Railtie automatically.
|
|
6
6
|
|
|
7
|
-
##
|
|
7
|
+
## Request middleware
|
|
8
8
|
|
|
9
|
-
E11y
|
|
9
|
+
`E11y::Middleware::Request` is inserted into the Rack stack (before `Rails::Rack::Logger` when present). It sets trace and request context on `E11y::Current`, optionally starts the **ephemeral (request-scoped) buffer** for debug events, and adds `X-E11y-Trace-Id` / `X-E11y-Span-Id` response headers.
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|-----------|--------------|----------|
|
|
13
|
-
| **HTTP Requests** | Request, StartProcessing, Redirect, SendFile | `lib/e11y/events/rails/http/` |
|
|
14
|
-
| **ActiveRecord** | Query | `lib/e11y/events/rails/database/` |
|
|
15
|
-
| **ActiveJob** | Enqueued, Started, Completed, Failed, Scheduled | `lib/e11y/events/rails/job/` |
|
|
16
|
-
| **Cache** | Read, Write, Delete | `lib/e11y/events/rails/cache/` |
|
|
17
|
-
| **View** | Render | `lib/e11y/events/rails/view/` |
|
|
11
|
+
## Rails instrumentation (`ActiveSupport::Notifications`)
|
|
18
12
|
|
|
19
|
-
|
|
13
|
+
When **`config.rails_instrumentation_enabled = true`**, E11y subscribes to Rails instrumentation and maps notifications to typed events (see `lib/e11y/instruments/rails_instrumentation.rb`).
|
|
20
14
|
|
|
21
|
-
|
|
15
|
+
| Area | Event classes (under `E11y::Events::Rails::`) |
|
|
16
|
+
|------|-----------------------------------------------|
|
|
17
|
+
| HTTP | `Http::Request`, `Http::StartProcessing`, `Http::Redirect`, `Http::SendFile` |
|
|
18
|
+
| Database | `Database::Query` |
|
|
19
|
+
| Active Job (notification names) | `Job::Enqueued`, `Job::Scheduled`, `Job::Started`, `Job::Completed`, `Job::Failed` |
|
|
20
|
+
| Cache | `Cache::Read`, `Cache::Write`, `Cache::Delete` |
|
|
21
|
+
| Views | `View::Render` |
|
|
22
22
|
|
|
23
|
-
|
|
23
|
+
This is **independent** of the Sidekiq and Active Job toggles below: instrumentation listens to Rails; the job toggles add **extra** process integration (buffer lifecycle, middleware, callbacks).
|
|
24
|
+
|
|
25
|
+
## Sidekiq
|
|
26
|
+
|
|
27
|
+
Enable **only if** you use Sidekiq:
|
|
28
|
+
|
|
29
|
+
```ruby
|
|
30
|
+
E11y.configure do |config|
|
|
31
|
+
config.sidekiq_enabled = true
|
|
32
|
+
end
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
The Railtie registers client and server middleware (`E11y::Instruments::Sidekiq`) so jobs participate in the same **ephemeral buffer** semantics as HTTP requests when `config.ephemeral_buffer_enabled` is true.
|
|
36
|
+
|
|
37
|
+
On enqueue, **`E11y::Current.user_id`** (when set, e.g. from request middleware) is merged into **`e11y_baggage`** together with any allowed `Current.baggage` keys. The worker restores **`E11y::Current.baggage`** and **`E11y::Current.user_id`** from that hash. Key **`user_id`** is in the default baggage allowlist (`E11y::BAGGAGE_PROTECTION_DEFAULT_ALLOWED_KEYS`).
|
|
38
|
+
|
|
39
|
+
## Active Job
|
|
40
|
+
|
|
41
|
+
Enable when you want callbacks and buffer handling on **`ActiveJob::Base`** (and **`ApplicationJob`** when that constant is already defined at hook time):
|
|
42
|
+
|
|
43
|
+
```ruby
|
|
44
|
+
E11y.configure do |config|
|
|
45
|
+
config.active_job_enabled = true
|
|
46
|
+
end
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
You can use **both** `rails_instrumentation_enabled` and `active_job_enabled`; they complement each other. If you only enqueue via Sidekiq without Active Job, you may rely on `sidekiq_enabled` alone.
|
|
50
|
+
|
|
51
|
+
The **`before_enqueue`** callback applies the same **`e11y_baggage`** merge as Sidekiq (including **`user_id`** from `E11y::Current`).
|
|
52
|
+
|
|
53
|
+
## Rails.logger bridge
|
|
54
|
+
|
|
55
|
+
Optional wrapper that still delegates to the original logger but also emits **`E11y::Events::Rails::Log::*`** events (`lib/e11y/events/rails/log.rb`):
|
|
24
56
|
|
|
25
57
|
```ruby
|
|
26
58
|
E11y.configure do |config|
|
|
27
|
-
config.
|
|
59
|
+
config.logger_bridge_enabled = true
|
|
60
|
+
# Optional: only these severities (Symbol or String); nil / empty = all
|
|
61
|
+
config.logger_bridge_track_severities = %i[warn error fatal]
|
|
62
|
+
# Optional: skip noisy lines (String substrings or Regexp)
|
|
63
|
+
config.logger_bridge_ignore_patterns = [%r{health}]
|
|
28
64
|
end
|
|
29
65
|
```
|
|
66
|
+
|
|
67
|
+
Filtering uses **`logger_bridge_track_severities`** and **`logger_bridge_ignore_patterns`** only.
|
|
68
|
+
|
|
69
|
+
## Configuration reference
|
|
70
|
+
|
|
71
|
+
| Flag | Purpose |
|
|
72
|
+
|------|---------|
|
|
73
|
+
| `rails_instrumentation_enabled` | Map `ActiveSupport::Notifications` to E11y events |
|
|
74
|
+
| `sidekiq_enabled` | Sidekiq client/server middleware |
|
|
75
|
+
| `active_job_enabled` | `ActiveJob::Base` / `ApplicationJob` callbacks |
|
|
76
|
+
| `logger_bridge_enabled` | Wrap `Rails.logger` with `E11y::Logger::Bridge` |
|
|
77
|
+
| `ephemeral_buffer_enabled` | Request/job-scoped debug buffer (see README) |
|
|
78
|
+
|
|
79
|
+
Further detail: [ADR-008: Rails integration](architecture/ADR-008-rails-integration.md), [Quick Start](QUICK-START.md).
|