Class: RMTools::RMLogger

Inherits:
Object show all
Defined in:
lib/rmtools/dev/logging.rb

Overview

lazy logger with caller processing and highlighting

Constant Summary collapse

Modes =
[:debug, :log, :info, :warn, :error]
NOPRINT =
8
NOLOG =
4
PREV_CALLER =
2
INLINE =
1

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(format = {}) ⇒ RMLogger

Returns a new instance of RMLogger.



21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
# File 'lib/rmtools/dev/logging.rb', line 21

def initialize format={}
  @c = Painter
  @highlight = {
      :error => @c.red_bold("ERROR"),
      :warn => @c.red_bold("WARN"),
      :log => @c.cyan("INFO"),
      :info => @c.cyan_bold("INFO"),
      :debug => @c.gray_bold("DEBUG")
  }
  @file_formats = Hash.new(@default_format = {})
  set_format :global, format
  
  if ENV['LOGLEVEL']
    self.log_level = ENV['LOGLEVEL']
  elsif ENV['DEBUG'] || ENV['VERBOSE']
    self.log_level = 'DEBUG'
  elsif ENV['WARN'] || ENV['QUIET']
    self.log_level = 'WARN'
  elsif ENV['SILENT']
    self.log_level = 'ERROR'
  end
end

Instance Attribute Details

#default_formatObject (readonly)

Returns the value of attribute default_format.



13
14
15
# File 'lib/rmtools/dev/logging.rb', line 13

def default_format
  @default_format
end

#mute_debugObject

Returns the value of attribute mute_debug.



12
13
14
# File 'lib/rmtools/dev/logging.rb', line 12

def mute_debug
  @mute_debug
end

#mute_errorObject

Returns the value of attribute mute_error.



12
13
14
# File 'lib/rmtools/dev/logging.rb', line 12

def mute_error
  @mute_error
end

#mute_infoObject

Returns the value of attribute mute_info.



12
13
14
# File 'lib/rmtools/dev/logging.rb', line 12

def mute_info
  @mute_info
end

#mute_logObject

Returns the value of attribute mute_log.



12
13
14
# File 'lib/rmtools/dev/logging.rb', line 12

def mute_log
  @mute_log
end

#mute_warnObject

Returns the value of attribute mute_warn.



12
13
14
# File 'lib/rmtools/dev/logging.rb', line 12

def mute_warn
  @mute_warn
end

Instance Method Details

#_print(mode, text, opts, caler, bind, cfg) ⇒ Object

TODO: добавить фильтров, например, для обработки текста, который будет логирован



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
# File 'lib/rmtools/dev/logging.rb', line 113

def _print mode, text, opts, caler, bind, cfg
  log_ = opts&NOLOG==0
  print_ = opts&NOPRINT==0
  str = cfg.fmt.dup
  str.gsub! "%mode", @highlight[mode]
  if bind
    text = bind.report text
  elsif !text.is String
    text = text.inspect
  elsif cfg.detect_comments and text =~ /\A[ \t]*#[ \t]+\S/
    text = "\n" + @c.green(text.gsub(/^([ \t]*#[ \t])?/, cfg.precede_comments).chop)
  end
  out = cfg.out
  if cfg._time or cfg.path_format
    now = Time.now
    if cfg._time
      time = now.strftime cfg.tf[0]
      time << ".#{cfg.tf[1]%[now.usec/1000]}" if cfg.tf[1]
      str.gsub! "%time", time
    end
    out = now.strftime cfg.out if cfg.path_format
  end
  if caler
    caler.sub!(/block (?:\((\d+) levels\) )?in/) {"{#{$1||1}}"}
    str.gsub! "%caller", caler.sub(String::SIMPLE_CALLER_RE, cfg.cf)
  end
  str.gsub! "%text", text
  str << "\n" if opts&INLINE==0
  log_str = cfg.color_out ? str : @c.clean(str)
  RMTools.write out, log_str if log_
  Kernel::print str if print_
end

#_set_format(file, format) ⇒ Object



44
45
46
47
48
49
50
51
52
53
54
55
56
57
# File 'lib/rmtools/dev/logging.rb', line 44

def _set_format file, format
  file.print = !format.q
  file.out = format.out || format.log_file
  file.color_out = format.color_out || format.color_log
  file.detect_comments = !!format.detect_comments
  file.precede_comments = format.precede_comments || "# "
            
  file.path_format = '%'.in file.out if file.out
  file.tf   = format.time.to_a
  file.cf0 = format.caller
  file.cf = file.cf0.sub('%p') {'\1'}.sub('%f') {'\2'}.sub('%l') {'\3'}.sub('%m') {'\4'}
  file.fmt = format.format
  file._time, file._caller = '%time'.in(file.fmt), '%caller'.in(file.fmt)
end

#debug(*args) ⇒ Object Also known as: <=



205
206
207
208
209
210
211
212
213
214
# File 'lib/rmtools/dev/logging.rb', line 205

def debug *args
  cfg = get_config!
  if (cfg.print or cfg.out && cfg.out_all) && !@mute_debug
    text, bind, opts = args.get_opts [!block_given? && args[0].kinda(Hash) ? args[0] : "\b\b ", nil], :mute => 0
    opts[:mute] |= NOLOG if !(cfg.out && cfg.out_all)
    opts[:mute] |= NOPRINT if !cfg.print
    return if block_given? && (text = yield).nil?
    _print(:debug, text, opts[:mute], cfg._caller && (@current_caller || caller)[opts[:caller].to_i], bind, cfg)
  end 
end

#defaultsObject Also known as: usage



59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
# File 'lib/rmtools/dev/logging.rb', line 59

def defaults
  Kernel::puts %{    # #{@c.y 'common options:'}
:q => false,   # not print
:out => false, # output to file, may contain strftime's %H%M%Y etc for filename
:time => ["%H:%M:%S", "%03d"], # strftime, [msecs]
:type => :console, # or :html
# #{@c.y 'console values:'}
:caller => "#{@c.gray('%f:%l')} #{@c.red_bold(':%m')}", # "file:line :method", %p is for fullpath
:format => "%time %mode [%caller]: %text" # format of entire log string, %mode is {#{%w(debug log info warn).map {|i| @highlight[i.to_sym]}*', '}}
:color_out => false, # do not clean control characters that make output to file colorful; set to true makes more readable output of `tail' but hardly readable by gui file output
:detect_comments => false, # highlight and strip comments blocks
:precede_comments => "# ",
# :detect_comments with default :precede_comments allows comment blocks looking like:
$log<<<<-'#'
# ... comment string one ...
# ... comment string two ...
#
be logged like #{@c.green "\n# ... comment string one ...\n# ... comment string two ..."}
# #{@c.y 'html options:'}
:caller => "<a class='l'>%f:%l</a> <a class='m'>:%m</a>",
:format => "<div class='line'><a class='t'>%time</a> <a class='%mode'>%mode</m> [%caller]: <p>%text</p>%att</div>", # %att is for array of objects that should be formatted by the next option
:att =>"<div class='att'><div class='hide'>+</div><pre>%s</pre></div>", # .hide should be scripted to work like a spoiler
:serializer => RMTools::RMLogger::HTML # should respond to :render(obj); nil value means each object will be just #inspect'ed}
end

#error(*args) ⇒ Object Also known as: fatal

controls:

  • @mute_warn, @mute_info, @mute_log, @mute_debug:

    do not print this messages regardless of any globals
    
  • @out_all: write to file info and debug messages

  • @out: write to file

  • @print: write to stdout



161
162
163
164
165
166
167
168
169
170
# File 'lib/rmtools/dev/logging.rb', line 161

def error *args
  cfg = get_config!
  if (cfg.out or cfg.print) && !@mute_error
    text, bind, opts = args.get_opts [!block_given? && args[0].kinda(Hash) ? args[0] : "\b\b ", nil], :mute => 0
    opts[:mute] |= NOLOG if !cfg.out
    opts[:mute] |= NOPRINT if !cfg.print
    return if block_given? && (text = yield).nil?
    _print(:error, text, opts[:mute], cfg._caller && (@current_caller || caller)[opts[:caller].to_i], bind, cfg)
  end  
end

#get_config(file = nil) ⇒ Object



150
151
152
# File 'lib/rmtools/dev/logging.rb', line 150

def get_config(file=nil)
  @file_formats[file && File.expand_path(file)]
end

#get_config!Object



146
147
148
# File 'lib/rmtools/dev/logging.rb', line 146

def get_config!
  @file_formats.empty? ? @default_format : @file_formats[File.expand_path((@current_caller = caller)[1].till ':')]
end

#get_format(file = nil) ⇒ Object



105
106
107
108
109
# File 'lib/rmtools/dev/logging.rb', line 105

def get_format file=nil
  cfg = @file_formats[file && File.expand_path(file)]
  modes = Modes.reject {|m| send :"mute_#{m}"}
  %{<Logger #{cfg.fmt.sub('%time', "%time(#{cfg.tf*'.'})").sub('%caller', "%caller(#{cfg.cf0})")}#{' -> '+cfg.out if cfg.out} #{modes.b ? modes.inspect : 'muted'}>}
end

#info(*args) ⇒ Object Also known as: <<, puts



194
195
196
197
198
199
200
201
202
203
# File 'lib/rmtools/dev/logging.rb', line 194

def info *args
  cfg = get_config!
  if (cfg.print or cfg.out && cfg.out_all) && !@mute_info
    text, bind, opts = args.get_opts [!block_given? && args[0].kinda(Hash) ? args[0] : "\b\b ", nil], :mute => 0
    opts[:mute] |= NOLOG if !(cfg.out && cfg.out_all)
    opts[:mute] |= NOPRINT if !cfg.print
    return if block_given? && (text = yield).nil?
    _print(:info, text, opts[:mute], cfg._caller && (@current_caller || caller)[opts[:caller].to_i], bind, cfg)
  end 
end

#inspectObject



246
# File 'lib/rmtools/dev/logging.rb', line 246

def inspect() get_format end

#log(*args) ⇒ Object



183
184
185
186
187
188
189
190
191
192
# File 'lib/rmtools/dev/logging.rb', line 183

def log *args
  cfg = get_config!
  if (cfg.out or cfg.print) && !@mute_log
    text, bind, opts = args.get_opts [!block_given? && args[0].kinda(Hash) ? args[0] : "\b\b ", nil], :mute => 0
    opts[:mute] |= NOLOG if !cfg.out
    opts[:mute] |= NOPRINT if !cfg.print
    return if block_given? && (text = yield).nil?
    _print(:log, text, opts[:mute], cfg._caller && (@current_caller || caller)[opts[:caller].to_i], bind, cfg)
  end
end

#log_level=(level) ⇒ Object



226
227
228
229
230
231
232
233
234
235
# File 'lib/rmtools/dev/logging.rb', line 226

def log_level=(level)
  unless level.is_a? Integer
    level = ::Logger.const_get(level.to_s.upcase)
  end
  self.debug = level < 1
  self.info     = level < 2
  self.log      = level < 2
  self.warn   = level < 3
  self.error   = level < 4
end


222
223
224
# File 'lib/rmtools/dev/logging.rb', line 222

def print text
  info text, caller: 1, mute: INLINE 
end

#set_format(*args) ⇒ Object

set any needed params, the rest will be set by default



86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
# File 'lib/rmtools/dev/logging.rb', line 86

def set_format *args
  global, format = args.fetch_opts [nil], :type => :console, :time => ["%H:%M:%S", "%03d"]                  
  format = if format[:type] == :html; {
                :caller => "<a class='l'>%f:%l</a> <a class='m'>:%m</a>", 
                :format => "<div class='line'><a class='t'>%time</a> <a class='%mode'>%mode</m> [%caller]: <p>%text</p>%att</div>",
                :att =>"<div class='att'><div class='hide'>+</div><pre>%s</pre></div>",
                :serializer => RMTools::RMLogger::HTML
              }; else {
                :caller => "#{@c.gray('%f:%l')} #{@c.red_bold(':%m')}", 
                :format => "%time %mode [%caller]: %text"
              } end.merge format
  if global
    _set_format @default_format, format
  else
    _set_format(file_format={}, format)
    @file_formats[File.expand_path(caller[0].till ':')] = file_format
  end
end

#warn(*args) ⇒ Object Also known as: <



172
173
174
175
176
177
178
179
180
181
# File 'lib/rmtools/dev/logging.rb', line 172

def warn *args
  cfg = get_config!
  if (cfg.out or cfg.print) && !@mute_warn
    text, bind, opts = args.get_opts [!block_given? && args[0].kinda(Hash) ? args[0] : "\b\b ", nil], :mute => 0
    opts[:mute] |= NOLOG if !cfg.out
    opts[:mute] |= NOPRINT if !cfg.print
    return if block_given? && (text = yield).nil?
    _print(:warn, text, opts[:mute], cfg._caller && (@current_caller || caller)[opts[:caller].to_i], bind, cfg)
  end  
end