Logging System

pcapkit.utilities.logging integrates pcapkit with the standard logging system. It owns the package-wide logger hierarchy rooted at logger and the configuration API through which an application decides what, if anything, pcapkit emits.

pcapkit.utilities.logging.logger

Logger instance named after pcapkit, at the root of the package’s logger hierarchy. Per-module loggers are its children, so configuring this one configures all of pcapkit.

Type:

logging.Logger

The Logger Hierarchy

pcapkit is the root. Every module inside the package logs through its own child logger, named after the module and obtained from get_logger(), so a record carries the name of the code that emitted it and any subtree can be addressed on its own:

import logging

# quieten the registry's bookkeeping, keep everything else
logging.getLogger('pcapkit.foundation.registry').setLevel(logging.WARNING)

# or follow just the extraction path
logging.getLogger('pcapkit.foundation.extraction').setLevel(logging.DEBUG)

The names in use are the module paths themselves, e.g. pcapkit.foundation.extraction, pcapkit.foundation.registry.protocols, pcapkit.foundation.engines.pcap, pcapkit.foundation.reassembly.reassembly, pcapkit.foundation.traceflow.tcp, pcapkit.utilities.warnings.

pcapkit.utilities.logging.get_logger(name=None)[source]

Retrieve a logger inside pcapkit’s hierarchy.

This is the accessor every module in pcapkit uses, as logger = get_logger(__name__), so that records carry the emitting module’s name and an application can address one subtree at a time.

Parameters:

name (str | None) – Dotted logger name, normally the caller’s __name__. None or 'pcapkit' yields the root logger. A name outside the pcapkit hierarchy – notably '__main__', which is what __name__ reports for a module run as a script – is placed under the root rather than beside it, since a sibling of pcapkit would escape every pcapkit-level configuration.

Return type:

Logger

Returns:

The requested logger.

pcapkit.utilities.logging.ROOT_LOGGER_NAME = 'pcapkit'

Name of the logger at the root of pcapkit’s hierarchy.

Type:

str

What DEBUG Will Tell You

At logging.DEBUG the library explains what it did with a file, without descending to per-field parsing: which input was opened, which engine was requested and which was actually used (including a fallback when an optional dependency is missing), the file format identified from the magic number, the output format and dumper, whether reassembly and flow tracing were enabled and with which flags, how many frames were read, and when cleanup ran. Reassembly reports datagram counts on flush and flow tracing reports flows opening and closing.

Note

Nothing is logged from inside per-frame or per-field parsing loops, so enabling DEBUG does not turn a capture with a million packets into a million records. Registration bookkeeping across pcapkit.foundation.registry is also at DEBUG rather than INFO, since a library announcing its own registry entries is not news to its consumer.

Configuring the Output

Importing pcapkit configures no logging output: the only handler attached to logger is a logging.NullHandler, and no level is set. This is the behaviour recommended for libraries – the application keeps control of its own logging, and pcapkit’s records simply propagate into whatever it has configured, typically via logging.basicConfig() or logging.config.

For an application that would rather let pcapkit set up its own output, configure() does so at runtime:

import logging
import sys

from pcapkit.utilities.logging import configure, reset

# everything pcapkit does, on stderr
configure(logging.DEBUG, stream=sys.stderr)

# to a file, with a format of your own
configure(logging.INFO, handler=logging.FileHandler('pcapkit.log'),
          fmt='%(asctime)s %(name)s %(levelname)s %(message)s')

# loud in general, quiet about the registry
configure(logging.DEBUG, stream=sys.stderr)
configure(logging.WARNING, name='pcapkit.foundation.registry')

# and back to the pristine, library-neutral state
reset()
pcapkit.utilities.logging.configure(level=None, *, name=None, stream=None, handler=None, fmt=None, datefmt=None, propagate=None, replace=True)[source]

Configure pcapkit’s logging at runtime.

Every argument is optional and only the ones supplied take effect, so this is usable both as a one-shot setup call and as a targeted adjustment.

Parameters:
  • level (int | str | None) – Level for the logger, as either a str name ('DEBUG') or an int (logging.DEBUG). Left untouched when None, which for a freshly imported pcapkit means the level is inherited from the application.

  • name (str | None) – Logger to configure, as accepted by get_logger(). Defaults to the root logger; pass e.g. 'pcapkit.foundation.registry' to configure one subtree.

  • stream (IO[str] | None) – Writable text stream to log to, e.g. sys.stderr. A logging.StreamHandler is created for it and given a logging.Formatter built from fmt and datefmt.

  • handler (Handler | None) – An already-built handler to attach instead, for anything a plain stream cannot express – a RotatingFileHandler, a queue handler, a test double. Mutually exclusive with stream. Its formatter is only replaced if fmt or datefmt is given.

  • fmt (str | None) – Format string for the handler this call creates. Defaults to DEFAULT_FORMAT.

  • datefmt (str | None) – Date format string for the handler this call creates. Defaults to DEFAULT_DATE_FORMAT.

  • propagate (bool | None) – Whether records should reach ancestor loggers. Setting this to False on the root logger keeps pcapkit’s records out of the application’s own handlers.

  • replace (bool) – Whether to detach the logger’s existing handlers first, so that repeated calls replace rather than accumulate output. Pass False to add a second destination. Unlike reset(), this only touches handlers – the level and propagation are left alone unless the corresponding arguments are given.

Return type:

Logger

Returns:

The logger that was configured, for chaining or inspection.

Raises:

ValueError – If both stream and handler are given, since which one is meant to receive fmt would be ambiguous.

Example

Restore the pre-1.4 default of sys.stderr at logging.INFO:

configure(logging.INFO, stream=sys.stderr)

Send everything to a file, but keep the registry’s bookkeeping out:

configure(logging.DEBUG, handler=logging.FileHandler('pcapkit.log'))
configure(logging.INFO, name='pcapkit.foundation.registry')
pcapkit.utilities.logging.reset(name=None)[source]

Restore a pcapkit logger to its pristine, library-neutral state.

That is: no handlers other than the logging.NullHandler on the root, no level of its own (logging.NOTSET, so the level is inherited from the application’s configuration), and propagation enabled.

Parameters:

name (str | None) – Logger to reset, as accepted by get_logger(). Defaults to the root logger, which also resets nothing else – children keep any level explicitly set on them.

Return type:

Logger

Returns:

The logger that was reset.

Note

This discards the PCAPKIT_DEVMODE bootstrap along with everything else. To reinstate it, call configure(logging.DEBUG, stream=sys.stderr).

pcapkit.utilities.logging.ensure_output(level=10, *, stream=None)[source]

Guarantee that pcapkit’s records have somewhere to go.

This is for a caller that has switched something on precisely because it wants to see the output, and for which staying silent merely because the application never configured logging would be unhelpful.

Note that Extractor(verbose=True) and the CLI’s -v do not go through here: their frame chains are user-facing output and are written to sys.stdout with print(), so they are visible with no logging configuration at all. Nothing in pcapkit calls this function itself; it exists for consumers.

An application that has configured its own handlers has already answered the question, so nothing is changed in that case.

Parameters:
  • level (int | str) – Level to configure if, and only if, a handler has to be added.

  • stream (IO[str] | None) – Where to write, defaulting to sys.stderr.

Return type:

bool

Returns:

True if a handler was added, False if output was already going somewhere and the existing configuration was left alone.

Formatting

pcapkit.utilities.logging.DEFAULT_FORMAT = '[%(levelname)s] %(asctime)s - %(message)s'

Default logging.Formatter format string.

Type:

str

pcapkit.utilities.logging.DEFAULT_DATE_FORMAT = '%m/%d/%Y %I:%M:%S %p'

Default logging.Formatter date format string.

Type:

str

pcapkit.utilities.logging.formatter

Default formatter, used by any handler that configure() creates and by the PCAPKIT_DEVMODE bootstrap.

Type:

logging.Formatter

pcapkit.utilities.logging.handler

The historical sys.stderr handler. It is only attached under PCAPKIT_DEVMODE; it is constructed unconditionally so that logger.addHandler(handler) remains a one-line way back to the pre-1.4 default output.

Type:

logging.StreamHandler

Environment Variables

pcapkit.utilities.logging.DEVMODE

Development mode flag.

Type:

bool

See also

This variable can be configured through the environment variable PCAPKIT_DEVMODE.

pcapkit.utilities.logging.VERBOSE

Verbose output flag.

Type:

bool

See also

This variable can be configured through the environment variable PCAPKIT_VERBOSE.

pcapkit.utilities.logging.SPHINX_TYPE_CHECKING

This is a workaround for typing.TYPE_CHECKING in Sphinx.

Type:

bool

See also

This variable can be configured through the environment variable PCAPKIT_SPHINX.

Compatibility Note

Warning

pcapkit used to attach a logging.StreamHandler on sys.stderr and force the level to logging.INFO (or logging.DEBUG under PCAPKIT_DEVMODE) at import time. That is no longer done, because it hijacked the logging configuration of every application that imported pcapkit.

Two consequences are visible to existing code:

  1. Messages that used to appear on stderr no longer do. In particular the registered ... bookkeeping is now at logging.DEBUG rather than logging.INFO. Restore the old output in one line:

    import logging, sys
    from pcapkit.utilities.logging import configure
    configure(logging.INFO, stream=sys.stderr)
    

    Equivalently, re-attach the module’s own handler, which is still built and still carries the historical format:

    from pcapkit.utilities.logging import handler, logger
    logger.setLevel(logging.INFO)
    logger.addHandler(handler)
    
  2. The handler is no longer at logger.handlers[0]. Code that reached into that list to remove or reconfigure the handler should call reset() or configure() instead.

Unaffected: logger remains public, importable from both pcapkit.utilities.logging and pcapkit.utilities, and named pcapkit; PCAPKIT_DEVMODE still produces the stderr handler at logging.DEBUG; and Extractor(verbose=True) – like the CLI’s -v – still prints a line per frame to sys.stdout. That output is a feature of the tool rather than diagnostics, so it deliberately stays on print(): routing it through logging would have moved it to another stream and made it invisible until the consumer configured a handler.

Note

The warning channel is documented separately, in User Defined Warnings. In short: pcapkit.utilities.warnings.warn() reports each warning exactly once per channel – one logging.WARNING record and one warnings.warn() – and constructing a warning no longer mutates the process-wide warning filters, so suppression is the application’s to configure.