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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 954b1805423f92d59582e41e86d55ac489577ef5c76d20701c0fbcd76956f2a8
4
- data.tar.gz: 8464e352949c6eb14636ead83e5f0a556b8eb7dcabfd35186f35b3749ae8ac0a
3
+ metadata.gz: ad0751f86ff717630ea62f478707c758fc9d45540721c54016a55e19c86030be
4
+ data.tar.gz: 6192f331657a761ee7d537c29ded481629cfedfb1da74eb819e9181677010036
5
5
  SHA512:
6
- metadata.gz: 2c75f6813431fe8922454592a7dfb170fbddab4258a696901e79d0e1ec56699834cd7d9d0200d8eef1a7a3067dc95988e7bd0419b66b0ee6566bf0f342301dfd
7
- data.tar.gz: 7054bee0d5f25f35513c9697bfe5000128d7932df335beae13acaeb43af5522fde160c045554526a505efacbe326d9892689756b4ea8b289d04869d7c73fc565
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.3.0...HEAD
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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module RequestTrail
4
- VERSION = "0.3.0"
4
+ VERSION = "0.4.0"
5
5
  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
- @formatter ||= Formatter.new
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.3.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