pwnlib.log — Logging stuff

Logging module for printing status during an exploit, and internally within pwntools.

Exploit Developers

By using the standard from pwn import *, an object named log will be inserted into the global namespace. You can use this to print out status messages during exploitation.

For example,:

log.info('Hello, world!')

prints:

[*] Hello, world!

Additionally, there are some nifty mechanisms for performing status updates on a running job (e.g. when brute-forcing).:

p = log.progress('Working')
p.status('Reticulating splines')
time.sleep(1)
p.success('Got a shell!')

The verbosity of logging can be most easily controlled by setting log_level on the global context object.:

log.info("No you see me")
context.log_level = 'error'
log.info("Now you don't")

The purpose of this attribute is to control what gets printed to the screen, not what gets emitted. This means that you can put all logging events into a log file, while only wanting to see a small subset of them on your screen.

Pwnlib Developers

A module-specific logger can be imported into the module via:

from .log import getLogger
log = getLogger(__name__)

This provides an easy way to filter logging programmatically or via a configuration file for debugging.

When using progress, you should use the with keyword to manage scoping, to ensure the spinner stops if an exception is thrown.

Technical details

Familiarity with the logging module is assumed.

A pwnlib root logger named ‘pwnlib’ is created and a custom handler and formatter is installed for it. The handler determines its logging level from context.log_level.

Ideally context.log_level should only affect which records will be emitted by the handler such that e.g. logging to a file will not be changed by it. But for performance reasons it is not feasible log everything in the normal case. In particular there are tight loops inside pwnlib.tubes.tube, which we would like to be able to debug, but if we are not debugging them, they should not spit out messages (even to a log file). For this reason there are a few places inside pwnlib, that will not even emit a record without context.log_level being set to logging.DEBUG or below.

Log records created by Progress and Logger objects will set 'pwnlib_msgtype' on the extra field to signal which kind of message was generated. This information is used by the formatter to prepend a symbol to the message, e.g. '[+] ' in '[+] got a shell!'

This field is ignored when using the logging module’s standard formatters.

All status updates (which are not dropped due to throttling) on progress loggers result in a log record being created. The extra field then carries a reference to the Progress logger as 'pwnlib_progress'.

If the custom handler determines that term.term_mode is enabled, log records that have a 'pwnlib_progess' in their extra field will not result in a message being emitted but rather an animated progress line (with a spinner!) being created. Note that other handlers will still see a meaningful log record.

The custom handler will only handle log records whith a level of at least context.log_level. Thus if e.g. the level for the 'pwnlib.tubes.ssh' is set to 'DEBUG' no additional output will show up unless context.log_level is also set to 'DEBUG'. Other handlers will however see the extra log records generated by the 'pwnlib.tubes.ssh' logger.

pwnlib.log.install_default_handler()[source]

Instantiates a Handler and Formatter and installs them for the pwnlib root logger. This function is automatically called from when importing pwn.

class pwnlib.log.Progress(logger, msg, status, level, args, kwargs)[source]

Progress logger used to generate log records associated with some running job. Instances can be used as context managers which will automatically declare the running job a success upon exit or a failure upon a thrown exception. After success() or failure() is called the status can no longer be updated.

This class is intended for internal use. Progress loggers should be created using Logger.progress().

status(status, *args, **kwargs)[source]

Logs a status update for the running job.

If the progress logger is animated the status line will be updated in place.

Status updates are throttled at one update per 100ms.

success(status = 'Done', *args, **kwargs)[source]

Logs that the running job succeeded. No further status updates are allowed.

If the Logger is animated, the animation is stopped.

failure(message)[source]

Logs that the running job failed. No further status updates are allowed.

If the Logger is animated, the animation is stopped.

class pwnlib.log.Logger(logger=None)[source]

A class akin to the logging.LoggerAdapter class. All public methods defined on logging.Logger instances are defined on this class.

Also adds some pwnlib flavor:

Adds pwnlib-specific information for coloring, indentation and progress logging via log records extra field.

Loggers instantiated with getLogger() will be of this class.

progress(message, status='', *args, level=logging.INFO, **kwargs) → Progress[source]

Creates a new progress logger which creates log records with log level level.

Progress status can be updated using Progress.status() and stopped using Progress.success() or Progress.failure().

If term.term_mode is enabled the progress logger will be animated.

The progress manager also functions as a context manager. Using context managers ensures that animations stop even if an exception is raised.

with log.progress('Trying something...') as p:
    for i in range(10):
        p.status("At %i" % i)
        time.sleep(0.5)
    x = 1/0
waitfor(*args, **kwargs)[source]

Alias for progress().

indented(message, *args, level = logging.INFO, **kwargs)[source]

Log a message but don’t put a line prefix on it.

Parameters:level (int) – Alternate log level at which to set the indented message. Defaults to logging.INFO.
success(message, *args, **kwargs)[source]

Logs a success message.

failure(message, *args, **kwargs)[source]

Logs a failure message.

info_once(message, *args, **kwargs)[source]

Logs an info message. The same message is never printed again.

warning_once(message, *args, **kwargs)[source]

Logs a warning message. The same message is never printed again.

warn_once(*args, **kwargs)[source]

Alias for warning_once().

debug(message, *args, **kwargs)[source]

Logs a debug message.

info(message, *args, **kwargs)[source]

Logs an info message.

warning(message, *args, **kwargs)[source]

Logs a warning message.

warn(*args, **kwargs)[source]

Alias for warning().

error(message, *args, **kwargs)[source]

To be called outside an exception handler.

Logs an error message, then raises a PwnlibException.

exception(message, *args, **kwargs)[source]

To be called from an exception handler.

Logs a error message, then re-raises the current exception.

critical(message, *args, **kwargs)[source]

Logs a critical message.

log(level, message, *args, **kwargs)[source]

Logs a message with log level level. The pwnlib formatter will use the default logging formater to format this message.

isEnabledFor(level) → bool[source]

See if the underlying logger is enabled for the specified level.

setLevel(level)[source]

Set the logging level for the underlying logger.

addHandler(handler)[source]

Add the specified handler to the underlying logger.

removeHandler(handler)[source]

Remove the specified handler from the underlying logger.

class pwnlib.log.Formatter(fmt=None, datefmt=None, style='%')[source]

Logging formatter which performs custom formatting for log records containing the 'pwnlib_msgtype' attribute. Other records are formatted using the logging modules default formatter.

If 'pwnlib_msgtype' is set, it performs the following actions:

  • A prefix looked up in _msgtype_prefixes is prepended to the message.
  • The message is prefixed such that it starts on column four.
  • If the message spans multiple lines they are split, and all subsequent lines are indented.

This formatter is used by the handler installed on the 'pwnlib' logger.