API Reference
Complete API documentation for Apathetic Python Logger.
Note: This library uses camelCase naming to match Pythonâs standard library
loggingmodule conventions.By default, this library provides improved behavior with enhancements over the standard library. For stdlib-compatible behavior with no breaking changes, enable Compatibility Mode.
Quick Reference: apathetic_logging Module Functions
New Functions
| Function | Summary |
|---|---|
getLoggerOfType() |
Get a logger of the specified type, creating it if necessary |
registerLogger() |
Register a logger for use by getLogger() |
registerCompatibilityMode() |
Register the compatibility mode setting for stdlib drop-in replacement |
getCompatibilityMode() |
Get the compatibility mode setting |
registerLogLevelEnvVars() |
Register environment variable names to check for log level |
registerDefaultLogLevel() |
Register the default log level to use when no other source is found |
registerTargetPythonVersion() |
Register the target Python version for compatibility checking |
registerPropagate() |
Register the propagate setting for loggers |
safeLog() |
Emergency logger that never fails |
safeTrace() |
Debug tracing function for test development |
makeSafeTrace() |
Create a test trace function with a custom icon |
hasLogger() |
Check if a logger exists in the logging managerâs registry |
removeLogger() |
Remove a logger from the logging managerâs registry |
getDefaultLoggerName() |
Get default logger name with optional inference from callerâs frame |
getLogLevelEnvVars() |
Get the environment variable names to check for log level |
getDefaultLogLevel() |
Get the default log level |
getRegisteredLoggerName() |
Get the registered logger name |
getRootLogger() |
Return the root logger instance (primary way to access root logger) |
getTargetPythonVersion() |
Get the target Python version |
getDefaultPropagate() |
Get the default propagate setting |
getLevelNumber() |
Convert a log level name to its numeric value |
getLevelNameStr() |
Convert a log level to its string name (always returns string) |
test() |
Log a message at TEST level |
Changed Functions
| Function | Summary |
|---|---|
getLogger() |
Return the registered logger instance (auto-infers name when None) |
getLevelName() |
Get the level name for a numeric level (extended version that always returns string) |
Unchanged Functions
| Function | Summary |
|---|---|
basicConfig() |
Configure logging system |
addLevelName() |
Associate a level name with a numeric level |
getLevelNamesMapping() |
3.11+: Get mapping of level names to numeric values |
getLoggerClass() |
Return the class to be used when instantiating a logger |
setLoggerClass() |
Set the class to be used when instantiating a logger |
getLogRecordFactory() |
Return the factory function used to create LogRecords |
setLogRecordFactory() |
Set the factory function used to create LogRecords |
shutdown() |
Perform an orderly shutdown of the logging system |
disable() |
Disable all logging calls of severity âlevelâ and below |
captureWarnings() |
Capture warnings issued by the warnings module |
critical() |
Log a message with severity CRITICAL |
debug() |
Log a message with severity DEBUG |
detail() |
Log a message with severity DETAIL |
error() |
Log a message with severity ERROR |
exception() |
Log a message with severity ERROR with exception info |
fatal() |
Log a message with severity CRITICAL |
info() |
Log a message with severity INFO |
log() |
Log a message with an explicit level |
brief() |
Log a message with severity BRIEF |
test() |
Log a message with severity TEST |
trace() |
Log a message with severity TRACE |
warn() |
Log a message with severity WARNING |
warning() |
Log a message with severity WARNING |
getHandlerByName() |
3.12+: Get a handler with the specified name |
getHandlerNames() |
3.12+: Return all known handler names |
makeLogRecord() |
Create a LogRecord from the given parameters |
currentframe() |
Return the frame object for the callerâs stack frame |
Quick Reference: apathetic_logging.Logger Class Methods
New Methods
| Method | Summary |
|---|---|
determineLogLevel() |
Resolve log level from CLI â env â root config â default |
determineColorEnabled() |
Return True if colored output should be enabled (classmethod) |
extendLoggingModule() |
Extend Pythonâs logging module with TRACE and SILENT levels (classmethod) |
trace() |
Log a message at TRACE level |
detail() |
Log a message at DETAIL level |
brief() |
Log a message at BRIEF level |
test() |
Log a message at TEST level |
errorIfNotDebug() |
Log an error with full traceback only if debug/trace is enabled |
criticalIfNotDebug() |
Log a critical error with full traceback only if debug/trace is enabled |
colorize() |
Apply ANSI color codes to text |
logDynamic() |
Log a message at a dynamically specified level |
useLevel() |
Context manager to temporarily change log level |
useLevelMinimum() |
Context manager to temporarily change log level (only if more verbose) |
usePropagate() |
Context manager to temporarily change propagate setting |
setLevelAndPropagate() |
Set level and propagate together with smart defaults |
useLevelAndPropagate() |
Context manager to temporarily set level and propagate together |
setLevelMinimum() |
Set level only if itâs more verbose than current level |
setLevelInherit() |
Set logger to inherit level from parent |
levelName |
Return the explicit level name set on this logger (property) |
effectiveLevel |
Return the effective level (whatâs actually used) (property) |
effectiveLevelName |
Return the effective level name (whatâs actually used) (property) |
getLevel() |
Return the explicit level set on this logger |
getLevelName() |
Return the explicit level name set on this logger |
getEffectiveLevelName() |
Return the effective level name (whatâs actually used) |
ensureHandlers() |
Ensure handlers are attached to this logger |
validateLevel() |
Validate that a level value is positive (> 0) (staticmethod) |
Changed Methods
| Method | Summary |
|---|---|
setLevel() |
Set the logging level (accepts string names and has minimum parameter) |
_log() |
Log a message with the specified level (automatically ensures handlers) |
addLevelName() |
Associate a level name with a numeric level (validates level > 0) (staticmethod) |
Unchanged Methods
All other methods from logging.Logger are inherited unchanged. See the Python logging.Logger documentation for the complete list.
Version-specific methods:
getChildren()- 3.12+: Return a set of loggers that are immediate children of this logger
apathetic_logging Function Reference
getLogger
getLogger(
logger_name: str | None = None,
*,
level: str | int | None = None,
minimum: bool | None = None
) -> Logger
Return the registered logger instance.
Uses Pythonâs built-in logging registry (logging.getLogger()) to retrieve the logger. If no logger name is provided, uses the registered logger name or attempts to auto-infer the logger name from the calling moduleâs top-level package.
Behavior: When
logger_nameisNone, the logger name is auto-inferred from the calling module (improved behavior). To get the root logger, usegetLogger("")instead. In Compatibility Mode,getLogger(None)returns the root logger (stdlib behavior).
Parameters:
| Parameter | Type | Description |
|---|---|---|
logger_name |
str | None | Optional logger name. If not provided, uses the registered logger name or auto-infers from the calling module. Use "" to get the root logger. |
level |
str | int | None | Exact log level to set on the logger. Accepts both string names (case-insensitive) and numeric values. If provided, sets the loggerâs level to this value. Defaults to None (no change). |
minimum |
bool | None | If True, only set the level if itâs more verbose (lower numeric value) than the current level. This prevents downgrading from a more verbose level (e.g., TRACE) to a less verbose one (e.g., DEBUG). If None, defaults to False. Only used when level is provided. |
Returns:
- The logger instance from
logging.getLogger()(asapathetic_logging.Loggertype)
Raises:
RuntimeError: If no logger name is provided and no logger name has been registered and auto-inference fails.ValueError: If an invalid log level is provided.
Example:
from apathetic_logging import getLogger, registerLogger
# Using registered logger name
registerLogger("my_app")
logger = getLogger() # Gets "my_app" logger
# Or specify logger name directly
logger = getLogger("my_app") # Gets "my_app" logger
# Set exact log level
logger = getLogger("my_app", level="debug") # Sets level to DEBUG
# Set minimum log level (only if current is less verbose)
logger = getLogger("my_app", level="info", minimum=True) # At least INFO
# To get root logger (use "" instead of None)
logger = getLogger("") # Returns root logger
getRootLogger
getRootLogger() -> Logger
Return the root logger instance.
This is the primary way to access the root logger. Itâs more explicit and discoverable than using logging.getLogger("") or getLogger("").
Returns:
- The root logger instance
Example:
from apathetic_logging import getRootLogger
# Get root logger
root = getRootLogger()
# Set root level
root.setLevel("debug")
# Log to root logger
root.info("This logs to the root logger")
# Access root properties
print(root.levelName)
getLoggerOfType
getLoggerOfType(
name: str | None,
class_type: type[Logger],
skip_frames: int = 1,
*args: Any,
level: str | int | None = None,
minimum: bool | None = None,
**kwargs: Any
) -> Logger
Get a logger of the specified type, creating it if necessary.
Parameters:
| Parameter | Type | Description |
|---|---|---|
name |
str | None | The name of the logger to get. If None, auto-infers from the calling module. Use "" for root logger. |
class_type |
type[Logger] | The logger class type to use. |
skip_frames |
int | Number of frames to skip when inferring logger name (default: 1). |
*args |
Any | Additional positional arguments (for future-proofing) |
level |
str | int | None | Exact log level to set on the logger. Accepts both string names (case-insensitive) and numeric values. If provided, sets the loggerâs level to this value. Defaults to None (no change). |
minimum |
bool | None | If True, only set the level if itâs more verbose (lower numeric value) than the current level. This prevents downgrading from a more verbose level (e.g., TRACE) to a less verbose one (e.g., DEBUG). If None, defaults to False. Only used when level is provided. |
**kwargs |
Any | Additional keyword arguments (for future-proofing) |
Returns:
- A logger instance of the specified type
Raises:
ValueError: If an invalid log level is provided.
Example:
from apathetic_logging import Logger, getLoggerOfType
class AppLogger(Logger):
pass
logger = getLoggerOfType("my_app", AppLogger)
# Set exact log level
logger = getLoggerOfType("my_app", AppLogger, level="debug")
# Set minimum log level
logger = getLoggerOfType("my_app", AppLogger, level="info", minimum=True)
registerLogger
registerLogger(
logger_name: str | None = None,
logger_class: type[Logger] | None = None,
*,
target_python_version: tuple[int, int] | None = None,
log_level_env_vars: list[str] | None = None,
default_log_level: str | None = None,
propagate: bool | None = None,
compat_mode: bool | None = None
) -> None
Register a logger for use by getLogger(). This registers the logger name and extends the logging module with custom levels if needed.
If logger_name is not provided, the top-level package is automatically extracted from the calling moduleâs __package__ attribute.
If logger_class is provided and has an extendLoggingModule() method, it will be called to extend the logging module with custom levels and set the logger class. If logger_class is not provided, the default Logger class will be used.
Parameters:
| Parameter | Type | Description |
|---|---|---|
logger_name |
str | None | The logger name to register. If None, auto-infers from the calling module. |
logger_class |
type[Logger] | None | Optional logger class to use. If provided and the class has an extendLoggingModule() method, it will be called. If None, defaults to the standard Logger class. |
target_python_version |
tuple[int, int] | None | Optional target Python version (major, minor) tuple. If provided, sets the target Python version in the registry permanently. Defaults to None (no change). |
log_level_env_vars |
list[str] | None | Optional list of environment variable names to check for log level. If provided, sets the log level environment variables in the registry permanently. Defaults to None (no change). |
default_log_level |
str | None | Optional default log level name. If provided, sets the default log level in the registry permanently. Defaults to None (no change). |
propagate |
bool | None | Optional propagate setting. If provided, sets the propagate value in the registry permanently. If None, uses registered propagate setting or falls back to DEFAULT_PROPAGATE from constants.py. Defaults to None (no change). |
compat_mode |
bool | None | Optional compatibility mode setting. If provided, sets the compatibility mode in the registry permanently. When True, enables stdlib-compatible behavior with no breaking changes (e.g., getLogger(None) returns root logger). When False (default), uses improved behavior with enhancements. If None, uses registered compatibility mode setting or defaults to False. Defaults to None (no change). |
Example:
from apathetic_logging import registerLogger
registerLogger("my_app")
# Or let it auto-infer:
registerLogger() # Uses top-level package name
# Or with a custom logger class:
from apathetic_logging import Logger
class AppLogger(Logger):
pass
registerLogger("my_app", AppLogger)
# Or with convenience parameters to configure registry settings:
registerLogger(
"my_app",
target_python_version=(3, 10),
log_level_env_vars=["MYAPP_LOG_LEVEL", "LOG_LEVEL"],
default_log_level="info",
propagate=False,
compat_mode=True, # Enable stdlib compatibility
)
registerCompatibilityMode
registerCompatibilityMode(compat_mode: bool) -> None
Register the compatibility mode setting for stdlib drop-in replacement.
This sets the compatibility mode that will be used when creating loggers. If not set, the library defaults to False (improved behavior with enhancements).
Compatibility Modes:
compat_mode=False(default): Improved behavior with enhancements. May include changes from stdlib behavior (e.g.,getLogger(None)auto-infers logger name from calling module).compat_mode=True: Standard library compatible behavior with no breaking changes. Restores stdlib behavior where possible (e.g.,getLogger(None)returns root logger).
Parameters:
| Parameter | Type | Description |
|---|---|---|
compat_mode |
bool | Compatibility mode setting. When True, enables stdlib-compatible behavior with no breaking changes. When False (default), uses improved behavior with enhancements. |
Example:
from apathetic_logging import registerCompatibilityMode
# Enable stdlib-compatible behavior (no breaking changes)
registerCompatibilityMode(compat_mode=True)
# Now getLogger(None) returns root logger (stdlib behavior)
# Use improved behavior with enhancements (default)
registerCompatibilityMode(compat_mode=False)
# Now getLogger(None) auto-infers logger name (improved behavior)
getCompatibilityMode
getCompatibilityMode() -> bool
Get the compatibility mode setting.
Returns the registered compatibility mode setting, or False (improved behavior) if not registered.
Returns:
bool: Compatibility mode setting.Falsemeans improved behavior with enhancements (default).Truemeans stdlib-compatible behavior with no breaking changes.
Example:
from apathetic_logging import getCompatibilityMode
compat_mode = getCompatibilityMode()
print(compat_mode) # False (default: improved behavior)
registerLogLevelEnvVars
registerLogLevelEnvVars(env_vars: list[str]) -> None
Register environment variable names to check for log level.
The environment variables will be checked in order, and the first non-empty value found will be used.
Parameters:
| Parameter | Type | Description |
|---|---|---|
env_vars |
list[str] | List of environment variable names to check (e.g., ["MYAPP_LOG_LEVEL", "LOG_LEVEL"]) |
Example:
from apathetic_logging import registerLogLevelEnvVars
registerLogLevelEnvVars(["MYAPP_LOG_LEVEL", "LOG_LEVEL"])
registerDefaultLogLevel
registerDefaultLogLevel(default_level: str) -> None
Register the default log level to use when no other source is found.
Parameters:
| Parameter | Type | Description |
|---|---|---|
default_level |
str | Default log level name (e.g., "info", "warning") |
Example:
from apathetic_logging import registerDefaultLogLevel
registerDefaultLogLevel("warning")
registerTargetPythonVersion
registerTargetPythonVersion(version: tuple[int, int] | None) -> None
Register the target Python version for compatibility checking.
This sets the global target Python version that the library will use when checking for feature availability. Functions requiring a newer Python version than the registered target will raise a NotImplementedError, even if the runtime Python version is sufficient.
If not set, the library defaults to TARGET_PYTHON_VERSION (3.10) from constants.py.
Parameters:
| Parameter | Type | Description |
|---|---|---|
version |
tuple[int, int] | None | A tuple (major, minor) representing the target Python version (e.g., (3, 10) for Python 3.10). If None, the registration is skipped. |
Example:
from apathetic_logging import registerTargetPythonVersion
# Target Python 3.10
registerTargetPythonVersion((3, 10))
# Target Python 3.11
registerTargetPythonVersion((3, 11))
Note: This is useful when developing on a newer Python version (e.g., 3.12) but targeting an older version (e.g., 3.10). The library will validate function calls against your target version, preventing accidental use of features that donât exist in your target environment.
registerPropagate
registerPropagate(*, propagate: bool | None) -> None
Register the propagate setting for loggers.
This sets the default propagate value that will be used when creating loggers. If not set, the library defaults to DEFAULT_PROPAGATE (False) from constants.py.
When propagate is False, loggers do not propagate messages to parent loggers, avoiding duplicate root logs.
Parameters:
| Parameter | Type | Description |
|---|---|---|
propagate |
bool | None | Propagate setting (True or False). If None, the registration is skipped. |
Example:
from apathetic_logging import registerPropagate
# Enable propagation (messages propagate to parent loggers)
registerPropagate(propagate=True)
# Disable propagation (default, avoids duplicate logs)
registerPropagate(propagate=False)
safeLog
safeLog(msg: str) -> None
Emergency logger that never fails.
This function bypasses the normal logging system and writes directly to sys.__stderr__. Itâs designed for use in error handlers where the logging system itself might be broken.
Parameters:
| Parameter | Type | Description |
|---|---|---|
msg |
str | Message to log |
Example:
from apathetic_logging import safeLog
try:
# Some operation
pass
except Exception:
safeLog("Critical error: logging system may be broken")
safeTrace
safeTrace(label: str, *args: Any, icon: str = "đ§Ș") -> None
Debug tracing function for test development. Only active when safe trace is enabled via environment variables.
Safe trace is enabled when any of the following conditions are met:
SAFE_TRACEenvironment variable is set to"1","true", or"yes"(case insensitive)LOG_LEVELenvironment variable (case insensitive) is set to"TRACE"or"TEST"LOG_LEVELnumeric value is less than or equal toTRACE_LEVEL(supports both numeric strings like"5"and standard logging level names like"DEBUG")
Parameters:
| Parameter | Type | Description |
|---|---|---|
label |
str | Trace label |
*args |
Any | Additional arguments to trace |
icon |
str | Icon to use (default: "đ§Ș") |
Example:
from apathetic_logging import safeTrace
import os
# Enable via SAFE_TRACE
os.environ["SAFE_TRACE"] = "1"
safeTrace("debug", "message") # Will output
# Enable via LOG_LEVEL
os.environ["LOG_LEVEL"] = "TRACE"
safeTrace("debug", "message") # Will output
# Or via numeric LOG_LEVEL
os.environ["LOG_LEVEL"] = "5" # TRACE_LEVEL is 5
safeTrace("debug", "message") # Will output
makeSafeTrace
makeSafeTrace(icon: str = "đ§Ș") -> Callable
Create a test trace function with a custom icon.
Parameters:
| Parameter | Type | Description |
|---|---|---|
icon |
str | Icon to use |
Returns:
Callable: Test trace function
hasLogger
hasLogger(logger_name: str) -> bool
Check if a logger exists in the logging managerâs registry.
Parameters:
| Parameter | Type | Description |
|---|---|---|
logger_name |
str | The name of the logger to check |
Returns:
bool: True if the logger exists, False otherwise
removeLogger
removeLogger(logger_name: str) -> None
Remove a logger from the logging managerâs registry.
Parameters:
| Parameter | Type | Description |
|---|---|---|
logger_name |
str | The name of the logger to remove |
getDefaultLoggerName
getDefaultLoggerName(
logger_name: str | None = None,
*,
check_registry: bool = True,
skip_frames: int = 1,
raise_on_error: bool = False,
infer: bool = True,
register: bool = False
) -> str | None
Get default logger name with optional inference from callerâs frame.
Parameters:
| Parameter | Type | Description |
|---|---|---|
logger_name |
str | None | Explicit logger name, or None to infer (default: None) |
check_registry |
bool | If True, check registry before inferring (default: True) |
skip_frames |
int | Number of frames to skip (default: 1) |
raise_on_error |
bool | If True, raise RuntimeError if logger name cannot be resolved. If False (default), return None instead |
infer |
bool | If True (default), attempt to infer logger name from callerâs frame when not found in registry. If False, skip inference |
register |
bool | If True, store inferred name in registry. If False (default), do not modify registry. Note: Explicit names are never stored regardless of this parameter |
Returns:
str | None: Resolved logger name, or None if cannot be resolved and raise_on_error=False
Raises:
RuntimeError: If logger name cannot be resolved and raise_on_error=True
getLogLevelEnvVars
getLogLevelEnvVars() -> list[str]
Get the environment variable names to check for log level.
Returns the registered environment variable names, or the default environment variables if none are registered.
Returns:
list[str]: List of environment variable names to check for log level. Defaults to["LOG_LEVEL"]if not registered
getDefaultLogLevel
getDefaultLogLevel() -> str
Get the default log level.
Returns the registered default log level, or the module default if none is registered.
Returns:
str: Default log level name (e.g., âdetailâ, âinfoâ). Defaults to"detail"if not registered
getRegisteredLoggerName
getRegisteredLoggerName() -> str | None
Get the registered logger name.
Returns the registered logger name, or None if no logger name has been registered. Unlike getDefaultLoggerName(), this does not perform inference - it only returns the explicitly registered value.
Returns:
str | None: Registered logger name, or None if not registered
getTargetPythonVersion
getTargetPythonVersion() -> tuple[int, int]
Get the target Python version.
Returns the registered target Python version, or the minimum supported version if none is registered.
Returns:
tuple[int, int]: Target Python version as (major, minor) tuple. Defaults to(3, 10)if not registered
getDefaultPropagate
getDefaultPropagate() -> bool
Get the default propagate setting.
Returns the registered propagate setting, or the module default if none is registered.
Returns:
bool: Default propagate setting (True or False). Defaults toFalseif not registered
basicConfig
basicConfig(*args: Any, **kwargs: Any) -> None
Wrapper for logging.basicConfig(). Configure the logging system.
For detailed documentation, see the Python logging.basicConfig() documentation.
addLevelName
addLevelName(level: int, level_name: str) -> None
Wrapper for logging.addLevelName(). Associate a level name with a numeric level.
For detailed documentation, see the Python logging.addLevelName() documentation.
getLevelName
getLevelName(level: int | str, *, strict: bool = False) -> str | int
Return the textual or numeric representation of a logging level.
Behavior depends on compatibility mode (set via registerCompatibilityMode()):
Compatibility mode enabled (compat_mode=True):
- Behaves like stdlib
logging.getLevelName()(bidirectional) - Returns
strfor integer input,intfor string input (known levels) - Returns
"Level {level}"string for unknown levels - Value-add: Uppercases string inputs before processing (case-insensitive)
Compatibility mode disabled (compat_mode=False, default):
- Accepts both integer and string input
- For string input: uppercases and returns the string (value-add, no conversion)
- For integer input: returns level name as string (never returns
int) - Optional strict mode to raise
ValueErrorfor unknown integer levels
Parameters:
| Parameter | Type | Description |
|---|---|---|
level |
int | str | Log level as integer or string name |
strict |
bool | If True, raise ValueError for unknown levels. If False (default), returns âLevel {level}â format for unknown integer levels (matching stdlib behavior). Only used when compatibility mode is disabled and level is an integer. |
Returns:
- Compatibility mode enabled:
str | int(bidirectional like stdlib) - Compatibility mode disabled:
str(always string; string input is uppercased and returned, int input is converted to name)
Raises:
ValueError: If strict=True and level is an integer that cannot be resolved to a known level name
Example:
from apathetic_logging import getLevelName, getLevelNumber, registerCompatibilityMode
# Compatibility mode enabled (stdlib-like behavior):
registerCompatibilityMode(compat_mode=True)
getLevelName(10) # "DEBUG" (str)
getLevelName("DEBUG") # 10 (int)
getLevelName("debug") # 10 (int, case-insensitive)
# Compatibility mode disabled (improved behavior):
registerCompatibilityMode(compat_mode=False)
getLevelName(10) # "DEBUG"
getLevelName("DEBUG") # "DEBUG" (uppercased and returned)
getLevelName("debug") # "DEBUG" (uppercased)
getLevelName(999, strict=True) # ValueError: Unknown log level: 999
# For stringâint conversion when compat mode disabled, use getLevelNumber()
getLevelNumber("DEBUG") # 10
getLevelNumber
getLevelNumber(level: str | int) -> int
Convert a log level name to its numeric value.
Recommended way to convert string level names to integers. This function explicitly performs stringâint conversion, unlike getLevelName() which has bidirectional behavior for backward compatibility.
Handles all levels registered via logging.addLevelName() (including standard library levels, custom apathetic levels, and user-registered levels).
Parameters:
| Parameter | Type | Description |
|---|---|---|
level |
str | int | Log level as string name (case-insensitive) or integer |
Returns:
int: Integer level value
Raises:
ValueError: If level cannot be resolved to a known level
Example:
from apathetic_logging import getLevelNumber
# Known levels return int
getLevelNumber("DEBUG") # 10
getLevelNumber("TRACE") # 5
getLevelNumber(20) # 20
# Unknown level raises ValueError
getLevelNumber("UNKNOWN") # ValueError: Unknown log level: 'UNKNOWN'
See Also:
getLevelName()- Bidirectional conversion with compatibility modegetLevelNameStr()- Unidirectional conversion (always returns string)
getLevelNameStr
getLevelNameStr(level: int | str, *, strict: bool = False) -> str
Convert a log level to its string name representation.
Unidirectional function that always returns a string. This is the recommended way to convert log levels to strings when you want guaranteed string output without compatibility mode behavior.
Unlike getLevelName() which has compatibility mode and bidirectional behavior, this function always returns a string:
- Integer input: converts to level name string (returns âLevel {level}â for unknown levels unless strict=True)
- String input: validates level exists, then returns uppercased string
Handles all levels registered via logging.addLevelName() (including standard library levels, custom apathetic levels, and user-registered levels).
Parameters:
| Parameter | Type | Description |
|---|---|---|
level |
int | str | Log level as integer or string name (case-insensitive) |
strict |
bool | If True, raise ValueError for unknown integer levels. If False (default), returns âLevel {level}â format for unknown integer levels (matching stdlib behavior). |
Returns:
str: Level name as uppercase string
Raises:
ValueError: If string level cannot be resolved to a known level, or if strict=True and integer level cannot be resolved to a known level
Example:
from apathetic_logging import getLevelNameStr
# Integer input converts to level name
getLevelNameStr(10) # "DEBUG"
getLevelNameStr(5) # "TRACE"
getLevelNameStr(20) # "INFO"
# String input validates and returns uppercased string
getLevelNameStr("DEBUG") # "DEBUG"
getLevelNameStr("debug") # "DEBUG"
getLevelNameStr("Info") # "INFO"
# Unknown integer levels return "Level {level}" format (strict=False, default)
getLevelNameStr(999) # "Level 999"
# Unknown integer levels raise ValueError when strict=True
getLevelNameStr(999, strict=True) # ValueError: Unknown log level: 999
# Unknown string input raises ValueError
getLevelNameStr("UNKNOWN") # ValueError: Unknown log level: 'UNKNOWN'
See Also:
getLevelNumber()- Convert string to int (complementary function)getLevelName()- Bidirectional conversion with compatibility mode
getLevelNamesMapping
getLevelNamesMapping() -> dict[int, str]
Requires Python 3.11+
Wrapper for logging.getLevelNamesMapping(). Get mapping of level names to numeric values.
For detailed documentation, see the Python logging.getLevelNamesMapping() documentation.
getLoggerClass
getLoggerClass() -> type[logging.Logger]
Wrapper for logging.getLoggerClass(). Return the class to be used when instantiating a logger.
For detailed documentation, see the Python logging.getLoggerClass() documentation.
setLoggerClass
setLoggerClass(klass: type[logging.Logger]) -> None
Wrapper for logging.setLoggerClass(). Set the class to be used when instantiating a logger.
For detailed documentation, see the Python logging.setLoggerClass() documentation.
getLogRecordFactory
getLogRecordFactory() -> Callable
Wrapper for logging.getLogRecordFactory(). Return the factory function used to create LogRecords.
For detailed documentation, see the Python logging.getLogRecordFactory() documentation.
setLogRecordFactory
setLogRecordFactory(factory: Callable) -> None
Wrapper for logging.setLogRecordFactory(). Set the factory function used to create LogRecords.
For detailed documentation, see the Python logging.setLogRecordFactory() documentation.
shutdown
shutdown() -> None
Wrapper for logging.shutdown(). Perform an orderly shutdown of the logging system.
For detailed documentation, see the Python logging.shutdown() documentation.
disable
disable(level: int) -> None
Wrapper for logging.disable(). Disable all logging calls of severity âlevelâ and below.
For detailed documentation, see the Python logging.disable() documentation.
captureWarnings
captureWarnings(capture: bool) -> None
Wrapper for logging.captureWarnings(). Capture warnings issued by the warnings module.
For detailed documentation, see the Python logging.captureWarnings() documentation.
critical
critical(msg: str, *args: Any, **kwargs: Any) -> None
Wrapper for logging.critical(). Log a message with severity CRITICAL.
For detailed documentation, see the Python logging.critical() documentation.
debug
debug(msg: str, *args: Any, **kwargs: Any) -> None
Wrapper for logging.debug(). Log a message with severity DEBUG.
For detailed documentation, see the Python logging.debug() documentation.
error
error(msg: str, *args: Any, **kwargs: Any) -> None
Wrapper for logging.error(). Log a message with severity ERROR.
For detailed documentation, see the Python logging.error() documentation.
exception
exception(msg: str, *args: Any, **kwargs: Any) -> None
Wrapper for logging.exception(). Log a message with severity ERROR with exception info.
For detailed documentation, see the Python logging.exception() documentation.
fatal
fatal(msg: str, *args: Any, **kwargs: Any) -> None
Wrapper for logging.fatal(). Log a message with severity CRITICAL.
For detailed documentation, see the Python logging.fatal() documentation.
info
info(msg: str, *args: Any, **kwargs: Any) -> None
Wrapper for logging.info(). Log a message with severity INFO.
For detailed documentation, see the Python logging.info() documentation.
log
log(level: int, msg: str, *args: Any, **kwargs: Any) -> None
Wrapper for logging.log(). Log a message with an explicit level.
For detailed documentation, see the Python logging.log() documentation.
warn
warn(msg: str, *args: Any, **kwargs: Any) -> None
Wrapper for logging.warn(). Log a message with severity WARNING.
For detailed documentation, see the Python logging.warn() documentation.
warning
warning(msg: str, *args: Any, **kwargs: Any) -> None
Wrapper for logging.warning(). Log a message with severity WARNING.
For detailed documentation, see the Python logging.warning() documentation.
trace
trace(msg: str, *args: Any, **kwargs: Any) -> None
Log a message with severity TRACE on the root logger.
TRACE is more verbose than DEBUG. This function gets an apathetic_logging.Logger instance (ensuring the root logger is an apathetic logger) and calls its trace() method.
If the logger has no handlers, basicConfig() is automatically called to add a console handler with a pre-defined format.
Parameters:
| Parameter | Type | Description |
|---|---|---|
msg |
str | Message to log |
*args |
Any | Format arguments for message formatting |
**kwargs |
Any | Additional keyword arguments (e.g., exc_info, stacklevel) |
Example:
import apathetic_logging
# Log a trace message
apathetic_logging.trace("Detailed trace information: %s", variable)
detail
detail(msg: str, *args: Any, **kwargs: Any) -> None
Log a message with severity DETAIL on the root logger.
DETAIL is more detailed than INFO. This function gets an apathetic_logging.Logger instance (ensuring the root logger is an apathetic logger) and calls its detail() method.
If the logger has no handlers, basicConfig() is automatically called to add a console handler with a pre-defined format.
Parameters:
| Parameter | Type | Description |
|---|---|---|
msg |
str | Message to log |
*args |
Any | Format arguments for message formatting |
**kwargs |
Any | Additional keyword arguments (e.g., exc_info, stacklevel) |
Example:
import apathetic_logging
# Log a detail message
apathetic_logging.detail("Additional detail: %s", information)
brief
brief(msg: str, *args: Any, **kwargs: Any) -> None
Log a message with severity BRIEF on the root logger.
BRIEF is less detailed than INFO. This function gets an apathetic_logging.Logger instance (ensuring the root logger is an apathetic logger) and calls its brief() method.
If the logger has no handlers, basicConfig() is automatically called to add a console handler with a pre-defined format.
Parameters:
| Parameter | Type | Description |
|---|---|---|
msg |
str | Message to log |
*args |
Any | Format arguments for message formatting |
**kwargs |
Any | Additional keyword arguments (e.g., exc_info, stacklevel) |
Example:
import apathetic_logging
# Log a brief message
apathetic_logging.brief("brief information: %s", summary)
test
test(msg: str, *args: Any, **kwargs: Any) -> None
Log a message at TEST level.
TEST is the most verbose level and bypasses capture. This function gets an apathetic_logging.Logger instance (ensuring the root logger is an apathetic logger) and calls its test() method.
Parameters:
| Parameter | Type | Description |
|---|---|---|
msg |
str | Message to log |
*args |
Any | Format arguments |
**kwargs |
Any | Additional keyword arguments |
Example:
import apathetic_logging
# Log a test message
apathetic_logging.test("Test message: %s", variable)
getHandlerByName
getHandlerByName(name: str) -> logging.Handler | None
Requires Python 3.12+
Wrapper for logging.getHandlerByName(). Get a handler with the specified name.
For detailed documentation, see the Python logging.getHandlerByName() documentation.
getHandlerNames
getHandlerNames() -> list[str]
Requires Python 3.12+
Wrapper for logging.getHandlerNames(). Return all known handler names.
For detailed documentation, see the Python logging.getHandlerNames() documentation.
makeLogRecord
makeLogRecord(
name: str,
level: int,
fn: str,
lno: int,
msg: str,
args: tuple,
exc_info: Any
) -> logging.LogRecord
Wrapper for logging.makeLogRecord(). Create a LogRecord from the given parameters.
For detailed documentation, see the Python logging.makeLogRecord() documentation.
currentframe
currentframe(*args: Any, **kwargs: Any) -> FrameType | None
Wrapper for logging.currentframe(). Return the frame object for the callerâs stack frame.
For detailed documentation, see the Python logging.currentframe() documentation.
4. apathetic_logging.Logger Function Reference
Constructor
Logger(
name: str,
level: int = logging.NOTSET,
*,
enable_color: bool | None = None
)
Logger class for all Apathetic tools. Extends Pythonâs standard logging.Logger.
Parameters:
| Parameter | Type | Description |
|---|---|---|
name |
str | Logger name |
level |
int | Initial log level (defaults to INHERIT_LEVEL (i.e. logging.NOTSET)) |
enable_color |
bool | None | Whether to enable colorized output. If None, auto-detects based on TTY and environment variables. |
setLevel
setLevel(level: int | str, *, minimum: bool | None = False, allow_inherit: bool = False) -> None
Set the logging level. Accepts both string names (case-insensitive) and numeric values.
Changed from stdlib: Accepts string level names and has minimum and allow_inherit parameters. In improved mode (default), validates that levels are > 0 to prevent accidental INHERIT_LEVEL (i.e. NOTSET) inheritance. In compatibility mode, accepts any level value (including 0 and negative) matching stdlib behavior.
Parameters:
| Parameter | Type | Description |
|---|---|---|
level |
int | str | Log level name or numeric value |
minimum |
bool | None | If True, only set the level if itâs more verbose (lower numeric value) than the current level. Defaults to False. |
allow_inherit |
bool | If True, allows setting level to 0 (INHERIT_LEVEL, i.e. NOTSET) in improved mode. In compatibility mode, this parameter is ignored and 0 is always accepted. Defaults to False. |
Behavior:
- Improved mode (default): Rejects level 0 (INHERIT_LEVEL, i.e. NOTSET) unless
allow_inherit=Trueis explicitly provided. This prevents accidental INHERIT_LEVEL (i.e. NOTSET) inheritance from custom levels that accidentally evaluate to 0. - Compatibility mode: Accepts any level value (including 0 and negative) matching stdlib behavior. The
allow_inheritparameter is ignored in this mode.
Example:
logger.setLevel("debug")
logger.setLevel(logging.DEBUG)
# Set to INHERIT_LEVEL (i.e. NOTSET) (inherits from parent) - requires explicit allow_inherit=True
logger.setLevel(0, allow_inherit=True)
# In compatibility mode, INHERIT_LEVEL (i.e. NOTSET) is accepted without allow_inherit
from apathetic_logging import registerCompatibilityMode
registerCompatibilityMode(compat_mode=True)
logger.setLevel(0) # Works in compat mode
setLevelMinimum
setLevelMinimum(level: int | str) -> None
Set the logging level only if itâs more verbose than the current level.
This convenience method is equivalent to calling setLevel(level, minimum=True). It prevents downgrading from a more verbose level (e.g., TRACE) to a less verbose one (e.g., DEBUG).
Parameters:
| Parameter | Type | Description |
|---|---|---|
level |
int | str | Log level name or numeric value. Only set if itâs more verbose (lower numeric value) than the current effective level. |
Example:
logger.setLevel("TRACE")
# This won't downgrade from TRACE to DEBUG
logger.setLevelMinimum("DEBUG")
assert logger.levelName == "TRACE" # Still TRACE
# This will upgrade from INFO to DEBUG
logger.setLevel("INFO")
logger.setLevelMinimum("DEBUG")
assert logger.levelName == "DEBUG" # Upgraded to DEBUG
setLevelInherit
setLevelInherit() -> None
Set the logger to inherit its level from the parent logger.
This convenience method is equivalent to calling setLevel(NOTSET, allow_inherit=True). It explicitly sets the logger to INHERIT_LEVEL (i.e. NOTSET) so it inherits its effective level from the root logger or parent logger.
Example:
logger.setLevel("DEBUG")
# Set to inherit from root logger
logger.setLevelInherit()
assert logger.levelName == "NOTSET"
assert logger.effectiveLevel == root.level # Inherits from root
determineLogLevel
determineLogLevel(
*,
args: argparse.Namespace | None = None,
root_log_level: str | None = None
) -> str
Resolve log level from CLI â env â root config â default.
Parameters:
| Parameter | Type | Description |
|---|---|---|
args |
argparse.Namespace | None | Parsed command-line arguments (checks for args.log_level) |
root_log_level |
str | None | Root logger level to use as fallback |
Returns:
str: Resolved log level name (uppercase)
Example:
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("--log-level", default="info")
args = parser.parse_args()
level = logger.determineLogLevel(args=args)
logger.setLevel(level)
determineColorEnabled
determineColorEnabled() -> bool
Return True if colored output should be enabled. (classmethod)
Checks:
NO_COLORenvironment variable (disables colors)FORCE_COLORenvironment variable (enables colors)- TTY detection (enables colors if stdout is a TTY)
Returns:
bool: True if colors should be enabled
extendLoggingModule
extendLoggingModule() -> bool
Extend Pythonâs logging module with TRACE and SILENT levels. (classmethod)
This method:
- Sets
apathetic_logging.Loggeras the default logger class - Adds
TRACEandSILENTlevel names - Adds
logging.TRACEandlogging.SILENTconstants
Returns:
bool: True if the extension ran, False if it was already extended
trace
trace(msg: str, *args: Any, **kwargs: Any) -> None
Log a message at TRACE level.
Parameters:
| Parameter | Type | Description |
|---|---|---|
msg |
str | Message to log |
*args |
Any | Format arguments |
**kwargs |
Any | Additional keyword arguments (e.g., exc_info, stacklevel) |
detail
detail(msg: str, *args: Any, **kwargs: Any) -> None
Log a message at DETAIL level.
Parameters:
| Parameter | Type | Description |
|---|---|---|
msg |
str | Message to log |
*args |
Any | Format arguments |
**kwargs |
Any | Additional keyword arguments |
brief
brief(msg: str, *args: Any, **kwargs: Any) -> None
Log a message at BRIEF level.
Parameters:
| Parameter | Type | Description |
|---|---|---|
msg |
str | Message to log |
*args |
Any | Format arguments |
**kwargs |
Any | Additional keyword arguments |
test
test(msg: str, *args: Any, **kwargs: Any) -> None
Log a message at TEST level.
Parameters:
| Parameter | Type | Description |
|---|---|---|
msg |
str | Message to log |
*args |
Any | Format arguments |
**kwargs |
Any | Additional keyword arguments |
errorIfNotDebug
errorIfNotDebug(msg: str, *args: Any, **kwargs: Any) -> None
Log an error with full traceback only if debug/trace is enabled.
If debug mode is enabled, shows full exception traceback. Otherwise, shows only the error message.
Parameters:
| Parameter | Type | Description |
|---|---|---|
msg |
str | Error message |
*args |
Any | Format arguments |
**kwargs |
Any | Additional keyword arguments |
Example:
try:
risky_operation()
except Exception:
logger.errorIfNotDebug("Operation failed")
criticalIfNotDebug
criticalIfNotDebug(msg: str, *args: Any, **kwargs: Any) -> None
Log a critical error with full traceback only if debug/trace is enabled.
Similar to errorIfNotDebug() but logs at CRITICAL level.
Parameters:
| Parameter | Type | Description |
|---|---|---|
msg |
str | Error message |
*args |
Any | Format arguments |
**kwargs |
Any | Additional keyword arguments |
colorize
colorize(text: str, color: str, *, enable_color: bool | None = None) -> str
Apply ANSI color codes to text.
Parameters:
| Parameter | Type | Description |
|---|---|---|
text |
str | Text to colorize |
color |
str | ANSI color code (e.g., ANSIColors.CYAN, ANSIColors.RED) |
enable_color |
bool | None | Override color enablement. If None, uses instance setting. |
Returns:
str: Colorized text (or original text if colors disabled)
logDynamic
logDynamic(level: str | int, msg: str, *args: Any, **kwargs: Any) -> None
Log a message at a dynamically specified level.
Parameters:
| Parameter | Type | Description |
|---|---|---|
level |
str | int | Log level name or numeric value |
msg |
str | Message to log |
*args |
Any | Format arguments |
**kwargs |
Any | Additional keyword arguments |
Example:
logger.logDynamic("warning", "This is a warning")
logger.logDynamic(logging.ERROR, "This is an error")
useLevel
useLevel(level: str | int, *, minimum: bool = False) -> ContextManager
Context manager to temporarily change log level.
Parameters:
| Parameter | Type | Description |
|---|---|---|
level |
str | int | Log level to use |
minimum |
bool | If True, only set the level if itâs more verbose (lower numeric value) than the current level. Prevents downgrading from a more verbose level. |
Returns:
- Context manager that restores the previous level on exit
Example:
with logger.useLevel("debug"):
logger.debug("This will be shown")
# Level is restored after the context
useLevelMinimum
useLevelMinimum(level: str | int) -> ContextManager
Context manager to temporarily change log level, only if itâs more verbose than the current level.
This convenience method is equivalent to calling useLevel(level, minimum=True). It prevents downgrading from a more verbose level (e.g., TRACE) to a less verbose one (e.g., DEBUG).
Parameters:
| Parameter | Type | Description |
|---|---|---|
level |
str | int | Log level to use. Only applied if itâs more verbose than the current effective level. |
Returns:
- Context manager that restores the previous level on exit
Example:
logger.setLevel("TRACE")
# This won't downgrade from TRACE to DEBUG
with logger.useLevelMinimum("DEBUG"):
assert logger.levelName == "TRACE" # Still TRACE
# This will upgrade from INFO to DEBUG
logger.setLevel("INFO")
with logger.useLevelMinimum("DEBUG"):
assert logger.levelName == "DEBUG" # Upgraded to DEBUG
usePropagate
usePropagate(propagate: bool, *, manage_handlers: bool | None = None) -> ContextManager
Context manager to temporarily change propagate setting.
Parameters:
| Parameter | Type | Description |
|---|---|---|
propagate |
bool | If True, messages propagate to parent loggers. If False, messages only go to this loggerâs handlers. |
manage_handlers |
bool | None | If True, automatically manage apathetic handlers based on propagate setting. If None, uses DEFAULT_MANAGE_HANDLERS from constants. If False, only sets propagate without managing handlers. In compat_mode, this may default to False. |
Returns:
- Context manager that restores the previous propagate setting on exit
Example:
# Temporarily disable propagation to capture logs locally
with logger.usePropagate(False):
logger.info("This message only goes to logger's handlers")
# Do something that should not propagate to root
# Propagate setting is restored after the context
setLevelAndPropagate
setLevelAndPropagate(
level: int | str,
*,
minimum: bool | None = False,
allow_inherit: bool = False,
manage_handlers: bool | None = None
) -> None
Set the logging level and propagate setting together in a smart way.
This convenience method combines setLevel() and setPropagate() with intelligent defaults:
- If level is
INHERIT_LEVEL(NOTSET): setspropagate=True - If level is a specific level: sets
propagate=False - On root logger: only sets level (propagate is unchanged)
This matches common use cases: when inheriting level, you typically want to propagate to parent handlers. When setting an explicit level, you typically want isolated logging with your own handler.
Parameters:
| Parameter | Type | Description |
|---|---|---|
level |
int | str | Log level name or numeric value. Use INHERIT_LEVEL (0) or âNOTSETâ to inherit. |
minimum |
bool | None | If True, only set the level if itâs more verbose (lower numeric value) than the current level. Defaults to False. |
allow_inherit |
bool | If True, allows setting level to 0 (INHERIT_LEVEL, i.e. NOTSET) in improved mode. Defaults to False. |
manage_handlers |
bool | None | If True, automatically manage apathetic handlers based on propagate setting. If None, uses DEFAULT_MANAGE_HANDLERS from constants. If False, only sets propagate without managing handlers. |
Example:
logger = getLogger("mymodule")
# Set to inherit level and propagate to root
from apathetic_logging import INHERIT_LEVEL
logger.setLevelAndPropagate(INHERIT_LEVEL, allow_inherit=True)
# Set explicit level and disable propagation (isolated logging)
logger.setLevelAndPropagate("debug")
useLevelAndPropagate
useLevelAndPropagate(
level: str | int,
*,
minimum: bool = False,
manage_handlers: bool | None = None
) -> ContextManager
Context manager to temporarily set level and propagate together.
This convenience context manager combines useLevel() and usePropagate() with intelligent defaults:
- If level is
INHERIT_LEVEL(NOTSET): setspropagate=True - If level is a specific level: sets
propagate=False - On root logger: only sets level (propagate is unchanged)
Both settings are restored when the context exits.
Parameters:
| Parameter | Type | Description |
|---|---|---|
level |
str | int | Log level to use (string name or numeric value). Use INHERIT_LEVEL (0) or âNOTSETâ to inherit. |
minimum |
bool | If True, only set the level if itâs more verbose (lower numeric value) than the current effective level. Prevents downgrading from a more verbose level. Defaults to False. |
manage_handlers |
bool | None | If True, automatically manage apathetic handlers based on propagate setting. If None, uses DEFAULT_MANAGE_HANDLERS from constants. If False, only sets propagate without managing handlers. |
Returns:
- Context manager that restores both the previous level and propagate setting on exit
Example:
logger = getLogger("mymodule")
# Temporarily inherit level and propagate
from apathetic_logging import INHERIT_LEVEL
with logger.useLevelAndPropagate(INHERIT_LEVEL):
logger.info("This propagates to root")
# Temporarily set explicit level with isolated logging
with logger.useLevelAndPropagate("debug"):
logger.debug("This only goes to logger's handlers")
# Both level and propagate are restored after the context
levelName
levelName: str
Return the explicit level name set on this logger (read-only property).
This property returns the name of the level explicitly set on this logger.
For the effective level name (whatâs actually used, considering inheritance),
use effectiveLevelName instead.
Example:
logger.setLevel("debug")
print(logger.levelName) # "DEBUG"
effectiveLevel
effectiveLevel: int
Return the effective level (whatâs actually used) (read-only property).
This property returns the effective logging level for this logger, considering
inheritance from parent loggers. This is the preferred way to get the effective
level. Also available via getEffectiveLevel() for stdlib compatibility.
Example:
parent = getLogger("parent")
parent.setLevel("info")
child = getLogger("parent.child")
print(child.level) # 0 (INHERIT_LEVEL, i.e. NOTSET - explicit)
print(child.effectiveLevel) # 20 (INFO - effective, from parent)
effectiveLevelName
effectiveLevelName: str
Return the effective level name (whatâs actually used) (read-only property).
This property returns the name of the effective logging level for this logger,
considering inheritance from parent loggers. This is the preferred way to get
the effective level name. Also available via getEffectiveLevelName() for
consistency.
Example:
parent = getLogger("parent")
parent.setLevel("info")
child = getLogger("parent.child")
print(child.levelName) # "NOTSET" (explicit - INHERIT_LEVEL, i.e. NOTSET)
print(child.effectiveLevelName) # "INFO" (effective, from parent)
getLevel
getLevel() -> int
Return the explicit level set on this logger.
This method returns the level explicitly set on this logger (same as level
property). For the effective level, use getEffectiveLevel() or the
effectiveLevel property.
Returns:
int: The explicit level value set on this logger
Example:
logger.setLevel("debug")
print(logger.getLevel()) # 10
getLevelName
getLevelName() -> str
Return the explicit level name set on this logger.
This method returns the name of the level explicitly set on this logger (same
as levelName property). For the effective level name, use
getEffectiveLevelName() or the effectiveLevelName property.
Returns:
str: The explicit level name set on this logger
Example:
logger.setLevel("debug")
print(logger.getLevelName()) # "DEBUG"
getEffectiveLevelName
getEffectiveLevelName() -> str
Return the effective level name (whatâs actually used).
This method returns the name of the effective logging level for this logger,
considering inheritance from parent loggers. Prefer the effectiveLevelName property
for convenience, or use this method for consistency with getEffectiveLevel().
Returns:
str: The effective level name for this logger
Example:
parent = getLogger("parent")
parent.setLevel("info")
child = getLogger("parent.child")
print(child.getEffectiveLevelName()) # "INFO" (from parent)
getChildren
getChildren() -> set[logging.Logger]
Requires Python 3.12+
Return a set of loggers that are immediate children of this logger.
This method returns only the direct children of the logger (loggers whose names are one level deeper in the hierarchy). For example, if you have loggers named foo, foo.bar, and foo.bar.baz, calling getLogger("foo").getChildren() will return a set containing only the foo.bar logger, not foo.bar.baz.
Returns:
set[logging.Logger]: A set of Logger instances that are immediate children of this logger
Example:
from apathetic_logging import getLogger
root = getLogger("")
foo = getLogger("foo")
bar = getLogger("foo.bar")
baz = getLogger("foo.bar.baz")
# Get immediate children of root logger
children = root.getChildren() # {foo logger}
# Get immediate children of foo logger
children = foo.getChildren() # {bar logger}
# Get immediate children of bar logger
children = bar.getChildren() # {baz logger}
For detailed documentation, see the Python logging.Logger.getChildren() documentation.
ensureHandlers
ensureHandlers() -> None
Ensure handlers are attached to this logger.
DualStreamHandler is what will ensure logs go to the write channel. Rebuilds handlers if theyâre missing or if stdout/stderr have changed.
validateLevel
validateLevel(level: int, *, level_name: str | None = None, allow_inherit: bool = False) -> None
Validate that a level value is positive (> 0). (staticmethod)
Custom levels with values <= 0 will inherit from the root logger, causing INHERIT_LEVEL (i.e. NOTSET) inheritance issues. In compatibility mode, validation is skipped.
Parameters:
| Parameter | Type | Description |
|---|---|---|
level |
int | The numeric level value to validate |
level_name |
str | None | Optional name for the level (for error messages). If None, will attempt to get from getLevelName() |
allow_inherit |
bool | If True, allows level 0 (INHERIT_LEVEL, i.e. NOTSET). Defaults to False. |
Raises:
ValueError: If level <= 0 (or level == 0 withoutallow_inherit=True)
Example:
Logger.validateLevel(5, level_name="TRACE")
Logger.validateLevel(0, level_name="TEST")
# ValueError: setLevel(0) sets the logger to INHERIT_LEVEL (i.e. NOTSET)...
Logger.validateLevel(0, level_name="TEST", allow_inherit=True)
# Passes validation
_log
_log(level: int, msg: str, args: tuple[Any, ...], **kwargs: Any) -> None
Log a message with the specified level.
Changed from stdlib: Automatically ensures handlers are attached via ensureHandlers().
Parameters:
| Parameter | Type | Description |
|---|---|---|
level |
int | The numeric logging level |
msg |
str | The message format string |
args |
tuple[Any, âŠ] | Arguments for the message format string |
**kwargs |
Any | Additional keyword arguments passed to the base implementation |
addLevelName
addLevelName(level: int, level_name: str) -> None
Associate a level name with a numeric level. (staticmethod)
Changed from stdlib: Validates that level value is positive (> 0) to prevent INHERIT_LEVEL (i.e. NOTSET)
inheritance issues. Sets logging.<LEVEL_NAME> attribute for convenience.
Parameters:
| Parameter | Type | Description |
|---|---|---|
level |
int | The numeric level value (must be > 0 for custom levels) |
level_name |
str | The name to associate with this level |
Raises:
ValueError: If level <= 0 (which would cause INHERIT_LEVEL (i.e. NOTSET) inheritance)ValueError: Iflogging.<LEVEL_NAME>already exists with an invalid value
Classes
TagFormatter
Custom formatter that adds colored tags to log messages.
Constructor
TagFormatter(format: str)
Parameters:
| Parameter | Type | Description |
|---|---|---|
format |
str | Format string (typically "%(message)s") |
The formatter automatically adds tags based on log level:
TRACEâ[TRACE](gray)DEBUGâ[DEBUG](cyan)WARNINGââ ïžERRORââCRITICALâđ„
DualStreamHandler
Stream handler that routes messages to stdout or stderr based on log level.
- stdout: Used for INFO messages
- stderr: Used for TRACE, DEBUG, WARNING, ERROR, and CRITICAL messages
Constructor
DualStreamHandler()
Properties
enable_color: bool
Whether to enable colorized output for this handler.
Constants
Log Levels
TRACE_LEVELâ Numeric value for TRACE level (logging.DEBUG - 5)SILENT_LEVELâ Numeric value for SILENT level (logging.CRITICAL + 1)LEVEL_ORDERâ List of all log level names in order:["trace", "debug", "info", "warning", "error", "critical", "silent"]
ANSI Colors
Access via ANSIColors class:
ANSIColors.RESETâ ANSI reset code (\033[0m)ANSIColors.CYANâ Cyan color (\033[36m)ANSIColors.YELLOWâ Yellow color (\033[93m)ANSIColors.REDâ Red color (\033[91m)ANSIColors.GREENâ Green color (\033[92m)ANSIColors.GRAYâ Gray color (\033[90m)
Example:
from apathetic_logging import ANSIColors
message = f"{ANSIColors.CYAN}Colored text{ANSIColors.RESET}"
Tag Styles
TAG_STYLESâ Dictionary mapping level names to (color, tag_text) tuples
Defaults
DEFAULT_APATHETIC_LOG_LEVELâ Default log level string ("info")DEFAULT_APATHETIC_LOG_LEVEL_ENV_VARSâ Default environment variable names (["LOG_LEVEL"])
Testing Utilities
SAFE_TRACE(label: str, *args: Any, icon: str = âđ§”â) -> None
Debug tracing function for test development. Only active when safe trace is enabled via environment variables.
Safe trace is enabled when any of the following conditions are met:
SAFE_TRACEenvironment variable is set to"1","true", or"yes"(case insensitive)LOG_LEVELenvironment variable (case insensitive) is set to"TRACE"or"TEST"LOG_LEVELnumeric value is less than or equal toTRACE_LEVEL(supports both numeric strings like"5"and standard logging level names like"DEBUG")
Parameters:
| Parameter | Type | Description |
|---|---|---|
label |
str | Trace label |
*args |
Any | Additional arguments to trace |
icon |
str | Icon to use (default: "đ§”") |
make_test_trace(icon: str = âđ§”â) -> Callable
Create a test trace function with a custom icon.
Parameters:
| Parameter | Type | Description |
|---|---|---|
icon |
str | Icon to use |
Returns:
Callable: Test trace function
SAFE_TRACE_ENABLED: bool
Boolean flag indicating if safe trace is enabled. This is determined by checking environment variables at module import time.
Safe trace is enabled when any of the following conditions are met:
SAFE_TRACEenvironment variable is set to"1","true", or"yes"(case insensitive)LOG_LEVELenvironment variable (case insensitive) is set to"TRACE"or"TEST"LOG_LEVELnumeric value is less than or equal toTRACE_LEVEL(supports both numeric strings like"5"and standard logging level names like"DEBUG")
Note: This value is computed once at module import time. To change it at runtime, you can directly assign to this attribute (useful for testing).
Example:
from apathetic_logging import SAFE_TRACE_ENABLED, safeTrace
import os
# Check if safe trace is enabled
if SAFE_TRACE_ENABLED:
safeTrace("debug", "message") # Will output
# Enable via environment variable before import
os.environ["SAFE_TRACE"] = "1"
# Note: You need to re-import for the change to take effect
# Or override directly (useful in tests)
import apathetic_logging
apathetic_logging.SAFE_TRACE_ENABLED = True
safeTrace("debug", "message") # Will output
Compatibility Mode
This library provides two modes of operation:
Default Mode (Improved Behavior)
When compatibility mode is disabled (compat_mode=False, the default), the library provides improved behavior with enhancements over the standard library:
- Auto-inference:
getLogger(None)auto-infers the logger name from the calling moduleâs__package__attribute, making it easier to use the logger without explicitly registering a name. - Enhanced features: Additional improvements and quality-of-life enhancements.
Compatibility Mode (Standard Library Compatible)
When compatibility mode is enabled (compat_mode=True), the library maintains standard library compatible behavior with no breaking changes:
- Stdlib behavior:
getLogger(None)returns the root logger (matching standard library behavior). - Full compatibility: All behavior matches the Python standard library
loggingmodule.
Enabling Compatibility Mode
To enable compatibility mode for stdlib-compatible behavior:
from apathetic_logging import registerCompatibilityMode
registerCompatibilityMode(compat_mode=True)
# Now getLogger(None) returns root logger (stdlib behavior)
You can also set it when registering a logger:
from apathetic_logging import registerLogger
registerLogger("my_app", compat_mode=True)
Behavior Differences
getLogger(None) behavior:
- Default mode (
compat_mode=False): Auto-infers logger name from calling module (improved behavior) - Compatibility mode (
compat_mode=True): Returns root logger (stdlib behavior)
To get root logger in default mode:
logger = getLogger("") # Returns root logger (works in both modes)
See registerCompatibilityMode() for more details.