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,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
|