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()[source]
Instantiates a
Handler
andFormatter
and installs them for thepwnlib
root logger. This function is automatically called from when importingpwn
.
- 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()
orfailure()
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.
- class pwnlib.log.Logger(logger=None)[source]
A class akin to the
logging.LoggerAdapter
class. All public methods defined onlogging.Logger
instances are defined on this class.Also adds some
pwnlib
flavor:progress()
(aliaswaitfor()
)warning_once()
(aliaswarn_once()
)
Adds
pwnlib
-specific information for coloring, indentation and progress logging via log recordsextra
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 usingProgress.success()
orProgress.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
.
- 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()
.
- maybe_hexdump(self, message, *args, **kwargs)[source]
Logs a message using indented. Repeated single byte is compressed, and unprintable message is hexdumped.
- 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.
- class pwnlib.log.Handler(stream=None)[source]
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.
- class pwnlib.log.Formatter(fmt=None, datefmt=None, style='%', validate=True, *, defaults=None)[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.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 orstring.Template
formatting in your format string.Changed in version 3.2: Added the
style
parameter.- format(record)[source]
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.