-
-
Notifications
You must be signed in to change notification settings - Fork 155
/
pretty_log_formatter.cr
149 lines (124 loc) · 3.53 KB
/
pretty_log_formatter.cr
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
struct Lucky::PrettyLogFormatter < Dexter::BaseFormatter
ENTRY_FORMATTERS = [
RequestStartedFormatter,
RequestEndedFormatter,
ExceptionFormatter,
AnyOtherDataFormatter,
]
def call : Nil
ENTRY_FORMATTERS.each do |entry_formatter|
formatter = entry_formatter.new(io, entry)
if formatter.should_format?
formatter.write
break
end
end
end
private abstract class EntryFormatter
private getter io, entry
delegate severity, to: entry
def initialize(@io : IO, @entry : ::Log::Entry)
end
abstract def should_format? : Bool
abstract def write : Nil
def local_context
res = Hash(String, ::Log::Metadata::Value).new
entry.context[:local]?.try &.as_h.each do |key, value|
res[key.to_s] = value
end
res
end
private def add_arrow : Nil
io << " #{arrow} "
end
private def arrow
arrow = "▸"
case severity.value
when ::Log::Severity::Warn.value
arrow.colorize.yellow
when .>= ::Log::Severity::Error.value
arrow.colorize.red
else
arrow.colorize.dim
end
end
private def add_request_id : Nil
if id = local_context["request_id"].to_s.presence
io << " (#{id.colorize.dim})"
end
end
end
private class RequestStartedFormatter < EntryFormatter
def should_format? : Bool
(Lucky::LogHandler::REQUEST_START_KEYS.values.to_a - local_context.keys).empty?
end
def write : Nil
io << "\n#{local_context["method"]} #{local_context["path"].colorize.underline}"
add_request_id
end
end
private class RequestEndedFormatter < EntryFormatter
def should_format? : Bool
(Lucky::LogHandler::REQUEST_END_KEYS.values.to_a - local_context.keys).empty?
end
def write : Nil
add_arrow
http_status = Lucky::LoggerHelpers.colored_http_status(local_context["status"].as_i)
io << "Sent #{http_status} (#{local_context["duration"]})"
add_request_id
end
end
private class ExceptionFormatter < EntryFormatter
def should_format? : Bool
entry.exception.present?
end
def write : Nil
add_arrow
entry.exception.try do |ex|
io << " #{ex.class.name} ".colorize.bold.on_red
if ex.message.try(&.lines)
io << "\n"
ex.message.try(&.lines).try(&.each do |line|
io << "\n "
io << line
end)
end
if backtrace = ex.backtrace?
io << "\n\n "
io << " Backtrace ".colorize.bold.black.on_white
io << "\n"
backtrace.each do |trace_line|
trace_line = trace_line.colorize.dim unless trace_line.starts_with?(/src|spec/)
io << "\n #{trace_line}"
end
io << "\n"
end
end
end
end
private class AnyOtherDataFormatter < EntryFormatter
private property index = 0
def should_format? : Bool
true
end
def write : Nil
add_arrow
io << "#{entry.message}" unless entry.message.empty?
io << local_context.map do |key, value|
"#{Wordsmith::Inflector.humanize(key)} #{colored(value.to_s)}".tap do
self.index += 1
end
end.join(". ")
end
private def colored(value : String)
if printing_first_value_of_warning?
value.colorize.bold.yellow
else
value.colorize.bold
end
end
private def printing_first_value_of_warning?
severity.value == ::Log::Severity::Warn.value && index.zero?
end
end
end