Python günlüğü: saat biçiminde milisaniye kullanın


163

Varsayılan logging.Formatter('%(asctime)s')olarak aşağıdaki biçimde yazdırır:

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

burada 638 milisaniyedir. Virgül bir noktaya değiştirmek gerekir:

2011-06-09 10:54:40.638

Kullanabileceğim zamanı biçimlendirmek için:

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

ancak belgeler milisaniyenin nasıl biçimlendirileceğini belirtmez. Mikrosaniyeler hakkında konuşan bu SO sorusunu buldum , ama a) Milisaniye tercih ediyorum ve b) aşağıdaki Python 2.6 (üzerinde çalışıyorum) nedeniyle çalışmıyor %f:

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

1
Belki yerel ayarı değiştirmek yardımcı olabilir?
pajton

1
@ pajton - aşağıdaki bağlantıda "Yerel ayar bilgisi, sonraki () tarafından kullanılmıyor" yazıyor
Jonathan

%fpython 2.7.9 veya
3.5.1'de de çalışmıyor

4
Burada güzel sohbet. Buraya geldim çünkü loggingvarsayılan zaman formatı ISO 8601'i takip ediyor. Ondalık noktası değil, kesirli saniyeler için zamanı ve virgül ayırmak için "T" değil, boşluk kullanır. Nasıl bu kadar yanlış olabilirlerdi?
LS

Yanıtlar:


76

Lütfen Craig McDaniel'in çözümünün daha iyi olduğunu unutmayın .


forgingter formatTimeyöntemi şu şekildedir :

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

Virgülün içine dikkat edin "%s,%03d". Bu belirterek tamir edilemez datefmtçünkü ctbir time.struct_timeve bu nesneler rekor milisaniye yapamaz.

ctBir datetimenesneyi a yerine bir nesne yapmak için tanımını değiştirirsek, struct_time(en azından Python'un modern sürümlerinde) arayabiliriz ct.strftimeve sonra %fmikrosaniyeleri biçimlendirmek için kullanabiliriz :

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.

Veya milisaniye almak için virgülün ondalık basamağa değiştirilmesini sağlayın ve datefmtargümanı atlayın :

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
% f aslında milisaniye değil mikrosaniye verirdi, değil mi?
Jonathan

@Jonathan: Hata! Haklısın, %fmikrosaniye verir. Milisaniye almanın en kolay yolunun virgül ondalık bir noktaya değiştirmek olduğunu varsayalım (yukarıdaki düzenlemeye bakın).
unutbu

3
Aslında bu, STANDART biçimlendirme seçeneklerini kullanabilmeniz için sizi en iyi şekilde cevapladığından en iyi cevap olduğunu düşünüyorum. Aslında mikrosaniye istedim ve bunu yapabilen tek seçenek buydu!
trumpetlicks

Teşekkürler. Bu cevap mikrosaniye almak için kolay bir çözüm sağlar.
Yongwei Wu

337

Bu da işe yarar:

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

12
Teşekkürler: Bunlar için dokümanlar: docs.python.org/2/library/logging.html#logrecord-attributes docs.python.org/3/library/logging.html#logrecord-attributes .. Bir yolu var mı hala saat dilimi (% z) eklensin mi? ... Python günlüklerindeki ISO8601 biçim süreleri (, ->.) Çok iyi olurdu.
Wes Turner

19
Eğer varsa, çünkü bu çözüm, özürlü olduğu %zveya %ZGözlerinde farklı datefmtbunu daha önce değil, milisaniyeden SONRA görünmesini istiyorum.
wim

1
Ve ayrıca AMveya olan 12 saatlik bir saat kullanıyorsanızPM
DollarAkshay

1
@ önceki yorumumu takip etmek için wim (artık düzenleyemedi ...), işte yaptığım şey: 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 Zaman dilimini default_msec_format(Python 3.7'den itibaren) gömemezsiniz, çünkü sadece zaman ve milisaniyeler ikame edilir. loggingKaynaktan:self.default_msec_format % (t, record.msecs)
M. Dudley

27

Msecs eklemek daha iyi bir seçimdi, teşekkürler. İşte bunu Blender'daki Python 3.5.3 ile kullanıyorum

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
Şimdiye kadar en basit ve en temiz seçenek. Sadece logging.info (msg) vb. Çağırabildiğinizde neden kaydediciyi aldığınızdan emin değilim, ancak biçim tam olarak aradığım şeydi. Kullanılabilir tüm özellikleri arayan herkes buraya bakabilir: docs.python.org/3.6/library/logging.html#logrecord-attributes
naphier

Hmmm ilginç nokta, yorum için teşekkürler kesin düşünce besindir. Ya da muhtemelen orada neler olup bittiğine bir ders olarak ekledim ve orada olduğundan emin olmak için ve birden fazla şey sordum, çünkü onu almak için ebeveyne ('.') Birden fazla çağrıya gerek yok. .İnfo veya .debug'u tekrar çağırdıysanız, referans arama döngüsünü kaydetmenizi önerdiğim için bunları doğrudan tekrar kaydederim. [let info = logging.info]
Usta James

Jason dediğin için teşekkürler. Bazen dünyayı görmenin daha basit bir yolu vardır, herhangi bir durum olmasa da birçok insanda bu gerçeği keşfetmeye çalışmaktan korkmayın.
Usta James

15

Bulduğum en basit yol default_msec_format'ı geçersiz kılmaktı:

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

1
İlginç, teşekkürler. Ama bu benim için Python 2.7'de işe yaramadı. Python 3.x içinde yalnızca bazı x değerleri için çalışabilir.
nealmcb

1
@nealmcb Bu, dokümanlar
Mark

3

Bir örnek oluşturduktan sonra Formattergenellikle ayarladım formatter.converter = gmtime. Yani @ unutbu'nun cevabının bu durumda çalışması için ihtiyacınız olacak:

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

datetimeModül gerektirmeyen ve diğer bazı çözümler gibi özürlü olmayan basit bir genişleme, aşağıdaki gibi basit dize değiştirme kullanmaktır:

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

Bu şekilde, %Fmilisaniye boyunca bölge farklarına izin vermekle bile, istediğiniz şekilde bir tarih biçimi yazılabilir . Örneğin:

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

Ok kullanıyorsanız veya ok kullanmayı düşünmüyorsanız. Python'un zaman biçimlendirmesini ok yerine değiştirebilirsiniz.

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)

Şimdi tüm kullanabilirsiniz okunun zamanda biçimlendirme içinde datefmtözniteliği.


-1

tl; dr, burada ISO formatlı bir tarih arayanlar için:

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


-3

Şu andan itibaren aşağıdakiler python 3 ile mükemmel çalışır.

         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')

Aşağıdaki çıktıyı verir

2020/01/11 18: 51: 19.011 BILGI


1
Bu çalışmıyor. % d tarihi yazdırıyor. Örneğinizde tarih, önünde 0 yastıklı olacak şekilde yazdırılır.
Klik
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.