Class: Beaker::Logger

Inherits:
Object
  • Object
show all
Defined in:
lib/beaker/logger.rb

Overview

The Beaker Logger class This class handles message reporting for Beaker, it reports based upon a provided log level to a given destination (be it a string or file)

Constant Summary collapse

NORMAL =
"\e[00;00m"
BRIGHT_NORMAL =
"\e[00;01m"
BLACK =
"\e[00;30m"
RED =
"\e[00;31m"
GREEN =
"\e[00;32m"
YELLOW =
"\e[00;33m"
BLUE =
"\e[00;34m"
MAGENTA =
"\e[00;35m"
CYAN =
"\e[00;36m"
WHITE =
"\e[00;37m"
GREY =

Some terms can’t handle grey, use normal

"\e[00;00m"
BRIGHT_RED =
"\e[01;31m"
BRIGHT_GREEN =
"\e[01;32m"
BRIGHT_YELLOW =
"\e[01;33m"
BRIGHT_BLUE =
"\e[01;34m"
BRIGHT_MAGENTA =
"\e[01;35m"
BRIGHT_CYAN =
"\e[01;36m"
BRIGHT_WHITE =
"\e[01;37m"
NONE =
""
LOG_LEVELS =

The defined log levels. Each log level also reports messages at levels lower than itself

{
  :trace   => 6,
  :debug   => 5,
  :verbose => 3,
  :info    => 2,
  :notify  => 1,
  :warn    => 0,
}

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(dests) ⇒ Logger #initialize(dests, options) ⇒ Logger

Initialization of the Logger class

Overloads:

  • #initialize(dests) ⇒ Logger

    Initialize a Logger object that reports to the provided destinations, use default options

    Parameters:

    • Array (Array<String, IO>)

      of IO and strings (assumed to be file paths) to be reported to

  • #initialize(dests, options) ⇒ Logger

    Initialize a Logger object that reports to the provided destinations, use options from provided option hash

    Parameters:

    • Array (Array<String, IO>)

      of IO and strings (assumed to be file paths) to be reported to

    • options (Hash)

      Hash of options

    Options Hash (options):

    • :color (Boolean) — default: true

      Print color code before log messages

    • :quiet (Boolean) — default: false

      Do not log messages to STDOUT

    • :log_level (String) — default: "info"

      Log level (one of “debug” - highest level, “verbose”, “info”, “notify” and “warn” - lowest level (see LOG_LEVELS)) The log level indicates that messages at that log_level and lower will be reported.



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
# File 'lib/beaker/logger.rb', line 59

def initialize(*args)
  options = args.last.is_a?(Hash) ? args.pop : {}
  @color = options[:color]
  @sublog = nil
  case options[:log_level]
  when /trace/i, :trace
    @log_level = :trace
  when /debug/i, :debug
    @log_level = :debug
  when /info/i, :info
    @log_level = :info
  when /notify/i, :notify
    @log_level = :notify
  when /warn/i, :warn
    @log_level = :warn
  else
    @log_level = :verbose
  end

  @last_result = nil
  @line_prefix = ''

  @destinations = []

  @log_colors =  {
    :error => RED,
    :warn => BRIGHT_RED,
    :success => MAGENTA,
    :notify => BLUE,
    :info => GREEN,
    :debug => WHITE,
    :trace => BRIGHT_YELLOW,
    :perf => BRIGHT_MAGENTA,
    :host => YELLOW
  }

  @log_colors.merge!(options[:log_colors]) if options[:log_colors]

  # if a user overrides any of the log_colors, we will no longer
  # override the colors at all on a CI build. This is b/c it is
  # assumed that if a user is overriding the colors, they know
  # what they are doing. We could potentially add an additional
  # option a user can pass to be explicit about still allowing
  # the override.
  unless options[:log_colors]
    # Jenkins exposed variable - should be present on the slave directing
    # the beaker run
    ci_build = ENV['BUILD_NUMBER'] != nil

    @log_colors[:notify] = NORMAL if ci_build
    @log_colors[:info] = NORMAL if ci_build
  end

  dests = args
  dests << STDOUT unless options[:quiet]
  dests.uniq!
  dests.each {|dest| add_destination(dest)}
end

Instance Attribute Details

#colorObject

Returns the value of attribute color.



44
45
46
# File 'lib/beaker/logger.rb', line 44

def color
  @color
end

#destinationsObject

Returns the value of attribute destinations.



44
45
46
# File 'lib/beaker/logger.rb', line 44

def destinations
  @destinations
end

#last_resultObject

The results of the most recently run command



9
10
11
# File 'lib/beaker/logger.rb', line 9

def last_result
  @last_result
end

#line_prefixObject

Determines the spacing that happens before an output line



12
13
14
# File 'lib/beaker/logger.rb', line 12

def line_prefix
  @line_prefix
end

#log_colorsObject

Returns the value of attribute log_colors.



44
45
46
# File 'lib/beaker/logger.rb', line 44

def log_colors
  @log_colors
end

#log_levelObject

Returns the value of attribute log_level.



44
45
46
# File 'lib/beaker/logger.rb', line 44

def log_level
  @log_level
end

Class Method Details

.generate_dated_log_folder(base_dir, log_prefix, timestamp) ⇒ String

Note:

since this uses ‘mkdir -p’, log_prefix can be a number of nested directories

Utility method to centralize dated log folder generation

Examples:

base_dir = ‘junit’, log_prefix = ‘pants’, timestamp = ‘2015-03-04 10:35:37 -0800’

returns 'junit/pants/2015-03-04_10_35_37'

Parameters:

  • base_dir (String)

    Path of the directory for the dated log folder to live in

  • log_prefix (String)

    Prefix to use for the log files

  • timestamp (Time)

    Timestamp that should be used to generate the dated log folder

Returns:

  • (String)

    the path of the dated log folder generated



402
403
404
405
406
# File 'lib/beaker/logger.rb', line 402

def Logger.generate_dated_log_folder(base_dir, log_prefix, timestamp)
  log_dir = File.join(base_dir, log_prefix, timestamp.strftime("%F_%H_%M_%S"))
  FileUtils.mkdir_p(log_dir) unless File.directory?(log_dir)
  log_dir
end

.strip_color_codes(text) ⇒ String

Remove color codes from provided string. Color codes are of the format /(e[dd;ddm)+/.

Parameters:

  • text (String)

    The string to remove color codes from

Returns:

  • (String)

    The text without color codes



411
412
413
# File 'lib/beaker/logger.rb', line 411

def Logger.strip_color_codes(text)
  text.gsub(/(\e|\^\[)\[(\d*;)*\d*m/, '')
end

Instance Method Details

#add_destination(dest) ⇒ Object

Construct an array of open steams for printing log messages to

Parameters:

  • dest (Array<IO, String>)

    Array of strings (each used as a file path) and IO steams that messages will be printed to



131
132
133
134
135
136
137
138
139
140
# File 'lib/beaker/logger.rb', line 131

def add_destination(dest)
  case dest
  when IO, StringIO
    @destinations << dest
  when String
    @destinations << File.open(dest, 'w')
  else
    raise "Unsuitable log destination #{dest.inspect}"
  end
end

#color_host_output(*args) ⇒ Object

Custom reporting for messages generated by host SUTs - to preserve output Will not print unless we are at LOG_LEVELS ‘verbose’ or higher. Preserves outout by not stripping out colour codes

Parameters:

  • args (Array<String>)

    Strings to be reported



269
270
271
272
273
# File 'lib/beaker/logger.rb', line 269

def color_host_output *args
  return unless is_verbose?
  string = args.join
  optionally_color NONE, string, false
end

#convert(string) ⇒ Object

Remove invalid UTF-8 codes from provided string(s)

Parameters:

  • string (String, Array<String>)

    The string(s) to remove invalid codes from



193
194
195
196
197
198
199
200
201
202
203
# File 'lib/beaker/logger.rb', line 193

def convert string
  if string.kind_of?(Array)
    string.map do |s|
      convert s
    end
  else
    # Remove invalid and undefined UTF-8 character encodings
    string = string.to_s.dup.force_encoding('UTF-8')
    return string.to_s.chars.select{|i| i.valid_encoding?}.join
  end
end

#debug(*args) ⇒ Object

Report a debug message. Will not print unless we are at LOG_LEVELS ‘debug’ or higher.

Parameters:

  • args (Array<String>)

    Strings to be reported



294
295
296
297
# File 'lib/beaker/logger.rb', line 294

def debug *args
  return unless is_verbose?
  optionally_color @log_colors[:debug], *args
end

#error(*args) ⇒ Object

Report an error message. Will always be reported.

Parameters:

  • args (Array<String>)

    Strings to be reported



335
336
337
# File 'lib/beaker/logger.rb', line 335

def error *args
  optionally_color @log_colors[:error], *args
end

#get_sublogObject

Return the contents of the sublog



385
386
387
388
# File 'lib/beaker/logger.rb', line 385

def get_sublog
  @sublog.rewind
  @sublog.read
end

#host_output(*args) ⇒ Object

Custom reporting for messages generated by host SUTs. Will not print unless we are at LOG_LEVELS ‘verbose’ or higher. Strips any color codes already in the provided messages, then adds logger color codes before reporting

Parameters:

  • args (Array<String>)

    Strings to be reported



258
259
260
261
262
263
# File 'lib/beaker/logger.rb', line 258

def host_output *args
  return unless is_verbose?
  strings = strip_colors_from args
  string = strings.join
  optionally_color @log_colors[:host], string, false
end

#info(*args) ⇒ Object

Report an info message. Will not print unless we are at LOG_LEVELS ‘info’ or higher.

Parameters:

  • args (Array<String>)

    Strings to be reported



312
313
314
315
# File 'lib/beaker/logger.rb', line 312

def info *args
  return unless is_info?
  optionally_color @log_colors[:info], *args
end

#is_debug?Boolean

Are we at LOG_LEVELS debug?

Returns:

  • (Boolean)

    true if ‘debug’ or higher, false if not ‘debug’ LOG_LEVELS or lower



163
164
165
# File 'lib/beaker/logger.rb', line 163

def is_debug?
  LOG_LEVELS[@log_level] >= LOG_LEVELS[:debug]
end

#is_info?Boolean

Are we at LOG_LEVELS info?

Returns:

  • (Boolean)

    true if ‘info’ or higher, false if not ‘info’ LOG_LEVELS or lower



181
182
183
# File 'lib/beaker/logger.rb', line 181

def is_info?
  LOG_LEVELS[@log_level] >= LOG_LEVELS[:info]
end

#is_notify?Boolean

Are we at LOG_LEVELS notify?

Returns:

  • (Boolean)

    true if ‘notify’ or higher, false if not ‘notify’ LOG_LEVELS or lower



187
188
189
# File 'lib/beaker/logger.rb', line 187

def is_notify?
  LOG_LEVELS[@log_level] >= LOG_LEVELS[:notify]
end

#is_trace?Boolean

Are we at LOG_LEVELS trace?

Returns:

  • (Boolean)

    true if ‘trace’ or higher, false if not ‘trace’ LOG_LEVELS or lower



157
158
159
# File 'lib/beaker/logger.rb', line 157

def is_trace?
  LOG_LEVELS[@log_level] >= LOG_LEVELS[:trace]
end

#is_verbose?Boolean

Are we at LOG_LEVELS verbose?

Returns:

  • (Boolean)

    true if ‘verbose’ or higher, false if not ‘verbose’ LOG_LEVELS or lower



169
170
171
# File 'lib/beaker/logger.rb', line 169

def is_verbose?
  LOG_LEVELS[@log_level] >= LOG_LEVELS[:verbose]
end

#is_warn?Boolean

Are we at LOG_LEVELS warn?

Returns:

  • (Boolean)

    true if ‘warn’ or higher, false if not ‘warn’ LOG_LEVELS or lower



175
176
177
# File 'lib/beaker/logger.rb', line 175

def is_warn?
  LOG_LEVELS[@log_level] >= LOG_LEVELS[:warn]
end

#notify(*args) ⇒ Object

Report a notify message. Will not print unless we are at LOG_LEVELS ‘notify’ or higher.

Parameters:

  • args (Array<String>)

    Strings to be reported



327
328
329
330
# File 'lib/beaker/logger.rb', line 327

def notify *args
  return unless is_notify?
  optionally_color @log_colors[:notify], *args
end

#optionally_color(color_code, msg, add_newline = true) ⇒ Object

Print the provided message to the set destination streams, using color codes if appropriate

Parameters:

  • color_code (String)

    The color code to pre-pend to the message

  • msg (String)

    The message to be reported

  • add_newline (Boolean) (defaults to: true)

    (true) Add newlines between the color codes and the message



352
353
354
355
356
357
358
359
360
361
362
# File 'lib/beaker/logger.rb', line 352

def optionally_color color_code, msg, add_newline = true
  print_statement = add_newline ? :puts : :print
  msg = convert(msg)
  msg = prefix_log_line(msg)
  @destinations.each do |to|
    to.print color_code if @color
    to.send print_statement, msg
    to.print NORMAL if @color unless color_code == NONE
    to.flush
  end
end

#perf_output(*args) ⇒ Object

Custom reporting for performance/sysstat messages Will not print unless we are at LOG_LEVELS ‘debug’ or higher.

Parameters:

  • args (Array<String>)

    Strings to be reported



278
279
280
281
# File 'lib/beaker/logger.rb', line 278

def perf_output *args
  return unless is_debug?
  optionally_color @log_colors[:perf], *args
end

#prefix_log_line(line) ⇒ String

Prefixes a log line with the appropriate amount of whitespace for the level of test that’s running.

Parameters:

  • line (String)

    the line to prefix

Returns:

  • (String)

    the prefixed line



211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
# File 'lib/beaker/logger.rb', line 211

def prefix_log_line line
  if line.kind_of?(Array)
    line.map do |s|
      prefix_log_line s
    end
  else
    line.delete!("\r")
    has_ending_newline = line.end_with?("\n")
    actual_lines = line.split("\n")
    actual_lines.map! do |actual_line|
      @line_prefix + actual_line
    end
    new_line = actual_lines.join("\n")
    new_line << "\n" if has_ending_newline
    new_line
  end
end

#pretty_backtrace(backtrace = caller(1)) ⇒ String

Utility method to get the current call stack and format it to a human-readable string (which some IDEs/editors will recognize as links to the line numbers in the trace). Beaker associated files will be purged from backtrace unless log level is ‘debug’ or higher

Parameters:

  • backtrace (String) (defaults to: caller(1))

    (caller(1)) The backtrace to format

Returns:

  • (String)

    The formatted backtrace



370
371
372
373
# File 'lib/beaker/logger.rb', line 370

def pretty_backtrace backtrace = caller(1)
  trace = is_debug? ? backtrace : purge_harness_files_from( backtrace )
  expand_symlinks( trace ).join "\n"
end

#quiet(off = true) ⇒ Object

Turn on/off STDOUT logging

Parameters:

  • off (Boolean) (defaults to: true)

    If true, disable STDOUT logging, if false enable STDOUT logging



120
121
122
123
124
125
126
127
# File 'lib/beaker/logger.rb', line 120

def quiet(off = true)
  if off
    remove_destination(STDOUT) #turn off the noise!
  else
    remove_destination(STDOUT) #in case we are calling this in error and we are already noisy
    add_destination(STDOUT)
  end
end

#remove_destination(dest) ⇒ Object

Remove a steam from the destinations array based upon it’s name or file path

Parameters:

  • dest (String, IO)

    String representing a file path or IO stream



144
145
146
147
148
149
150
151
152
153
# File 'lib/beaker/logger.rb', line 144

def remove_destination(dest)
  case dest
  when IO, StringIO
    @destinations.delete(dest)
  when String
    @destinations.delete_if {|d| d.respond_to?(:path) and d.path == dest}
  else
    raise "Unsuitable log destination #{dest.inspect}"
  end
end

#start_sublogObject

Create a new StringIO log to track the current output



376
377
378
379
380
381
382
# File 'lib/beaker/logger.rb', line 376

def start_sublog
  if @sublog
    remove_destination(@sublog)
  end
  @sublog = StringIO.new
  add_destination(@sublog)
end

#step_inObject

Deprecated.

Sets the step level appropriately for logging to be indented correctly

Returns:

  • nil



242
243
244
# File 'lib/beaker/logger.rb', line 242

def step_in
  self.line_prefix = self.line_prefix + '  '
end

#step_outObject

Deprecated.

Sets the step level appropriately for logging to be indented correctly

Returns:

  • nil



250
251
252
# File 'lib/beaker/logger.rb', line 250

def step_out
  self.line_prefix = self.line_prefix.chop.chop
end

#strip_colors_from(lines) ⇒ Array<String>

Strip any color codes from provided string(s)

Parameters:

  • lines (String)

    A single or array of lines to removed color codes from

Returns:

  • (Array<String>)

    An array of strings that do not have color codes



342
343
344
345
346
# File 'lib/beaker/logger.rb', line 342

def strip_colors_from lines
  Array( lines ).map do |line|
    Logger.strip_color_codes(convert(line))
  end
end

#success(*args) ⇒ Object

Report a success message. Will always be reported.

Parameters:

  • args (Array<String>)

    Strings to be reported



320
321
322
# File 'lib/beaker/logger.rb', line 320

def success *args
  optionally_color @log_colors[:success], *args
end

#trace(*args) ⇒ Object

Report a trace message. Will not print unless we are at LOG_LEVELS ‘trace’ or higher.

Parameters:

  • args (Array<String>)

    Strings to be reported



286
287
288
289
# File 'lib/beaker/logger.rb', line 286

def trace *args
  return unless is_trace?
  optionally_color @log_colors[:trace], *args
end

#warn(*args) ⇒ Object

Report a warning message. Will not print unless we are at LOG_LEVELS ‘warn’ or higher. Will pre-pend the message with “Warning: ”.

Parameters:

  • args (Array<String>)

    Strings to be reported



303
304
305
306
307
# File 'lib/beaker/logger.rb', line 303

def warn *args
  return unless is_warn?
  strings = args.map {|msg| "Warning: #{msg}" }
  optionally_color @log_colors[:warn], strings
end

#with_indentObject

Indent the step level for the duration of block.



230
231
232
233
234
235
236
# File 'lib/beaker/logger.rb', line 230

def with_indent()
  old_line_prefix = self.line_prefix.dup
  self.line_prefix << '  '
  yield
ensure
  self.line_prefix = old_line_prefix
end