select_rails_log 0.2.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 (45) hide show
  1. checksums.yaml +7 -0
  2. data/.rubocop.yml +13 -0
  3. data/CHANGELOG.md +22 -0
  4. data/CODE_OF_CONDUCT.md +132 -0
  5. data/LICENSE.txt +21 -0
  6. data/README.md +93 -0
  7. data/Rakefile +16 -0
  8. data/exe/select_rails_log +5 -0
  9. data/images/boxplot.png +0 -0
  10. data/images/histgram.png +0 -0
  11. data/images/text.png +0 -0
  12. data/lib/select_rails_log/command_line_options.rb +71 -0
  13. data/lib/select_rails_log/constants.rb +36 -0
  14. data/lib/select_rails_log/extension.rb +59 -0
  15. data/lib/select_rails_log/filter/base_filter.rb +35 -0
  16. data/lib/select_rails_log/filter/controller_action_filter.rb +50 -0
  17. data/lib/select_rails_log/filter/duration_range_filter.rb +40 -0
  18. data/lib/select_rails_log/filter/http_method_filter.rb +26 -0
  19. data/lib/select_rails_log/filter/http_status_filter.rb +39 -0
  20. data/lib/select_rails_log/filter/logs_regexp_filter.rb +27 -0
  21. data/lib/select_rails_log/filter/params_regexp_filter.rb +27 -0
  22. data/lib/select_rails_log/filter/range_pattern.rb +32 -0
  23. data/lib/select_rails_log/filter/request_id_filter.rb +28 -0
  24. data/lib/select_rails_log/filter/time_range_filter.rb +43 -0
  25. data/lib/select_rails_log/filter.rb +16 -0
  26. data/lib/select_rails_log/options.rb +20 -0
  27. data/lib/select_rails_log/printer/base_printer.rb +117 -0
  28. data/lib/select_rails_log/printer/boxplot_printer.rb +83 -0
  29. data/lib/select_rails_log/printer/data_serializable.rb +43 -0
  30. data/lib/select_rails_log/printer/histgram_printer.rb +48 -0
  31. data/lib/select_rails_log/printer/json_printer.rb +43 -0
  32. data/lib/select_rails_log/printer/jsonl_printer.rb +27 -0
  33. data/lib/select_rails_log/printer/null_printer.rb +19 -0
  34. data/lib/select_rails_log/printer/raw_printer.rb +45 -0
  35. data/lib/select_rails_log/printer/statistics_printer.rb +84 -0
  36. data/lib/select_rails_log/printer/text_printer.rb +51 -0
  37. data/lib/select_rails_log/printer/tsv_printer.rb +54 -0
  38. data/lib/select_rails_log/printer.rb +17 -0
  39. data/lib/select_rails_log/runner.rb +151 -0
  40. data/lib/select_rails_log/scanner.rb +142 -0
  41. data/lib/select_rails_log/selector.rb +32 -0
  42. data/lib/select_rails_log/version.rb +5 -0
  43. data/lib/select_rails_log.rb +22 -0
  44. data/sig/select_rails_log.rbs +4 -0
  45. metadata +131 -0
@@ -0,0 +1,84 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "enumerable/statistics"
4
+
5
+ module SelectRailsLog
6
+ module Printer
7
+ class StatisticsPrinter < BasePrinter
8
+ STAT_TOTAL_DURATION = "Total"
9
+
10
+ DEFAULT_TARGETS = [
11
+ STAT_TOTAL_DURATION,
12
+ PERFORMANCE_ACTIVE_RECORD,
13
+ PERFORMANCE_VIEWS,
14
+ PERFORMANCE_ALLOCATIONS
15
+ ].freeze
16
+
17
+ PERCENTILES = [25, 50, 75, 90, 95, 99].freeze
18
+
19
+ define_options :statistics_printer do
20
+ option :output, "--stats [FILE]", "-s", "Output statistics in TSV format", default: DEFAULT_OUTPUT
21
+ option :stats_targets,
22
+ "--stats-targets TARGETs",
23
+ " Statistics targets", Array,
24
+ " target can be one of #{DEFAULT_TARGETS.join(", ")}, or etc."
25
+ end
26
+
27
+ def initialize(*)
28
+ super
29
+
30
+ @stats_data = {}
31
+ @stats_targets = options[:stats_targets] || DEFAULT_TARGETS
32
+ end
33
+
34
+ def close
35
+ print_statistics
36
+ super
37
+ end
38
+
39
+ private
40
+
41
+ def init_output_destination
42
+ super
43
+ return unless output_directory?
44
+
45
+ raise CommandLineOptionError, "output to directory is not supported for statistics"
46
+ end
47
+
48
+ def build_stat_data
49
+ @stats_targets.each_with_object({}) do |target, hash|
50
+ hash[target] = []
51
+ end
52
+ end
53
+
54
+ def print_data(_output, data)
55
+ stat_data = @stats_data[data.values_at(CONTROLLER, ACTION)] ||= build_stat_data
56
+ stat_data.each do |target, values|
57
+ value = if target == STAT_TOTAL_DURATION
58
+ data[DURATION]
59
+ else
60
+ data[PERFORMANCE][target]
61
+ end
62
+ values << value if value
63
+ end
64
+ end
65
+
66
+ def print_statistics
67
+ print_row ["percentile", *PERCENTILES]
68
+
69
+ @stats_data.keys.sort.each do |(controller, action)|
70
+ @stats_data[[controller, action]].each do |target, values|
71
+ next if values.empty?
72
+
73
+ print_row ["#{controller}##{action} #{target}",
74
+ *PERCENTILES.map { |percentile| values.percentile(percentile) }]
75
+ end
76
+ end
77
+ end
78
+
79
+ def print_row(values)
80
+ @output_file.puts values.join("\t")
81
+ end
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SelectRailsLog
4
+ module Printer
5
+ class TextPrinter < BasePrinter
6
+ SUFFIX = ".txt"
7
+ DATETIME_FORMAT = "%FT%T.%6N"
8
+
9
+ define_options :text_printer do
10
+ option :output, "--text [PATH]", "Output in text format (default)", default: DEFAULT_OUTPUT
11
+ end
12
+
13
+ def initialize(options, standard_output, fallback_output: nil)
14
+ @fallback_output = fallback_output
15
+ @first = true
16
+ super(options, standard_output)
17
+ end
18
+
19
+ private
20
+
21
+ def output_option
22
+ options[:output] || @fallback_output
23
+ end
24
+
25
+ def print_data(output, data)
26
+ output.puts unless @first || output_directory?
27
+ @first = false if @first
28
+
29
+ print_header(output, data)
30
+ print_body(output, data)
31
+ end
32
+
33
+ def print_header(output, data)
34
+ output.puts "time: #{data[STARTED]&.strftime(DATETIME_FORMAT)} " \
35
+ ".. #{data[COMPLETED]&.strftime(DATETIME_FORMAT)}"
36
+ output.puts "request_id: #{data[REQUEST_ID]}" if data[REQUEST_ID]
37
+ output.print <<~END_OF_HEADER
38
+ pid: #{data[PID]}
39
+ status: #{data[HTTP_STATUS]}
40
+ duration: #{data[DURATION]}ms
41
+ END_OF_HEADER
42
+ end
43
+
44
+ def print_body(output, data)
45
+ each_log(data) do |log|
46
+ output.printf "[%<interval>8.3f] %<message>s\n", interval: log[INTERVAL] * 1_000, message: log[MESSAGE]
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "csv"
4
+
5
+ module SelectRailsLog
6
+ module Printer
7
+ class TsvPrinter < BasePrinter
8
+ DATETIME_FORMAT = "%F %T.%6N"
9
+
10
+ COLUMNS = [
11
+ STARTED, REQUEST_ID, "controller_action",
12
+ HTTP_STATUS, HTTP_METHOD, PATH,
13
+ "total_duration",
14
+ "active_record_duration",
15
+ "views_duration",
16
+ "allocations"
17
+ ].freeze
18
+
19
+ define_options :tsv_printer do
20
+ option :output, "--tsv [FILE]", "-t", "Output in TSV format", default: DEFAULT_OUTPUT
21
+ end
22
+
23
+ private
24
+
25
+ def init_output_destination
26
+ super
27
+ return unless output_directory?
28
+
29
+ raise CommandLineOptionError, "output to directory is not supported for TSV format"
30
+ end
31
+
32
+ def prepare
33
+ super
34
+ @csv = CSV.new(@output_file, col_sep: "\t", write_headers: true, headers: COLUMNS)
35
+ end
36
+
37
+ def print_data(_output, data)
38
+ @csv << row(data)
39
+ end
40
+
41
+ def row(data)
42
+ [
43
+ data[STARTED].strftime(DATETIME_FORMAT),
44
+ data[REQUEST_ID], "#{data[CONTROLLER]}##{data[ACTION]}",
45
+ data[HTTP_STATUS], data[HTTP_METHOD], data[PATH],
46
+ data[DURATION],
47
+ data[PERFORMANCE][PERFORMANCE_ACTIVE_RECORD],
48
+ data[PERFORMANCE][PERFORMANCE_VIEWS],
49
+ data[PERFORMANCE][PERFORMANCE_ALLOCATIONS]
50
+ ]
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "printer/base_printer"
4
+ require_relative "printer/text_printer"
5
+ require_relative "printer/raw_printer"
6
+ require_relative "printer/json_printer"
7
+ require_relative "printer/jsonl_printer"
8
+ require_relative "printer/tsv_printer"
9
+ require_relative "printer/statistics_printer"
10
+ require_relative "printer/histgram_printer"
11
+ require_relative "printer/boxplot_printer"
12
+ require_relative "printer/null_printer"
13
+
14
+ module SelectRailsLog
15
+ module Printer
16
+ end
17
+ end
@@ -0,0 +1,151 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SelectRailsLog
4
+ class Runner < Extension
5
+ include Constants
6
+
7
+ define_options :runner do
8
+ separator ""
9
+ separator "other options:"
10
+
11
+ option :help, "--help", "-h", "Show help"
12
+ option :version, "--version", "Show version"
13
+ option :debug, "--debug", "Enable debug print"
14
+ end
15
+
16
+ class << self
17
+ def run(argv, argf, out = $stdout)
18
+ runner = setup_runner(argv, out)
19
+
20
+ begin
21
+ runner.run(Scanner.new(argf)) if runner.runnable?
22
+ rescue StopIteration, Errno::EPIPE, Interrupt
23
+ # noop
24
+ end
25
+
26
+ runner.success?
27
+ rescue StandardError => e
28
+ raise e if runner&.debug?
29
+
30
+ warn e.message
31
+ false
32
+ end
33
+
34
+ private
35
+
36
+ def setup_runner(argv, out)
37
+ options = CommandLineOptions.new
38
+ options.parse!(argv)
39
+
40
+ runner = Runner.new(options, out)
41
+ if runner.help?
42
+ out.puts options.parser
43
+ elsif runner.version?
44
+ print_version(out)
45
+ end
46
+
47
+ runner
48
+ end
49
+
50
+ def print_version(io)
51
+ io.print <<~VERSION
52
+ select_rails_log #{VERSION}
53
+ - csv #{CSV::VERSION}
54
+ - enumerable-statistics #{EnumerableStatistics::VERSION}
55
+ - unicode_plot #{UnicodePlot::VERSION}
56
+ - #{RUBY_ENGINE} #{RUBY_VERSION} [#{RUBY_PLATFORM}]
57
+ VERSION
58
+ end
59
+ end
60
+
61
+ def initialize(options, standard_output)
62
+ super(options)
63
+ @count = 0
64
+ @standard_output = standard_output
65
+ end
66
+
67
+ def help?
68
+ options[:help]
69
+ end
70
+
71
+ def version?
72
+ options[:version]
73
+ end
74
+
75
+ def debug?
76
+ options[:debug]
77
+ end
78
+
79
+ def success?
80
+ help? || version? || @count.positive?
81
+ end
82
+
83
+ def runnable?
84
+ !help? && !version?
85
+ end
86
+
87
+ def run(scanner)
88
+ selector, printers = setup
89
+ counter_thread = counter_thread() if output_tty?(printers)
90
+
91
+ keep_raw = include_raw_printer?(printers)
92
+ scanner.select(selector, keep_raw:) do |data|
93
+ @count += 1
94
+ printers.each { _1.print(data) }
95
+ end
96
+ ensure
97
+ counter_thread&.kill
98
+ printers&.each(&:close)
99
+ end
100
+
101
+ private
102
+
103
+ def output_tty?(printers)
104
+ @standard_output.tty? && printers.none?(&:output_stdout?)
105
+ end
106
+
107
+ def setup
108
+ filters = setup_filters
109
+ printers = setup_printers
110
+ printers << default_printer if printers.empty?
111
+ selector = Selector.new(filters)
112
+
113
+ [selector, printers]
114
+ end
115
+
116
+ def setup_filters
117
+ @whole_options.extensions(:filter).filter_map do |ext_class|
118
+ ext = ext_class.new(@whole_options)
119
+ ext if ext.runnable?
120
+ end
121
+ end
122
+
123
+ def setup_printers
124
+ @whole_options.extensions(:printer).filter_map do |ext_class|
125
+ ext = ext_class.new(@whole_options, @standard_output)
126
+ ext if ext.runnable?
127
+ end
128
+ end
129
+
130
+ def default_printer
131
+ Printer::TextPrinter.new(@whole_options, @standard_output, fallback_output: DEFAULT_OUTPUT)
132
+ end
133
+
134
+ def include_raw_printer?(printers)
135
+ printers.any? { _1.is_a?(Printer::RawPrinter) }
136
+ end
137
+
138
+ def counter_thread
139
+ Thread.new do
140
+ lambda do
141
+ loop do
142
+ sleep 1
143
+ print "\r#{@count}"
144
+ end
145
+ ensure
146
+ puts "\r#{@count}"
147
+ end
148
+ end
149
+ end
150
+ end
151
+ end
@@ -0,0 +1,142 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "time"
4
+
5
+ module SelectRailsLog
6
+ class Scanner
7
+ include Constants
8
+
9
+ reqid_regexp = /\[(?<reqid>\h{8}-\h{4}-\h{4}-\h{4}-\h{12})\]/
10
+ LOG_REGEXP = /\A., \[(?<time>\S+) #(?<pid>\d+)\] *(?<severity>\S+) -- :(?: #{reqid_regexp})? (?<message>.*)/
11
+ ANSI_ESCAPE_SEQ_REGEXP = /\e\[(?:\d{1,2}(?:;\d{1,2})?)?[mK]/
12
+
13
+ DATETIME_FORMAT = "%FT%T.%N"
14
+ REQUEST_FILTER_APPLIED = "request_filter_applied" # internal data keys
15
+ private_constant :DATETIME_FORMAT, :REQUEST_FILTER_APPLIED
16
+
17
+ def initialize(io)
18
+ @io = io
19
+ end
20
+
21
+ def select(selector, keep_raw: true)
22
+ buff = {}
23
+ prev_time = nil
24
+ prev_data = nil
25
+ found = false
26
+ stop_iteration = false
27
+
28
+ @io.each_line do |line|
29
+ m = LOG_REGEXP.match(line)
30
+ unless m
31
+ if prev_data && prev_data[LOGS].any?
32
+ prev_data[LOGS].last[MESSAGE] << "\n" << line.chomp.gsub(ANSI_ESCAPE_SEQ_REGEXP, "")
33
+ prev_data[RAW_LOGS].last << line if keep_raw
34
+ end
35
+ next
36
+ end
37
+
38
+ begin
39
+ time = Time.strptime(m[:time], DATETIME_FORMAT)
40
+ rescue ArgumentError
41
+ # ignore invalid time format
42
+ end
43
+
44
+ pid = m[:pid]
45
+ reqid = m[:reqid]
46
+ message = m[:message]
47
+ log = {
48
+ TIME => time,
49
+ MESSAGE => message,
50
+ SEVERITY => m[:severity]
51
+ }
52
+
53
+ ident = reqid || pid
54
+ data = prev_data = buff[ident] if buff.key?(ident)
55
+
56
+ if /\AStarted (?<http_method>\S+) "(?<path>[^"]*)" for (?<client>\S+)/ =~ message
57
+ buff.delete(ident)
58
+ if stop_iteration
59
+ prev_data = nil
60
+ buff.empty? ? break : next
61
+ end
62
+
63
+ log[INTERVAL] = 0.0
64
+ prev_time = time
65
+
66
+ data = {
67
+ ID => reqid || time.strftime("%Y%m%d-%H%M%S-%6N-#{pid}"),
68
+ STARTED => time,
69
+ PID => pid,
70
+ REQUEST_ID => reqid,
71
+ HTTP_METHOD => http_method,
72
+ PATH => path,
73
+ CLIENT => client,
74
+ LOGS => [log],
75
+ REQUEST_FILTER_APPLIED => false
76
+ }
77
+ data[RAW_LOGS] = [line] if keep_raw
78
+ buff[ident] = data
79
+ next
80
+ end
81
+
82
+ unless data
83
+ prev_data = nil
84
+ next
85
+ end
86
+
87
+ message.gsub!(ANSI_ESCAPE_SEQ_REGEXP, "")
88
+ log[INTERVAL] = (time && prev_time) ? time - prev_time : 0.0
89
+ prev_time = time
90
+
91
+ if /\AProcessing by (?<controller>[^\s#]+)#(?<action>\S+)/ =~ message
92
+ data[CONTROLLER] = controller
93
+ data[ACTION] = action
94
+ data[LOGS] << log
95
+ data[RAW_LOGS] << line if keep_raw
96
+
97
+ data.delete(REQUEST_FILTER_APPLIED)
98
+ begin
99
+ reqf_result = selector.run_request_filters(data)
100
+ rescue StopIteration
101
+ stop_iteration = true
102
+ end
103
+ if !reqf_result || stop_iteration
104
+ buff.delete(ident)
105
+ prev_data = nil
106
+ end
107
+ elsif /\A Parameters: (?<params>.*)/ =~ message
108
+ data[PARAMETERS] = params
109
+ data[LOGS] << log
110
+ data[RAW_LOGS] << line if keep_raw
111
+ elsif /\ACompleted (?<http_status>\d+) .* in (?<duration>\d+)ms \((?<durations>.*)\)/ =~ message
112
+ data[HTTP_STATUS] = http_status
113
+ data[DURATION] = duration.to_i
114
+ data[PERFORMANCE] = durations.scan(/(\S+): (\d+(\.\d+)?)/)
115
+ .to_h { |type, dur, dur_f| [type, dur_f ? dur.to_f : dur.to_i] }
116
+ data[COMPLETED] = time
117
+ data[LOGS] << log
118
+ data[RAW_LOGS] << line if keep_raw
119
+
120
+ if data.key?(REQUEST_FILTER_APPLIED)
121
+ data.delete(REQUEST_FILTER_APPLIED)
122
+ reqf_result = selector.run_request_filters(data)
123
+ else
124
+ reqf_result = true
125
+ end
126
+
127
+ reqf_result && selector.run_line_filters(data) do |i|
128
+ yield(i)
129
+ found = true
130
+ end
131
+ buff.delete(ident)
132
+ prev_data = nil
133
+ else
134
+ data[LOGS] << log
135
+ data[RAW_LOGS] << line if keep_raw
136
+ end
137
+ end
138
+
139
+ found
140
+ end
141
+ end
142
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SelectRailsLog
4
+ class Selector
5
+ def initialize(filters)
6
+ @request_filters = filters.select(&:request_filter?)
7
+ @line_filters = filters - @request_filters
8
+ end
9
+
10
+ def run_request_filters(data)
11
+ run_filters(data, @request_filters)
12
+ end
13
+
14
+ def run_line_filters(data, &)
15
+ run_filters(data, @line_filters, &)
16
+ end
17
+
18
+ private
19
+
20
+ def run_filters(data, filters)
21
+ result = if filters.empty?
22
+ true
23
+ else
24
+ filters.all? { |filter| filter.run(data) }
25
+ end
26
+
27
+ return yield(data) if result && block_given?
28
+
29
+ result
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SelectRailsLog
4
+ VERSION = "0.2.0"
5
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "select_rails_log/constants"
4
+ require_relative "select_rails_log/command_line_options"
5
+ require_relative "select_rails_log/extension"
6
+ require_relative "select_rails_log/filter"
7
+ require_relative "select_rails_log/printer"
8
+ require_relative "select_rails_log/selector"
9
+ require_relative "select_rails_log/runner"
10
+ require_relative "select_rails_log/scanner"
11
+ require_relative "select_rails_log/version"
12
+
13
+ module SelectRailsLog
14
+ class Error < RuntimeError; end
15
+ class CommandLineOptionError < Error; end
16
+
17
+ class << self
18
+ def run
19
+ exit(Runner.run(ARGV, ARGF) ? 0 : 1)
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,4 @@
1
+ module SelectRailsLog
2
+ VERSION: String
3
+ # See the writing guide of rbs: https://github.com/ruby/rbs#guides
4
+ end
metadata ADDED
@@ -0,0 +1,131 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: select_rails_log
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.0
5
+ platform: ruby
6
+ authors:
7
+ - akira yamada
8
+ bindir: exe
9
+ cert_chain: []
10
+ date: 2025-01-18 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: csv
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - ">="
17
+ - !ruby/object:Gem::Version
18
+ version: '0'
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - ">="
24
+ - !ruby/object:Gem::Version
25
+ version: '0'
26
+ - !ruby/object:Gem::Dependency
27
+ name: enumerable-statistics
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ version: '0'
40
+ - !ruby/object:Gem::Dependency
41
+ name: unicode_plot
42
+ requirement: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: '0'
47
+ type: :runtime
48
+ prerelease: false
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ description: select_rails_log is a tool for extracting request logs from Rails log
55
+ files.
56
+ email:
57
+ - akira@arika.org
58
+ executables:
59
+ - select_rails_log
60
+ extensions: []
61
+ extra_rdoc_files: []
62
+ files:
63
+ - ".rubocop.yml"
64
+ - CHANGELOG.md
65
+ - CODE_OF_CONDUCT.md
66
+ - LICENSE.txt
67
+ - README.md
68
+ - Rakefile
69
+ - exe/select_rails_log
70
+ - images/boxplot.png
71
+ - images/histgram.png
72
+ - images/text.png
73
+ - lib/select_rails_log.rb
74
+ - lib/select_rails_log/command_line_options.rb
75
+ - lib/select_rails_log/constants.rb
76
+ - lib/select_rails_log/extension.rb
77
+ - lib/select_rails_log/filter.rb
78
+ - lib/select_rails_log/filter/base_filter.rb
79
+ - lib/select_rails_log/filter/controller_action_filter.rb
80
+ - lib/select_rails_log/filter/duration_range_filter.rb
81
+ - lib/select_rails_log/filter/http_method_filter.rb
82
+ - lib/select_rails_log/filter/http_status_filter.rb
83
+ - lib/select_rails_log/filter/logs_regexp_filter.rb
84
+ - lib/select_rails_log/filter/params_regexp_filter.rb
85
+ - lib/select_rails_log/filter/range_pattern.rb
86
+ - lib/select_rails_log/filter/request_id_filter.rb
87
+ - lib/select_rails_log/filter/time_range_filter.rb
88
+ - lib/select_rails_log/options.rb
89
+ - lib/select_rails_log/printer.rb
90
+ - lib/select_rails_log/printer/base_printer.rb
91
+ - lib/select_rails_log/printer/boxplot_printer.rb
92
+ - lib/select_rails_log/printer/data_serializable.rb
93
+ - lib/select_rails_log/printer/histgram_printer.rb
94
+ - lib/select_rails_log/printer/json_printer.rb
95
+ - lib/select_rails_log/printer/jsonl_printer.rb
96
+ - lib/select_rails_log/printer/null_printer.rb
97
+ - lib/select_rails_log/printer/raw_printer.rb
98
+ - lib/select_rails_log/printer/statistics_printer.rb
99
+ - lib/select_rails_log/printer/text_printer.rb
100
+ - lib/select_rails_log/printer/tsv_printer.rb
101
+ - lib/select_rails_log/runner.rb
102
+ - lib/select_rails_log/scanner.rb
103
+ - lib/select_rails_log/selector.rb
104
+ - lib/select_rails_log/version.rb
105
+ - sig/select_rails_log.rbs
106
+ homepage: https://github.com/arika/select_rails_log
107
+ licenses:
108
+ - MIT
109
+ metadata:
110
+ homepage_uri: https://github.com/arika/select_rails_log
111
+ source_code_uri: https://github.com/arika/select_rails_log
112
+ changelog_uri: https://github.com/arika/select_rails_log/blob/main/CHANGELOG.md
113
+ rubygems_mfa_required: 'true'
114
+ rdoc_options: []
115
+ require_paths:
116
+ - lib
117
+ required_ruby_version: !ruby/object:Gem::Requirement
118
+ requirements:
119
+ - - ">="
120
+ - !ruby/object:Gem::Version
121
+ version: 3.1.0
122
+ required_rubygems_version: !ruby/object:Gem::Requirement
123
+ requirements:
124
+ - - ">="
125
+ - !ruby/object:Gem::Version
126
+ version: '0'
127
+ requirements: []
128
+ rubygems_version: 3.6.2
129
+ specification_version: 4
130
+ summary: Rails log selector
131
+ test_files: []