select_rails_log 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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: []
|