MCPcopy Create free account
hub / github.com/apify/crawlee-python / CrawleeLogFormatter

Class CrawleeLogFormatter

src/crawlee/_log_config.py:84–167  ·  view source on GitHub ↗

Log formatter that prints out the log message nicely formatted, with colored level and stringified extra fields. It formats the log records so that they: - start with the level (colorized, and padded to 5 chars so that it is nicely aligned) - then have the actual log message, if

Source from the content-addressed store, hash-verified

82
83
84class CrawleeLogFormatter(logging.Formatter):
85 """Log formatter that prints out the log message nicely formatted, with colored level and stringified extra fields.
86
87 It formats the log records so that they:
88 - start with the level (colorized, and padded to 5 chars so that it is nicely aligned)
89 - then have the actual log message, if it's multiline then it's nicely indented
90 - then have the stringified extra log fields
91 - then, if an exception is a part of the log record, prints the formatted exception.
92 """
93
94 # The fields that are added to the log record with `logger.log(..., extra={...})` are just merged in the log record
95 # with the other log record properties, and you can't get them in some nice, isolated way. So, to get the extra
96 # fields, we just compare all the properties present in the log record with properties present in an empty log
97 # record, and extract all the extra ones not present in the empty log record.
98 empty_record = logging.LogRecord('dummy', 0, 'dummy', 0, 'dummy', None, None)
99
100 def __init__(
101 self,
102 include_logger_name: bool = True, # noqa: FBT001, FBT002
103 *args: Any,
104 **kwargs: Any,
105 ) -> None:
106 """Initialize a new instance.
107
108 Args:
109 include_logger_name: Include logger name at the beginning of the log line.
110 args: Arguments passed to the parent class.
111 kwargs: Keyword arguments passed to the parent class.
112 """
113 super().__init__(*args, **kwargs)
114 self.include_logger_name = include_logger_name
115
116 def _get_extra_fields(self, record: logging.LogRecord) -> dict[str, Any]:
117 extra_fields: dict[str, Any] = {}
118 for key, value in record.__dict__.items():
119 if key not in self.empty_record.__dict__:
120 extra_fields[key] = value # noqa: PERF403
121
122 return extra_fields
123
124 def format(self, record: logging.LogRecord) -> str:
125 """Format the log record nicely.
126
127 This formats the log record so that it:
128 - starts with the level (colorized, and padded to 5 chars so that it is nicely aligned)
129 - then has the actual log message, if it's multiline then it's nicely indented
130 - then has the stringified extra log fields
131 - then, if an exception is a part of the log record, prints the formatted exception.
132 """
133 logger_name_string = f'{_LOG_NAME_COLOR}[{record.name}]{Style.RESET_ALL} '
134
135 # Colorize the log level, and shorten it to 6 chars tops
136 level_color_code = _LOG_LEVEL_COLOR.get(record.levelno, '')
137 level_short_alias = _LOG_LEVEL_SHORT_ALIAS.get(record.levelno, record.levelname)
138 level_string = f'{level_color_code}{level_short_alias}{Style.RESET_ALL} '
139
140 # Format the extra log record fields, if there were some
141 # Just stringify them to JSON and color them gray

Callers 4

test_formatted_messageFunction · 0.90
configure_loggerFunction · 0.85

Calls

no outgoing calls

Tested by 3

test_formatted_messageFunction · 0.72