最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

說一說Python logging

 更新時間:2016年04月15日 08:49:40   作者:正_午  
這篇文章主要和大家聊一聊Python logging,Python logging是什么,Python logging的作用是什么,感興趣的小伙伴們可以參考一下

最近有個需求是把以前字符串輸出的log 改為json 格式,看了別人的例子,還是有些比較茫然,索性就把logging 整個翻了一邊,做點(diǎn)小總結(jié).

初看log

在程序中, log 的用處寫代碼的你用你知道,log 有等級,DEBUG, INFO,...之類,還會記錄時間,log 發(fā)生的位置,在Python 中用的多的就是logging 這個標(biāo)準(zhǔn)庫中的包了.當(dāng)打log 的時候究竟發(fā)生了什么? 是如何把不同級別的log 輸出到不同文件里,還能在控制臺輸出.......

最簡單的用法

import logging
logging.basicConfig(format='%(levelname)s:%(message)s', level=logging.DEBUG)
logging.debug('This message should go to the log file')
logging.info('So should this')
logging.warning('And this, too')
1,第一行導(dǎo)入包 2,第二行利用basicConfig 對輸出的格式,和輸出級別做了限制 3, 后面分別輸出了三條不同級別的 log

Logging Levels

共有幾個等級, 每個等級對應(yīng)一個Int 型整數(shù) ,每個等級都會有一個方法與之對應(yīng),這樣輸出的內(nèi)容就有了不同的等級.

logger 流程,

整個過程,還是不是很詳細(xì),貼個圖吧, 現(xiàn)在看還太早,也說不清真?zhèn)€過程到底發(fā)生了什么,先放著,回頭來看會比較好懂. loger flow

讀代碼

代碼結(jié)構(gòu)

logging 在源碼中有三個文件,結(jié)構(gòu)如下:

├── config.py
├── handlers.py
└── __init__.py
_int.py中實(shí)現(xiàn)了基礎(chǔ)功能,主要的邏輯就在這個文件中 handlers.py 是一些Handlers (用處后面會明白)用起來很方便的. config.py 是對配置做處理的方法.

objects

LogRecord Objects

每一次log 都會實(shí)例化一個Record 對象,這個對象有很多屬性,最后對LogRecord 做一下format 就輸出了,格式化的log ,里面就基本就是這個對象的屬性了。

class LogRecord(object):
  def __init__(self, name, level, pathname, lineno,
         msg, args, exc_info, func=None):
    ct = time.time()
    self.name = name
    self.msg = msg
    if (args and len(args) == 1 and isinstance(args[0], collections.Mapping)
      and args[0]):
      args = args[0]
    self.args = args
    self.levelname = getLevelName(level)
    self.levelno = level
    self.pathname = pathname
    try:
      self.filename = os.path.basename(pathname)
      self.module = os.path.splitext(self.filename)[0]
    except (TypeError, ValueError, AttributeError):
      self.filename = pathname
      self.module = "Unknown module"
    self.exc_info = exc_info
    self.exc_text = None   # used to cache the traceback text
    self.lineno = lineno
    self.funcName = func
    self.created = ct
    self.msecs = (ct - long(ct)) * 1000
    self.relativeCreated = (self.created - _startTime) * 1000
    if logThreads and thread:
      self.thread = thread.get_ident()
      self.threadName = threading.current_thread().name
    else:
      self.thread = None
      self.threadName = None
    if not logMultiprocessing:
      self.processName = None
    else:
      self.processName = 'MainProcess'
      mp = sys.modules.get('multiprocessing')
      if mp is not None:
        try:
          self.processName = mp.current_process().name
        except StandardError:
          pass
    if logProcesses and hasattr(os, 'getpid'):
      self.process = os.getpid()
    else:
      self.process = None

  def __str__(self):
    return '<LogRecord: %s, %s, %s, %s, "%s">'%(self.name, self.levelno,
      self.pathname, self.lineno, self.msg)

  def getMessage(self):
     pass

看代碼就發(fā)現(xiàn), 這個類沒做什么事情,就是一個model 而已, 有一個得到msg 的方法

Formatter Objects

Formatter 就是對Record 專門格式化的對象,它有一個format 方法,我們實(shí)現(xiàn)這個方法就能 做到不同的輸出,我的需求是做json 格式的log 其實(shí)關(guān)鍵就在寫一個Formatter 就好了

class Formatter(object):
  converter = time.localtime

  def __init__(self, fmt=None, datefmt=None):
    if fmt:
      self._fmt = fmt
    else:
      self._fmt = "%(message)s"
    self.datefmt = datefmt

  def formatTime(self, record, datefmt=None):
    pass


  def formatException(self, ei):
    pass

  def usesTime(self):
    return self._fmt.find("%(asctime)") >= 0

  def format(self, record):
    pass

刪掉源代碼中的實(shí)現(xiàn)細(xì)節(jié),這個類里面主要的是format 方法,這是默認(rèn)最基本的Formater ,還有專門對exception ,時間做格式化的方法。具體是哪個,看方法名就很清楚了,具體每個方法怎么實(shí)現(xiàn)的,一眼也就懂了。fmt 是制定格式化的,具體怎么指定在最基礎(chǔ)的用法中就有例子,datefmt 是對時間格式的指定。

Filter Objects

這個類是Logger 和Handler 的基類,主要有一個Filter 方法,和一個filters 屬性

Handler Objects

叫Handler 的類還真的不少,在SocketServer 中也有看到,具體的功能都在Handler 中.在這里,組合所有的Formatter ,和控制log 的輸出的方向,繼承自Filter.

 def __init__(self, level=NOTSET):
    Filterer.__init__(self)
    self._name = None
    self.level = _checkLevel(level)
    self.formatter = None
    _addHandlerRef(self)
    self.createLock()

在init方法中看到,Handler 也有一個屬性,通過把自身的屬性和LogRecord 的level對比來決定是否處理這個LogRecord 的。每個Handler 都有一個Formatter 屬性,其實(shí)就是上面介紹的Formatter 。Handler 就是來控制LogRecord 和Formatter 的,它還可以控制輸出的方式,在后面會有,StreamHandler,FileHandler等。通過名稱也就能明白具體能干什么,這就是編程取名的智慧。

Logger Objects

這個類通常會通過getLogger()或者getLogger(name)來得到,不會直接new 一個出來.它會有info(msg, *args, kwargs) ,warn(msg, args, *kwargs)等方法,

  def __init__(self, name, level=NOTSET):
    Filterer.__init__(self)
    self.name = name
    self.level = _checkLevel(level)
    self.parent = Noneou
    self.handlers = []
    self.disabled = 0

從init方法中能看到handlers 屬性,這是一個list ,每個LogRecord 通過Handlers 不同的handlers 就能以不同的格式輸出到不同的地方了。每個Logger 可以通過addHandler(hdlr)方法來添加各種Handler, 知道這些你就基本可以隨意定制化了 下面就是我實(shí)現(xiàn)的json 格式的Formater,支持控制臺顏色變化,當(dāng)然前提是你的控制終端支持(Ubuntu14.04測試通過)

import re
import logging
import socket
import json
import traceback
import datetime
import time

try:
  from collections import OrderedDict
except ImportError:
  pass


RESERVED_ATTRS = (
  'args', 'asctime', 'created', 'exc_info', 'exc_text', 'filename',
  'funcName', 'levelname', 'levelno', 'lineno', 'module',
  'msecs', 'message', 'msg', 'name', 'pathname', 'process',
  'processName', 'relativeCreated', 'stack_info', 'thread', 'threadName')


RESERVED_ATTR_HASH = dict(zip(RESERVED_ATTRS, RESERVED_ATTRS))

COLORS ={
  'HEADER' : '\033[95m',
  'INFO' : '\033[94m',
  'DEBUG' : '\033[92m',
  'WARNING' : '\033[93m',
  'ERROR' : '\033[91m',
  'ENDC' : '\033[0m',
}

def merge_record_extra(record, target, reserved=RESERVED_ATTR_HASH):
  for key, value in record.__dict__.items():
    if (key not in reserved
      and not (hasattr(key, "startswith")
           and key.startswith('_'))):
      target[key] = value
  return target

def get_host_info():
  host_name = ''
  local_ip = ''
  try:
    host_name = socket.gethostname()
    local_ip = socket.gethostbyname(host_name)
  except Exception, e:
    pass

  return host_name, local_ip

class JsonFormatterBase(logging.Formatter):

  def __init__(self, *args, **kwargs):

    logging.Formatter.__init__(self, *args, **kwargs)
    self._required_fields = self.parse()
    self._skip_fields = dict(zip(self._required_fields,self._required_fields))
    self._skip_fields.update(RESERVED_ATTR_HASH)
  def parse(self):
    standard_formatters = re.compile(r'\((.+?)\)', re.IGNORECASE)
    return standard_formatters.findall(self._fmt)


  def add_fields(self, record ):
    log_record = {}

    for field in self._required_fields:
      log_record[field] = record.__dict__.get(field)

    host_name , local_ip = get_host_info()

    log_record[u'@hostName'] = host_name
    log_record[u'@localIp'] = local_ip
    return log_record

    #merge_record_extra(record, log_record, reserved=self._skip_fields)


  def process_log_record(self, log_record):
    """
    Override this method to implement custom logic
    on the possibly ordered dictionary.
    """

    try:
      new_record = OrderedDict()
    except Exception, e:
      return log_record

    key_list = [
      'asctime',
      'levelname',
      '@hostName',
      '@localIp',
      'threadName',
      'thread',
      'name',
      'pathname',
      'lineno',
      'message',
    ]
    for k in key_list:
      new_record[k] = log_record.get(k)
    new_record.update(log_record)
    return new_record

  def jsonify_log_record(self, log_record):
    """Returns a json string of the log record."""

    return json.dumps(log_record, ensure_ascii=False)


  def format_col(self, message_str, level_name):
    """

    是否需要顏色
    """
    return message_str

  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

  def format(self, record):


    if isinstance(record.msg, dict):
      record.message = record.msg

    elif isinstance(record.msg, list) or isinstance(record.msg, tuple):
      record.message = record.msg

    elif isinstance(record.msg, basestring):
      record.message = record.getMessage().split('\n')

    elif isinstance(record.msg, Exception):
      record.message = traceback.format_exc(record.msg).split('\n')

    else :
      record.message = repr(record.msg)

    if "asctime" in self._required_fields:
      record.asctime = self.formatTime(record, self.datefmt)

    #
    # if record.exc_info and not message_dict.get('exc_info'):
    #   message_dict['message'] = traceback.format_exception(*record.exc_info)
    log_record = self.add_fields(record)
    log_record = self.process_log_record(log_record)
    message_str = self.jsonify_log_record(log_record)
    message_str = self.format_col(message_str, level_name=record.levelname)
    return message_str



class ConsoleFormater(JsonFormatterBase):

  def __init__(self, *args, **kwargs):
    JsonFormatterBase.__init__(self, *args, **kwargs)

  def format_col(self, message_str, level_name):
    if level_name in COLORS.keys():
      message_str = COLORS.get(level_name) + message_str + COLORS.get('ENDC')
    return message_str

  def jsonify_log_record(self, log_record):
    return json.dumps(log_record, ensure_ascii=False, indent=4)


class JsonFileFormater(JsonFormatterBase):

  def __init__(self, *args, **kewars):
    JsonFormatterBase.__init__(self, *args, **kewars)

  def jsonify_log_record(self, log_record):
    return json.dumps(log_record, ensure_ascii=False)

配置

很多時候我們并不是這樣自己去實(shí)現(xiàn)一些Handler ,F(xiàn)ormater ,之類的代碼,用logging 提供的config 就能做到了,如何寫config下面舉個例子解釋下,

SC_LOGGING_CONF = {
  "version": 1,
  "disable_existing_loggers": False,
  "formatters": {
    "simple": {
      "format": "%(asctime)s [%(levelname)s] [%(threadName)s:%(thread)d] [%(name)s:%(lineno)d] - %(message)s"
    }
  },

  "handlers": {
    "console": {
      "class": "logging.StreamHandler",
      "level": "DEBUG",
      "formatter": "simple",
      "stream": "ext://sys.stdout"
    },
    "info_file_handler": {
      "class": "logging.handlers.RotatingFileHandler",
      "level": "INFO",
      "formatter": "simple",
      "filename": PATH + "info-" + date.today().isoformat() + ".log",
      "maxBytes": 10485760,
      "backupCount": 20,
      "encoding": "utf8"
    },
    "error_file_handler": {
      "class": "logging.handlers.RotatingFileHandler",
      "level": "ERROR",
      "formatter": "simple",
      "filename": PATH + "errors-" + date.today().isoformat() + ".log",
      "maxBytes": 10485760,
      "backupCount": 20,
      "encoding": "utf8"
    }
  },
    "": {
      "level": "INFO",
      "handlers": ["console", "info_file_handler", "error_file_handler"]
    }
  }
}

首先定義了一個formater 叫simaple , 然后定義了三個Handler ,分別是輸出到控制臺,輸出到文件和info,error的。

 logging.config.dictConfig(CONFIG.SC_LOGGING_CONF)
通過這句就能讓這些配置產(chǎn)生效果了,這也是config.py做的事情,不需要寫很多代碼也能定制個性化的log.。

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助。

相關(guān)文章

  • Python的Django框架中settings文件的部署建議

    Python的Django框架中settings文件的部署建議

    這篇文章主要介紹了Python的Django框架中settings文件的部署建議,包括對local_settings的弊病的一些簡單分析,需要的朋友可以參考下
    2015-05-05
  • python實(shí)現(xiàn)Simhash算法

    python實(shí)現(xiàn)Simhash算法

    這篇文章主要介紹了python實(shí)現(xiàn)Simhash算法,simhash算法用來進(jìn)行文本比對的,simhash包含分詞、hash、加權(quán)、合并、降維五大步驟,下文圍繞更多相關(guān)資料介紹,需要的小伙伴可以參考一下
    2022-02-02
  • PyTorch模型調(diào)試與故障排除指南

    PyTorch模型調(diào)試與故障排除指南

    在當(dāng)代深度學(xué)習(xí)領(lǐng)域,PyTorch 已成為開發(fā)和訓(xùn)練神經(jīng)網(wǎng)絡(luò)的主要框架之一,然而隨著模型復(fù)雜度的增加和數(shù)據(jù)規(guī)模的擴(kuò)大,開發(fā)者常常面臨各種調(diào)試和優(yōu)化挑戰(zhàn),本文旨在為 PyTorch 開發(fā)者提供一個全面的調(diào)試指南,涵蓋從基礎(chǔ)概念到高級技術(shù)的廣泛內(nèi)容,需要的朋友可以參考下
    2024-09-09
  • Tensorflow使用支持向量機(jī)擬合線性回歸

    Tensorflow使用支持向量機(jī)擬合線性回歸

    這篇文章主要為大家詳細(xì)介紹了Tensorflow使用支持向量機(jī)擬合線性回歸,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-09-09
  • python?matplotlib庫繪圖實(shí)戰(zhàn)之繪制散點(diǎn)圖

    python?matplotlib庫繪圖實(shí)戰(zhàn)之繪制散點(diǎn)圖

    Python有著強(qiáng)大的繪圖庫 matplotlib,該庫集成了大量的繪制函數(shù),可以滿足我們平時絕大多數(shù)的繪圖要求,這篇文章主要給大家介紹了關(guān)于python?matplotlib庫繪圖實(shí)戰(zhàn)之繪制散點(diǎn)圖的相關(guān)資料,需要的朋友可以參考下
    2022-07-07
  • Python實(shí)現(xiàn)的簡單dns查詢功能示例

    Python實(shí)現(xiàn)的簡單dns查詢功能示例

    這篇文章主要介紹了Python實(shí)現(xiàn)的簡單dns查詢功能,結(jié)合實(shí)例形式分析了Python基于socket模塊的dns信息查詢實(shí)現(xiàn)技巧,需要的朋友可以參考下
    2017-05-05
  • 使用OpenCV-python3實(shí)現(xiàn)滑動條更新圖像的Canny邊緣檢測功能

    使用OpenCV-python3實(shí)現(xiàn)滑動條更新圖像的Canny邊緣檢測功能

    這篇文章主要介紹了使用OpenCV-python3實(shí)現(xiàn)滑動條更新圖像的Canny邊緣檢測功能,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價值,需要的朋友可以參考下
    2019-12-12
  • 淺談Python從全局與局部變量到裝飾器的相關(guān)知識

    淺談Python從全局與局部變量到裝飾器的相關(guān)知識

    今天給大家?guī)淼氖顷P(guān)于Python的相關(guān)知識,文章圍繞著Python從全局與局部變量到裝飾器的相關(guān)知識展開,文中有非常詳細(xì)的介紹及代碼示例,需要的朋友可以參考下
    2021-06-06
  • python中字典的常見操作總結(jié)1

    python中字典的常見操作總結(jié)1

    這篇文章主要介紹了python中字典的常見操作總結(jié),文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價值,需要的小伙伴可以參考一下
    2022-07-07
  • Python中利用LSTM模型進(jìn)行時間序列預(yù)測分析的實(shí)現(xiàn)

    Python中利用LSTM模型進(jìn)行時間序列預(yù)測分析的實(shí)現(xiàn)

    這篇文章主要介紹了Python中利用LSTM模型進(jìn)行時間序列預(yù)測分析的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-07-07

最新評論

江北区| 陈巴尔虎旗| 奉节县| 浙江省| 蓬莱市| 丘北县| 衡南县| 喜德县| 万盛区| 宁化县| 宣城市| 大连市| 华亭县| 黎川县| 于都县| 顺义区| 水城县| 平阴县| 麦盖提县| 黔西县| 阿鲁科尔沁旗| 天柱县| 新建县| 离岛区| 津市市| 麦盖提县| 桓台县| 昌都县| 汶川县| 日喀则市| 安阳市| 青川县| 潍坊市| 依兰县| 兴城市| 宣城市| 隆化县| 怀仁县| 新营市| 台山市| 日土县|