| 166 | self._normal = "" |
| 167 | |
| 168 | def format(self, record: Any) -> str: |
| 169 | try: |
| 170 | message = record.getMessage() |
| 171 | assert isinstance(message, basestring_type) # guaranteed by logging |
| 172 | # Encoding notes: The logging module prefers to work with character |
| 173 | # strings, but only enforces that log messages are instances of |
| 174 | # basestring. In python 2, non-ascii bytestrings will make |
| 175 | # their way through the logging framework until they blow up with |
| 176 | # an unhelpful decoding error (with this formatter it happens |
| 177 | # when we attach the prefix, but there are other opportunities for |
| 178 | # exceptions further along in the framework). |
| 179 | # |
| 180 | # If a byte string makes it this far, convert it to unicode to |
| 181 | # ensure it will make it out to the logs. Use repr() as a fallback |
| 182 | # to ensure that all byte strings can be converted successfully, |
| 183 | # but don't do it by default so we don't add extra quotes to ascii |
| 184 | # bytestrings. This is a bit of a hacky place to do this, but |
| 185 | # it's worth it since the encoding errors that would otherwise |
| 186 | # result are so useless (and tornado is fond of using utf8-encoded |
| 187 | # byte strings wherever possible). |
| 188 | record.message = _safe_unicode(message) |
| 189 | except Exception as e: |
| 190 | record.message = f"Bad message ({e!r}): {record.__dict__!r}" |
| 191 | |
| 192 | record.asctime = self.formatTime(record, cast(str, self.datefmt)) |
| 193 | |
| 194 | if record.levelno in self._colors: |
| 195 | record.color = self._colors[record.levelno] |
| 196 | record.end_color = self._normal |
| 197 | else: |
| 198 | record.color = record.end_color = "" |
| 199 | |
| 200 | formatted = self._fmt % record.__dict__ |
| 201 | |
| 202 | if record.exc_info: |
| 203 | if not record.exc_text: |
| 204 | record.exc_text = self.formatException(record.exc_info) |
| 205 | if record.exc_text: |
| 206 | # exc_text contains multiple lines. We need to _safe_unicode |
| 207 | # each line separately so that non-utf8 bytes don't cause |
| 208 | # all the newlines to turn into '\n'. |
| 209 | lines = [formatted.rstrip()] |
| 210 | lines.extend(_safe_unicode(ln) for ln in record.exc_text.split("\n")) |
| 211 | formatted = "\n".join(lines) |
| 212 | return formatted.replace("\n", "\n ") |
| 213 | |
| 214 | |
| 215 | def enable_pretty_logging( |