Class: Pwnlib::Logger::LoggerType

Inherits:
Logger
  • Object
show all
Extended by:
MethodSource::CodeHelpers
Includes:
Context
Defined in:
lib/pwnlib/logger.rb

Overview

The type for logger which inherits Ruby builtin Logger. Main difference is using context.log_level instead of level in logging methods.

Constant Summary collapse

SEV_COLOR =

Color codes for pretty logging.

{
  'DEBUG' => '#ff5f5f',
  'INFO' => '#87ff00',
  'WARN' => '#ffff00',
  'ERROR' => '#ff5f00',
  'FATAL' => '#ff0000'
}.freeze

Instance Method Summary collapse

Constructor Details

#initializeLoggerType

Instantiate a Pwnlib::Logger::LoggerType object.



36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
# File 'lib/pwnlib/logger.rb', line 36

def initialize
  super($stdout)
  @formatter = proc do |severity, _datetime, progname, msg|
    format("[%s] %s\n", Rainbow(progname || severity).color(SEV_COLOR[severity]), msg)
  end

  # Cache the file content so we can modify the file when it's running.
  # If the source is modified before the first call, parsing source file
  # might still fail.
  @source_of_file_cache = Hash.new do |h, key|
    next if key.nil?

    h[key] = IO.read(key)
  end

  # As a naive heuristic for the most common single file use case, adding
  # the last file from the execution stack.
  @source_of_file_cache[caller_locations.last.absolute_path]
end

Instance Method Details

#dump(*args) ⇒ Object

Note:

This method does NOT work in a REPL shell (such as irb and pry).

Note:

The source code where invoked log.dump will be parsed by using ruby_parser, therefore this method fails in some situations, such as:

log.dump(&something) # will fail in souce code parsing
log.dump { 1 }; log.dump { 2 } # 1 will be logged two times

Log the arguments and their evalutated results.

This method has same severity as INFO.

The difference between using arguments and passing a block is the block will be executed if the logger’s level is sufficient to log a message.

Examples:

x = 2
y = 3
log.dump(x + y, x * y)
# [DUMP] (x + y) = 5, (x * y) = 6
libc = 0x7fc0bdd13000
log.dump libc.hex
# [DUMP] libc.hex = "0x7fc0bdd13000"

libc = 0x7fc0bdd13000
log.dump { libc.hex }
# [DUMP] libc.hex = "0x7fc0bdd13000"
log.dump { libc = 12345678; libc.hex }
# [DUMP] libc = 12345678
#        libc.hex = "0xbc614e"
log.dump do
  meow = 123
  # comments will be ignored
  meow <<= 1 # this is a comment
  meow
end
# [DUMP] meow = 123
#        meow = (meow << 1)
#        meow = 246

Parameters:

  • args (Array<#inspect>)

    Anything. See examples.

Yield Returns:

  • (#inspect)

    See examples. Block will be invoked only if args is empty.

Returns:

  • See ::Logger#add.



122
123
124
125
126
127
128
129
130
131
132
133
134
# File 'lib/pwnlib/logger.rb', line 122

def dump(*args)
  severity = INFO
  # Don't invoke the block if it's unnecessary.
  return true if severity < context.log_level

  caller_ = caller_locations(1, 1).first
  src = source_of(caller_.absolute_path, caller_.lineno)
  results = args.empty? ? [[yield, source_of_block(src)]] : args.zip(source_of_args(src))
  msg = results.map { |res, expr| "#{expr.strip} = #{res.inspect}" }.join(', ')
  # do indent if msg contains multiple lines
  first, *remain = msg.split("\n")
  add(severity, ([first] + remain.map { |r| '[DUMP] '.gsub(/./, ' ') + r }).join("\n"), 'DUMP')
end

#indented(message, level: DEBUG) ⇒ Object

Log the message with indent.

Parameters:

  • message (String)

    The message to log.

  • level (DEBUG, INFO, WARN, ERROR, FATAL, UNKNOWN) (defaults to: DEBUG)

    The severity of the message.



62
63
64
65
66
67
68
69
# File 'lib/pwnlib/logger.rb', line 62

def indented(message, level: DEBUG)
  return if @logdev.nil? || level < context.log_level

  @logdev.write(
    "#{message.lines.map { |s| "    #{s}" }.join}\n"
  )
  true
end