Ghi nhật ký Python: sử dụng mili giây ở định dạng thời gian


163

Theo mặc định logging.Formatter('%(asctime)s')in với định dạng sau:

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

trong đó 638 là mili giây. Tôi cần thay đổi dấu phẩy thành dấu chấm:

2011-06-09 10:54:40.638

Để định dạng thời gian tôi có thể sử dụng:

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

tuy nhiên tài liệu không chỉ định cách định dạng mili giây. Tôi đã tìm thấy câu hỏi SO này nói về micro giây, nhưng a) Tôi thích mili giây và b) sau đây không hoạt động trên Python 2.6 (mà tôi đang làm việc) do %f:

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

1
Có lẽ thay đổi địa phương có thể giúp đỡ?
pyjama

1
@ Pajton - trong đường dẫn sau nó nói "thông tin Locale không được sử dụng bởi asctime ()" - docs.python.org/library/time.html#time.asctime
Jonathan

%fcũng không hoạt động trên python 2.7.9 hoặc 3.5.1
Antony Hatchkins

4
Cuộc trò chuyện tốt ở đây. Tôi đến đây vì loggingtuyên bố định dạng thời gian mặc định của nó tuân theo ISO 8601. Không. Nó sử dụng không gian, không phải "T" để phân tách thời gian và dấu phẩy cho các giây phân số, không phải dấu thập phân. Làm thế nào họ có thể sai như vậy?
LS

Câu trả lời:


76

Xin lưu ý giải pháp của Craig McDaniel rõ ràng là tốt hơn.


formatTimePhương thức của log.Formatter trông như thế này:

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

Chú ý dấu phẩy trong "%s,%03d". Điều này không thể được sửa bằng cách chỉ định a datefmtbởi vì cta time.struct_timevà các đối tượng này không ghi lại mili giây.

Nếu chúng ta thay đổi định nghĩa ctđể biến nó thành một datetimeđối tượng thay vì a struct_time, thì (ít nhất là với các phiên bản hiện đại của Python), chúng ta có thể gọi ct.strftimevà sau đó chúng ta có thể sử dụng %fđể định dạng micro giây:

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.

Hoặc, để có được mili giây, thay đổi dấu phẩy thành dấu thập phân và bỏ qua datefmtđối số:

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
vậy% f thực sự sẽ cho micro giây, chứ không phải mili giây, phải không?
Jonathan

@Jonathan: Rất tiếc, bạn đã đúng, %fcho micro giây. Tôi cho rằng cách dễ nhất để có được mili giây là thay đổi dấu phẩy thành dấu thập phân (xem chỉnh sửa ở trên).
unutbu

3
Tôi thực sự nghĩ rằng đây là câu trả lời tốt nhất do thực tế là nó giúp bạn quay lại ngay để có thể sử dụng các tùy chọn định dạng STANDARD. Tôi thực sự muốn micro giây, và đây là lựa chọn duy nhất có thể làm điều đó!
kèn

Cảm ơn. Câu trả lời này đưa ra một giải pháp dễ dàng để có được micro giây.
Yongwei Wu

336

Điều này cũng nên làm việc:

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

12
Thanks: Dưới đây là các tài liệu cho các: docs.python.org/2/library/logging.html#logrecord-attributes docs.python.org/3/library/logging.html#logrecord-attributes .. Có một cách để vẫn bao gồm múi giờ (% z)? ... Thời gian định dạng ISO8601 trong nhật ký Python (, ->.) Sẽ rất tuyệt.
Wes Turner

19
Giải pháp này bị vô hiệu hóa, bởi vì nếu bạn có %zhoặc %Ztrong datefmtbạn muốn điều đó xuất hiện SAU các msec, không phải trước đó.
wim

1
Và nếu bạn đang sử dụng đồng hồ 12 giờ có AMhoặcPM
DollarAkshay

1
@wim như một cách theo dõi nhận xét trước đây của tôi (không thể chỉnh sửa nữa ...), đây là những gì tôi đã thực hiện: 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)
Đánh dấu

1
@Mark Bạn không thể nhúng múi giờ vào default_msec_format(kể từ Python 3.7) vì chỉ có thời gian và mili giây được thay thế. Từ loggingnguồn:self.default_msec_format % (t, record.msecs)
M. Dudley

27

Thêm msecs là lựa chọn tốt hơn, Cảm ơn. Đây là sửa đổi của tôi bằng cách sử dụng điều này với Python 3.5.3 trong 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
Cho đến nay các tùy chọn đơn giản và sạch sẽ nhất. Không chắc chắn lý do tại sao bạn nhận được logger khi bạn chỉ có thể gọi log.info (tin nhắn), v.v., nhưng định dạng chính xác là những gì tôi đang tìm kiếm. Bất cứ ai khác tìm kiếm tất cả các thuộc tính có thể sử dụng có thể xem ở đây: docs.python.org/3.6/library/logging.html#logrecord-attributes
naphier

Hmmm điểm thú vị, cảm ơn vì nhận xét đó là thực phẩm cho suy nghĩ chắc chắn. Tôi có lẽ chỉ cần thêm nó như một bài học về những gì đang diễn ra ở đó, và để chắc chắn rằng nó ở đó và vì tôi đã hỏi nhiều thứ nên nó không cần nhiều cuộc gọi đến phụ huynh (thông qua '.') Để lấy nó. Nếu bạn gọi .info hoặc .debug một lần nữa, tôi có thể lưu lại chúng trực tiếp khi bạn đề xuất để lưu chu trình tra cứu tham chiếu. [hãy để thông tin = log.info]
Master James

Cảm ơn vì đã nói Jason. Đôi khi có một cách đơn giản hơn để nhìn thế giới, đừng ngại thử và khám phá sự thật đó trong nhiều trường hợp nếu không phải là bất kỳ / mọi tình huống.
Master James

15

Cách đơn giản nhất mà tôi tìm thấy là ghi đè default_msec_format:

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

1
Thú vị, cảm ơn. Nhưng điều này không làm việc cho tôi trong Python 2.7. Nó chỉ có thể hoạt động trong Python 3.x với một số giá trị của x.
nealmcb

1
@nealmcb điều này không khả dụng cho đến khi Python 3.3 trên mỗi tài liệu
Đánh dấu

3

Sau khi bắt đầu, Formattertôi thường đặt formatter.converter = gmtime. Vì vậy, để câu trả lời của @ unutbu hoạt động trong trường hợp này, bạn sẽ cần:

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

Một mở rộng đơn giản không yêu cầu datetimemô-đun và không bị khuyết tật như một số giải pháp khác là sử dụng thay thế chuỗi đơn giản như vậy:

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

Bằng cách này, một định dạng ngày có thể được viết theo bất kỳ cách nào bạn muốn, thậm chí cho phép có sự khác biệt theo vùng, bằng cách sử dụng %Ftrong một phần nghìn giây. Ví dụ:

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

Nếu bạn đang sử dụng mũi tên hoặc nếu bạn không phiền khi sử dụng mũi tên. Bạn có thể thay thế định dạng thời gian của python cho một mũi tên.

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)

Bây giờ bạn có thể sử dụng tất cả các định dạng thời gian của mũi tên trong datefmtthuộc tính.


-1

tl; dr cho mọi người đang tìm kiếm ngày định dạng ISO:

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


-3

Cho đến bây giờ các hoạt động sau đây hoàn hảo với 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')

đưa ra đầu ra sau

2020/01/11 18: 51: 19.011 THÔNG TIN


1
Điều này không hoạt động. % d đang in ngày. Trong ví dụ của bạn, ngày được in bằng 0 ở phía trước.
Klik
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.