six8 / logaware Goto Github PK
View Code? Open in Web Editor NEWPython Logger that is context aware
License: BSD 2-Clause "Simplified" License
Python Logger that is context aware
License: BSD 2-Clause "Simplified" License
Example:
logger.error(message, extra={"foo": "bar"})
logaware will treat extra
as a regular keyword argument which eventually gets added as a key to the LogRecord.extra
property. So you end up with a log record like:
record.extra["extra"] == {"foo": "bar"}
logaware does not use extra
, but the standard library logger does. For better compatibility with the standard library, logware should merge extra
with kwargs
so it is not double-nested.
When trying to dump a LogMeta
object to a JSON string, it errors because LogMeta
objects subclass Mapping
, not dict
, which the json
module does understand how to format into a JSON string.
Hi,
While investigating the mechanics of the stdlib's logging
module, I had a chance to peak into how the internal _log()
method is working and how the extra={}
is handled.
I have noticed that the MetaAwareLogger
that in return inherits from AwareLogger
does not exactly respect the process of passing in an extra
dictionary with the log message. I wonder if this is an issue or a feature?
meta.set_meta(context='cli')
log = MetaAwareLogger(lambda: meta.get_meta())
log.debug('Hello World?', extra={'event': 'buffer'})
Would fail with a formatter such as [%s(meta)s] [%s(event)s]
as internally the extra
is stored inside a nested dictionary data {}
. So there are two main dictionaries meta {}
and data {}
. meta {}
makes sense, but to be able to access the contents of data {}
one would need a custom Formatter
to display data['extra'] with the above specified formatter template. To get his:
[{"contex":"cli"}] [{"event":"buffer"}]
Just checking. Thanks.
logaware expects messages to use {name}
in log messages to format log keyword arguments.
logger.error("message {example}", example="foo")
This can be a problem if the message comes from a third party library which may have "{" in the messages, but not for string formatting purposes.
logaware should allow you to bypass the string formatting.
Hi,
I have been doing a bit of testing and I think I am getting pretty comfortable with the API of logaware. The examples and our discussions in the previous issues was really helpful. Thank you very much for that.
Right now, I am trying to minimise the boiler plate stuff required to get the logger working across an application and any modules. It is already very efficient and it seems like it is all working very well.
So this is what I have in my main app:
#myApp.py
# Native logging.
import logging
# logaware specific imports.
from logaware.logger import AwareLogger, LogFormatException, LogLevel, log_method_factory
from logaware.metalogger import LogMetaManager, MetaAwareLogger
# logaware extension specific to this project.
from logger import ContextLogFormatter
# First configure top-level logger using the native logging.
logger = logging.getLogger()
logger.setLevel(logging.DEBUG)
# Initialize the meta logger.
meta = LogMetaManager()
# Assign a context to the logger. This should be 'vim' if we are running inside vim or
# simply 'cli' if we are running as a command line.
meta.set_meta(context='cli')
# Initialize the MetaAwareLogger.
log = MetaAwareLogger(lambda: meta.get_meta())
# From here on, it is all the usual logging procedures (handlers, formatters etc.)
(...)
The question is, in a module that is also required to use the same logger, do we need to do anything special? For example, this is how I have things set-up in a module:
# entity.py - which is a module of myApp.py
# Initial imports
import logging
# logaware specific imports.
from logaware.logger import AwareLogger, LogFormatException, LogLevel, log_method_factory
from logaware.metalogger import LogMetaManager, MetaAwareLogger
# Introduce the logaware meta logger.
meta = LogMetaManager()
meta.set_meta(context='cli')
#Assign an initial context.
log = MetaAwareLogger(lambda: meta.get_meta())
# From here on, it is only log messages.
(...)
And I am getting this:
[2016-11-04 16:59:58,818] [context=cli] <myApp:<module>:43> DEBUG: Hello World!
[2016-11-04 16:59:58,819] [context=cli] <myApp:<module>:49> DEBUG: Is this a debug message?
[2016-11-04 16:59:58,820] [context=cli] <entity:__init__:30> DEBUG: Class instance call.
[2016-11-04 16:59:58,820] [context=cli] <entity:get_name:38> INFO: PET name is Molly
[2016-11-04 16:59:58,820] [context=cli] <entity:third_party:43> INFO: Initial message from: _THIRD_PARTY!
[2016-11-04 16:59:58,820] [context=cli] <entity:another_function:48> WARNING: Message from: _ANOTHER_FUNCTION
[2016-11-04 16:59:58,821] [context=cli] <myApp:cmd:62> WARNING: Hello from __CMD!
[2016-11-04 16:59:58,821] [context=cli] <myApp:foo:58> DEBUG: Hello from __FOO?
[2016-11-04 16:59:58,821] [context=cli] <myApp:foo:59> INFO: Also inside __FOO?
Which is really working well for me. So usually, with the native logging it would be something like:
log = logging.getLogger('main')
at the start of the main application and then in the module:
log=logging.getLogger('main.entity')
and the logging will be simply connecting to the same logger. It seems like we do not need that with the logaware
module? How much of the initial logaware
boiler plate code do I need at the start of a module?
Thanks.
Hello Again,
Is it possible to pass extra information together with the log message. It is a bit like the meta
information, which I start to understand, but updated with every log
call.
For example:
log.debug('Hello World!', req=5, sup=4)
outputs:
[2016-11-04 18:50:10,008] [context=cli] [req(5)>sup(4)] <myApp:foo:74> INFO: Also inside __FOO?
I know how to pass that information to the logger, however, with logaware
, I am not sure which bit to wrap so that I have control on the log.record
. And about the formatting that looks like this [req(5)>sup(4)]
, I can do that with my own Formatter, the question is how to get those into the log.record
?
From the example, you have provided, I know that it is possible to wrap logaware
classes and prepare our own Loggers
, however I am not sure how to implement that. I can see it is possible in the following example.
class CustomLogger(AwareLogger):
"""
Logger with additional levels for auditing and debugging.
"""
(...)
This project is doing it successfully and in a simple way. But it uses a custom logging class. So if that is the case, what would be the best way to approach this issue? Do we inherit from the AwareLogger
just like we inherit from the logging.Logger
and simply inject into the record
with every log.level
call?
Thanks.
Hi,
Thank you very much for creating this logging module. Could you please help me by providing a simple example regarding the usage of this module? I tried couple of things, however was not able to get it working. A simple case example would be really helpful. (All the tox
tests are passing by the way and I am on Python 2.7). Thanks.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.