Реєстрація Python: використання мілісекунд у форматі часу


163

За замовчуванням logging.Formatter('%(asctime)s')друкується у такому форматі:

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

де 638 - мілісекунда. Мені потрібно змінити кому на крапку:

2011-06-09 10:54:40.638

Для форматування часу, який я можу використовувати:

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

однак документація не вказує, як форматувати мілісекунди. Я знайшов це питання SO, який говорить про мікросекунди, але а) я вважаю за краще мілісекунди; б) наступне не працює на Python 2.6 (над яким я працюю) через %f:

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

1
Можливо, зміна локалі може допомогти?
pajton

1
@ pajton - у наступному посиланні написано: "Інформація про локаль не використовується asctime ()" - docs.python.org/library/time.html#time.asctime
Джонатан

%fтакож не працює на python 2.7.9 або 3.5.1
Antony Hatchkins

4
Гарна розмова тут. Я прийшов сюди, оскільки loggingстверджує, що його формат часу за замовчуванням відповідає ISO 8601. Це не так. Він використовує простір, а не "T" для розділення часу і коми через дробові секунди, а не десяткову точку. Як вони могли так помилитися?
LS

Відповіді:


76

Зверніть увагу , що рішення Крейга Макданіеля явно краще.


Метод Форматера formatTimeвиглядає так:

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

Зауважте кома в "%s,%03d". Це неможливо виправити, вказавши a, datefmtоскільки ctце a, time.struct_timeі ці об'єкти не записують мілісекунд.

Якщо ми змінимо визначення, ctщоб зробити його datetimeоб'єктом замість a struct_time, то (принаймні, із сучасними версіями Python) ми можемо викликати, ct.strftimeа потім можемо використовувати %fдля форматування мікросекунд:

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.

Або, щоб отримати мілісекунди, змініть кому на десяткову точку та опустіть 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.

1
так що% f насправді дасть мікросекунди, а не мілісекунди, правда?
Джонатан

@Jonathan: ой, ти прав, %fдає мікросекунди. Я припускаю, що найпростіший спосіб отримати мілісекунди - це зміни коми через десяткову точку (див. Редагування вище).
unutbu

3
Насправді я вважаю, що це найкраща відповідь через те, що вона повертає вас до того, що ви можете використовувати параметри форматування STANDARD. Я насправді хотів мікросекунд, і це був єдиний варіант, який міг це зробити!
сурми

Дякую. Ця відповідь дає просте рішення отримати мікросекунди.
Yongwei Wu

337

Це також має працювати:

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

12
Дякуємо: Ось документи для таких: docs.python.org/2/library/logging.html#logrecord-attributes docs.python.org/3/library/logging.html#logrecord-attributes .. Чи є спосіб все ще включають часовий пояс (% z)? ... Часи формату ISO8601 в журналах Python (, ->.) Були б чудовими.
Уес Тернер

19
Це рішення гальмувалося, бо якщо у вас є %zабо %Zв ваших datefmtви хочете, щоб з'явитися після мілісекунд, а не раніше.
Вім

1
А також якщо ви використовуєте 12-годинний годинник, який має AMабоPM
DollarAkshay

1
@wim як продовження мого попереднього коментаря (не можу більше редагувати ...), ось що я зробив: 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)
Марк

1
@Mark Ви не можете вбудувати часовий пояс у default_msec_format(на Python 3.7), тому що замінено лише час і мілісекунди. loggingДжерело:self.default_msec_format % (t, record.msecs)
М. Дадлі

27

Додавання msecs було кращим варіантом, спасибі. Ось моя поправка, використовуючи цю програму з Python 3.5.3 в 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
На сьогоднішній день найпростіший і чистий варіант. Не впевнений, чому ви отримуєте реєстратор, коли ви можете просто зателефонувати на logging.info (msg) тощо, але формат саме такий, який я шукав. Усі, хто шукає усі корисні атрибути, можуть подивитися тут: docs.python.org/3.6/library/logging.html#logrecord-attributes
naphier

Хммм цікавий момент, дякую за коментар - це їжа для думки точно. Я, ймовірно, я просто додав це як урок того, що там теж відбувається, і щоб переконатися, що він є, і тому, що я запитав кілька речей, щоб йому не потрібно було багато дзвінків до батьків (через '.'), Щоб отримати його. Якщо ви зателефонували .info або .debug ще раз, я, можливо, збережу їх безпосередньо знову, як ви пропонуєте зберегти цикл пошуку посилань. [нехай info = logging.info]
Майстер Джеймс

Дякую за те, що сказав Джейсон. Іноді існує простіший спосіб побачити світ, не бійтеся намагатися відкрити цю правду в багатьох, якщо не в будь-якій ситуації.
Майстер Джеймс

15

Найпростіший спосіб, який я знайшов - це перекрити default_msec_format:

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

1
Цікаво, дякую. Але це не спрацювало для мене в Python 2.7. Він може працювати лише в Python 3.x для деякого значення x.
nealmcb

1
@nealmcb це недоступно, поки Python 3.3 за документи
Марк

3

Після екземпляра Formatterя зазвичай встановлюю formatter.converter = gmtime. Отже, щоб відповідь @ unutbu спрацювала в цьому випадку, вам знадобиться:

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

Просте розширення, яке не вимагає datetimeмодуля і не має інвалідності, як деякі інші рішення, полягає у використанні простої заміни рядків, наприклад:

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

Таким чином можна записати формат дати, проте ви хочете, навіть враховуючи різниці регіонів, використовуючи %Fпротягом мілісекунд. Наприклад:

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

Якщо ви використовуєте стрілку або якщо ви не проти використовувати стрілку. Ви можете замінити формат часу пітона на формат стрілки.

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)

Тепер ви можете використовувати все формат часу стрілки в datefmtатрибуті.



-3

На сьогоднішній день наступне чудово працює з 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')

дає наступний вихід

2020/01/11 18: 51: 19.011 ІНФОРМАЦІЯ


1
Це не працює. % d друкує дату. У вашому прикладі дата друкується із 0, накладеним перед нею.
Клік
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.