web-dev-qa-db-ja.com

Pythonロギングでタイムゾーンを変更する方法は?

現在のタイムゾーンを反映するようにログファイルのタイムスタンプを変更して、エラーをより高速でデバッグできるようにしたいのですが、

ログファイルのタイムゾーンを変更することはできますか?

現在私の設定は:

logging.basicConfig(filename='audit.log',
                filemode='w',
                level=logging.INFO,
                format='%(asctime)s %(message)s',
                datefmt='%m/%d/%Y %I:%M:%S %p')
15
25mhz
#!/usr/bin/env python
from datetime import datetime
import logging
import time

from pytz import timezone, utc


def main():
    logging.basicConfig(format="%(asctime)s %(message)s",
                        datefmt="%Y-%m-%d %H:%M:%S")
    logger = logging.getLogger(__name__)
    logger.error("default")

    logging.Formatter.converter = time.localtime
    logger.error("localtime")

    logging.Formatter.converter = time.gmtime
    logger.error("gmtime")

    def customTime(*args):
        utc_dt = utc.localize(datetime.utcnow())
        my_tz = timezone("US/Eastern")
        converted = utc_dt.astimezone(my_tz)
        return converted.timetuple()

    logging.Formatter.converter = customTime
    logger.error("customTime")

    # to find the string code for your desired tz...
    # print(pytz.all_timezones)
    # print(pytz.common_timezones)


if __name__ == "__main__":
    main()
  • 一見すると、pytzパッケージは、Pythonでタイムゾーンを変換するための祝福された方法です。 datetimeから始めて、変換し、(不変)time_Tupleを取得して、timeメソッドの戻り値の型に一致させます
  • この回答では、logging.Formatter.converter関数の設定が推奨されています:( Pythonロギング:時間をGMTに設定する方法 )。
  • 最終行のコメントを外して、お気に入りのTZコードを見つけます
7
Ryan J McCall

タイムゾーンを記録する方法

%Z from strftime 形式

ウィンドウズ

>>> import logging
>>> logging.basicConfig(format="%(asctime)s %(message)s", datefmt="%m/%d/%Y %I:%M:%S %p %Z")
>>> logging.error('test')
11/03/2017 02:29:54 PM Mountain Daylight Time test

Linux

>>> import logging
>>> logging.basicConfig(format="%(asctime)s %(message)s", datefmt="%m/%d/%Y %I:%M:%S %p %Z")
>>> logging.error('test')
11/03/2017 02:30:50 PM MDT test

質問が

サーバーの現地時間とは異なるタイムゾーンにログインするにはどうすればよいですか?

答えの一部は logging.Formatter.converter ですが、素朴で意識的な datetime オブジェクトを理解する必要があります。独自のタイムゾーンモジュールを作成する場合を除き、 pytz ライブラリ(pip install pytz)を強くお勧めします。 Python 3にはUTCとUTCオフセットのタイムゾーンが含まれていますが、夏時間やその他のオフセットのために実装する必要のあるルールがあるため、python 3。

例えば、

>>> import datetime
>>> utc_now = datetime.datetime.utcnow()
>>> utc_now.isoformat()
'2019-05-21T02:30:09.422638'
>>> utc_now.tzinfo
(None)

このdatetimeオブジェクトにタイムゾーンを適用しても、時間は変更されません(または<python 3.7ish)に対してValueErrorが発行されます)。

>>> mst_now = utc_now.astimezone(pytz.timezone('America/Denver'))
>>> mst_now.isoformat()
'2019-05-21T02:30:09.422638-06:00'
>>> utc_now.isoformat()
'2019-05-21T02:30:09.422638'

ただし、代わりに

>>> import pytz
>>> utc_now = datetime.datetime.now(tz=pytz.timezone('UTC'))
>>> utc_now.tzinfo
<UTC>

これで、適切に翻訳されたdatetimeオブジェクトを任意のタイムゾーンで作成できます

>>> mst_now = utc_now.astimezone(pytz.timezone('America/Denver'))
>>> mst_now.isoformat()
'2019-05-20T20:31:44.913939-06:00'

ああ!これをロギングモジュールに適用します。

タイムゾーン付きの文字列表現へのエポックタイムスタンプ

LogRecordの作成属性は、TimeモジュールからLogRecordが作成された時刻( time.time() によって返される)に設定されます。これはタイムスタンプ( エポックからの秒数 )を返します。あなたは与えられたタイムゾーンにあなた自身の翻訳をすることができますが、コンバーターをオーバーライドすることによって、私はpytzを提案します。

import datetime
import logging
import pytz

class Formatter(logging.Formatter):
    """override logging.Formatter to use an aware datetime object"""
    def converter(self, timestamp):
        dt = datetime.datetime.fromtimestamp(timestamp)
        tzinfo = pytz.timezone('America/Denver')
        return tzinfo.localize(dt)

    def formatTime(self, record, datefmt=None):
        dt = self.converter(record.created)
        if datefmt:
            s = dt.strftime(datefmt)
        else:
            try:
                s = dt.isoformat(timespec='milliseconds')
            except TypeError:
                s = dt.isoformat()
        return s

Python 3.5、2.7

>>> logger = logging.root
>>> handler = logging.StreamHandler()
>>> handler.setFormatter(Formatter("%(asctime)s %(message)s"))
>>> logger.addHandler(handler)
>>> logger.setLevel(logging.DEBUG)
>>> logger.debug('test')
2019-05-20T22:25:10.758782-06:00 test

Python 3.7

>>> logger = logging.root
>>> handler = logging.StreamHandler()
>>> handler.setFormatter(Formatter("%(asctime)s %(message)s"))
>>> logger.addHandler(handler)
>>> logger.setLevel(logging.DEBUG)
>>> logger.debug('test')
2019-05-20T22:29:21.678-06:00 test

代替America/DenverAmerica/Anchorageは、pytzで定義されたposixタイムゾーン

>>> next(_ for _ in pytz.common_timezones if 'Alaska' in _)
'US/Alaska'

US/Alaska is deprecated

>>> [_ for _ in pytz.all_timezones if 'Anchorage' in _]
['America/Anchorage']

地元

この質問に答えてローカルタイムゾーンをログに記録する方法を探している場合は、タイムゾーンをハードコーディングする代わりに、 tzlocalpip install tzlocal)と置換

        tzinfo = pytz.timezone('America/Denver')

        tzinfo = tzlocal.get_localzone()

これで、サーバーのタイムゾーンを使用して、スクリプトを実行するすべてのサーバーで機能します。

UTCを記録しない場合の注意

アプリケーションに応じて、ローカルタイムゾーンにログインすると、年に2回あいまいさが発生する可能性があります。この場合、午前2時がスキップされるか、午前1時が繰り返されます。

5
Wyrmwood

tc offset がわかっている場合は、時間を修正する関数を定義して、それを_logging.Formatter.converter_に渡すことができます。

たとえば、時刻をUTC + 8タイムゾーンに変換する場合は、次のようにします。

_import logging
import datetime


def beijing(sec, what):
    '''sec and what is unused.'''
    beijing_time = datetime.datetime.now() + datetime.timedelta(hours=8)
    return beijing_time.timetuple()


logging.Formatter.converter = beijing

logging.basicConfig(
    format="%(asctime)s %(levelname)s: %(message)s",
    level=logging.INFO,
    datefmt="%Y-%m-%d %H:%M:%S",
)
_

状況に応じてdatetime.timedelta(hours=8)で時間を変更するだけです。

リファレンス: https://alanlee.fun/2019/01/06/how-to-change-logging-date-timezone/

0
secsilm