如何更改Python日志记录中的时区?

时间:2015-09-04 16:18:47

标签: python-2.7 audit-logging

我想更改日志文件中的时间戳,以便它反映我当前的时区,以便我可以更快的速度调试错误,

我可以更改日志文件中的时区吗?

目前我的配置是:

logging.basicConfig(filename='audit.log',
                filemode='w',
                level=logging.INFO,
                format='%(asctime)s %(message)s',
                datefmt='%m/%d/%Y %I:%M:%S %p')

7 个答案:

答案 0 :(得分:5)

#!/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 logging: How to set time to GMT)。
  • 通过取消注释结束行
  • 找到您最喜欢的TZ代码

答案 1 :(得分:5)

只需将此pythonic行添加到您的代码中(使用pytz和日期时间)即可:

from pytz import timezone
from datetime import datetime

logging.Formatter.converter = lambda *args: datetime.now(tz=timezone('tz string name')).timetuple()

# quoting Ryan J McCall: to find the string name for your desired timezone...
# print(pytz.all_timezones)
# or print(pytz.common_timezones)

答案 2 :(得分:3)

如何记录时区

来自strftime格式

%Z

Windows

>>> 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偏移时区,但是您必须为夏令时或其他偏移量实施规则,所以我建议使用pytz库,即使对于python 3也是如此。

例如,

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

如果我将时区应用于此日期时间对象,则时间不会发生变化(或将为< 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>

现在我们可以在我们希望的任何时区创建一个正确翻译的日期时间对象

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

啊哈!现在将其应用于日志记录模块。

带有时区的字符串表示的纪元时间戳

LogRecord created属性设置为从时间模块创建LogRecord(由time.time()返回)的时间。这将返回时间戳(seconds since the epoch)。你可以自己翻译到一个给定的时区,但我再次建议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/Denver代替America/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']

本地

如果你有这个问题和答案,寻找如何记录当地时区,那么不要硬编码时区,而是tzlocal(pip install tzlocal)并替换

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

        tzinfo = tzlocal.get_localzone()

现在它可以在运行脚本的任何服务器上运行,并在服务器上使用时区。

不记录UTC时的警告

我应该添加,根据应用程序,登录本地时区可能会产生两次模糊,其中2 AM被跳过或1 AM重复,可能还有其他。

答案 3 :(得分:2)

如果您想使用日志配置功能的替代解决方案:

import pytz
import logging
import logging.config
from datetime import datetime

tz = pytz.timezone('Asia/Tokyo')

class TokyoFormatter(logging.Formatter):
    converter = lambda *args: datetime.now(tz).timetuple()

LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'formatters': {
        'Tokyo': {
            '()': TokyoFormatter,
            'format': '%(asctime)s %(levelname)s: %(message)s',
            'datefmt': '%Y-%m-%d %H:%M:%S'
        },
    },
    'handlers': {
        'console': {
            'class': 'logging.StreamHandler',
            'formatter': 'Tokyo'
        },
    },
    'loggers': {
        'foo': {
            'handlers': ['console'],
            'level': 'INFO'
        },
    }
}

logging.config.dictConfig(LOGGING)
logger = logging.getLogger('foo')
logger.info('Just a test.')

定义日志格式化程序,例如“TokyoFormatter”。它有一个属性“转换器”,完成转换时区的工作。 详情请参阅Customizing handlers with dictConfig()

答案 4 :(得分:0)

如果您知道自己的utc 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/

答案 5 :(得分:0)

require('rootpath')()
const db = require('helpers/db.ts')
const mongoose = require('mongoose')
const multer = require('multer')
const GridFsStorage = require('multer-gridfs-storage')
const Grid = require('gridfs-stream')
const myCrypto = require('crypto')
const path = require('path')



var gfs = Grid(mongoose.connection, mongoose.mongo);  
gfs.collection('uploads');


var storage = new GridFsStorage({
    //url: mongoose.connection.client.s.url,
    //options: options,
    db: mongoose.connection,
    file: (req, file) => {
      return new Promise((resolve, reject) => {
        myCrypto.randomBytes(16, (err, buf) => {
          if (err) {
            return reject(err);
          }
          const filename = buf.toString('hex') + path.extname(file.originalname);
          const fileInfo = {
            filename: filename,
            bucketName: 'uploads'
          };
          resolve(fileInfo);
        });
      });
    }
  });
  const upload = multer({ storage });

  module.exports = {
      upload
  }

使用pytz定义相对于UTC的时区。
基于以下示例:secsilm

答案 6 :(得分:-2)

import logging, time
from datetime import datetime, timedelta
logger = logging.getLogger(__name__)
converter = lambda x, y: (datetime.utcnow() - timedelta(
    hours=7 if time.localtime().tm_isdst else 6)
).timetuple()
logging.Formatter.converter = converter

编辑为Elias指出原始答案未检查DST。

相关问题