web-dev-qa-db-fra.com

Python journalisation: utiliser des millisecondes au format heure

Par défaut, logging.Formatter('%(asctime)s') imprime le format suivant:

2011-06-09 10:54:40,638

où 638 est la milliseconde. J'ai besoin de changer la virgule en un point:

2011-06-09 10:54:40.638

Pour formater le temps que je peux utiliser:

logging.Formatter(fmt='%(asctime)s',datestr=date_format_str)

cependant, documentation ne spécifie pas comment formater les millisecondes. J'ai trouvé this SO question qui parle de microsecondes, mais a) je préférerais des millisecondes et b) ce qui suit ne fonctionne pas sur Python 2.6 (sur lequel je travaille) en raison de la %f:

logging.Formatter(fmt='%(asctime)s',datefmt='%Y-%m-%d,%H:%M:%S.%f')
135
Jonathan

Veuillez noter que la solution de Craig McDaniel est clairement meilleur.


la méthode formatTime de logging.Formatter ressemble à ceci:

def formatTime(self, record, datefmt=None):
    ct = self.converter(record.created)
    if datefmt:
        s = time.strftime(datefmt, ct)
    else:
        t = time.strftime("%Y-%m-%d %H:%M:%S", ct)
        s = "%s,%03d" % (t, record.msecs)
    return s

Notez la virgule dans "%s,%03d". Ceci ne peut pas être corrigé en spécifiant un datefmt car ct est un time.struct_time et ces objets n'enregistrent pas les millisecondes.

Si nous changeons la définition de ct pour en faire un objet datetime à la place de struct_time, alors (du moins avec les versions modernes de Python), on peut appeler ct.strftime et ensuite nous pouvons utiliser %f pour formater des microsecondes:

import logging
import datetime as dt

class MyFormatter(logging.Formatter):
    converter=dt.datetime.fromtimestamp
    def formatTime(self, record, datefmt=None):
        ct = self.converter(record.created)
        if datefmt:
            s = ct.strftime(datefmt)
        else:
            t = ct.strftime("%Y-%m-%d %H:%M:%S")
            s = "%s,%03d" % (t, record.msecs)
        return s

logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)

console = logging.StreamHandler()
logger.addHandler(console)

formatter = MyFormatter(fmt='%(asctime)s %(message)s',datefmt='%Y-%m-%d,%H:%M:%S.%f')
console.setFormatter(formatter)

logger.debug('Jackdaws love my big sphinx of quartz.')
# 2011-06-09,07:12:36.553554 Jackdaws love my big sphinx of quartz.

Ou, pour obtenir des millisecondes, modifiez la virgule en point décimal et omettez l'argument datefmt:

class MyFormatter(logging.Formatter):
    converter=dt.datetime.fromtimestamp
    def formatTime(self, record, datefmt=None):
        ct = self.converter(record.created)
        if datefmt:
            s = ct.strftime(datefmt)
        else:
            t = ct.strftime("%Y-%m-%d %H:%M:%S")
            s = "%s.%03d" % (t, record.msecs)
        return s

...
formatter = MyFormatter(fmt='%(asctime)s %(message)s')
...
logger.debug('Jackdaws love my big sphinx of quartz.')
# 2011-06-09 08:14:38.343 Jackdaws love my big sphinx of quartz.
66
unutbu

Cela devrait fonctionner aussi:

logging.Formatter(fmt='%(asctime)s.%(msecs)03d',datefmt='%Y-%m-%d,%H:%M:%S')
276
Craig McDaniel

L'ajout de msecs était la meilleure option, merci. Voici mon amendement utilisant ceci avec Python 3.5.3 dans Blender

import logging
logging.basicConfig(level=logging.DEBUG, format='%(asctime)s.%(msecs)03d %(levelname)s:\t%(message)s', datefmt='%Y-%m-%d %H:%M:%S')
log = logging.getLogger(__name__)
log.info("Logging Info")
log.debug("Logging Debug")
14
Master James

Le moyen le plus simple que j'ai trouvé était de remplacer default_msec_format:

formatter = logging.Formatter('%(asctime)s')
formatter.default_msec_format = '%s.%03d'
11
Mickey B

Après avoir instancié un Formatter, je règle généralement formatter.converter = gmtime. Donc, pour que la réponse de @ unutbu fonctionne dans ce cas, vous aurez besoin de:

class MyFormatter(logging.Formatter):
    def formatTime(self, record, datefmt=None):
        ct = self.converter(record.created)
        if datefmt:
            s = time.strftime(datefmt, ct)
        else:
            t = time.strftime("%Y-%m-%d %H:%M:%S", ct)
            s = "%s.%03d" % (t, record.msecs)
        return s
4
Jonathan

Une simple extension qui ne nécessite pas le module datetime et qui n’est pas handicapée comme d’autres solutions consiste à utiliser un simple remplacement de chaîne, comme ceci:

import logging
import time

class MyFormatter(logging.Formatter):
    def formatTime(self, record, datefmt=None):
    ct = self.converter(record.created)
    if datefmt:
        if "%F" in datefmt:
            msec = "%03d" % record.msecs
            datefmt = datefmt.replace("%F", msec)
        s = time.strftime(datefmt, ct)
    else:
        t = time.strftime("%Y-%m-%d %H:%M:%S", ct)
        s = "%s,%03d" % (t, record.msecs)
    return s

De cette façon, un format de date peut être écrit comme vous le souhaitez, même en tenant compte des différences de région, en utilisant %F pendant des millisecondes. Par exemple:

log = logging.getLogger(__name__)
log.setLevel(logging.INFO)

sh = logging.StreamHandler()
log.addHandler(sh)

fm = MyFormatter(fmt='%(asctime)s-%(levelname)s-%(message)s',datefmt='%H:%M:%S.%F')
sh.setFormatter(fm)

log.info("Foo, Bar, Baz")
# 03:26:33.757-INFO-Foo, Bar, Baz
2
torrentails

Si vous utilisez flèche ou si l'utilisation de la flèche ne vous dérange pas. Vous pouvez substituer la mise en forme de l'heure par python par celle de arrow.

import logging

from arrow.arrow import Arrow


class ArrowTimeFormatter(logging.Formatter):

    def formatTime(self, record, datefmt=None):
        arrow_time = Arrow.fromtimestamp(record.created)

        if datefmt:
            arrow_time = arrow_time.format(datefmt)

        return str(arrow_time)


logger = logging.getLogger(__name__)

default_handler = logging.StreamHandler()
default_handler.setFormatter(ArrowTimeFormatter(
    fmt='%(asctime)s',
    datefmt='YYYY-MM-DD HH:mm:ss.SSS'
))

logger.setLevel(logging.DEBUG)
logger.addHandler(default_handler)

Vous pouvez maintenant utiliser tous les formatage de la flèche dans l'attribut datefmt.

1
Slapy