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,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SelectRailsLog
|
4
|
+
module Filter
|
5
|
+
class LogsRegexpFilter < BaseFilter
|
6
|
+
define_options :logs_regexp_filter do
|
7
|
+
option :regexp,
|
8
|
+
"--logs-regexp REGEXP", "-L", Regexp,
|
9
|
+
"Filter by log messages",
|
10
|
+
%q( ex: '"^ Rendering .*\.json"')
|
11
|
+
end
|
12
|
+
|
13
|
+
def initialize(...)
|
14
|
+
super
|
15
|
+
@regexp = options[:regexp]
|
16
|
+
end
|
17
|
+
|
18
|
+
def runnable?
|
19
|
+
!!@regexp
|
20
|
+
end
|
21
|
+
|
22
|
+
def run(data)
|
23
|
+
data[LOGS].any? { |log| @regexp.match?(log[MESSAGE]) }
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SelectRailsLog
|
4
|
+
module Filter
|
5
|
+
class ParamsRegexpFilter < BaseFilter
|
6
|
+
define_options :params_regexp_filter do
|
7
|
+
option :regexp,
|
8
|
+
"--params-regexp REGEXP", "-P", Regexp,
|
9
|
+
"Filter by parameters",
|
10
|
+
%q( ex: '"foo"=>"ba[rz]"')
|
11
|
+
end
|
12
|
+
|
13
|
+
def initialize(...)
|
14
|
+
super
|
15
|
+
@regexp = options[:regexp]
|
16
|
+
end
|
17
|
+
|
18
|
+
def runnable?
|
19
|
+
!!@regexp
|
20
|
+
end
|
21
|
+
|
22
|
+
def run(data)
|
23
|
+
@regexp.match?(data[PARAMETERS])
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SelectRailsLog
|
4
|
+
module Filter
|
5
|
+
module RangePattern
|
6
|
+
private
|
7
|
+
|
8
|
+
def parse_range_pattern(pattern)
|
9
|
+
if /\A(?<range_begin>.*?[^.])?\.\.(?<exclude_end>\.)?(?<range_end>[^.].*)?\z/ =~ pattern
|
10
|
+
range_begin = yield(range_begin) if range_begin
|
11
|
+
range_end = yield(range_end) if range_end
|
12
|
+
exclude_end = !exclude_end.nil?
|
13
|
+
range_by_begin_end(range_begin, range_end, exclude_end)
|
14
|
+
elsif /\A(?<base>.+),(?<delta>[^,]+)\z/ =~ pattern
|
15
|
+
delta = delta.to_f
|
16
|
+
base = yield(base)
|
17
|
+
range_by_base_delta(base, delta)
|
18
|
+
else
|
19
|
+
raise ArgumentError
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def range_by_begin_end(begin_time, end_time, exclude_end)
|
24
|
+
Range.new(begin_time, end_time, exclude_end)
|
25
|
+
end
|
26
|
+
|
27
|
+
def range_by_base_delta(base, delta)
|
28
|
+
range_by_begin_end(base - delta, base + delta, true)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SelectRailsLog
|
4
|
+
module Filter
|
5
|
+
class RequestIdFilter < BaseFilter
|
6
|
+
filter_type :request
|
7
|
+
|
8
|
+
define_options :request_id_filter do
|
9
|
+
option :request_ids, "--request-ids IDs", "-I", Array, "Filter by request-id"
|
10
|
+
end
|
11
|
+
|
12
|
+
def initialize(...)
|
13
|
+
super
|
14
|
+
@request_ids = options[:request_ids].dup
|
15
|
+
end
|
16
|
+
|
17
|
+
def runnable?
|
18
|
+
!!@request_ids&.any?
|
19
|
+
end
|
20
|
+
|
21
|
+
def run(data)
|
22
|
+
raise StopIteration if @request_ids.empty?
|
23
|
+
|
24
|
+
!!@request_ids.delete(data[REQUEST_ID])
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "range_pattern"
|
4
|
+
|
5
|
+
module SelectRailsLog
|
6
|
+
module Filter
|
7
|
+
class TimeRangeFilter < BaseFilter
|
8
|
+
include RangePattern
|
9
|
+
|
10
|
+
define_options :time_range_filter do
|
11
|
+
option :pattern,
|
12
|
+
"--time-range RANGE", "-T", String,
|
13
|
+
"Filter by time range",
|
14
|
+
" range format is 'time1..time2', 'time1...time2', or 'time,seconds'.",
|
15
|
+
" ex: '2018-01-02 12:00..2018-02-01 12:00', '1/2 12:00...2/2 12:00', '3/5 12:00,30'"
|
16
|
+
end
|
17
|
+
|
18
|
+
def initialize(...)
|
19
|
+
super
|
20
|
+
|
21
|
+
pattern = options[:pattern]
|
22
|
+
return unless pattern
|
23
|
+
|
24
|
+
begin
|
25
|
+
@range = parse_range_pattern(pattern) { |time_str| Time.parse(time_str) }
|
26
|
+
rescue ArgumentError
|
27
|
+
raise CommandLineOptionError, "invalid time range pattern `#{pattern}`"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def runnable?
|
32
|
+
!!@range
|
33
|
+
end
|
34
|
+
|
35
|
+
def run(data)
|
36
|
+
return true if @range.cover?(data[STARTED]) || @range.cover?(data[COMPLETED])
|
37
|
+
|
38
|
+
range = data[STARTED]..data[COMPLETED]
|
39
|
+
range.cover?(@range.begin) || range.cover?(@range.end)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "filter/base_filter"
|
4
|
+
require_relative "filter/request_id_filter"
|
5
|
+
require_relative "filter/controller_action_filter"
|
6
|
+
require_relative "filter/http_method_filter"
|
7
|
+
require_relative "filter/http_status_filter"
|
8
|
+
require_relative "filter/time_range_filter"
|
9
|
+
require_relative "filter/duration_range_filter"
|
10
|
+
require_relative "filter/params_regexp_filter"
|
11
|
+
require_relative "filter/logs_regexp_filter"
|
12
|
+
|
13
|
+
module SelectRailsLog
|
14
|
+
module Filter
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "forwardable"
|
4
|
+
|
5
|
+
module SelectRailsLog
|
6
|
+
class Options
|
7
|
+
extend Forwardable
|
8
|
+
|
9
|
+
def_delegators :@options, :key?, :[]=
|
10
|
+
|
11
|
+
def initialize
|
12
|
+
@options = {}
|
13
|
+
end
|
14
|
+
|
15
|
+
def fetch(key)
|
16
|
+
@options.fetch(key)
|
17
|
+
end
|
18
|
+
alias [] fetch
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,117 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "fileutils"
|
4
|
+
|
5
|
+
module SelectRailsLog
|
6
|
+
module Printer
|
7
|
+
class BasePrinter < Extension
|
8
|
+
include Constants
|
9
|
+
|
10
|
+
define_options :base_printer do
|
11
|
+
separator ""
|
12
|
+
separator "printer options:"
|
13
|
+
|
14
|
+
option :default_output, "--default-output PATH", "-O", "Output to file or directory"
|
15
|
+
option :exclude_debug_logs, "--exclude-debug-logs", "-x", "Exclude debug logs"
|
16
|
+
end
|
17
|
+
|
18
|
+
OUTPUT_FILE_DATETIME_FORMAT = "%Y%m%d-%H%M%S.%6N"
|
19
|
+
private_constant :OUTPUT_FILE_DATETIME_FORMAT
|
20
|
+
|
21
|
+
def initialize(options, standard_output)
|
22
|
+
super(options)
|
23
|
+
|
24
|
+
@common_options = @whole_options[:base_printer]
|
25
|
+
@output_file = @standard_output = standard_output
|
26
|
+
@output_filename = @output_directory = nil
|
27
|
+
init_output_destination
|
28
|
+
|
29
|
+
@prepared = false
|
30
|
+
end
|
31
|
+
|
32
|
+
def close
|
33
|
+
@output_file&.close unless output_directory? || output_stdout?
|
34
|
+
end
|
35
|
+
|
36
|
+
def print(data)
|
37
|
+
unless @prepared
|
38
|
+
prepare
|
39
|
+
@prepared = true
|
40
|
+
end
|
41
|
+
|
42
|
+
with_output(data) do |io|
|
43
|
+
print_data(io, data)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def runnable?
|
48
|
+
!!output_option
|
49
|
+
end
|
50
|
+
|
51
|
+
def output_stdout?
|
52
|
+
!output_directory? && @output_file == @standard_output
|
53
|
+
end
|
54
|
+
|
55
|
+
def output_directory?
|
56
|
+
!!@output_directory
|
57
|
+
end
|
58
|
+
|
59
|
+
private
|
60
|
+
|
61
|
+
def init_output_destination
|
62
|
+
dest = output_option
|
63
|
+
dest = @common_options[:default_output] if dest == DEFAULT_OUTPUT
|
64
|
+
return if !dest || dest == "-"
|
65
|
+
|
66
|
+
if dest.end_with?("/")
|
67
|
+
@output_directory = dest.chomp("/")
|
68
|
+
elsif File.directory?(dest)
|
69
|
+
@output_directory = dest
|
70
|
+
else
|
71
|
+
@output_filename = dest
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def output_option
|
76
|
+
options.key?(:output) && options[:output]
|
77
|
+
end
|
78
|
+
|
79
|
+
def prepare
|
80
|
+
return unless @output_filename
|
81
|
+
|
82
|
+
@output_file = File.open(@output_filename, "w")
|
83
|
+
end
|
84
|
+
|
85
|
+
def with_output(data, &)
|
86
|
+
return yield(@output_file) unless output_directory?
|
87
|
+
|
88
|
+
FileUtils.mkdir_p(@output_directory)
|
89
|
+
File.open("#{@output_directory}/#{output_filename(data)}",
|
90
|
+
File::CREAT | File::TRUNC | File::WRONLY, &)
|
91
|
+
end
|
92
|
+
|
93
|
+
def output_filename(data)
|
94
|
+
timestr = data[STARTED].strftime(OUTPUT_FILE_DATETIME_FORMAT)
|
95
|
+
"#{timestr}_#{data[ID]}#{self.class::SUFFIX}"
|
96
|
+
end
|
97
|
+
|
98
|
+
def print_data(_output, _data)
|
99
|
+
raise NotImplementedError
|
100
|
+
end
|
101
|
+
|
102
|
+
def each_log_with_index(data)
|
103
|
+
data[LOGS].each_with_index do |log, i|
|
104
|
+
next if @common_options[:exclude_debug_logs] && log[SEVERITY] == DEBUG
|
105
|
+
|
106
|
+
yield(log, i)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
def each_log(data)
|
111
|
+
each_log_with_index(data) do |log, _i|
|
112
|
+
yield(log)
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "unicode_plot"
|
4
|
+
require "io/console"
|
5
|
+
|
6
|
+
module SelectRailsLog
|
7
|
+
module Printer
|
8
|
+
class BoxplotPrinter < BasePrinter
|
9
|
+
PLOT_TOTAL_DURATION = "Total duration"
|
10
|
+
|
11
|
+
define_options :boxplot_printer do
|
12
|
+
option :output, "--boxplot [FILE]", "-B", "Output statistics boxplot", default: DEFAULT_OUTPUT
|
13
|
+
option :min, "--boxplot-min MIN", " Minimum value for boxplot", Float
|
14
|
+
option :max, "--boxplot-max MAX", " Maximum value for boxplot", Float
|
15
|
+
option :width, "--boxplot-width NUM", " Width of boxplot column", Integer
|
16
|
+
end
|
17
|
+
|
18
|
+
def initialize(*)
|
19
|
+
super
|
20
|
+
|
21
|
+
@plot_data = Hash.new { |h, k| h[k] = [] }
|
22
|
+
@controller_actions = Hash.new { |h, k| h[k] = {} }
|
23
|
+
end
|
24
|
+
|
25
|
+
def close
|
26
|
+
print_plot
|
27
|
+
super
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def init_output_destination
|
33
|
+
super
|
34
|
+
return unless output_directory?
|
35
|
+
|
36
|
+
raise CommandLineOptionError, "output to directory is not supported for plot"
|
37
|
+
end
|
38
|
+
|
39
|
+
def print_plot
|
40
|
+
return if @plot_data.empty?
|
41
|
+
|
42
|
+
boxplot.render(@output_file)
|
43
|
+
end
|
44
|
+
|
45
|
+
def boxplot
|
46
|
+
opts = {
|
47
|
+
title: PLOT_TOTAL_DURATION,
|
48
|
+
data: @plot_data.keys.sort.each_with_object({}) { |k, h| h[k] = @plot_data[k] },
|
49
|
+
width: boxplot_width,
|
50
|
+
xlim: boxplot_xlim
|
51
|
+
}.compact
|
52
|
+
UnicodePlot.boxplot(**opts)
|
53
|
+
end
|
54
|
+
|
55
|
+
def boxplot_width
|
56
|
+
return options[:width] if options[:width]
|
57
|
+
|
58
|
+
begin
|
59
|
+
_rows, cols = @output_file.winsize
|
60
|
+
rescue Errno::ENOTTY, Errno::ENODEV, NoMethodError
|
61
|
+
return nil
|
62
|
+
end
|
63
|
+
|
64
|
+
cols - @plot_data.keys.map(&:size).max - 8
|
65
|
+
end
|
66
|
+
|
67
|
+
def boxplot_xlim
|
68
|
+
return unless options[:min] || options[:max]
|
69
|
+
|
70
|
+
[
|
71
|
+
options[:min] || 0,
|
72
|
+
options[:max] || 0
|
73
|
+
]
|
74
|
+
end
|
75
|
+
|
76
|
+
def print_data(_output, data)
|
77
|
+
controller, action = data.values_at(CONTROLLER, ACTION)
|
78
|
+
controller_action = @controller_actions[controller][action] ||= "#{controller}##{action}"
|
79
|
+
@plot_data[controller_action] << data[DURATION]
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "json"
|
4
|
+
|
5
|
+
module SelectRailsLog
|
6
|
+
module Printer
|
7
|
+
module DataSerializable
|
8
|
+
include Constants
|
9
|
+
|
10
|
+
DATETIME_FORMAT = "%FT%T.%6N%:z"
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def serialize_data(data)
|
15
|
+
serialized = data.slice(
|
16
|
+
REQUEST_ID, CONTROLLER, ACTION,
|
17
|
+
HTTP_STATUS, HTTP_METHOD, PATH, PARAMETERS, CLIENT,
|
18
|
+
DURATION, PERFORMANCE
|
19
|
+
)
|
20
|
+
|
21
|
+
serialized[STARTED] = strftime(data[STARTED])
|
22
|
+
serialized[COMPLETED] = strftime(data[COMPLETED])
|
23
|
+
serialized[PID] = data[PID].to_i
|
24
|
+
serialized[LOGS] = collect_logs(data)
|
25
|
+
serialized
|
26
|
+
end
|
27
|
+
|
28
|
+
def collect_logs(data)
|
29
|
+
logs = []
|
30
|
+
|
31
|
+
each_log(data) do |log|
|
32
|
+
logs << log.merge(TIME => strftime(log[TIME]))
|
33
|
+
end
|
34
|
+
|
35
|
+
logs
|
36
|
+
end
|
37
|
+
|
38
|
+
def strftime(time)
|
39
|
+
time&.strftime(DATETIME_FORMAT)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "unicode_plot"
|
4
|
+
|
5
|
+
module SelectRailsLog
|
6
|
+
module Printer
|
7
|
+
class HistgramPrinter < BasePrinter
|
8
|
+
PLOT_TOTAL_DURATION = "Total duration"
|
9
|
+
|
10
|
+
define_options :histgram_printer do
|
11
|
+
option :output, "--histgram [FILE]", "-H", "Output statistics histgram", default: DEFAULT_OUTPUT
|
12
|
+
option :nbins, "--histgram-nbins NUM", " Number of bins for histgram", Integer
|
13
|
+
end
|
14
|
+
|
15
|
+
def initialize(*)
|
16
|
+
super
|
17
|
+
|
18
|
+
@plot_data = []
|
19
|
+
end
|
20
|
+
|
21
|
+
def close
|
22
|
+
print_plot
|
23
|
+
super
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def init_output_destination
|
29
|
+
super
|
30
|
+
return unless output_directory?
|
31
|
+
|
32
|
+
raise CommandLineOptionError, "output to directory is not supported for plot"
|
33
|
+
end
|
34
|
+
|
35
|
+
def print_plot
|
36
|
+
return if @plot_data.empty?
|
37
|
+
|
38
|
+
UnicodePlot
|
39
|
+
.histogram(@plot_data, title: PLOT_TOTAL_DURATION, nbins: options[:nbins])
|
40
|
+
.render(@output_file)
|
41
|
+
end
|
42
|
+
|
43
|
+
def print_data(_output, data)
|
44
|
+
@plot_data << data[DURATION]
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "data_serializable"
|
4
|
+
|
5
|
+
module SelectRailsLog
|
6
|
+
module Printer
|
7
|
+
class JsonPrinter < BasePrinter
|
8
|
+
include DataSerializable
|
9
|
+
|
10
|
+
SUFFIX = ".json"
|
11
|
+
|
12
|
+
define_options :json_printer do
|
13
|
+
option :output, "--json [PATH]", "-j", "Output in JSON format", default: DEFAULT_OUTPUT
|
14
|
+
end
|
15
|
+
|
16
|
+
def initialize(...)
|
17
|
+
super
|
18
|
+
@no_output = true
|
19
|
+
end
|
20
|
+
|
21
|
+
def close
|
22
|
+
@output_file.puts "]" unless output_directory?
|
23
|
+
super
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def print_data(output, data)
|
29
|
+
unless output_directory?
|
30
|
+
if @no_output
|
31
|
+
output.print "["
|
32
|
+
@no_output = false
|
33
|
+
else
|
34
|
+
output.print ","
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
output.print JSON.fast_generate(serialize_data(data))
|
39
|
+
output.puts if output_directory?
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "data_serializable"
|
4
|
+
|
5
|
+
module SelectRailsLog
|
6
|
+
module Printer
|
7
|
+
class JsonlPrinter < BasePrinter
|
8
|
+
include DataSerializable
|
9
|
+
|
10
|
+
SUFFIX = ".jsonl"
|
11
|
+
|
12
|
+
define_options :jsonl_printer do
|
13
|
+
option :output, "--jsonl [PATH]", "-J", "Output in JSON Lines format", default: DEFAULT_OUTPUT
|
14
|
+
end
|
15
|
+
|
16
|
+
def runnable?
|
17
|
+
!!@options[:output]
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def print_data(output, data)
|
23
|
+
output.puts JSON.fast_generate(serialize_data(data))
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SelectRailsLog
|
4
|
+
module Printer
|
5
|
+
class NullPrinter < BasePrinter
|
6
|
+
define_options :null_printer do
|
7
|
+
option :enabled, "--no-output", "-n", "No output", TrueClass
|
8
|
+
end
|
9
|
+
|
10
|
+
def runnable?
|
11
|
+
!!options[:enabled]
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def print_data(...); end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SelectRailsLog
|
4
|
+
module Printer
|
5
|
+
class RawPrinter < BasePrinter
|
6
|
+
SUFFIX = ".log"
|
7
|
+
DATETIME_FORMAT = "%FT%T.%6N"
|
8
|
+
|
9
|
+
define_options :raw_printer do
|
10
|
+
option :output, "--raw [PATH]", "-r", "Output in raw format", default: DEFAULT_OUTPUT
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def print_data(output, data)
|
16
|
+
return print_logs(output, data) unless data.key?(RAW_LOGS)
|
17
|
+
|
18
|
+
each_log_with_index(data) do |_log, index|
|
19
|
+
output.puts data[RAW_LOGS][index]
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def print_logs(output, data)
|
24
|
+
pid, request_id = data.values_at(PID, REQUEST_ID)
|
25
|
+
reqid = "[#{request_id}] " if request_id
|
26
|
+
each_log(data) do |log|
|
27
|
+
print_log_line(output, pid, reqid, log)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def print_log_line(output, pid, reqid, log)
|
32
|
+
severity = log[SEVERITY]
|
33
|
+
output.printf(
|
34
|
+
"%<sev>s, [%<time>s #%<pid>d] %<severity>5s -- : %<reqid>s%<message>s\n",
|
35
|
+
sev: severity[0],
|
36
|
+
severity:,
|
37
|
+
pid:,
|
38
|
+
reqid:,
|
39
|
+
time: log[TIME].strftime(DATETIME_FORMAT),
|
40
|
+
message: log[MESSAGE]
|
41
|
+
)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|