การบันทึก 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 นี้ซึ่งพูดถึง microseconds แต่ a) ฉันต้องการมิลลิวินาทีและ b) สิ่งต่อไปนี้ใช้ไม่ได้กับ Python 2.6 (ซึ่งฉันใช้งานอยู่) เนื่องจาก%f:

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

1
การเปลี่ยนสถานที่อาจช่วยได้บ้าง
pajton

1
@ pajton - ในลิงค์ต่อไปนี้ระบุว่า "ไม่มีข้อมูล locale โดย asctime ()" - docs.python.org/library/time.html#time.asctime
Jonathan

%fไม่ทำงานบน python 2.7.9 หรือ 3.5.1 เช่นกัน
Antony Hatchkins

4
การสนทนาที่ดีที่นี่ ฉันมาที่นี่เพราะloggingอ้างว่ารูปแบบเวลาเริ่มต้นของมันเป็นไปตาม ISO 8601 มันไม่ได้ มันใช้ช่องว่างไม่ใช่ "T" เพื่อแยกเวลาและเครื่องหมายจุลภาคเป็นวินาทีเศษส่วนไม่ใช่ทศนิยม พวกเขาจะผิดอย่างไรได้อย่างไร?
LS

คำตอบ:


76

โปรดทราบว่าทางออกของ Craig McDanielนั้นดีกว่ามาก


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"ขอให้สังเกตเครื่องหมายจุลภาคใน สิ่งนี้ไม่สามารถแก้ไขได้โดยการระบุdatefmtเพราะctเป็น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
ฉันคิดว่านี่เป็นคำตอบที่ดีที่สุดเนื่องจากคุณสามารถใช้รูปแบบมาตรฐานได้ ฉันต้องการไมโครวินาทีและนี่เป็นตัวเลือกเดียวที่ทำได้!
trumpetlicks

ขอบคุณ คำตอบนี้ให้ทางออกง่าย ๆ ในการรับไมโครวินาที
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 (, ->.) น่าจะดี
Wes Turner

19
วิธีการแก้ปัญหานี้เป็นคนพิการเพราะถ้าคุณมี%zหรือ%Zในที่datefmtคุณต้องการที่จะปรากฏหลังจากที่ msecs ไม่ก่อน
Wim

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

1
@ Mark คุณไม่สามารถฝังเขตเวลาdefault_msec_formatเป็น (ใน Python 3.7) เนื่องจากมีการแทนที่เวลาและมิลลิวินาทีจากloggingแหล่งที่มา:self.default_msec_format % (t, record.msecs)
M. Dudley

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

Hmmm จุดที่น่าสนใจขอบคุณสำหรับความคิดเห็นมันเป็นอาหารสำหรับความคิดอย่างแน่นอน ใช่ฉันแค่เพิ่มมันเป็นบทเรียนในสิ่งที่เกิดขึ้นที่นั่นและเพื่อให้แน่ใจว่ามันอยู่ที่นั่นและเพราะฉันถามหลายสิ่งหลายอย่างดังนั้นจึงไม่จำเป็นต้องมีการโทรไปยังผู้ปกครองหลายคน (ผ่าน '.') เพื่อดึงข้อมูล หากคุณเรียกว่า. info หรือ. debug อีกครั้งฉันอาจจะบันทึกสิ่งเหล่านั้นอีกครั้งโดยตรงตามที่คุณแนะนำให้บันทึกรอบการค้นหาอ้างอิง [let info = logging.info]
มาสเตอร์เจมส์

ขอบคุณที่พูด Jason บางครั้งมีวิธีที่ง่ายกว่าในการมองโลกไม่ต้องกลัวที่จะลองและค้นพบความจริงนั้นในหลาย ๆ กรณีหากไม่มีสถานการณ์ใด ๆ
อาจารย์เจมส์

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 ต่อเอกสาร
Mark

3

หลังจาก instantiating ฉันมักจะตั้ง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 เบาะด้านหน้าของมัน
Klik
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.