console 1.8.2 → 1.10.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/console.rb +7 -48
- data/lib/console/capture.rb +10 -5
- data/lib/console/event.rb +2 -0
- data/lib/console/event/failure.rb +8 -2
- data/lib/console/event/generic.rb +7 -0
- data/lib/console/event/metric.rb +49 -0
- data/lib/console/event/progress.rb +75 -0
- data/lib/console/event/spawn.rb +5 -0
- data/lib/console/filter.rb +1 -1
- data/lib/console/logger.rb +52 -0
- data/lib/console/progress.rb +142 -0
- data/lib/console/resolver.rb +30 -0
- data/lib/console/terminal/logger.rb +13 -1
- data/lib/console/version.rb +1 -1
- metadata +27 -20
- data/.editorconfig +0 -6
- data/.gitignore +0 -12
- data/.rspec +0 -4
- data/.travis.yml +0 -19
- data/Gemfile +0 -8
- data/README.md +0 -212
- data/Rakefile +0 -6
- data/console.gemspec +0 -27
- data/proposal.md +0 -84
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8a777953a8fd749c475d101a185f5f45ab11005574c3f23e413c16058e22500b
|
4
|
+
data.tar.gz: 778b3da976350ffc23d5aad6d142a9398ffbd0be6c8e5931c8c5c9b4f3c49f63
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: '0280c9d59cd23431f0c2ede8da258795790af325c64dacc63dc791a0682baad85348ddbd04ef954ad17ade370958a606b6f83e42ae4c8873eaea4bc11f4a409a'
|
7
|
+
data.tar.gz: eb013fb3e45477510bf1cdf40fbfbba739be5cb3fda1f8366eb97c3898d31a7eb932a3c72c8a668e6e78f0ea57cc0d813207f50567168d0e6ea723ef09898533
|
data/lib/console.rb
CHANGED
@@ -20,65 +20,24 @@
|
|
20
20
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
21
|
# THE SOFTWARE.
|
22
22
|
|
23
|
+
require_relative 'console/version'
|
23
24
|
require_relative 'console/logger'
|
24
|
-
require_relative 'console/resolver'
|
25
|
-
require_relative 'console/terminal/logger'
|
26
25
|
|
27
26
|
module Console
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
# Set the default log level based on `$DEBUG` and `$VERBOSE`.
|
32
|
-
# You can also specify CONSOLE_LEVEL=debug or CONSOLE_LEVEL=info in environment.
|
33
|
-
# https://mislav.net/2011/06/ruby-verbose-mode/ has more details about how it all fits together.
|
34
|
-
def default_log_level(env = ENV)
|
35
|
-
if level = (env['CONSOLE_LEVEL'] || env['CONSOLE_LOG_LEVEL'])
|
36
|
-
Logger::LEVELS[level.to_sym] || Logger.warn
|
37
|
-
elsif $DEBUG
|
38
|
-
Logger::DEBUG
|
39
|
-
elsif $VERBOSE.nil?
|
40
|
-
Logger::WARN
|
41
|
-
else
|
42
|
-
Logger::INFO
|
43
|
-
end
|
44
|
-
end
|
45
|
-
|
46
|
-
def default_resolver(logger, env = ENV)
|
47
|
-
if names = env['CONSOLE_DEBUG']&.split(',')
|
48
|
-
resolver = Resolver.new
|
49
|
-
|
50
|
-
resolver.bind(names) do |klass|
|
51
|
-
logger.enable(klass, Logger::DEBUG)
|
52
|
-
end
|
53
|
-
|
54
|
-
return resolver
|
55
|
-
end
|
56
|
-
end
|
57
|
-
|
58
|
-
# Controls verbose output using `$VERBOSE`.
|
59
|
-
def verbose?
|
60
|
-
!$VERBOSE.nil?
|
61
|
-
end
|
62
|
-
|
63
|
-
def build(output, verbose: self.verbose?, level: self.default_log_level)
|
64
|
-
terminal = Terminal::Logger.new(output, verbose: verbose)
|
65
|
-
|
66
|
-
logger = Logger.new(terminal, verbose: verbose, level: level)
|
67
|
-
|
68
|
-
return logger
|
69
|
-
end
|
27
|
+
def self.logger
|
28
|
+
Logger.instance
|
70
29
|
end
|
71
30
|
|
72
|
-
|
73
|
-
|
74
|
-
|
31
|
+
def self.logger= instance
|
32
|
+
Logger.instance= instance
|
33
|
+
end
|
75
34
|
|
76
35
|
def logger= logger
|
77
36
|
@logger = logger
|
78
37
|
end
|
79
38
|
|
80
39
|
def logger
|
81
|
-
@logger ||
|
40
|
+
@logger || Logger.instance
|
82
41
|
end
|
83
42
|
|
84
43
|
def self.extended(klass)
|
data/lib/console/capture.rb
CHANGED
@@ -21,15 +21,20 @@
|
|
21
21
|
require_relative 'filter'
|
22
22
|
|
23
23
|
module Console
|
24
|
+
# A general sink which captures all events into a buffer.
|
24
25
|
class Capture
|
25
26
|
def initialize
|
26
|
-
@
|
27
|
+
@buffer = []
|
27
28
|
end
|
28
29
|
|
29
|
-
attr :
|
30
|
+
attr :buffer
|
30
31
|
|
31
32
|
def last
|
32
|
-
@
|
33
|
+
@buffer.last
|
34
|
+
end
|
35
|
+
|
36
|
+
def clear
|
37
|
+
@buffer.clear
|
33
38
|
end
|
34
39
|
|
35
40
|
def verbose!(value = true)
|
@@ -37,7 +42,7 @@ module Console
|
|
37
42
|
|
38
43
|
def call(subject = nil, *arguments, severity: UNKNOWN, **options, &block)
|
39
44
|
message = {
|
40
|
-
time: Time.now.iso8601,
|
45
|
+
time: ::Time.now.iso8601,
|
41
46
|
severity: severity,
|
42
47
|
**options,
|
43
48
|
}
|
@@ -60,7 +65,7 @@ module Console
|
|
60
65
|
end
|
61
66
|
end
|
62
67
|
|
63
|
-
@
|
68
|
+
@buffer << message
|
64
69
|
end
|
65
70
|
end
|
66
71
|
end
|
data/lib/console/event.rb
CHANGED
@@ -49,6 +49,10 @@ module Console
|
|
49
49
|
terminal[:exception_backtrace] ||= terminal.style(:red)
|
50
50
|
end
|
51
51
|
|
52
|
+
def to_h
|
53
|
+
{exception: @exception, root: @root}
|
54
|
+
end
|
55
|
+
|
52
56
|
def format(output, terminal, verbose)
|
53
57
|
format_exception(@exception, nil, output, terminal, verbose)
|
54
58
|
end
|
@@ -62,12 +66,14 @@ module Console
|
|
62
66
|
output.puts " #{terminal[:exception_detail]}#{line}#{terminal.reset}"
|
63
67
|
end
|
64
68
|
|
69
|
+
root_expr = /^#{@root}\// if @root
|
70
|
+
|
65
71
|
exception.backtrace&.each_with_index do |line, index|
|
66
72
|
path, offset, message = line.split(":")
|
67
73
|
|
68
74
|
# Make the path a bit more readable
|
69
|
-
path.
|
70
|
-
|
75
|
+
path.sub!(root_expr, "./") if root_expr
|
76
|
+
|
71
77
|
output.puts " #{index == 0 ? "→" : " "} #{terminal[:exception_backtrace]}#{path}:#{offset}#{terminal.reset} #{message}"
|
72
78
|
end
|
73
79
|
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# Copyright, 2017, by Samuel G. D. Williams. <http://www.codeotaku.com>
|
2
|
+
#
|
3
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
+
# of this software and associated documentation files (the "Software"), to deal
|
5
|
+
# in the Software without restriction, including without limitation the rights
|
6
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
+
# copies of the Software, and to permit persons to whom the Software is
|
8
|
+
# furnished to do so, subject to the following conditions:
|
9
|
+
#
|
10
|
+
# The above copyright notice and this permission notice shall be included in
|
11
|
+
# all copies or substantial portions of the Software.
|
12
|
+
#
|
13
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19
|
+
# THE SOFTWARE.
|
20
|
+
|
21
|
+
require_relative 'generic'
|
22
|
+
|
23
|
+
module Console
|
24
|
+
module Event
|
25
|
+
class Metric < Generic
|
26
|
+
def self.[](**parameters)
|
27
|
+
parameters.map(&self.method(:new))
|
28
|
+
end
|
29
|
+
|
30
|
+
def initialize(name, value, **tags)
|
31
|
+
@name = name
|
32
|
+
@value = value
|
33
|
+
@tags = tags
|
34
|
+
end
|
35
|
+
|
36
|
+
attr :name
|
37
|
+
attr :value
|
38
|
+
attr :tags
|
39
|
+
|
40
|
+
def to_h
|
41
|
+
{name: @name, value: @value, tags: @tags}
|
42
|
+
end
|
43
|
+
|
44
|
+
def format(output, terminal, verbose)
|
45
|
+
output.puts "#{@name}=#{@value} #{@tags.inspect}"
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
# Copyright, 2017, by Samuel G. D. Williams. <http://www.codeotaku.com>
|
2
|
+
#
|
3
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
+
# of this software and associated documentation files (the "Software"), to deal
|
5
|
+
# in the Software without restriction, including without limitation the rights
|
6
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
+
# copies of the Software, and to permit persons to whom the Software is
|
8
|
+
# furnished to do so, subject to the following conditions:
|
9
|
+
#
|
10
|
+
# The above copyright notice and this permission notice shall be included in
|
11
|
+
# all copies or substantial portions of the Software.
|
12
|
+
#
|
13
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19
|
+
# THE SOFTWARE.
|
20
|
+
|
21
|
+
require_relative 'generic'
|
22
|
+
|
23
|
+
module Console
|
24
|
+
module Event
|
25
|
+
class Progress < Generic
|
26
|
+
BLOCK = [
|
27
|
+
" ",
|
28
|
+
"▏",
|
29
|
+
"▎",
|
30
|
+
"▍",
|
31
|
+
"▌",
|
32
|
+
"▋",
|
33
|
+
"▊",
|
34
|
+
"▉",
|
35
|
+
"█",
|
36
|
+
]
|
37
|
+
|
38
|
+
def initialize(current, total)
|
39
|
+
@current = current
|
40
|
+
@total = total
|
41
|
+
end
|
42
|
+
|
43
|
+
attr :current
|
44
|
+
attr :total
|
45
|
+
|
46
|
+
def value
|
47
|
+
@current.to_f / @total.to_f
|
48
|
+
end
|
49
|
+
|
50
|
+
def bar(value = self.value, width = 70)
|
51
|
+
blocks = width * value
|
52
|
+
full_blocks = blocks.floor
|
53
|
+
partial_block = ((blocks - full_blocks) * BLOCK.size).floor
|
54
|
+
|
55
|
+
if partial_block.zero?
|
56
|
+
BLOCK.last * full_blocks
|
57
|
+
else
|
58
|
+
"#{BLOCK.last * full_blocks}#{BLOCK[partial_block]}"
|
59
|
+
end.ljust(width)
|
60
|
+
end
|
61
|
+
|
62
|
+
def self.register(terminal)
|
63
|
+
terminal[:progress_bar] ||= terminal.style(:blue, :white)
|
64
|
+
end
|
65
|
+
|
66
|
+
def to_h
|
67
|
+
{current: @current, total: @total}
|
68
|
+
end
|
69
|
+
|
70
|
+
def format(output, terminal, verbose)
|
71
|
+
output.puts "#{terminal[:progress_bar]}#{self.bar}#{terminal.reset} #{sprintf('%6.2f', self.value * 100)}%"
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
data/lib/console/event/spawn.rb
CHANGED
@@ -24,6 +24,7 @@ module Console
|
|
24
24
|
module Event
|
25
25
|
class Spawn < Generic
|
26
26
|
def self.for(*arguments, **options)
|
27
|
+
# Extract out the command environment:
|
27
28
|
if arguments.first.is_a?(Hash)
|
28
29
|
self.new(*arguments, **options)
|
29
30
|
else
|
@@ -51,6 +52,10 @@ module Console
|
|
51
52
|
terminal[:shell_command] ||= terminal.style(:blue, nil, :bold)
|
52
53
|
end
|
53
54
|
|
55
|
+
def to_h
|
56
|
+
{environment: @environment, arguments: @arguments, options: @options}
|
57
|
+
end
|
58
|
+
|
54
59
|
def format(output, terminal, verbose)
|
55
60
|
arguments = @arguments.flatten.collect(&:to_s)
|
56
61
|
|
data/lib/console/filter.rb
CHANGED
data/lib/console/logger.rb
CHANGED
@@ -19,13 +19,65 @@
|
|
19
19
|
# THE SOFTWARE.
|
20
20
|
|
21
21
|
require_relative 'filter'
|
22
|
+
require_relative 'progress'
|
23
|
+
|
24
|
+
require_relative 'resolver'
|
25
|
+
require_relative 'terminal/logger'
|
26
|
+
|
27
|
+
require 'fiber/local'
|
22
28
|
|
23
29
|
module Console
|
24
30
|
class Logger < Filter[debug: 0, info: 1, warn: 2, error: 3, fatal: 4]
|
31
|
+
extend Fiber::Local
|
32
|
+
|
33
|
+
# Set the default log level based on `$DEBUG` and `$VERBOSE`.
|
34
|
+
# You can also specify CONSOLE_LEVEL=debug or CONSOLE_LEVEL=info in environment.
|
35
|
+
# https://mislav.net/2011/06/ruby-verbose-mode/ has more details about how it all fits together.
|
36
|
+
def self.default_log_level(env = ENV)
|
37
|
+
if level = (env['CONSOLE_LEVEL'] || env['CONSOLE_LOG_LEVEL'])
|
38
|
+
LEVELS[level.to_sym] || level.to_i
|
39
|
+
elsif $DEBUG
|
40
|
+
DEBUG
|
41
|
+
elsif $VERBOSE.nil?
|
42
|
+
WARN
|
43
|
+
else
|
44
|
+
INFO
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
# Controls verbose output using `$VERBOSE`.
|
49
|
+
def self.verbose?(env = ENV)
|
50
|
+
!$VERBOSE.nil? || env['CONSOLE_VERBOSE']
|
51
|
+
end
|
52
|
+
|
53
|
+
def self.default_logger(output, verbose: self.verbose?, level: self.default_log_level)
|
54
|
+
terminal = Terminal::Logger.new(output, verbose: verbose)
|
55
|
+
|
56
|
+
logger = self.new(terminal, verbose: verbose, level: level)
|
57
|
+
Resolver.default_resolver(logger)
|
58
|
+
|
59
|
+
return logger
|
60
|
+
end
|
61
|
+
|
62
|
+
def self.local
|
63
|
+
self.default_logger($stderr)
|
64
|
+
end
|
65
|
+
|
25
66
|
DEFAULT_LEVEL = 1
|
26
67
|
|
27
68
|
def initialize(output, **options)
|
28
69
|
super(output, **options)
|
29
70
|
end
|
71
|
+
|
72
|
+
def progress(subject, total, **options)
|
73
|
+
Progress.new(self, subject, total, **options)
|
74
|
+
end
|
75
|
+
|
76
|
+
# @deprecated Please use {progress}.
|
77
|
+
alias measure progress
|
78
|
+
|
79
|
+
def failure(subject, exception, *arguments, &block)
|
80
|
+
fatal(subject, *arguments, Event::Failure.new(exception), &block)
|
81
|
+
end
|
30
82
|
end
|
31
83
|
end
|
@@ -0,0 +1,142 @@
|
|
1
|
+
# Copyright, 2019, by Samuel G. D. Williams. <http://www.codeotaku.com>
|
2
|
+
#
|
3
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
+
# of this software and associated documentation files (the "Software"), to deal
|
5
|
+
# in the Software without restriction, including without limitation the rights
|
6
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
+
# copies of the Software, and to permit persons to whom the Software is
|
8
|
+
# furnished to do so, subject to the following conditions:
|
9
|
+
#
|
10
|
+
# The above copyright notice and this permission notice shall be included in
|
11
|
+
# all copies or substantial portions of the Software.
|
12
|
+
#
|
13
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19
|
+
# THE SOFTWARE.
|
20
|
+
|
21
|
+
require_relative 'event/progress'
|
22
|
+
|
23
|
+
module Console
|
24
|
+
class Progress
|
25
|
+
def self.now
|
26
|
+
Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
27
|
+
end
|
28
|
+
|
29
|
+
def initialize(output, subject, total = 0, minimum_output_duration: 1.0)
|
30
|
+
@output = output
|
31
|
+
@subject = subject
|
32
|
+
|
33
|
+
@start_time = Progress.now
|
34
|
+
|
35
|
+
@last_output_time = nil
|
36
|
+
@minimum_output_duration = 0.1
|
37
|
+
|
38
|
+
@current = 0
|
39
|
+
@total = total
|
40
|
+
end
|
41
|
+
|
42
|
+
attr :subject
|
43
|
+
attr :current
|
44
|
+
attr :total
|
45
|
+
|
46
|
+
def duration
|
47
|
+
Progress.now - @start_time
|
48
|
+
end
|
49
|
+
|
50
|
+
def progress
|
51
|
+
@current.to_f / @total.to_f
|
52
|
+
end
|
53
|
+
|
54
|
+
def remaining
|
55
|
+
@total - @current
|
56
|
+
end
|
57
|
+
|
58
|
+
def average_duration
|
59
|
+
if @current > 0
|
60
|
+
duration / @current
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def estimated_remaining_time
|
65
|
+
if average_duration = self.average_duration
|
66
|
+
average_duration * remaining
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def increment(amount = 1)
|
71
|
+
@current += amount
|
72
|
+
|
73
|
+
if output?
|
74
|
+
@output.info(@subject, self) {Event::Progress.new(@current, @total)}
|
75
|
+
@last_output_time = Progress.now
|
76
|
+
end
|
77
|
+
|
78
|
+
return self
|
79
|
+
end
|
80
|
+
|
81
|
+
def resize(total)
|
82
|
+
@total = total
|
83
|
+
|
84
|
+
@output.info(@subject, self) {Event::Progress.new(@current, @total)}
|
85
|
+
@last_output_time = Progress.now
|
86
|
+
|
87
|
+
return self
|
88
|
+
end
|
89
|
+
|
90
|
+
def mark(*arguments)
|
91
|
+
@output.info(@subject, *arguments)
|
92
|
+
end
|
93
|
+
|
94
|
+
def to_s
|
95
|
+
if estimated_remaining_time = self.estimated_remaining_time
|
96
|
+
"#{@current}/#{@total} completed in #{formatted_duration(self.duration)}, #{formatted_duration(estimated_remaining_time)} remaining."
|
97
|
+
else
|
98
|
+
"#{@current}/#{@total} completed, waiting for estimate..."
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
private
|
103
|
+
|
104
|
+
def duration_since_last_output
|
105
|
+
if @last_output_time
|
106
|
+
Progress.now - @last_output_time
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
def output?
|
111
|
+
if remaining.zero?
|
112
|
+
return true
|
113
|
+
elsif duration = duration_since_last_output
|
114
|
+
return duration > @minimum_output_duration
|
115
|
+
else
|
116
|
+
return true
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
def formatted_duration(duration)
|
121
|
+
if duration < 60.0
|
122
|
+
return "#{duration.round(2)}s"
|
123
|
+
end
|
124
|
+
|
125
|
+
duration /= 60.0
|
126
|
+
|
127
|
+
if duration < 60.0
|
128
|
+
return "#{duration.round}m"
|
129
|
+
end
|
130
|
+
|
131
|
+
duration /= 60.0
|
132
|
+
|
133
|
+
if duration < 60.0
|
134
|
+
return "#{duration.round(1)}h"
|
135
|
+
end
|
136
|
+
|
137
|
+
duration /= 24.0
|
138
|
+
|
139
|
+
return "#{duration.round(1)}d"
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
data/lib/console/resolver.rb
CHANGED
@@ -22,6 +22,36 @@ require_relative 'filter'
|
|
22
22
|
|
23
23
|
module Console
|
24
24
|
class Resolver
|
25
|
+
# You can change the log level for different classes using CONSOLE_<LEVEL> env vars.
|
26
|
+
#
|
27
|
+
# e.g. `CONSOLE_WARN=Acorn,Banana CONSOLE_DEBUG=Cat` will set the log level for the classes Acorn and Banana to `warn` and Cat to `debug`. This overrides the default log level.
|
28
|
+
#
|
29
|
+
# @parameter logger [Logger] A logger instance to set the logging levels on.
|
30
|
+
# @parameter env [Hash] The environment to read levels from.
|
31
|
+
#
|
32
|
+
# @returns [Nil] If there were no custom logging levels specified in the environment.
|
33
|
+
# @returns [Resolver] If there were custom logging levels, then the created resolver is returned.
|
34
|
+
def self.default_resolver(logger, env = ENV)
|
35
|
+
# Find all CONSOLE_<LEVEL> variables from environment:
|
36
|
+
levels = Logger::LEVELS
|
37
|
+
.map{|label, level| [level, env["CONSOLE_#{label.upcase}"]&.split(',')]}
|
38
|
+
.to_h
|
39
|
+
.compact
|
40
|
+
|
41
|
+
# If we have any levels, then create a class resolver, and each time a class is resolved, set the log level for that class to the specified level:
|
42
|
+
if levels.any?
|
43
|
+
resolver = Resolver.new
|
44
|
+
|
45
|
+
levels.each do |level, names|
|
46
|
+
resolver.bind(names) do |klass|
|
47
|
+
logger.enable(klass, level)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
return resolver
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
25
55
|
def initialize
|
26
56
|
@names = {}
|
27
57
|
|
@@ -24,6 +24,8 @@ require_relative '../event'
|
|
24
24
|
require_relative 'text'
|
25
25
|
require_relative 'xterm'
|
26
26
|
|
27
|
+
require 'json'
|
28
|
+
|
27
29
|
module Console
|
28
30
|
module Terminal
|
29
31
|
# This, and all related methods, is considered private.
|
@@ -77,7 +79,9 @@ module Console
|
|
77
79
|
end
|
78
80
|
|
79
81
|
attr :io
|
82
|
+
|
80
83
|
attr_accessor :verbose
|
84
|
+
|
81
85
|
attr :start
|
82
86
|
attr :terminal
|
83
87
|
|
@@ -94,7 +98,7 @@ module Console
|
|
94
98
|
|
95
99
|
UNKNOWN = 'unknown'
|
96
100
|
|
97
|
-
def call(subject = nil, *arguments, name: nil, severity: UNKNOWN, &block)
|
101
|
+
def call(subject = nil, *arguments, name: nil, severity: UNKNOWN, **options, &block)
|
98
102
|
prefix = build_prefix(name || severity.to_s)
|
99
103
|
indent = " " * prefix.size
|
100
104
|
|
@@ -104,6 +108,10 @@ module Console
|
|
104
108
|
format_subject(severity, prefix, subject, buffer)
|
105
109
|
end
|
106
110
|
|
111
|
+
if options&.any?
|
112
|
+
format_options(options, buffer)
|
113
|
+
end
|
114
|
+
|
107
115
|
arguments.each do |argument|
|
108
116
|
format_argument(argument, buffer)
|
109
117
|
end
|
@@ -121,6 +129,10 @@ module Console
|
|
121
129
|
|
122
130
|
protected
|
123
131
|
|
132
|
+
def format_options(options, output)
|
133
|
+
format_value(options.to_json, output)
|
134
|
+
end
|
135
|
+
|
124
136
|
def format_argument(argument, output)
|
125
137
|
case argument
|
126
138
|
when Exception
|
data/lib/console/version.rb
CHANGED
metadata
CHANGED
@@ -1,15 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: console
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.10.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Samuel Williams
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-03-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: fiber-local
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
13
27
|
- !ruby/object:Gem::Dependency
|
14
28
|
name: bake
|
15
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -25,7 +39,7 @@ dependencies:
|
|
25
39
|
- !ruby/object:Gem::Version
|
26
40
|
version: '0'
|
27
41
|
- !ruby/object:Gem::Dependency
|
28
|
-
name:
|
42
|
+
name: bundler
|
29
43
|
requirement: !ruby/object:Gem::Requirement
|
30
44
|
requirements:
|
31
45
|
- - ">="
|
@@ -39,7 +53,7 @@ dependencies:
|
|
39
53
|
- !ruby/object:Gem::Version
|
40
54
|
version: '0'
|
41
55
|
- !ruby/object:Gem::Dependency
|
42
|
-
name:
|
56
|
+
name: covered
|
43
57
|
requirement: !ruby/object:Gem::Requirement
|
44
58
|
requirements:
|
45
59
|
- - ">="
|
@@ -80,31 +94,25 @@ dependencies:
|
|
80
94
|
- - "~>"
|
81
95
|
- !ruby/object:Gem::Version
|
82
96
|
version: '3.0'
|
83
|
-
description:
|
97
|
+
description:
|
84
98
|
email:
|
85
|
-
- samuel.williams@oriontransfer.co.nz
|
86
99
|
executables: []
|
87
100
|
extensions: []
|
88
101
|
extra_rdoc_files: []
|
89
102
|
files:
|
90
|
-
- ".editorconfig"
|
91
|
-
- ".gitignore"
|
92
|
-
- ".rspec"
|
93
|
-
- ".travis.yml"
|
94
|
-
- Gemfile
|
95
|
-
- README.md
|
96
|
-
- Rakefile
|
97
103
|
- bake/console.rb
|
98
|
-
- console.gemspec
|
99
104
|
- lib/console.rb
|
100
105
|
- lib/console/buffer.rb
|
101
106
|
- lib/console/capture.rb
|
102
107
|
- lib/console/event.rb
|
103
108
|
- lib/console/event/failure.rb
|
104
109
|
- lib/console/event/generic.rb
|
110
|
+
- lib/console/event/metric.rb
|
111
|
+
- lib/console/event/progress.rb
|
105
112
|
- lib/console/event/spawn.rb
|
106
113
|
- lib/console/filter.rb
|
107
114
|
- lib/console/logger.rb
|
115
|
+
- lib/console/progress.rb
|
108
116
|
- lib/console/resolver.rb
|
109
117
|
- lib/console/serialized/logger.rb
|
110
118
|
- lib/console/split.rb
|
@@ -113,12 +121,11 @@ files:
|
|
113
121
|
- lib/console/terminal/text.rb
|
114
122
|
- lib/console/terminal/xterm.rb
|
115
123
|
- lib/console/version.rb
|
116
|
-
- proposal.md
|
117
124
|
homepage: https://github.com/socketry/console
|
118
125
|
licenses:
|
119
126
|
- MIT
|
120
127
|
metadata: {}
|
121
|
-
post_install_message:
|
128
|
+
post_install_message:
|
122
129
|
rdoc_options: []
|
123
130
|
require_paths:
|
124
131
|
- lib
|
@@ -126,15 +133,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
126
133
|
requirements:
|
127
134
|
- - ">="
|
128
135
|
- !ruby/object:Gem::Version
|
129
|
-
version: '
|
136
|
+
version: '2.5'
|
130
137
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
131
138
|
requirements:
|
132
139
|
- - ">="
|
133
140
|
- !ruby/object:Gem::Version
|
134
141
|
version: '0'
|
135
142
|
requirements: []
|
136
|
-
rubygems_version: 3.
|
137
|
-
signing_key:
|
143
|
+
rubygems_version: 3.2.3
|
144
|
+
signing_key:
|
138
145
|
specification_version: 4
|
139
146
|
summary: Beautiful logging for Ruby.
|
140
147
|
test_files: []
|
data/.editorconfig
DELETED
data/.gitignore
DELETED
data/.rspec
DELETED
data/.travis.yml
DELETED
@@ -1,19 +0,0 @@
|
|
1
|
-
language: ruby
|
2
|
-
dist: xenial
|
3
|
-
cache: bundler
|
4
|
-
|
5
|
-
matrix:
|
6
|
-
include:
|
7
|
-
- rvm: 2.4
|
8
|
-
- rvm: 2.5
|
9
|
-
- rvm: 2.6
|
10
|
-
- rvm: 2.7
|
11
|
-
- rvm: 2.6
|
12
|
-
env: COVERAGE=PartialSummary,Coveralls
|
13
|
-
- rvm: truffleruby
|
14
|
-
- rvm: jruby-head
|
15
|
-
- rvm: ruby-head
|
16
|
-
allow_failures:
|
17
|
-
- rvm: truffleruby
|
18
|
-
- rvm: ruby-head
|
19
|
-
- rvm: jruby-head
|
data/Gemfile
DELETED
data/README.md
DELETED
@@ -1,212 +0,0 @@
|
|
1
|
-
# Console
|
2
|
-
|
3
|
-
Provides beautiful console logging for Ruby applications. Implements fast, buffered log output.
|
4
|
-
|
5
|
-
[![Build Status](https://travis-ci.com/socketry/console.svg)](http://travis-ci.com/socketry/console)
|
6
|
-
[![Coverage Status](https://coveralls.io/repos/socketry/console/badge.svg)](https://coveralls.io/r/socketry/console)
|
7
|
-
|
8
|
-
## Motivation
|
9
|
-
|
10
|
-
When Ruby decided to reverse the order of exception backtraces, I finally gave up using the built in logging and decided restore sanity to the output of my programs once and for all!
|
11
|
-
|
12
|
-
## Installation
|
13
|
-
|
14
|
-
Add this line to your application's Gemfile:
|
15
|
-
|
16
|
-
```ruby
|
17
|
-
gem 'console'
|
18
|
-
```
|
19
|
-
|
20
|
-
And then execute:
|
21
|
-
|
22
|
-
$ bundle
|
23
|
-
|
24
|
-
## Usage
|
25
|
-
|
26
|
-
As your code executes, it generates interesting events which you want to know about. The general approach is to use an `Console::Logger` which outputs text to the terminal. The text is generated by inspecting the console that occurred.
|
27
|
-
|
28
|
-
Capturing structured information allows it to be used in different ways. These events can be sent to a logger or some other system (e.g. web browser, syslog) and analysed in more detail.
|
29
|
-
|
30
|
-
### Default Logger
|
31
|
-
|
32
|
-
Generally speaking, use `Console.logger` which is suitable for logging to the user's terminal.
|
33
|
-
|
34
|
-
### Environment Variables
|
35
|
-
|
36
|
-
#### `CONSOLE_LEVEL=debug`
|
37
|
-
|
38
|
-
Control the default logger level. You can set it to any of the supported log levels: `debug`, `info`, `warn`, `error`, `fatal`.
|
39
|
-
|
40
|
-
#### `CONSOLE_DEBUG=MyClass,MyModule::MyClass`
|
41
|
-
|
42
|
-
Enable debug logging for the specified class names. You can specify one or more class names which will be resolved at runtime.
|
43
|
-
|
44
|
-
### Module Integration
|
45
|
-
|
46
|
-
```ruby
|
47
|
-
require 'console'
|
48
|
-
|
49
|
-
# Set the log level:
|
50
|
-
Console.logger.debug!
|
51
|
-
|
52
|
-
module MyModule
|
53
|
-
extend Console
|
54
|
-
|
55
|
-
def self.test_logger
|
56
|
-
logger.debug "GOTO LINE 1."
|
57
|
-
logger.info "5 things your doctor won't tell you!"
|
58
|
-
logger.warn "Something didn't work as expected!"
|
59
|
-
logger.error "The matrix has two cats!"
|
60
|
-
end
|
61
|
-
|
62
|
-
test_logger
|
63
|
-
end
|
64
|
-
```
|
65
|
-
|
66
|
-
### Class Integration
|
67
|
-
|
68
|
-
```ruby
|
69
|
-
require 'console'
|
70
|
-
|
71
|
-
# Set the log level:
|
72
|
-
Console.logger.debug!
|
73
|
-
|
74
|
-
class MyObject
|
75
|
-
include Console
|
76
|
-
|
77
|
-
def test_logger
|
78
|
-
logger.debug "GOTO LINE 1."
|
79
|
-
logger.info "5 things your doctor won't tell you!"
|
80
|
-
logger.warn "Something didn't work as expected!"
|
81
|
-
logger.error "The matrix has two cats!"
|
82
|
-
end
|
83
|
-
end
|
84
|
-
|
85
|
-
MyObject.new.test_logger
|
86
|
-
```
|
87
|
-
|
88
|
-
### Subject Logging
|
89
|
-
|
90
|
-
The first argument to the log method is the subject.
|
91
|
-
|
92
|
-
```ruby
|
93
|
-
class Thing
|
94
|
-
def call
|
95
|
-
Console.logger.info(self) {"Something is going on"}
|
96
|
-
end
|
97
|
-
end
|
98
|
-
```
|
99
|
-
|
100
|
-
Using this approach, you can turn on and off specific subjects by using the class name:
|
101
|
-
|
102
|
-
```ruby
|
103
|
-
$ CONSOLE_DEBUG=Thing ./script.rb
|
104
|
-
```
|
105
|
-
|
106
|
-
This will conditionally enable all log statements which have a subject of class `Thing`.
|
107
|
-
|
108
|
-
### Console Formatting
|
109
|
-
|
110
|
-
Console classes are used to wrap data which can generate structured log messages:
|
111
|
-
|
112
|
-
```ruby
|
113
|
-
require 'console'
|
114
|
-
|
115
|
-
class MyConsole < Console::Generic
|
116
|
-
def format(output, terminal, verbose)
|
117
|
-
output.puts "My console text!"
|
118
|
-
end
|
119
|
-
end
|
120
|
-
|
121
|
-
Console.logger.info("My Console", MyConsole.new)
|
122
|
-
```
|
123
|
-
|
124
|
-
#### Failure Events
|
125
|
-
|
126
|
-
`Console::Event::Failure` represents an exception and will log the message and backtrace recursively.
|
127
|
-
|
128
|
-
#### Spawn Events
|
129
|
-
|
130
|
-
`Console::Event::Spawn` represents the execution of a command, and will log the environment, arguments and options used to execute it.
|
131
|
-
|
132
|
-
### Custom Log Levels
|
133
|
-
|
134
|
-
`Console::Filter` implements support for multiple log levels.
|
135
|
-
|
136
|
-
```ruby
|
137
|
-
require 'console'
|
138
|
-
|
139
|
-
MyLogger = Console::Filter[noise: 0, stuff: 1, broken: 2]
|
140
|
-
|
141
|
-
# verbose: true - log severity/name/pid etc.
|
142
|
-
logger = MyLogger.new(Console.logger, name: "Java", verbose: true)
|
143
|
-
|
144
|
-
logger.broken("It's so janky.")
|
145
|
-
```
|
146
|
-
|
147
|
-
### Multiple Outputs
|
148
|
-
|
149
|
-
Use `Console::Split` to log to multiple destinations.
|
150
|
-
|
151
|
-
```ruby
|
152
|
-
require 'console/terminal'
|
153
|
-
require 'console/serialized/logger'
|
154
|
-
require 'console/logger'
|
155
|
-
require 'console/split'
|
156
|
-
|
157
|
-
terminal = Console::Terminal::Logger.new
|
158
|
-
file = Console::Serialized::Logger.new(File.open("log.json", "a"))
|
159
|
-
|
160
|
-
logger = Console::Logger.new(Console::Split[terminal, file])
|
161
|
-
|
162
|
-
logger.info "I can go everywhere!"
|
163
|
-
```
|
164
|
-
|
165
|
-
### Custom Logger Output
|
166
|
-
|
167
|
-
`Console::Logger` provides a default interface which is a drop in replacemnet for `Logger` and other similar implementations. The only method required for output is `#call(*arguments, **options, &block)`.
|
168
|
-
|
169
|
-
```ruby
|
170
|
-
require 'console/logger'
|
171
|
-
|
172
|
-
output = proc do |*arguments, **options, &block|
|
173
|
-
puts "arguments: #{arguments.inspect} options: #{options.inspect} block: #{block.call}"
|
174
|
-
end
|
175
|
-
|
176
|
-
logger = Console::Logger.new(output)
|
177
|
-
|
178
|
-
logger.info("Hello World!", meta: "data") {"block"}
|
179
|
-
# => arguments: ["Hello World!"] options: {:severity=>:info, :meta=>"data"} block: block
|
180
|
-
```
|
181
|
-
|
182
|
-
## Contributing
|
183
|
-
|
184
|
-
1. Fork it
|
185
|
-
2. Create your feature branch (`git checkout -b my-new-feature`)
|
186
|
-
3. Commit your changes (`git commit -am 'Add some feature'`)
|
187
|
-
4. Push to the branch (`git push origin my-new-feature`)
|
188
|
-
5. Create new Pull Request
|
189
|
-
|
190
|
-
## License
|
191
|
-
|
192
|
-
Released under the MIT license.
|
193
|
-
|
194
|
-
Copyright, 2019, by [Samuel Williams](https://www.codeotaku.com).
|
195
|
-
|
196
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
197
|
-
of this software and associated documentation files (the "Software"), to deal
|
198
|
-
in the Software without restriction, including without limitation the rights
|
199
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
200
|
-
copies of the Software, and to permit persons to whom the Software is
|
201
|
-
furnished to do so, subject to the following conditions:
|
202
|
-
|
203
|
-
The above copyright notice and this permission notice shall be included in
|
204
|
-
all copies or substantial portions of the Software.
|
205
|
-
|
206
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
207
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
208
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
209
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
210
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
211
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
212
|
-
THE SOFTWARE.
|
data/Rakefile
DELETED
data/console.gemspec
DELETED
@@ -1,27 +0,0 @@
|
|
1
|
-
|
2
|
-
require_relative "lib/console/version"
|
3
|
-
|
4
|
-
Gem::Specification.new do |spec|
|
5
|
-
spec.name = "console"
|
6
|
-
spec.version = Console::VERSION
|
7
|
-
spec.licenses = ["MIT"]
|
8
|
-
spec.authors = ["Samuel Williams"]
|
9
|
-
spec.email = ["samuel.williams@oriontransfer.co.nz"]
|
10
|
-
|
11
|
-
spec.summary = "Beautiful logging for Ruby."
|
12
|
-
spec.homepage = "https://github.com/socketry/console"
|
13
|
-
|
14
|
-
spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
|
15
|
-
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
16
|
-
end
|
17
|
-
|
18
|
-
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
19
|
-
spec.require_paths = ["lib"]
|
20
|
-
|
21
|
-
spec.add_development_dependency "bake"
|
22
|
-
|
23
|
-
spec.add_development_dependency "covered"
|
24
|
-
spec.add_development_dependency "bundler"
|
25
|
-
spec.add_development_dependency "rake", "~> 10.0"
|
26
|
-
spec.add_development_dependency "rspec", "~> 3.0"
|
27
|
-
end
|
data/proposal.md
DELETED
@@ -1,84 +0,0 @@
|
|
1
|
-
# Global Logger
|
2
|
-
|
3
|
-
Configure what logging looks like globally:
|
4
|
-
|
5
|
-
```ruby
|
6
|
-
Console.logger
|
7
|
-
```
|
8
|
-
|
9
|
-
Other logger instances would inherit their initial configuration from the global logger.
|
10
|
-
|
11
|
-
Rather than the output being configurable on the global logger, it would always route to `$stdout`. _Or perhaps no destinations should exist and you add one; there must be a way to attach a formatter to even the default destination._
|
12
|
-
|
13
|
-
# Adding Destinations
|
14
|
-
|
15
|
-
The global logger or any instance could log to multiple destinations:
|
16
|
-
|
17
|
-
```ruby
|
18
|
-
Console.add(some_io, formatter: some_formatter)
|
19
|
-
```
|
20
|
-
|
21
|
-
I _think_ that formatters would be defined on destinations. This would allow for writing in one format to `$stdout` and another to `syslog`, for example.
|
22
|
-
|
23
|
-
# Logger Instances
|
24
|
-
|
25
|
-
Named instances could be created with a given output:
|
26
|
-
|
27
|
-
```ruby
|
28
|
-
connection_logger = Console.new(:connection, output: ...)
|
29
|
-
```
|
30
|
-
|
31
|
-
Outputs would not reference an io object, but rather another named instance (defaulting to global). Again, Destinations + Formatters could be added to any instance. This would allow outputs to be chained.
|
32
|
-
|
33
|
-
## Instances As Subjects
|
34
|
-
|
35
|
-
Perhaps an interesting idea is letting logger instance names be subjects, controllable from the global logger. In the example above, `:connection` would become a known subject that could be enabled/disabled from the global logger:
|
36
|
-
|
37
|
-
```ruby
|
38
|
-
Console.disable(:connection)
|
39
|
-
```
|
40
|
-
|
41
|
-
This lets us very easily disable the logging of events of a particular type.
|
42
|
-
|
43
|
-
---
|
44
|
-
|
45
|
-
In [Pakyow's logger](https://gist.github.com/bryanp/0329d58c753f1fa6e99d970960ad006d#file-logger-rb), instances are created in these cases:
|
46
|
-
|
47
|
-
* Environment: Single logger for the environment, named `:pkyw`.
|
48
|
-
* Connection: Per-Request logger containing the connection id, named `:http`.
|
49
|
-
* WebSocket: Per-WebSocket logger containing the WebSocket id, named `:sock`.
|
50
|
-
* Async: The logger that async is configured with, named `:asnc`.
|
51
|
-
|
52
|
-
Instances could be initialized with metadata that is passed with the console to the formatter:
|
53
|
-
|
54
|
-
```ruby
|
55
|
-
connection_logger = Console.new(:http, output: ..., connection_id: "123")
|
56
|
-
```
|
57
|
-
|
58
|
-
# Formatters
|
59
|
-
|
60
|
-
Just a class with a `format` method that accepts an `console`, which is a hash or simple object containing the console data along with attached metadata (e.g. timestamp, metadata from the instance). Returns a string, and/or writes directly to the buffer.
|
61
|
-
|
62
|
-
# Custom Levels
|
63
|
-
|
64
|
-
Pakyow's logger uses the following levels:
|
65
|
-
|
66
|
-
* all
|
67
|
-
* verbose
|
68
|
-
* debug
|
69
|
-
* info
|
70
|
-
* warn
|
71
|
-
* error
|
72
|
-
* fatal
|
73
|
-
* unknown
|
74
|
-
* off
|
75
|
-
|
76
|
-
`all` and `off` aren't turned into logging methods in `Pakyow::Logger`, but rather the log level can be set to either one as an easy way to guarantee that all or no logs will be written, without knowing what the lowest and highest level of logging are in the system.
|
77
|
-
|
78
|
-
Projects often have different needs, so making this easily configurable on both the global logger and individual logger instances would be amazing:
|
79
|
-
|
80
|
-
```ruby
|
81
|
-
Console.levels(
|
82
|
-
%i(all verbose debug info warn error fatal unknown off)
|
83
|
-
)
|
84
|
-
```
|