console 1.7.2 → 1.9.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/bake/console.rb +15 -0
- data/lib/console.rb +23 -5
- data/lib/console/capture.rb +10 -5
- data/lib/console/event.rb +2 -0
- data/lib/console/event/failure.rb +4 -0
- 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 +12 -0
- data/lib/console/progress.rb +140 -0
- data/lib/console/terminal/logger.rb +13 -1
- data/lib/console/terminal/text.rb +30 -7
- data/lib/console/version.rb +1 -1
- metadata +26 -18
- 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 -13
- data/console.gemspec +0 -25
- 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: ebadd29a9248f8a155c3bc22550a6433e53af806acae2112fe96a3924c92fb8d
|
4
|
+
data.tar.gz: fd23c8cb36efc9a36f688c2caa0383feb85fe7fdab2992d269239650faa8f92a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 02b4cecf9844a7d6bb733da31953805d89590b5a43b68e7d6cc379bde7e2660e3064438385d40b147cde4c89b50b7f7f9f4cf3f58aa69e1498e0085f56015a86
|
7
|
+
data.tar.gz: 3bba83e7c801994f6fdb6a1a248fbac746a8a9987f786d30df73c91ba7d79032226d4f78d3eed9fb1a5d0eb9c339f89864c15fcceb823a2f877e81fe90c977f7
|
data/bake/console.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Increase the verbosity of the logger to info.
|
4
|
+
def info
|
5
|
+
require_relative '../lib/console'
|
6
|
+
|
7
|
+
Console.logger.info!
|
8
|
+
end
|
9
|
+
|
10
|
+
# Increase the verbosity of the logger to debug.
|
11
|
+
def debug
|
12
|
+
require_relative '../lib/console'
|
13
|
+
|
14
|
+
Console.logger.debug!
|
15
|
+
end
|
data/lib/console.rb
CHANGED
@@ -43,14 +43,32 @@ module Console
|
|
43
43
|
end
|
44
44
|
end
|
45
45
|
|
46
|
+
# You can change the log level for different classes using CONSOLE_<LEVEL> env vars.
|
47
|
+
#
|
48
|
+
# e.g. `CONSOLE_WARN=Acorn,Banana CONSOLE_DEBUG=Cat` will set the log level for Acorn and Banana to warn and Cat to
|
49
|
+
# debug. This overrides the default log level.
|
50
|
+
#
|
51
|
+
# @param logger [Logger] A logger instance to set the logging levels on.
|
52
|
+
# @param env [Hash] Environment to read levels from.
|
53
|
+
#
|
54
|
+
# @return [nil] if there were no custom logging levels specified in the environment.
|
55
|
+
# @return [Resolver] if there were custom logging levels, then the created resolver is returned.
|
46
56
|
def default_resolver(logger, env = ENV)
|
47
|
-
|
57
|
+
# find all CONSOLE_<LEVEL> variables from environment
|
58
|
+
levels = Logger::LEVELS
|
59
|
+
.map { |label, level| [level, env["CONSOLE_#{label.to_s.upcase}"]&.split(',')] }
|
60
|
+
.to_h
|
61
|
+
.compact
|
62
|
+
|
63
|
+
# if we have any levels, then create a class resolver, and each time a class is resolved, set the log level for
|
64
|
+
# that class to the specified level
|
65
|
+
if levels.any?
|
48
66
|
resolver = Resolver.new
|
49
|
-
|
50
|
-
|
51
|
-
|
67
|
+
levels.each do |level, names|
|
68
|
+
resolver.bind(names) do |klass|
|
69
|
+
logger.enable(klass, level)
|
70
|
+
end
|
52
71
|
end
|
53
|
-
|
54
72
|
return resolver
|
55
73
|
end
|
56
74
|
end
|
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
|
@@ -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,6 +19,7 @@
|
|
19
19
|
# THE SOFTWARE.
|
20
20
|
|
21
21
|
require_relative 'filter'
|
22
|
+
require_relative 'progress'
|
22
23
|
|
23
24
|
module Console
|
24
25
|
class Logger < Filter[debug: 0, info: 1, warn: 2, error: 3, fatal: 4]
|
@@ -27,5 +28,16 @@ module Console
|
|
27
28
|
def initialize(output, **options)
|
28
29
|
super(output, **options)
|
29
30
|
end
|
31
|
+
|
32
|
+
def progress(subject, total, **options)
|
33
|
+
Progress.new(self, subject, total, **options)
|
34
|
+
end
|
35
|
+
|
36
|
+
# @deprecated Please use {progress}.
|
37
|
+
alias measure progress
|
38
|
+
|
39
|
+
def failure(subject, exception, *arguments, &block)
|
40
|
+
fatal(subject, *arguments, Event::Failure.new(exception), &block)
|
41
|
+
end
|
30
42
|
end
|
31
43
|
end
|
@@ -0,0 +1,140 @@
|
|
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 #{self.formatted_duration self.duration}, #{self.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 duration = duration_since_last_output
|
112
|
+
return duration > @minimum_output_duration
|
113
|
+
else
|
114
|
+
return true
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
def formatted_duration(duration)
|
119
|
+
if duration < 60.0
|
120
|
+
return "#{duration.round(2)}s"
|
121
|
+
end
|
122
|
+
|
123
|
+
duration /= 60.0
|
124
|
+
|
125
|
+
if duration < 60.0
|
126
|
+
return "#{duration.round}m"
|
127
|
+
end
|
128
|
+
|
129
|
+
duration /= 60.0
|
130
|
+
|
131
|
+
if duration < 60.0
|
132
|
+
return "#{duration.round(1)}h"
|
133
|
+
end
|
134
|
+
|
135
|
+
duration /= 24.0
|
136
|
+
|
137
|
+
return "#{duration.round(1)}d"
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
@@ -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
|
@@ -26,7 +26,7 @@ module Console
|
|
26
26
|
class Text
|
27
27
|
def initialize(output)
|
28
28
|
@output = output
|
29
|
-
@styles = {}
|
29
|
+
@styles = {reset: self.reset}
|
30
30
|
end
|
31
31
|
|
32
32
|
def [] key
|
@@ -47,25 +47,48 @@ module Console
|
|
47
47
|
def reset
|
48
48
|
end
|
49
49
|
|
50
|
-
def write(*
|
50
|
+
def write(*arguments, style: nil)
|
51
51
|
if style and prefix = self[style]
|
52
52
|
@output.write(prefix)
|
53
|
-
@output.write(*
|
53
|
+
@output.write(*arguments)
|
54
54
|
@output.write(self.reset)
|
55
55
|
else
|
56
|
-
@output.write(*
|
56
|
+
@output.write(*arguments)
|
57
57
|
end
|
58
58
|
end
|
59
59
|
|
60
|
-
def puts(*
|
60
|
+
def puts(*arguments, style: nil)
|
61
61
|
if style and prefix = self[style]
|
62
62
|
@output.write(prefix)
|
63
|
-
@output.puts(*
|
63
|
+
@output.puts(*arguments)
|
64
64
|
@output.write(self.reset)
|
65
65
|
else
|
66
|
-
@output.puts(*
|
66
|
+
@output.puts(*arguments)
|
67
67
|
end
|
68
68
|
end
|
69
|
+
|
70
|
+
# Print out the given arguments.
|
71
|
+
# When the argument is a symbol, look up the style and inject it into the output stream.
|
72
|
+
# When the argument is a proc/lambda, call it with self as the argument.
|
73
|
+
# When the argument is anything else, write it directly to the output.
|
74
|
+
def print(*arguments)
|
75
|
+
arguments.each do |argument|
|
76
|
+
case argument
|
77
|
+
when Symbol
|
78
|
+
@output.write(self[argument])
|
79
|
+
when Proc
|
80
|
+
argument.call(self)
|
81
|
+
else
|
82
|
+
@output.write(argument)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
# Print out the arguments as per {#print}, followed by the reset sequence and a newline.
|
88
|
+
def print_line(*arguments)
|
89
|
+
print(*arguments)
|
90
|
+
@output.puts(self.reset)
|
91
|
+
end
|
69
92
|
end
|
70
93
|
end
|
71
94
|
end
|
data/lib/console/version.rb
CHANGED
metadata
CHANGED
@@ -1,17 +1,17 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: console
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.9.1
|
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: 2020-
|
11
|
+
date: 2020-10-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
|
-
name:
|
14
|
+
name: bake
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
17
|
- - ">="
|
@@ -38,6 +38,20 @@ dependencies:
|
|
38
38
|
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: covered
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
41
55
|
- !ruby/object:Gem::Dependency
|
42
56
|
name: rake
|
43
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -66,30 +80,25 @@ dependencies:
|
|
66
80
|
- - "~>"
|
67
81
|
- !ruby/object:Gem::Version
|
68
82
|
version: '3.0'
|
69
|
-
description:
|
83
|
+
description:
|
70
84
|
email:
|
71
|
-
- samuel.williams@oriontransfer.co.nz
|
72
85
|
executables: []
|
73
86
|
extensions: []
|
74
87
|
extra_rdoc_files: []
|
75
88
|
files:
|
76
|
-
-
|
77
|
-
- ".gitignore"
|
78
|
-
- ".rspec"
|
79
|
-
- ".travis.yml"
|
80
|
-
- Gemfile
|
81
|
-
- README.md
|
82
|
-
- Rakefile
|
83
|
-
- console.gemspec
|
89
|
+
- bake/console.rb
|
84
90
|
- lib/console.rb
|
85
91
|
- lib/console/buffer.rb
|
86
92
|
- lib/console/capture.rb
|
87
93
|
- lib/console/event.rb
|
88
94
|
- lib/console/event/failure.rb
|
89
95
|
- lib/console/event/generic.rb
|
96
|
+
- lib/console/event/metric.rb
|
97
|
+
- lib/console/event/progress.rb
|
90
98
|
- lib/console/event/spawn.rb
|
91
99
|
- lib/console/filter.rb
|
92
100
|
- lib/console/logger.rb
|
101
|
+
- lib/console/progress.rb
|
93
102
|
- lib/console/resolver.rb
|
94
103
|
- lib/console/serialized/logger.rb
|
95
104
|
- lib/console/split.rb
|
@@ -98,12 +107,11 @@ files:
|
|
98
107
|
- lib/console/terminal/text.rb
|
99
108
|
- lib/console/terminal/xterm.rb
|
100
109
|
- lib/console/version.rb
|
101
|
-
- proposal.md
|
102
110
|
homepage: https://github.com/socketry/console
|
103
111
|
licenses:
|
104
112
|
- MIT
|
105
113
|
metadata: {}
|
106
|
-
post_install_message:
|
114
|
+
post_install_message:
|
107
115
|
rdoc_options: []
|
108
116
|
require_paths:
|
109
117
|
- lib
|
@@ -111,7 +119,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
111
119
|
requirements:
|
112
120
|
- - ">="
|
113
121
|
- !ruby/object:Gem::Version
|
114
|
-
version: '
|
122
|
+
version: '2.5'
|
115
123
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
116
124
|
requirements:
|
117
125
|
- - ">="
|
@@ -119,7 +127,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
119
127
|
version: '0'
|
120
128
|
requirements: []
|
121
129
|
rubygems_version: 3.1.2
|
122
|
-
signing_key:
|
130
|
+
signing_key:
|
123
131
|
specification_version: 4
|
124
132
|
summary: Beautiful logging for Ruby.
|
125
133
|
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,25 +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 "covered"
|
22
|
-
spec.add_development_dependency "bundler"
|
23
|
-
spec.add_development_dependency "rake", "~> 10.0"
|
24
|
-
spec.add_development_dependency "rspec", "~> 3.0"
|
25
|
-
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
|
-
```
|