Registrazione Python: usa millisecondi nel formato orario


163

Per impostazione predefinita, logging.Formatter('%(asctime)s')stampa con il seguente formato:

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

dove 638 è il millisecondo. Devo cambiare la virgola in un punto:

2011-06-09 10:54:40.638

Per formattare il tempo che posso usare:

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

tuttavia la documentazione non specifica come formattare i millisecondi. Ho trovato questa domanda SO che parla di microsecondi, ma a) Preferirei millisecondi eb) quanto segue non funziona su Python 2.6 (su cui sto lavorando) a causa di %f:

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

1
Forse cambiare il locale potrebbe aiutare?
Pajton,

1
@ pajton - nel seguente link dice "Le informazioni sulla localizzazione
Jonathan

%fnon funziona su Python 2.7.9 o 3.5.1
Antony Hatchkins,

4
Buona conversazione qui. Sono venuto qui perché loggingafferma che il suo formato orario predefinito segue ISO 8601. Non è così. Usa lo spazio, non "T" per separare il tempo e la virgola per secondi frazionari, non il punto decimale. Come potrebbero essere così sbagliati?
LS

Risposte:


76

Si noti che la soluzione di Craig McDaniel è chiaramente migliore.


Il formatTimemetodo di formattazione è simile al seguente:

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

Notare la virgola in "%s,%03d". Questo non può essere risolto specificando a datefmtperché ctè a time.struct_timee questi oggetti non registrano millisecondi.

Se cambiamo la definizione di ctper renderlo un datetimeoggetto anziché un struct_time, quindi (almeno con le versioni moderne di Python) possiamo chiamare ct.strftimee quindi possiamo usare %fper formattare i microsecondi:

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.

Oppure, per ottenere millisecondi, modificare la virgola in un punto decimale e omettere l' datefmtargomento:

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.

1
quindi% f darebbe effettivamente microsecondi, non millisecondi, giusto?
Jonathan,

@Jonathan: oops, hai ragione, %fdà microsecondi. Suppongo che il modo più semplice per ottenere millisecondi sia cambiare la virgola in un punto decimale (vedi modifica sopra).
unutbu,

3
In realtà penso che questa sia la risposta migliore perché ti riporta subito alla possibilità di utilizzare le opzioni di formattazione STANDARD. In realtà volevo microsecondi, e questa era l'unica opzione che potesse farlo!
trumpetlicks,

Grazie. Questa risposta offre una soluzione semplice per ottenere microsecondi.
Yongwei Wu,

338

Anche questo dovrebbe funzionare:

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

12
Grazie: ecco i documenti per questi: docs.python.org/2/library/logging.html#logrecord-attributes docs.python.org/3/library/logging.html#logrecord-attributes .. C'è un modo per includi ancora il fuso orario (% z)? ... I tempi del formato ISO8601 nei log di Python (, ->.) Sarebbero fantastici.
Wes Turner,

19
Questa soluzione è per disabili, perché se lo hai %z o %Znel tuo datefmtvuoi che appaia DOPO i msec, non prima.
mercoledì

1
E anche se stai usando un orologio di 12 ore che ha AMoPM
DollarAkshay il

1
@wim come seguito al mio commento precedente (non potevo più modificare ...), ecco cosa ho fatto: from time import gmtime- # Use UTC rather than local date/time- logging.Formatter.converter = gmtime-logging.basicConfig(datefmt='%Y-%m-%dT%H:%M:%S', format='%(name)s | %(asctime)s.%(msecs)03dZ | %(message)s', level=log_level)
Mark

1
@Mark Non puoi incorporare il fuso orario default_msec_format(a partire da Python 3.7) perché vengono sostituiti solo il tempo e i millisecondi. Dalla loggingfonte:self.default_msec_format % (t, record.msecs)
M. Dudley,

28

L'aggiunta di msec era l'opzione migliore, grazie. Ecco il mio emendamento che usa questo con Python 3.5.3 in 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")

1
Di gran lunga l'opzione più semplice e pulita. Non sono sicuro del motivo per cui stai ricevendo il logger quando puoi semplicemente chiamare logging.info (msg) ecc., Ma il formato è esattamente quello che stavo cercando. Chiunque cerchi tutti gli attributi utilizzabili può consultare qui: docs.python.org/3.6/library/logging.html#logrecord-attributes
naphier

Hmmm punto interessante, grazie per il commento è sicuramente uno spunto di riflessione. Sì, probabilmente l'ho appena aggiunto come lezione su quello che sta succedendo lì, e per assicurarmi che sia lì e perché ho chiesto più cose in modo che non siano necessarie più chiamate ai genitori (tramite '.') Per recuperarlo. Se avessi chiamato di nuovo .info o .debug, forse li avrei salvati di nuovo direttamente come suggerisci di salvare un ciclo di ricerca di riferimento. [let info = logging.info]
Master James

Grazie per aver detto Jason. A volte c'è un modo più semplice di vedere il mondo, non abbiate paura di provare a scoprire quella verità in molte se non in qualsiasi situazione.
Master James,

15

Il modo più semplice che ho trovato è stato quello di sostituire default_msec_format:

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

1
Interessante, grazie. Ma questo non ha funzionato per me in Python 2.7. Può funzionare solo in Python 3.x per un valore di x.
nealmcb,

1
@nealmcb questo non è disponibile fino a Python 3.3 per i documenti
Segna il

3

Dopo aver istanziato un Formatterset di solito formatter.converter = gmtime. Quindi, affinché la risposta di @ unutbu funzioni in questo caso, dovrai:

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

2

Una semplice espansione che non richiede il datetimemodulo e non è handicappata come alcune altre soluzioni consiste nell'utilizzare una semplice sostituzione di stringa in questo modo:

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

In questo modo è possibile scrivere un formato data come desiderato, anche tenendo conto delle differenze regionali, utilizzando %Fper millisecondi. Per esempio:

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

1

Se stai usando la freccia o se non ti dispiace usare la freccia. Puoi sostituire la formattazione temporale di Python con quella della freccia.

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)

Ora è possibile utilizzare tutti i tempi di freccia formattazione in datefmtattributo.


-1

tl; dr per chi cerca qui una data in formato ISO:

datefmt: '% Y-% m-% d% H:% M:% S.% 03d% z'


-3

A partire da ora il seguente funziona perfettamente con Python 3.

         logging.basicConfig(level=logging.DEBUG,
                     format='%(asctime)s %(levelname)-8s %(message)s',
                     datefmt='%Y/%m/%d %H:%M:%S.%03d',
                     filename=self.log_filepath,
                     filemode='w')

fornisce il seguente output

2020/01/11 18: 51: 19.011 INFO


1
Questo non funziona. % d sta stampando la data. Nel tuo esempio, la data viene stampata con uno 0 davanti.
Klik,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.