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.
- checksums.yaml +7 -0
- data/.rubocop.yml +13 -0
- data/CHANGELOG.md +22 -0
- data/CODE_OF_CONDUCT.md +132 -0
- data/LICENSE.txt +21 -0
- data/README.md +93 -0
- data/Rakefile +16 -0
- data/exe/select_rails_log +5 -0
- data/images/boxplot.png +0 -0
- data/images/histgram.png +0 -0
- data/images/text.png +0 -0
- data/lib/select_rails_log/command_line_options.rb +71 -0
- data/lib/select_rails_log/constants.rb +36 -0
- data/lib/select_rails_log/extension.rb +59 -0
- data/lib/select_rails_log/filter/base_filter.rb +35 -0
- data/lib/select_rails_log/filter/controller_action_filter.rb +50 -0
- data/lib/select_rails_log/filter/duration_range_filter.rb +40 -0
- data/lib/select_rails_log/filter/http_method_filter.rb +26 -0
- data/lib/select_rails_log/filter/http_status_filter.rb +39 -0
- data/lib/select_rails_log/filter/logs_regexp_filter.rb +27 -0
- data/lib/select_rails_log/filter/params_regexp_filter.rb +27 -0
- data/lib/select_rails_log/filter/range_pattern.rb +32 -0
- data/lib/select_rails_log/filter/request_id_filter.rb +28 -0
- data/lib/select_rails_log/filter/time_range_filter.rb +43 -0
- data/lib/select_rails_log/filter.rb +16 -0
- data/lib/select_rails_log/options.rb +20 -0
- data/lib/select_rails_log/printer/base_printer.rb +117 -0
- data/lib/select_rails_log/printer/boxplot_printer.rb +83 -0
- data/lib/select_rails_log/printer/data_serializable.rb +43 -0
- data/lib/select_rails_log/printer/histgram_printer.rb +48 -0
- data/lib/select_rails_log/printer/json_printer.rb +43 -0
- data/lib/select_rails_log/printer/jsonl_printer.rb +27 -0
- data/lib/select_rails_log/printer/null_printer.rb +19 -0
- data/lib/select_rails_log/printer/raw_printer.rb +45 -0
- data/lib/select_rails_log/printer/statistics_printer.rb +84 -0
- data/lib/select_rails_log/printer/text_printer.rb +51 -0
- data/lib/select_rails_log/printer/tsv_printer.rb +54 -0
- data/lib/select_rails_log/printer.rb +17 -0
- data/lib/select_rails_log/runner.rb +151 -0
- data/lib/select_rails_log/scanner.rb +142 -0
- data/lib/select_rails_log/selector.rb +32 -0
- data/lib/select_rails_log/version.rb +5 -0
- data/lib/select_rails_log.rb +22 -0
- data/sig/select_rails_log.rbs +4 -0
- 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,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
|
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: []
|