# `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 pwnlib.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 with 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()

  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)

  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()`.

  __init__(logger, msg, status, level, args, kwargs)
  status(status, *args, **kwargs)

    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)

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

    If the Logger is animated, the animation is stopped.

  failure(message)

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

    If the Logger is animated, the animation is stopped.

  __weakref__

    list of weak references to the object

class pwnlib.log.Logger(logger=None)

  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:

  - `progress()` (alias `waitfor()`)

  - `success()`

  - `failure()`

  - `indented()`

  - `info_once()`

  - `warning_once()` (alias `warn_once()`)

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

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

  __init__(logger=None)
  progress(message, status='', *args, level=logging.INFO, **kwargs) → Progress

    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)

    Alias for `progress()`.

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

    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)

    Logs a success message.

  failure(message, *args, **kwargs)

    Logs a failure message.

  info_once(message, *args, **kwargs)

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

  warning_once(message, *args, **kwargs)

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

  warn_once(*args, **kwargs)

    Alias for `warning_once()`.

  debug(message, *args, **kwargs)

    Logs a debug message.

  info(message, *args, **kwargs)

    Logs an info message.

  maybe_hexdump(self, message, *args, **kwargs)

    Logs a message using indented. Repeated single byte is compressed, and unprintable message is hexdumped.

  warning(message, *args, **kwargs)

    Logs a warning message.

  warn(*args, **kwargs)

    Alias for `warning()`.

  error(message, *args, **kwargs)

    To be called outside an exception handler.

    Logs an error message, then raises a `PwnlibException`.

  exception(message, *args, **kwargs)

    To be called from an exception handler.

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

  critical(message, *args, **kwargs)

    Logs a critical message.

  log(level, message, *args, **kwargs)

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

  isEnabledFor(level) → bool

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

  setLevel(level)

    Set the logging level for the underlying logger.

  addHandler(handler)

    Add the specified handler to the underlying logger.

  removeHandler(handler)

    Remove the specified handler from the underlying logger.

  __weakref__

    list of weak references to the object

class pwnlib.log.Handler(stream=None)

  A custom handler class. This class will report whatever `context.log_level` is currently set to as its log level.

  If `term.term_mode` is enabled log records originating from a progress logger will not be emitted but rather an animated progress line will be created.

  An instance of this handler is added to the `'pwnlib'` logger.

  Initialize the handler.

  If stream is not specified, sys.stderr is used.

  emit(record)

    Emit a log record or create/update an animated progress logger depending on whether `term.term_mode` is enabled.

class pwnlib.log.Formatter(fmt=None, datefmt=None, style='%', validate=True, *, defaults=None)

  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.

  Initialize the formatter with specified format strings.

  Initialize the formatter either with the specified format string, or a default as described above. Allow for specialized date formatting with the optional datefmt argument. If datefmt is omitted, you get an ISO8601-like (or RFC 3339-like) format.

  Use a style parameter of ‘%’, ‘{’ or ‘$’ to specify that you want to use one of %-formatting, `str.format()` (`{}`) formatting or `string.Template` formatting in your format string.

  Changed in version 3.2: Added the `style` parameter.

  format(record)

    Format the specified record as text.

    The record’s attribute dictionary is used as the operand to a string formatting operation which yields the returned string. Before formatting the dictionary, a couple of preparatory steps are carried out. The message attribute of the record is computed using LogRecord.getMessage(). If the formatting string uses the time (as determined by a call to usesTime(), formatTime() is called to format the event time. If there is exception information, it is formatted using formatException() and appended to the message.