Mayil-AI-Sandbox / loguru-aug23

MIT License
0 stars 0 forks source link

Creating a custom logger #33

Open NobleMathews opened 5 months ago

NobleMathews commented 5 months ago

I'm trying to create a structured logger which outputs JSON, something using mentioned here:

My problem is I would like to have logger.error("some error") to result me error = record["exception"] with

{
    "type": error.type.__name__,
    "value": str(error.value),
    "traceback": None      hashtag No traceback, but error type is mentioned
}

But with logger.exception("something completely unknown") to result:

{
    "type": error.type.__name__,
    "value": str(error.value),
    "traceback": "".join(traceback.format_exception(*error))  hashtag complete traceback
}

I know there is logger.opt() but I would like to have something like above for ergonomic code.


My current idea is to do something like this:

def serialize(record):
    """Serialize to our custom needs for structured logging.

    With `logger.exception` all fields of `exception` key is populated.
    With `logger.error` `traceback` field remains unpopulated.

    Args:
        record: 

    Returns:

    """python
    error: loguru.RecordException = record["exception"] 
    error_by_default = sys.exc_info()   hashtag logger.error
    pipeline: str | None = record["extra"].get("pipeline", None)
    level: str = record["level"].name
    if error:  hashtag only set when exception.
        exception = {
            "type": error.type.__name__,
            "value": str(error.value),
            "traceback": "".join(traceback.format_exception(*error))
        }
    elif error_by_default[0]:  hashtag whenever error occurs
        _type, _value, _ = sys.exc_info()
        exception = {
            "type": _type.__name__,
            "value": str(_value),
            "traceback": None
        }
    else:
        exception = None

    to_serialize = {
        "level": level ,
        "message": record["message"],
        "time": record["time"].strftime("%d-%m-%YT%H:%M:%SZ"),
        "pipeline": pipeline,
        "exception": exception,
    }
    return json.dumps(to_serialize)
logger.error("Error occurred")   hashtag no traceback in `exception.traceback`
logger.exception("Exception occurred")   hashtag `exception.traceback` is populated 
mayil-ai[bot] commented 5 months ago

To address the issue of creating a custom logger in the loguru library that outputs structured JSON logs with different formats for logger.error and logger.exception, follow these steps:

  1. Check if record["exception"] is present.
  2. If present, include the traceback in the JSON output.
  3. If not present, exclude the traceback from the JSON output.

Here is the updated serialize function:

import json
import sys
import traceback
from loguru import logger

def serialize(record):
    error = record["exception"]
    level = record["level"].name

    if error:
        exception = {
            "type": error.type.__name__,
            "value": str(error.value),
            "traceback": "".join(traceback.format_exception(*error))
        }
    else:
        exception = {
            "type": None,
            "value": None,
            "traceback": None
        }

    to_serialize = {
        "level": level,
        "message": record["message"],
        "time": record["time"].strftime("%d-%m-%YT%H:%M:%SZ"),
        "exception": exception,
    }

    # Remove traceback if the log level is 'ERROR' and no exception is present
    if level == "ERROR" and not error:
        to_serialize["exception"]["traceback"] = None

    return json.dumps(to_serialize)

logger.add(sys.stderr, format=serialize)

This setup ensures that:

Usage:

logger.error("Error occurred")
logger.exception("Exception occurred")

Here are some code snippets that may help you get started:

💡 To rerun Mayil, comment mayil-ai rerun. Mayil will incorporate any new context added to the ticket. Include details in your rerun comment to guide Mayil!