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
43
44
# 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'
  else
    self.log_level = 'INFO'
  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

#log_levelObject

Returns the value of attribute log_level.



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

def log_level
  @log_level
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: добавить фильтров, например, для обработки текста, который будет логирован



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

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



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

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: <=



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

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] || opts[:caller_offset]).to_i], bind, cfg)
  end 
end

#defaultsObject Also known as: usage



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

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



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

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] || opts[:caller_offset]).to_i], bind, cfg)
  end  
end

#get_config(file = nil) ⇒ Object



152
153
154
# File 'lib/rmtools/dev/logging.rb', line 152

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

#get_config!Object



148
149
150
# File 'lib/rmtools/dev/logging.rb', line 148

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

#get_format(file = nil) ⇒ Object



107
108
109
110
111
# File 'lib/rmtools/dev/logging.rb', line 107

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



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

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] || opts[:caller_offset]).to_i], bind, cfg)
  end 
end

#inspectObject



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

def inspect() get_format end

#log(*args) ⇒ Object



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

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 && !@mute_debug)
    return if block_given? && (text = yield).nil?
    _print(:log, text, opts[:mute], cfg._caller && (@current_caller || caller)[(opts[:caller] || opts[:caller_offset]).to_i], bind, cfg)
  end
end


224
225
226
# File 'lib/rmtools/dev/logging.rb', line 224

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



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

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: <



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

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] || opts[:caller_offset]).to_i], bind, cfg)
  end  
end