console 0.5 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: d6d335e8b78f82a73be6a3cf6ab279594277fe4fd492d82db5da34695643219e
4
+ data.tar.gz: 22dd7d9b66f54a1bd38e563158d5ff58148e9f744d06a4d391ef8ae01676bb9d
5
+ SHA512:
6
+ metadata.gz: 9c4947d01b98cf603d14444be28815d4e7b6d3e3b7627be3b6f1d4d4d56f97702e7b61827c7c966533d696b73b9a0138b5a74fb2388fec645b5619b2e741ad2e
7
+ data.tar.gz: 8ecfe1ee0c30bc99b2662f6095defde0e99c8594a8a49b9c513f14914b80f84c9bc7ee7e13064097ac225a2f9a7a132ebae6b8f31c610cecd4c58e4cbfb77cf7
@@ -0,0 +1,11 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
9
+
10
+ # rspec failure tracking
11
+ .rspec_status
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
@@ -0,0 +1,15 @@
1
+ language: ruby
2
+ dist: xenial
3
+ cache: bundler
4
+
5
+ matrix:
6
+ include:
7
+ - rvm: 2.3
8
+ - rvm: 2.4
9
+ - rvm: 2.5
10
+ - rvm: 2.6
11
+ - rvm: 2.6
12
+ env: COVERAGE=BriefSummary,Coveralls
13
+ - rvm: ruby-head
14
+ - rvm: jruby-head
15
+ - rvm: truffleruby
data/Gemfile ADDED
@@ -0,0 +1,8 @@
1
+ source "https://rubygems.org"
2
+
3
+ git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
4
+
5
+ # Specify your gem's dependencies in console.gemspec
6
+ gemspec
7
+
8
+ gem "pry"
@@ -0,0 +1,165 @@
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
+ ### Module Integration
35
+
36
+ ```ruby
37
+ require 'console'
38
+
39
+ # Set the log level:
40
+ Console.logger.debug!
41
+
42
+ module MyModule
43
+ extend Console
44
+
45
+ def self.test_logger
46
+ logger.debug "GOTO LINE 1."
47
+ logger.info "5 things your doctor won't tell you!"
48
+ logger.warn "Something didn't work as expected!"
49
+ logger.error "The matrix has two cats!"
50
+ end
51
+
52
+ test_logger
53
+ end
54
+ ```
55
+
56
+ ### Class Integration
57
+
58
+ ```ruby
59
+ require 'console'
60
+
61
+ # Set the log level:
62
+ Console.logger.debug!
63
+
64
+ class MyObject
65
+ include Console
66
+
67
+ def test_logger
68
+ logger.debug "GOTO LINE 1."
69
+ logger.info "5 things your doctor won't tell you!"
70
+ logger.warn "Something didn't work as expected!"
71
+ logger.error "The matrix has two cats!"
72
+ end
73
+ end
74
+
75
+ MyObject.new.test_logger
76
+ ```
77
+
78
+ ### Console Formatting
79
+
80
+ Console classes are used to wrap data which can generate structured log messages:
81
+
82
+ ```ruby
83
+ require 'console'
84
+
85
+ class MyConsole < Console::Generic
86
+ def format(output, terminal, verbose)
87
+ output.puts "My console text!"
88
+ end
89
+ end
90
+
91
+ Console.logger.info("My Console", MyConsole.new)
92
+ ```
93
+
94
+ #### Error Events
95
+
96
+ `Console::Error` represents an error and will log the message and backtrace recursively.
97
+
98
+ #### Shell Events
99
+
100
+ `Console::Shell` represents the execution of a shell command, and will log the environment, arguments and options used to execute it.
101
+
102
+ ### Multiple Loggers
103
+
104
+ ### Custom Log Levels
105
+
106
+ `Console::Filter` implements support for multiple log levels.
107
+
108
+ ```ruby
109
+ require 'console'
110
+
111
+ MyLogger = Console::Filter[noise: 0, stuff: 1, broken: 2]
112
+
113
+ logger = MyLogger.new(Console.logger, name: "Java")
114
+ logger.verbose! # log severity/name/pid etc.
115
+
116
+ logger.broken("It's so janky.")
117
+ ```
118
+
119
+ ### Multiple Outputs
120
+
121
+ ```ruby
122
+ require 'console/terminal'
123
+ require 'console/serialized/logger'
124
+ require 'console/logger'
125
+ require 'console/split'
126
+
127
+ terminal = Console::Terminal::Logger.new
128
+ file = Console::Serialized::Logger.new(File.open("/tmp/log.json", "w"))
129
+
130
+ logger = Console::Logger.new(Console::Split[terminal, file])
131
+
132
+ logger.info "I can go everywhere!"
133
+ ```
134
+
135
+ ## Contributing
136
+
137
+ 1. Fork it
138
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
139
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
140
+ 4. Push to the branch (`git push origin my-new-feature`)
141
+ 5. Create new Pull Request
142
+
143
+ ## License
144
+
145
+ Released under the MIT license.
146
+
147
+ Copyright, 2019, by [Samuel Williams](https://www.codeotaku.com).
148
+
149
+ Permission is hereby granted, free of charge, to any person obtaining a copy
150
+ of this software and associated documentation files (the "Software"), to deal
151
+ in the Software without restriction, including without limitation the rights
152
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
153
+ copies of the Software, and to permit persons to whom the Software is
154
+ furnished to do so, subject to the following conditions:
155
+
156
+ The above copyright notice and this permission notice shall be included in
157
+ all copies or substantial portions of the Software.
158
+
159
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
160
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
161
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
162
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
163
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
164
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
165
+ THE SOFTWARE.
@@ -0,0 +1,13 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
7
+
8
+ task :console do
9
+ require 'pry'
10
+ require 'console'
11
+
12
+ binding.pry
13
+ end
@@ -0,0 +1,24 @@
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.authors = ["Samuel Williams"]
8
+ spec.email = ["samuel.williams@oriontransfer.co.nz"]
9
+
10
+ spec.summary = "Beautiful logging for Ruby."
11
+ spec.homepage = "https://github.com/socketry/console"
12
+
13
+ spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
14
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
15
+ end
16
+
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.require_paths = ["lib"]
19
+
20
+ spec.add_development_dependency "covered"
21
+ spec.add_development_dependency "bundler"
22
+ spec.add_development_dependency "rake", "~> 10.0"
23
+ spec.add_development_dependency "rspec", "~> 3.0"
24
+ end
@@ -0,0 +1,65 @@
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 'console/logger'
22
+ require_relative 'console/terminal/logger'
23
+
24
+ module Console
25
+ class << self
26
+ attr_accessor :logger
27
+
28
+ LEVELS = {
29
+ 'debug' => Logger::DEBUG,
30
+ 'info' => Logger::INFO,
31
+ }
32
+
33
+ # Set the default log level based on `$DEBUG` and `$VERBOSE`.
34
+ # You can also specify CONSOLE_LOG_LEVEL=debug or CONSOLE_LOG_LEVEL=info in environment.
35
+ def default_log_level(env = ENV)
36
+ if level = env['CONSOLE_LOG_LEVEL']
37
+ LEVELS[level] || Logger.warn
38
+ elsif $DEBUG
39
+ Logger::DEBUG
40
+ elsif $VERBOSE
41
+ Logger::INFO
42
+ else
43
+ Logger::WARN
44
+ end
45
+ end
46
+ end
47
+
48
+ # Create the logger instance:
49
+ @logger = Logger.new(
50
+ Terminal::Logger.new($stderr),
51
+ level: self.default_log_level,
52
+ )
53
+
54
+ def logger= logger
55
+ @logger = logger
56
+ end
57
+
58
+ def logger
59
+ @logger || Console.logger
60
+ end
61
+
62
+ def self.extended(klass)
63
+ klass.instance_variable_set(:@logger, nil)
64
+ end
65
+ end
@@ -0,0 +1,40 @@
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 'stringio'
22
+
23
+ module Console
24
+ class Buffer < StringIO
25
+ def initialize(prefix = nil)
26
+ @prefix = prefix
27
+
28
+ super()
29
+ end
30
+
31
+ def puts(*args, prefix: @prefix)
32
+ args.each do |arg|
33
+ self.write(prefix) if prefix
34
+ super(arg)
35
+ end
36
+ end
37
+
38
+ alias << puts
39
+ end
40
+ end
@@ -0,0 +1,66 @@
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 'filter'
22
+
23
+ module Console
24
+ class Capture
25
+ def initialize
26
+ @events = []
27
+ end
28
+
29
+ attr :events
30
+
31
+ def last
32
+ @events.last
33
+ end
34
+
35
+ def verbose!(value = true)
36
+ end
37
+
38
+ def call(subject = nil, *arguments, severity: UNKNOWN, **options, &block)
39
+ message = {
40
+ time: Time.now.iso8601,
41
+ severity: severity,
42
+ **options,
43
+ }
44
+
45
+ if subject
46
+ message[:subject] = subject
47
+ end
48
+
49
+ if arguments.any?
50
+ message[:arguments] = arguments
51
+ end
52
+
53
+ if block_given?
54
+ if block.arity.zero?
55
+ message[:message] = yield
56
+ else
57
+ buffer = StringIO.new
58
+ yield buffer
59
+ message[:message] = buffer.string
60
+ end
61
+ end
62
+
63
+ @events << message
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,76 @@
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 'generic'
22
+
23
+ module Console
24
+ class Error < Generic
25
+ def self.current_working_directory
26
+ Dir.getwd
27
+ rescue # e.g. Errno::EMFILE
28
+ nil
29
+ end
30
+
31
+ def self.for(exception)
32
+ self.new(exception, self.current_working_directory)
33
+ end
34
+
35
+ def initialize(exception, root = nil)
36
+ @exception = exception
37
+ @root = root
38
+ end
39
+
40
+ attr :exception
41
+ attr :root
42
+
43
+ def self.register(terminal)
44
+ terminal[:exception_title] ||= terminal.style(:red, nil, :bold)
45
+ terminal[:exception_detail] ||= terminal.style(:yellow)
46
+ terminal[:exception_backtrace] ||= terminal.style(:red)
47
+ end
48
+
49
+ def format(output, terminal, verbose)
50
+ format_exception(@exception, nil, output, terminal, verbose)
51
+ end
52
+
53
+ def format_exception(exception, prefix = nil, output, terminal, verbose)
54
+ lines = exception.message.lines.map(&:chomp)
55
+
56
+ output.puts " #{prefix}#{terminal[:exception_title]}#{exception.class}#{terminal.reset}: #{lines.shift}"
57
+
58
+ lines.each do |line|
59
+ output.puts " #{terminal[:exception_detail]}#{line}#{terminal.reset}"
60
+ end
61
+
62
+ exception.backtrace&.each_with_index do |line, index|
63
+ path, offset, message = line.split(":")
64
+
65
+ # Make the path a bit more readable
66
+ path.gsub!(/^#{@root}\//, "./") if @root
67
+
68
+ output.puts " #{index == 0 ? "→" : " "} #{terminal[:exception_backtrace]}#{path}:#{offset}#{terminal.reset} #{message}"
69
+ end
70
+
71
+ if exception.cause and verbose
72
+ format_exception(exception.cause, "Caused by ", output, terminal)
73
+ end
74
+ end
75
+ end
76
+ end