Better exception with custom serializer
Hi
There is already some related topics like #876
I am trying to use this method, but I ran into a problem with exception formatting. I want to see the better_exception format in my logs, but I can't find a way to achieve this with custom serializing.
because all of the documented ways called before this https://github.com/Delgan/loguru/blob/d379fedd9b19401e937c63de0154caf9a11252ec/loguru/_handler.py#L138
how I can use formatted exceptions as text message in my custom serializer instead of https://github.com/Delgan/loguru/blob/d379fedd9b19401e937c63de0154caf9a11252ec/loguru/_handler.py#L278-L280
Hi.
The way exception formatting works in Loguru depends on whether you provide a string or a function as the format argument.
When a string is used, the "\n{exception}" placeholder will automatically be appended for convenience. However, if a custom function is passed, Loguru gives you full control over the formatted placeholders.
In the ticket you linked, the sink is configured with format=lambda _: "{extra[serialized]}". This has the effect of disabling the exception formatting. However, you can re-enable it simply by using a string format="{extra[serialized]}" which will internally be expanded as format="{extra[serialized]}\n{exception}".
Yeah this way is obvious However, unfortunately, it makes the log unstructured and, for example, ELK does not recognize this
I want to achieve the same effect as using serialize=True but with my own serialization function
in the standard behavior, the formatted exception log goes into the .text field and does not break the JSON structure as if I had used format="{extra[serialized]}\n{exception}"
Then why not serialize the exception in your custom serializer?
You mean something like this?
from loguru._better_exceptions import ExceptionFormatter
exception_formatter = ExceptionFormatter(
colorize=False,
encoding='utf-8',
diagnose=settings.DEBUG,
backtrace=settings.DEBUG,
hidden_frames_filename=None,
prefix='',
)
def serialize_log(record) -> str:
subset = {
"time": record["time"].isoformat(),
"level": record["level"].name,
"trace_id": record["extra"].get("trace_id", None),
"message": record["message"]
}
if record["exception"]:
type_, value, tb = record["exception"]
lines = exception_formatter.format_exception(type_, value, tb, from_decorator=False)
subset.update({
"exception": "".join(lines)
})
entry = json.dumps(subset)
return entry
def json_formatter(record):
record["extra"]["serialized"] = serialize_log(record)
return "{extra[serialized]}\n"
logger.configure(
handlers=[
{
"sink": sys.stdout,
"format": json_formatter if settings.JSON_LOGS else loguru_defaults.LOGURU_FORMAT,
"level": settings.LEVEL,
}
],
)
It certainly works, but it doesn't looks like the right way to me 🤷♀️
Yes, I mean something like this, except that you don't have to use the non-public loguru._better_exceptions module, you can directly import and use better-exceptions or any other exception formatter of your choice.