-
-
Notifications
You must be signed in to change notification settings - Fork 404
/
Copy pathlogging.rb
205 lines (184 loc) · 6.11 KB
/
logging.rb
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
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
# encoding: utf-8
# frozen_string_literal: true
require 'logger'
require 'thread'
module YARD
# Handles console logging for info, warnings and errors.
# Uses the stdlib Logger class in Ruby for all the backend logic.
class Logger < ::Logger
# The list of characters displayed beside the progress bar to indicate
# "movement".
# @since 0.8.2
PROGRESS_INDICATORS = %w(⣷ ⣯ ⣟ ⡿ ⢿ ⣻ ⣽ ⣾)
# @return [IO] the IO object being logged to
# @since 0.8.2
def io; @logdev end
def io=(pipe) @logdev = pipe end
# @return [Boolean] whether backtraces should be shown (by default
# this is on).
def show_backtraces; @show_backtraces || level == DEBUG end
attr_writer :show_backtraces
# @return [Boolean] whether progress indicators should be shown when
# logging CLIs (by default this is off).
def show_progress
return false if YARD.ruby18? # threading is too ineffective for progress support
return false if YARD.windows? # windows has poor ANSI support
return false unless io.tty? # no TTY support on IO
return false unless level > INFO # no progress in verbose/debug modes
@show_progress
end
attr_writer :show_progress
# The logger instance
# @return [Logger] the logger instance
def self.instance(pipe = STDOUT)
@logger ||= new(pipe)
end
# Creates a new logger
def initialize(pipe, *args)
super(pipe, *args)
self.io = pipe
self.show_backtraces = true
self.show_progress = false
self.level = WARN
self.formatter = method(:format_log)
self.warned = false
@progress_indicator = 0
@mutex = Mutex.new
@progress_msg = nil
@progress_last_update = Time.now
end
# Changes the debug level to DEBUG if $DEBUG is set
# and writes a debugging message.
def debug(*args)
self.level = DEBUG if $DEBUG
super
end
# Remembers when a warning occurs and writes a warning message.
def warn(*args)
self.warned = true
super
end
attr_accessor :warned
# Captures the duration of a block of code for benchmark analysis. Also
# calls {#progress} on the message to display it to the user.
#
# @todo Implement capture storage for reporting of benchmarks
# @param [String] msg the message to display
# @param [Symbol, nil] nontty_log the level to log as if the output
# stream is not a TTY. Use +nil+ for no alternate logging.
# @yield a block of arbitrary code to benchmark
# @return [void]
def capture(msg, nontty_log = :debug)
progress(msg, nontty_log)
yield
ensure
clear_progress
end
# Displays a progress indicator for a given message. This progress report
# is only displayed on TTY displays, otherwise the message is passed to
# the +nontty_log+ level.
#
# @param [String] msg the message to log
# @param [Symbol, nil] nontty_log the level to log as if the output
# stream is not a TTY. Use +nil+ for no alternate logging.
# @return [void]
# @since 0.8.2
def progress(msg, nontty_log = :debug)
send(nontty_log, msg) if nontty_log
return unless show_progress
icon = ""
if defined?(::Encoding)
icon = PROGRESS_INDICATORS[@progress_indicator] + " "
end
@mutex.synchronize do
print("\e[2K\e[?25l\e[1m#{icon}#{msg}\e[0m\r")
@progress_msg = msg
if Time.now - @progress_last_update > 0.2
@progress_indicator += 1
@progress_indicator %= PROGRESS_INDICATORS.size
@progress_last_update = Time.now
end
end
Thread.new do
sleep(0.05)
progress(msg + ".", nil) if @progress_msg == msg
end
end
# Clears the progress indicator in the TTY display.
# @return [void]
# @since 0.8.2
def clear_progress
return unless show_progress
print_no_newline("\e[?25h\e[2K")
@progress_msg = nil
end
# Displays an unformatted line to the logger output stream, adding
# a newline.
# @param [String] msg the message to display
# @return [void]
# @since 0.8.2
def puts(msg = '')
print("#{msg}\n")
end
alias print_no_newline <<
private :print_no_newline
# Displays an unformatted line to the logger output stream.
# @param [String] msg the message to display
# @return [void]
# @since 0.8.2
def print(msg = '')
clear_line
print_no_newline(msg)
end
alias << print
# Prints the backtrace +exc+ to the logger as error data.
#
# @param [Array<String>] exc the backtrace list
# @param [Symbol] level_meth the level to log backtrace at
# @return [void]
def backtrace(exc, level_meth = :error)
return unless show_backtraces
send(level_meth, "#{exc.class.class_name}: #{exc.message}")
send(level_meth, "Stack trace:" +
exc.backtrace[0..5].map {|x| "\n\t#{x}" }.join + "\n")
end
# Warns that the Ruby environment does not support continuations. Applies
# to JRuby, Rubinius and MacRuby. This warning will only display once
# per Ruby process.
#
# @deprecated Continuations are no longer needed by YARD 0.8.0+.
# @return [void]
def warn_no_continuations
end
# Sets the logger level for the duration of the block
#
# @example
# log.enter_level(Logger::ERROR) do
# YARD.parse_string "def x; end"
# end
# @param [Fixnum] new_level the logger level for the duration of the block.
# values can be found in Ruby's Logger class.
# @yield the block with the logger temporarily set to +new_level+
def enter_level(new_level = level)
old_level = level
self.level = new_level
yield
ensure
self.level = old_level
end
private
# Override this internal Logger method to clear line
def add(*args)
clear_line
super(*args)
end
def clear_line
return unless @progress_msg
print_no_newline("\e[2K\r")
end
# Log format (from Logger implementation). Used by Logger internally
def format_log(sev, _time, _prog, msg)
"[#{sev.downcase}]: #{msg}\n"
end
end
end