logger
¶
Non-blocking logging with QueueHandler, Rich console output, and run tracking.
Configures multiple loggers (console, error, analytics), provides path shortening aliases, log rotation by runs, and compact formatting for both file and terminal output.
SafeQueueListener
¶
Bases: QueueListener
A QueueListener wrapper that safely handles stop() calls.
stop
¶
Stop the listener thread safely, handling cases where _thread is None.
Source code in src/core/logger.py
LogFormat
¶
Rich markup helpers for consistent log formatting.
Provides IDE-like syntax highlighting for log messages using Rich markup. Use these methods to wrap values that should be highlighted in console output.
Example
from core.logger import LogFormat as LF logger.info("Initializing %s...", LF.entity("CacheService")) logger.info("Loaded %s entries from %s", LF.number(100), LF.file("cache.json"))
entity
staticmethod
¶
Format entity/class name with IDE-like highlighting (yellow).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
Class, service, or component name |
required |
Returns:
| Type | Description |
|---|---|
str
|
Rich-formatted string with yellow highlighting |
Source code in src/core/logger.py
file
staticmethod
¶
Format filename with cyan highlighting.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
Filename or path |
required |
Returns:
| Type | Description |
|---|---|
str
|
Rich-formatted string with cyan highlighting |
number
staticmethod
¶
Format numbers with bright white highlighting.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
value
|
float
|
Numeric value to format (int or float, since int is a subtype) |
required |
Returns:
| Type | Description |
|---|---|
str
|
Rich-formatted string with bright white highlighting |
Source code in src/core/logger.py
success
staticmethod
¶
Format success status with green highlighting.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
text
|
str
|
Success message or status |
required |
Returns:
| Type | Description |
|---|---|
str
|
Rich-formatted string with green highlighting |
Source code in src/core/logger.py
error
staticmethod
¶
Format error status with red highlighting.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
text
|
str
|
Error message or status |
required |
Returns:
| Type | Description |
|---|---|
str
|
Rich-formatted string with red highlighting |
warning
staticmethod
¶
Format warning status with yellow highlighting.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
text
|
str
|
Warning message or status |
required |
Returns:
| Type | Description |
|---|---|
str
|
Rich-formatted string with yellow highlighting |
Source code in src/core/logger.py
duration
staticmethod
¶
Format duration with dim styling.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
seconds
|
float
|
Duration in seconds |
required |
Returns:
| Type | Description |
|---|---|
str
|
Rich-formatted string with duration |
label
staticmethod
¶
Format label/key with bold styling.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
text
|
str
|
Label text |
required |
Returns:
| Type | Description |
|---|---|
str
|
Rich-formatted string with bold styling |
dim
staticmethod
¶
Format text with dim styling for secondary info.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
text
|
str
|
Secondary text |
required |
Returns:
| Type | Description |
|---|---|
str
|
Rich-formatted string with dim styling |
LoggerFilter
¶
Filter that only allows records from specific logger names.
Initialize filter with allowed logger names.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
allowed_loggers
|
list[str]
|
List of logger names that should pass the filter. Child loggers (e.g., "main_logger.child") also pass if parent is allowed. |
required |
Source code in src/core/logger.py
filter
¶
Filter log records based on logger name.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
record
|
LogRecord
|
The log record to filter. |
required |
Returns:
| Type | Description |
|---|---|
bool
|
True if record's logger name matches or is child of allowed loggers. |
Source code in src/core/logger.py
RunHandler
¶
Handles tracking of script runs, adding separators between runs, and limiting logs to max number of runs.
Initialize the RunHandler for log run tracking.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
max_runs
|
int
|
Maximum number of runs to keep in log files. Older runs are trimmed during log cleanup. |
3
|
Source code in src/core/logger.py
format_run_header
staticmethod
¶
Create a formatted header for a new run.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
logger_name
|
str
|
Name of the logger starting the run. |
required |
Returns:
| Type | Description |
|---|---|
str
|
Formatted header string with timestamp and visual separators. |
Source code in src/core/logger.py
format_run_footer
¶
Create a formatted footer for the end of a run.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
logger_name
|
str
|
Name of the logger ending the run. |
required |
Returns:
| Type | Description |
|---|---|
str
|
Formatted footer string with elapsed time and visual separators. |
Source code in src/core/logger.py
trim_log_to_max_runs
¶
Trims a log file to contain only the most recent N runs, identified by run headers.
Source code in src/core/logger.py
CompactFormatter
¶
CompactFormatter(
fmt=None,
datefmt="%H:%M:%S",
style="%",
*,
include_separator=False,
config=None
)
Bases: Formatter
Custom log formatter for compact, readable output, primarily for file logs.
Features: Level abbreviation, short timestamps, and precise path shortening applied to specific log record fields. RichHandler is used for console output.
Initialize the CompactFormatter.
Source code in src/core/logger.py
format
¶
Format the LogRecord into a compact string, applying path shortening to specific attributes before standard formatting.
Source code in src/core/logger.py
636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 | |
RunTrackingHandler
¶
Bases: FileHandler
A file handler that adds run separation headers/footers and trims the log to a maximum number of runs based on headers.
Initialize the handler.
Source code in src/core/logger.py
emit
¶
Emit a log record with run tracking.
Writes the run header before the first record of a new run. Handles header write failures gracefully.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
record
|
LogRecord
|
The log record to emit. |
required |
Source code in src/core/logger.py
close
¶
Close the handler with run cleanup.
Writes the run footer, closes the file stream, and trims the log to maintain max_runs limit. Handles errors at each stage.
Source code in src/core/logger.py
Loggable
¶
Mixin providing console_logger and error_logger attributes.
Store the provided loggers.
Source code in src/core/logger.py
get_shared_console
¶
Get or create the shared Rich console instance.
All Rich output (logging, spinners, progress bars) should use this single Console instance to prevent output interleaving issues.
Returns:
| Type | Description |
|---|---|
Console
|
The shared Console instance. |
Source code in src/core/logger.py
spinner
async
¶
Async context manager for indeterminate spinner during long operations.
Use this for operations where progress cannot be tracked (e.g., AppleScript calls that return all data at once). The spinner provides visual feedback that the application is working.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
message
|
str
|
Message to display next to the spinner |
required |
console
|
Console | None
|
Optional Rich Console instance (creates new one if not provided) |
None
|
Yields:
| Type | Description |
|---|---|
AsyncGenerator[Status]
|
Rich Status object that can be used to update the message |
Example
async with spinner("Fetching all track IDs from Music.app..."): result = await run_applescript(...)
Source code in src/core/logger.py
ensure_directory
¶
Ensure that the given directory path exists, creating it if necessary.
Handles potential race conditions during creation. Logs errors using the provided logger.
Source code in src/core/logger.py
convert_path_value_to_string
¶
Convert a config path value to string with fallback and error handling.
Handles various input types from YAML config and provides safe conversion with logging on failure.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
path_value
|
str | int | None
|
The path value from config (str, int, or None). |
required |
default
|
str
|
Default string to return if conversion fails. |
required |
error_logger
|
Logger | None
|
Optional logger for error reporting. |
required |
Returns:
| Type | Description |
|---|---|
str
|
String representation of path_value, or default on failure. |
Source code in src/core/logger.py
get_path_from_config
¶
Extract relative path from the logging config section.
Safely retrieves a path value from the typed logging configuration using attribute access.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
config
|
AppConfig
|
Typed application configuration. |
required |
key
|
str
|
Attribute name in |
required |
default
|
str
|
Default path if attribute is missing or invalid. |
required |
error_logger
|
Logger | None
|
Optional logger for error reporting. |
required |
Returns:
| Type | Description |
|---|---|
str
|
Path string from config, or default if not found/invalid. |
Source code in src/core/logger.py
get_full_log_path
¶
Return the full log path by joining the base logs directory with the relative path.
Ensures the base directory and the log file's directory exist.
Source code in src/core/logger.py
build_config_alias_map
¶
Build alias mapping from config directories for path shortening.
Creates ordered list of (directory, alias) tuples used by shorten_path() to replace long paths with readable aliases like $SCRIPTS, $LOGS.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
config
|
AppConfig | None
|
Typed application configuration. |
required |
Returns:
| Type | Description |
|---|---|
list[tuple[str, str]]
|
List of (resolved_path, alias) tuples ordered by replacement priority. |
list[tuple[str, str]]
|
Returns empty list if config is None. |
Source code in src/core/logger.py
try_config_alias_replacement
¶
Attempt to replace path with config-based aliases.
Checks if the normalized path starts with any configured directory and returns the aliased version if found.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
norm_path
|
str
|
Normalized (os.path.normpath) absolute path. |
required |
config
|
AppConfig | None
|
Typed application configuration. |
required |
Returns:
| Type | Description |
|---|---|
str | None
|
Aliased path string (e.g., "$SCRIPTS/fetch.scpt") if match found, |
str | None
|
None otherwise. |
Source code in src/core/logger.py
try_home_directory_replacement
¶
Attempt to replace path with home directory shortcut (~).
Safely resolves home directory and replaces it with ~ for readability. Handles OSError if home directory cannot be determined.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
norm_path
|
str
|
Normalized absolute path to process. |
required |
error_logger
|
Logger | None
|
Optional logger for warning on home resolution failure. |
required |
Returns:
| Type | Description |
|---|---|
str | None
|
Path with home directory replaced by ~, or None if no replacement made. |
Source code in src/core/logger.py
shorten_path
¶
Return a shortened, human-friendly representation of path.
Priority of replacements (first match wins):
1. User-defined directories from config → $SCRIPTS, $LOGS, $MUSIC_LIB.
2. Current user's home directory → ~.
3. Any other absolute path collapses to its file name.
The function never raises and always returns some string, falling back to the
original path on errors. Internal issues are routed to error_logger or
stderr if the logger is unavailable.
Source code in src/core/logger.py
get_log_levels_from_config
¶
Extract log levels from config for different logger targets.
Reads the logging.levels section and converts string level
names to logging module constants.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
config
|
AppConfig
|
Typed application configuration. |
required |
Returns:
| Type | Description |
|---|---|
dict[str, int]
|
Dictionary mapping target names to logging level constants: |
dict[str, int]
|
|
Source code in src/core/logger.py
get_log_file_paths
¶
Get all log file paths from config with defaults.
Resolves full paths for each log file by combining logs_base_dir
with relative paths from the logging config section.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
config
|
AppConfig
|
Typed application configuration. |
required |
Returns:
| Type | Description |
|---|---|
dict[str, str]
|
Dictionary mapping log type to absolute file path: |
dict[str, str]
|
|
Source code in src/core/logger.py
create_console_logger
¶
Create and configure the console logger with RichHandler.
Sets up a logger named "console_logger" with Rich formatting for colorized, readable console output. Only adds handler if not already present.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
levels
|
dict[str, int]
|
Dictionary with "console" key containing logging level constant. |
required |
Returns:
| Type | Description |
|---|---|
Logger
|
Configured console logger instance with RichHandler attached. |
Source code in src/core/logger.py
setup_queue_logging
¶
Set up queue-based file logging with all handlers.
Source code in src/core/logger.py
get_loggers
¶
Create and return loggers with QueueHandler for non-blocking file logging.
Sets up multiple loggers with different purposes and a shared queue listener for efficient file I/O. Uses RichHandler for colorized console output.
Note
This function never raises exceptions. On setup failure, it returns fallback loggers with basic StreamHandler configuration.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
config
|
AppConfig
|
Typed application configuration. |
required |
Returns:
| Type | Description |
|---|---|
Logger
|
Tuple of (console_logger, error_logger, analytics_logger, |
Logger
|
db_verify_logger, listener). Listener is |
Source code in src/core/logger.py
create_fallback_loggers
¶
Create fallback loggers when main logger setup fails.
Configures basic logging as a safety net when QueueListener or RichHandler initialization fails. Logs the original error and returns simple StreamHandler loggers.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
e
|
Exception
|
The exception that caused main logger setup to fail. |
required |
Returns:
| Type | Description |
|---|---|
Logger
|
Tuple of (console_logger, error_logger, analytics_logger, db_verify_logger, None). |
Logger
|
The listener is None since queue-based logging failed. |
Source code in src/core/logger.py
get_html_report_path
¶
Get the path for HTML analytics report based on run mode.