Meine aktuelle Formatzeichenfolge lautet:
formatter = logging.Formatter('%(asctime)s : %(message)s')
und ich möchte ein neues Feld mit dem Namen hinzufügen, app_name
das in jedem Skript, das diesen Formatierer enthält, einen anderen Wert hat.
import logging
formatter = logging.Formatter('%(asctime)s %(app_name)s : %(message)s')
syslog.setFormatter(formatter)
logger.addHandler(syslog)
Ich bin mir jedoch nicht sicher, wie ich diesen app_name
Wert an den Logger übergeben soll, um ihn in die Formatzeichenfolge zu interpolieren. Ich kann es natürlich dazu bringen, in der Protokollnachricht zu erscheinen, indem ich es jedes Mal weitergebe, aber das ist chaotisch.
Ich habe es versucht:
logging.info('Log message', app_name='myapp')
logging.info('Log message', {'app_name', 'myapp'})
logging.info('Log message', 'myapp')
aber keine funktioniert.
log
Anruf weitergeben? Wenn ja, schauen Sie sich die Dokumente an, in denen steht: "Diese Funktionalität kann verwendet werden, um Ihre eigenen Werte in einen LogRecord einzufügen ...". Dies scheint jedoch ein Hauptfall für die Verwendunglogger = logging.getLogger('myapp')
und Einbringung in denlogger.info
Aufruf zu sein.logger
in jeder App ein anderes Objekt verwenden, können Sie dafür sorgen, dass jedes Objekt einen anderen Namen verwendet, indem Sie Ihr Objektlogger
wie folgt instanziieren :logger = logging.getLogger(myAppName)
. Beachten Sie, dass dies__name__
der Name des Python-Moduls ist. Wenn also jede App ein eigenes Python-Modul ist, funktioniert dies ebenfalls.Antworten:
Sie können einen LoggerAdapter verwenden, damit Sie die zusätzlichen Informationen nicht bei jedem Protokollierungsaufruf übergeben müssen:
import logging extra = {'app_name':'Super App'} logger = logging.getLogger(__name__) syslog = logging.StreamHandler() formatter = logging.Formatter('%(asctime)s %(app_name)s : %(message)s') syslog.setFormatter(formatter) logger.setLevel(logging.INFO) logger.addHandler(syslog) logger = logging.LoggerAdapter(logger, extra) logger.info('The sky is so blue')
Protokolle (so etwas wie)
2013-07-09 17:39:33,596 Super App : The sky is so blue
Filter können auch zum Hinzufügen von Kontextinformationen verwendet werden.
import logging class AppFilter(logging.Filter): def filter(self, record): record.app_name = 'Super App' return True logger = logging.getLogger(__name__) logger.addFilter(AppFilter()) syslog = logging.StreamHandler() formatter = logging.Formatter('%(asctime)s %(app_name)s : %(message)s') syslog.setFormatter(formatter) logger.setLevel(logging.INFO) logger.addHandler(syslog) logger.info('The sky is so blue')
erzeugt einen ähnlichen Protokolldatensatz.
quelle
config.ini
Datei angeben ? Ich möchte den aktuellen Hostnamen hinzufügensocket.gethostname()
.import uuid uniqueId = str(uuid.uuid4()) extra = {"u_id" : uniqueId} RotatingHandler = RotatingFileHandler(LOG_FILENAME,encoding='utf-8',maxBytes=maxSize, backupCount=batchSize) logger.basicConfig(handlers=[RotatingHandler],level=logLevel.upper(),format='%(levelname)s %(u_id)s %(funcName)s %(asctime)s %(message)s ',datefmt='%m/%d/%Y %I:%M:%S %p') logger = logger.LoggerAdapter(logger=logger, extra=extra)
Sie müssen das Diktat als Parameter an extra übergeben, um dies auf diese Weise zu tun.
logging.info('Log message', extra={'app_name': 'myapp'})
Beweis:
>>> import logging >>> logging.basicConfig(format="%(foo)s - %(message)s") >>> logging.warning('test', extra={'foo': 'bar'}) bar - test
Wenn Sie versuchen, eine Nachricht zu protokollieren, ohne das Diktat zu übergeben, schlägt dies fehl.
>>> logging.warning('test') Traceback (most recent call last): File "/usr/lib/python2.7/logging/__init__.py", line 846, in emit msg = self.format(record) File "/usr/lib/python2.7/logging/__init__.py", line 723, in format return fmt.format(record) File "/usr/lib/python2.7/logging/__init__.py", line 467, in format s = self._fmt % record.__dict__ KeyError: 'foo' Logged from file <stdin>, line 1
quelle
logging.info()
? Es ist fehlgeschlagen, als ich es zuletzt versucht habe. : /logging.Formatter
zuweisen, indem Sie die Klasse: class CustomFormatter (logging.Formatter): def format (self, record): Wenn nicht hasattr (record, 'foo'): record.foo = 'default_foo' return erweitern super (CustomFormatter, self.format (record) h = loggin.StreamHandler () h.setFormatter (CustomFormatter ('% (foo) s% (message) s') logger = logging.getLogger ('bar') logger.addHandler ( h) logger.error ('hey!', extra = {'foo': 'FOO'}) logger.error ('hey!')Python3
Ab Python3.2 können Sie jetzt LogRecordFactory verwenden
>>> import logging >>> logging.basicConfig(format="%(custom_attribute)s - %(message)s") >>> old_factory = logging.getLogRecordFactory() >>> def record_factory(*args, **kwargs): record = old_factory(*args, **kwargs) record.custom_attribute = "my-attr" return record >>> logging.setLogRecordFactory(record_factory) >>> logging.info("hello") my-attr - hello
Natürlich
record_factory
kann es so angepasst werden, dass es aufrufbar ist, und der Wert voncustom_attribute
kann aktualisiert werden, wenn Sie einen Verweis auf das werkseitig aufrufbare Objekt behalten.Warum ist das besser als die Verwendung von Adaptern / Filtern?
logger = logging.getLogger(..)
) und jetzt dasselbe Protokollformat haben. (Dies ist nicht der Fall bei Filtern / Adaptern, bei denen Sie dasselbe Logger-Objekt verwenden müssen.)quelle
Eine andere Möglichkeit besteht darin, einen benutzerdefinierten LoggerAdapter zu erstellen. Dies ist besonders nützlich, wenn Sie das Format nicht ändern können ODER wenn Ihr Format für Code freigegeben ist, der den eindeutigen Schlüssel nicht sendet (in Ihrem Fall Anwendungsname ):
class LoggerAdapter(logging.LoggerAdapter): def __init__(self, logger, prefix): super(LoggerAdapter, self).__init__(logger, {}) self.prefix = prefix def process(self, msg, kwargs): return '[%s] %s' % (self.prefix, msg), kwargs
Und in Ihrem Code würden Sie Ihren Logger wie gewohnt erstellen und initialisieren:
logger = logging.getLogger(__name__) # Add any custom handlers, formatters for this logger myHandler = logging.StreamHandler() myFormatter = logging.Formatter('%(asctime)s %(message)s') myHandler.setFormatter(myFormatter) logger.addHandler(myHandler) logger.setLevel(logging.INFO)
Schließlich würden Sie den Wrapper-Adapter erstellen, um nach Bedarf ein Präfix hinzuzufügen:
logger = LoggerAdapter(logger, 'myapp') logger.info('The world bores you when you are cool.')
Die Ausgabe sieht ungefähr so aus:
2013-07-09 17:39:33,596 [myapp] The world bores you when you are cool.
quelle
Ich habe diese SO-Frage gefunden, nachdem ich sie selbst implementiert habe. Hoffe es hilft jemandem. Im folgenden Code induziere ich einen zusätzlichen Schlüssel, der
claim_id
im Logger-Format aufgerufen wird . Die Claim_ID wird immer dann protokolliert, wennclaim_id
in der Umgebung ein Schlüssel vorhanden ist. In meinem Anwendungsfall musste ich diese Informationen für eine AWS Lambda-Funktion protokollieren.import logging import os LOG_FORMAT = '%(asctime)s %(name)s %(levelname)s %(funcName)s %(lineno)s ClaimID: %(claim_id)s: %(message)s' class AppLogger(logging.Logger): # Override all levels similarly - only info overriden here def info(self, msg, *args, **kwargs): return super(AppLogger, self).info(msg, extra={"claim_id": os.getenv("claim_id", "")}) def get_logger(name): """ This function sets log level and log format and then returns the instance of logger""" logging.setLoggerClass(AppLogger) logging.basicConfig(level=logging.INFO, format=LOG_FORMAT) logger = logging.getLogger(name) logger.setLevel(logging.INFO) return logger LOGGER = get_logger(__name__) LOGGER.info("Hey") os.environ["claim_id"] = "12334" LOGGER.info("Hey")
Inhalt: https://gist.github.com/ramanujam/306f2e4e1506f302504fb67abef50652
quelle
Mit der Antwort von mr2ert habe ich diese komfortable Lösung gefunden (obwohl ich denke, dass dies nicht empfohlen wird) - Überschreiben Sie die integrierten Protokollierungsmethoden, um das benutzerdefinierte Argument zu akzeptieren und das
extra
Wörterbuch innerhalb der Methoden zu erstellen :import logging class CustomLogger(logging.Logger): def debug(self, msg, foo, *args, **kwargs): extra = {'foo': foo} if self.isEnabledFor(logging.DEBUG): self._log(logging.DEBUG, msg, args, extra=extra, **kwargs) *repeat for info, warning, etc* logger = CustomLogger('CustomLogger', logging.DEBUG) formatter = logging.Formatter('%(asctime)s [%(foo)s] %(message)s') handler = logging.StreamHandler() handler.setFormatter(formatter) logger.addHandler(handler) logger.debug('test', 'bar')
Ausgabe:
2019-03-02 20:06:51,998 [bar] test
Dies ist die eingebaute Referenzfunktion:
def debug(self, msg, *args, **kwargs): """ Log 'msg % args' with severity 'DEBUG'. To pass exception information, use the keyword argument exc_info with a true value, e.g. logger.debug("Houston, we have a %s", "thorny problem", exc_info=1) """ if self.isEnabledFor(DEBUG): self._log(DEBUG, msg, args, **kwargs)
quelle
Protokollierung importieren;
Klasse LogFilter (logging.Filter):
def __init__(self, code): self.code = code def filter(self, record): record.app_code = self.code return True
logging.basicConfig (format = '[% (asctime) s:% (levelname) s] :: [% (modul) s ->% (name) s] - APP_CODE:% (app_code) s - MSG:% (message ) s ');
Klasse Logger:
def __init__(self, className): self.logger = logging.getLogger(className) self.logger.setLevel(logging.ERROR) @staticmethod def getLogger(className): return Logger(className) def logMessage(self, level, code, msg): self.logger.addFilter(LogFilter(code)) if level == 'WARN': self.logger.warning(msg) elif level == 'ERROR': self.logger.error(msg) else: self.logger.info(msg)
Klasse Test: logger = Logger.getLogger ('Test')
if __name__=='__main__': logger.logMessage('ERROR','123','This is an error')
quelle