request_trail 0.3.0 → 0.4.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 +9 -1
- data/README.md +23 -0
- data/ROADMAP.md +1 -14
- data/lib/request_trail/configuration.rb +5 -1
- data/lib/request_trail/formatters/flame_graph.rb +80 -0
- data/lib/request_trail/version.rb +1 -1
- data/lib/request_trail.rb +2 -2
- data/sig/request_trail/configuration.rbs +2 -0
- data/sig/request_trail/formatters/flame_graph.rbs +23 -0
- metadata +3 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: ad0751f86ff717630ea62f478707c758fc9d45540721c54016a55e19c86030be
|
|
4
|
+
data.tar.gz: 6192f331657a761ee7d537c29ded481629cfedfb1da74eb819e9181677010036
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 45d23c714ab2cebe3d5d33db4e8832301e69e496d3cd27419c370eef734bf8581c7d9f815485ab595acf7ce95d9c82c07d580eca805386526edbcd21bfffc74b
|
|
7
|
+
data.tar.gz: da3154bce7516976fdbff6437b877d639cf9b235a3308cb7101462d63e368b5b64530b932f101975f785cbb18365448e0ef18fbad84c2a5e2d8a3c9db126249c
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
## [Unreleased]
|
|
2
2
|
|
|
3
|
+
## [0.4.0] - 2026-06-12
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- `RequestTrail::Formatters::FlameGraph` — opt-in ASCII flame-graph formatter with proportional `█` bars and per-layer ANSI colour (auto-detected via TTY)
|
|
8
|
+
- Opt in via `config.formatter = RequestTrail::Formatters::FlameGraph.new`
|
|
9
|
+
|
|
3
10
|
## [0.3.0] - 2026-06-12
|
|
4
11
|
|
|
5
12
|
### Added
|
|
@@ -33,7 +40,8 @@
|
|
|
33
40
|
- `RequestTrail::Subscriber` — attach/detach API for notification subscriptions
|
|
34
41
|
- `RequestTrail::Collector` — thread-safe per-request event accumulator
|
|
35
42
|
|
|
36
|
-
[Unreleased]: https://github.com/eclectic-coding/request-trail/compare/v0.
|
|
43
|
+
[Unreleased]: https://github.com/eclectic-coding/request-trail/compare/v0.4.0...HEAD
|
|
44
|
+
[0.4.0]: https://github.com/eclectic-coding/request-trail/releases/tag/v0.4.0
|
|
37
45
|
[0.3.0]: https://github.com/eclectic-coding/request-trail/releases/tag/v0.3.0
|
|
38
46
|
[0.2.0]: https://github.com/eclectic-coding/request-trail/releases/tag/v0.2.0
|
|
39
47
|
[0.1.0]: https://github.com/eclectic-coding/request-trail/releases/tag/v0.1.0
|
data/README.md
CHANGED
|
@@ -54,6 +54,28 @@ Without controller data (plain Rack apps), a single-line summary is emitted:
|
|
|
54
54
|
[RequestTrail] GET /orders 142ms | SQL: 7/38.3ms | Cache: 4 hits, 1 miss, 2.0ms
|
|
55
55
|
```
|
|
56
56
|
|
|
57
|
+
### Flame graph formatter
|
|
58
|
+
|
|
59
|
+
Opt into the ASCII flame-graph formatter for a visual proportional breakdown:
|
|
60
|
+
|
|
61
|
+
```ruby
|
|
62
|
+
RequestTrail.configure do |config|
|
|
63
|
+
config.formatter = RequestTrail::Formatters::FlameGraph.new
|
|
64
|
+
end
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Output (with ANSI colour when stdout is a TTY):
|
|
68
|
+
|
|
69
|
+
```
|
|
70
|
+
[RequestTrail] GET /orders 142ms ████████████████████████████████████
|
|
71
|
+
controller 104ms ████████████████████████████
|
|
72
|
+
sql 38ms █████████
|
|
73
|
+
cache 2ms
|
|
74
|
+
view 22ms █████
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Colour scheme: controller = blue, sql = yellow, cache = green, view = magenta. Plain bars are emitted when stdout is not a TTY (e.g. log files, CI).
|
|
78
|
+
|
|
57
79
|
### Configuration
|
|
58
80
|
|
|
59
81
|
Add an initializer to customize behavior:
|
|
@@ -65,6 +87,7 @@ RequestTrail.configure do |config|
|
|
|
65
87
|
config.log_level = :info # Rails logger level (:debug, :info, :warn)
|
|
66
88
|
config.threshold_ms = 200 # only log requests slower than this (0 = log all)
|
|
67
89
|
config.logger = nil # defaults to Rails.logger
|
|
90
|
+
config.formatter = RequestTrail::Formatters::FlameGraph.new # optional
|
|
68
91
|
end
|
|
69
92
|
```
|
|
70
93
|
|
data/ROADMAP.md
CHANGED
|
@@ -2,26 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
`request_trail` traces a Rails request through every processing layer — middleware, controller, ActiveRecord, cache — and emits a flame-graph-style summary to the log. This roadmap describes the incremental path to a stable 1.0.0.
|
|
4
4
|
|
|
5
|
-
## 0.4.0 — Flame Graph Output
|
|
6
|
-
|
|
7
|
-
- Indented ASCII flame-graph renderer with proportional timing bars
|
|
8
|
-
- Optional ANSI colour with automatic TTY detection
|
|
9
|
-
- Ships as `Request::Trail::Formatters::FlameGraph` alongside the existing plain-text formatter:
|
|
10
|
-
```
|
|
11
|
-
[RequestTrail] GET /orders 142ms ████████████████████████████████████
|
|
12
|
-
middleware 4ms █
|
|
13
|
-
controller 100ms ████████████████████████
|
|
14
|
-
sql 38ms █████████
|
|
15
|
-
cache 2ms
|
|
16
|
-
view 22ms █████
|
|
17
|
-
```
|
|
18
|
-
|
|
19
5
|
## 0.5.0 — Filtering & Sampling
|
|
20
6
|
|
|
21
7
|
- Path filters: skip tracing for `/assets`, `/health`, or custom regex patterns
|
|
22
8
|
- Slow-request mode: only emit summaries above `threshold_ms`
|
|
23
9
|
- Sampling: trace only N% of requests (useful in production)
|
|
24
10
|
- Custom formatter API: `config.formatter = MyFormatter`
|
|
11
|
+
- FlameGraph colour overrides: `FlameGraph.new(colorize: true, colors: { controller: "\e[36m" })`
|
|
25
12
|
- Rails generator to scaffold the config initializer (`rails generate request_trail:install`)
|
|
26
13
|
|
|
27
14
|
## 0.6.0 — Structured Output & Integrations
|
|
@@ -4,7 +4,7 @@ require "logger"
|
|
|
4
4
|
|
|
5
5
|
module RequestTrail
|
|
6
6
|
class Configuration
|
|
7
|
-
attr_writer :logger
|
|
7
|
+
attr_writer :logger, :formatter
|
|
8
8
|
attr_accessor :enabled, :log_level, :threshold_ms
|
|
9
9
|
|
|
10
10
|
def initialize
|
|
@@ -17,6 +17,10 @@ module RequestTrail
|
|
|
17
17
|
@logger ||= rails_logger || Logger.new($stdout)
|
|
18
18
|
end
|
|
19
19
|
|
|
20
|
+
def formatter
|
|
21
|
+
@formatter ||= RequestTrail::Formatter.new
|
|
22
|
+
end
|
|
23
|
+
|
|
20
24
|
private
|
|
21
25
|
|
|
22
26
|
def rails_logger
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RequestTrail
|
|
4
|
+
module Formatters
|
|
5
|
+
class FlameGraph
|
|
6
|
+
BAR_WIDTH = 36
|
|
7
|
+
BAR_CHAR = "█"
|
|
8
|
+
|
|
9
|
+
COLORS = {
|
|
10
|
+
header: "\e[1m",
|
|
11
|
+
controller: "\e[34m",
|
|
12
|
+
sql: "\e[33m",
|
|
13
|
+
cache: "\e[32m",
|
|
14
|
+
view: "\e[35m"
|
|
15
|
+
}.freeze
|
|
16
|
+
RESET = "\e[0m"
|
|
17
|
+
|
|
18
|
+
def initialize(colorize: false)
|
|
19
|
+
@colorize = colorize
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def format(request, collector)
|
|
23
|
+
total = collector.elapsed_ms.to_f
|
|
24
|
+
lines = [header_line(request, collector)] + detail_rows(collector, total)
|
|
25
|
+
lines.join("\n")
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
private
|
|
29
|
+
|
|
30
|
+
def detail_rows(collector, total)
|
|
31
|
+
return tiered_rows(collector, total) if collector.action_duration_ms.positive?
|
|
32
|
+
|
|
33
|
+
flat_rows(collector, total)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def tiered_rows(collector, total)
|
|
37
|
+
[
|
|
38
|
+
row(" ", "controller", collector.action_duration_ms, total, :controller),
|
|
39
|
+
row(" ", "sql", collector.sql_duration_ms, total, :sql),
|
|
40
|
+
row(" ", "cache", collector.cache_duration_ms, total, :cache),
|
|
41
|
+
row(" ", "view", collector.view_duration_ms, total, :view)
|
|
42
|
+
]
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def flat_rows(collector, total)
|
|
46
|
+
[
|
|
47
|
+
row(" ", "sql", collector.sql_duration_ms, total, :sql),
|
|
48
|
+
row(" ", "cache", collector.cache_duration_ms, total, :cache)
|
|
49
|
+
]
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def header_line(request, collector)
|
|
53
|
+
elapsed = collector.elapsed_ms.round
|
|
54
|
+
bar = BAR_CHAR * BAR_WIDTH
|
|
55
|
+
line = "[RequestTrail] #{request.request_method} #{request.path} #{elapsed}ms #{bar}"
|
|
56
|
+
return line unless colorize?
|
|
57
|
+
|
|
58
|
+
"#{COLORS[:header]}#{line}#{RESET}"
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def row(indent, label, duration_ms, total_ms, color_key)
|
|
62
|
+
ms = duration_ms.round
|
|
63
|
+
bar = colorized_bar(duration_ms, total_ms, color_key)
|
|
64
|
+
"#{indent}#{label.ljust(11)}#{ms.to_s.rjust(4)}ms #{bar}"
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def colorized_bar(duration_ms, total_ms, color_key)
|
|
68
|
+
width = total_ms.positive? ? ((duration_ms.to_f / total_ms) * BAR_WIDTH).round : 0
|
|
69
|
+
bar = BAR_CHAR * width
|
|
70
|
+
return bar unless colorize? && width.positive?
|
|
71
|
+
|
|
72
|
+
"#{COLORS[color_key]}#{bar}#{RESET}"
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def colorize?
|
|
76
|
+
@colorize
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
data/lib/request_trail.rb
CHANGED
|
@@ -5,6 +5,7 @@ require_relative "request_trail/configuration"
|
|
|
5
5
|
require_relative "request_trail/collector"
|
|
6
6
|
require_relative "request_trail/subscriber"
|
|
7
7
|
require_relative "request_trail/formatter"
|
|
8
|
+
require_relative "request_trail/formatters/flame_graph"
|
|
8
9
|
require_relative "request_trail/middleware"
|
|
9
10
|
require_relative "request_trail/railtie" if defined?(Rails::Railtie)
|
|
10
11
|
|
|
@@ -21,12 +22,11 @@ module RequestTrail
|
|
|
21
22
|
end
|
|
22
23
|
|
|
23
24
|
def formatter
|
|
24
|
-
|
|
25
|
+
configuration.formatter
|
|
25
26
|
end
|
|
26
27
|
|
|
27
28
|
def reset!
|
|
28
29
|
@configuration = nil
|
|
29
|
-
@formatter = nil
|
|
30
30
|
end
|
|
31
31
|
end
|
|
32
32
|
end
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
module RequestTrail
|
|
2
2
|
class Configuration
|
|
3
3
|
attr_writer logger: ::Logger
|
|
4
|
+
attr_writer formatter: untyped
|
|
4
5
|
attr_accessor enabled: bool
|
|
5
6
|
attr_accessor log_level: Symbol
|
|
6
7
|
attr_accessor threshold_ms: Numeric
|
|
7
8
|
|
|
8
9
|
def initialize: () -> void
|
|
9
10
|
def logger: () -> ::Logger
|
|
11
|
+
def formatter: () -> untyped
|
|
10
12
|
end
|
|
11
13
|
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
module RequestTrail
|
|
2
|
+
module Formatters
|
|
3
|
+
class FlameGraph
|
|
4
|
+
BAR_WIDTH: Integer
|
|
5
|
+
BAR_CHAR: String
|
|
6
|
+
COLORS: Hash[Symbol, String]
|
|
7
|
+
RESET: String
|
|
8
|
+
|
|
9
|
+
def initialize: (?colorize: bool) -> void
|
|
10
|
+
def format: (::Rack::Request request, Collector collector) -> String
|
|
11
|
+
|
|
12
|
+
private
|
|
13
|
+
|
|
14
|
+
def detail_rows: (Collector collector, Float total) -> Array[String]
|
|
15
|
+
def tiered_rows: (Collector collector, Float total) -> Array[String]
|
|
16
|
+
def flat_rows: (Collector collector, Float total) -> Array[String]
|
|
17
|
+
def header_line: (::Rack::Request request, Collector collector) -> String
|
|
18
|
+
def row: (String indent, String label, Float duration_ms, Float total_ms, Symbol color_key) -> String
|
|
19
|
+
def colorized_bar: (Float duration_ms, Float total_ms, Symbol color_key) -> String
|
|
20
|
+
def colorize?: () -> bool
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: request_trail
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.4.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Chuck Smith
|
|
@@ -58,6 +58,7 @@ files:
|
|
|
58
58
|
- lib/request_trail/collector.rb
|
|
59
59
|
- lib/request_trail/configuration.rb
|
|
60
60
|
- lib/request_trail/formatter.rb
|
|
61
|
+
- lib/request_trail/formatters/flame_graph.rb
|
|
61
62
|
- lib/request_trail/middleware.rb
|
|
62
63
|
- lib/request_trail/railtie.rb
|
|
63
64
|
- lib/request_trail/subscriber.rb
|
|
@@ -66,6 +67,7 @@ files:
|
|
|
66
67
|
- sig/request_trail/collector.rbs
|
|
67
68
|
- sig/request_trail/configuration.rbs
|
|
68
69
|
- sig/request_trail/formatter.rbs
|
|
70
|
+
- sig/request_trail/formatters/flame_graph.rbs
|
|
69
71
|
- sig/request_trail/middleware.rbs
|
|
70
72
|
- sig/request_trail/subscriber.rbs
|
|
71
73
|
homepage: https://github.com/eclectic-coding/request-trail
|