Accept a Callable for the serialize argument when adding a sink
See original GitHub issueHello Delgan ! Love your library !
I was wondering what you would think about accepting a Callable for the serialize
parameter in logger.add
method ?
This would ease customization of the jsonified records. And I’m thinking about ELK stack usage for example.
I managed to achieve this purpose by overwriting the Handler._serialize_record
staticmethod:
import sys
import flask
import loguru
import orjson
import pytz
import stackprinter
from flask_login import current_user
def _serialize_record_elk(text, record):
# Format timestamp for Elasticache
timestamp = record["time"].astimezone(pytz.utc)
timestamp = timestamp.strftime("%Y-%m-%dT%H:%M:%S.{:03d}Z").format(
timestamp.microsecond // 1000
)
# Current User's email of flask app
user_email = getattr(current_user, "email", "anonymous")
# Can add some config variable of interest from the flask app
env = None
if flask.has_request_context():
if hasattr(flask.current_app, "config"):
env = flask.current_app.config["ENV"]
serializable = {
# Base fields
"@timestamp": timestamp, # Elasticache index overwrite
"icon": record["level"].icon,
"log": {"level": record["level"].name},
"name": record["name"],
"message": record["message"],
# App related:
"user": {"email": user_email},
"env": env,
# Extra
"extra": record["extra"],
"misc": {
"elapsed": {
"repr": record["elapsed"],
"seconds": record["elapsed"].total_seconds(),
},
"file": {"name": record["file"].name, "path": record["file"].path},
"function": record["function"],
"level": {
"icon": record["level"].icon,
"name": record["level"].name,
"no": record["level"].no,
},
"line": record["line"],
"module": record["module"],
"process": {"id": record["process"].id, "name": record["process"].name},
"thread": {"id": record["thread"].id, "name": record["thread"].name},
},
}
if record["exception"]:
exc_class = record["exception"].type
serializable = {
**serializable,
"exc": {
"type": f"{exc_class.__module__}.{exc_class.__name__}",
"value": record["exception"].value,
"traceback": stackprinter.format(record["exception"], show_vals="line"),
},
}
return orjson.dumps(serializable, default=str).decode("utf-8") + "\n"
loguru._handler.Handler._serialize_record = staticmethod(_serialize_record_elk)
loguru.logger.add(sink=sys.stdout, serialize=True, format="{message}")
Still, that would be a nice to have in official doc IMO ! 😉
Issue Analytics
- State:
- Created 3 years ago
- Comments:6 (4 by maintainers)
Top Results From Across the Web
java - Is there a way to take an argument in a callable method?
Adding to Jarle's answer -- in case you create Callable as instance of anonymous class, you can use final field outside of anonymous...
Read more >Agents - Self-organizing Stream Processors
A sink can be callable, async callable, a topic/channel or another agent. Function Callback. Regular functions take a single argument (the result after ......
Read more >loguru Documentation - Read the Docs
Using the serialize argument, each log message will be converted to a JSON string before being sent to the configured sink. logger.add( ...
Read more >Pipeline — NVIDIA DALI 1.20.0 documentation
Most DALI operators accept additional keyword arguments used to parametrize their ... Deserialize pipeline, previously serialized with serialize() method.
Read more >pyarrow.SerializationContext — Apache Arrow v3.0.0 - enpiar.com
custom_deserializer (callable) – This argument is optional, but can be provided to deserialize objects of the class in a particular way. serialize (self ......
Read more >Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start FreeTop Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
Top GitHub Comments
@gjeusel Oh yeah, sorry, I’m dumb. >.<
The
format
function should not create the log message by itself. It should not return a already formatted message. Instead, it should return a string which later will be used to actually create the logged message. The function should be used as a way to dynamically create a static format string.Here is what I mean:
The string returned by the
format
function is used to create the log message by callingreturned_string.format(**record)
.It’s a bit counter-intuitive (hence my mistake), but it’s necessary to allow the use of colors dynamically. The “idiomatic” workaround is to add the generated message to the
extra
dict and use it in the dynamicformat
returned:Again, it’s also possible to
patch()
thelogger
with_serialize_record_elk()
and useformat=lambda _: "{extra[serialized]}\n"
directly. It has the advantage of calling the function just once if you want to use it in multiple sinks.I added a small recipe to the documentation: Serializing log messages using a custom function.