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

詳解Python logging調(diào)用Logger.info方法的處理過程

 更新時間:2019年02月12日 10:52:31   作者:posuoren  
這篇文章主要介紹了詳解Python logging調(diào)用Logger.info方法的處理過程,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧

本次分析一下Logger.info的流程

1. Logger.info源碼:

 def info(self, msg, *args, **kwargs):
  """
  Log 'msg % args' with severity 'INFO'.

  To pass exception information, use the keyword argument exc_info with
  a true value, e.g.

  logger.info("Houston, we have a %s", "interesting problem", exc_info=1)
  """
  if self.isEnabledFor(INFO):
   self._log(INFO, msg, args, **kwargs)

注釋中反應(yīng)了可以通過 msg和不定參數(shù)args來進行日志的格式化。
真實的調(diào)用為:_log方法:

2. Logger._log方法:

 def _log(self, level, msg, args, exc_info=None, extra=None, stack_info=False):
  """
  Low-level logging routine which creates a LogRecord and then calls
  all the handlers of this logger to handle the record.
  """
  sinfo = None
  if _srcfile:
   #IronPython doesn't track Python frames, so findCaller raises an
   #exception on some versions of IronPython. We trap it here so that
   #IronPython can use logging.
   try:
    fn, lno, func, sinfo = self.findCaller(stack_info)
   except ValueError: # pragma: no cover
    fn, lno, func = "(unknown file)", 0, "(unknown function)"
  else: # pragma: no cover
   fn, lno, func = "(unknown file)", 0, "(unknown function)"
  if exc_info:
   if isinstance(exc_info, BaseException):
    exc_info = (type(exc_info), exc_info, exc_info.__traceback__)
   elif not isinstance(exc_info, tuple):
    exc_info = sys.exc_info()
  record = self.makeRecord(self.name, level, fn, lno, msg, args,
         exc_info, func, extra, sinfo)
  self.handle(record)

最后兩行:

生成日志記錄:

record = self.makeRecord(self.name, level, fn, lno, msg, args, exc_info, func, extra, sinfo)

處理日志記錄

self.handle(record)

2 生成日志記錄:

 def makeRecord(self, name, level, fn, lno, msg, args, exc_info,
     func=None, extra=None, sinfo=None):
  """
  A factory method which can be overridden in subclasses to create
  specialized LogRecords.
  """
  rv = _logRecordFactory(name, level, fn, lno, msg, args, exc_info, func,
        sinfo)
  if extra is not None:
   for key in extra:
    if (key in ["message", "asctime"]) or (key in rv.__dict__):
     raise KeyError("Attempt to overwrite %r in LogRecord" % key)
    rv.__dict__[key] = extra[key]
  return rv

調(diào)用_logRecordFactory初始化一個日志記錄實例,_logRecordFactory 其實就是LogRecord類,初始化時,可能包含logger的name, level、調(diào)用的函數(shù)、行號、日志字符串、模板參數(shù)、堆棧信息等。

再看extra信息,extra到底有何用?現(xiàn)在從代碼中可以看到,只是更新到生成的日志記錄實例的__dict__中去.猜測:肯定會在生成最終的日志字符串的時候會用到。繼續(xù)往下看。

3 處理日志記錄self.handle(record):

Logger繼承自Filterer,

 def handle(self, record):
  """
  Call the handlers for the specified record.

  This method is used for unpickled records received from a socket, as
  well as those created locally. Logger-level filtering is applied.
  """
  if (not self.disabled) and self.filter(record):
   self.callHandlers(record)

3.1 if語句中有一self.filter(record)的判斷,看函數(shù)名,是來篩選是否要繼續(xù)處理消息的,其核心源碼如下:

 def filter(self, record):
  """
  Determine if a record is loggable by consulting all the filters.

  The default is to allow the record to be logged; any filter can veto
  this and the record is then dropped. Returns a zero value if a record
  is to be dropped, else non-zero.

  .. versionchanged:: 3.2

   Allow filters to be just callables.
  """
  rv = True
  for f in self.filters:
   if hasattr(f, 'filter'):
    result = f.filter(record)
   else:
    result = f(record) # assume callable - will raise if not
   if not result:
    rv = False
    break
  return rv

可以看到, 如果在handler中的filter中如果有返回為False或空,則會屏蔽對應(yīng)的record,返回True或部位空的值,則會將record放行。那么我們就可以自定義自己的filter。

3.2 讓Logger中所有的handles去處理record:

def callHandlers(self, record):
  """
  Pass a record to all relevant handlers.

  Loop through all handlers for this logger and its parents in the
  logger hierarchy. If no handler was found, output a one-off error
  message to sys.stderr. Stop searching up the hierarchy whenever a
  logger with the "propagate" attribute set to zero is found - that
  will be the last logger whose handlers are called.
  """
  c = self
  found = 0
  while c:
   for hdlr in c.handlers:
    found = found + 1
    if record.levelno >= hdlr.level:
     hdlr.handle(record)
   if not c.propagate:
    c = None #break out
   else:
    c = c.parent
  if (found == 0):
   if lastResort:
    if record.levelno >= lastResort.level:
     lastResort.handle(record)
   elif raiseExceptions and not self.manager.emittedNoHandlerWarning:
    sys.stderr.write("No handlers could be found for logger"
         " \"%s\"\n" % self.name)
    self.manager.emittedNoHandlerWarning = True

代碼中會去循環(huán)調(diào)用當(dāng)前l(fā)ogger的所有handlers去處理record,for循環(huán)部分,之后,如果當(dāng)前的logger的propagate的值為False或空,則不向logger的父logger傳遞,即向上傳遞。

4. Handler 中的 handler(record) 部分:

def handle(self, record):
  """
  Conditionally emit the specified logging record.

  Emission depends on filters which may have been added to the handler.
  Wrap the actual emission of the record with acquisition/release of
  the I/O thread lock. Returns whether the filter passed the record for
  emission.
  """
  rv = self.filter(record)
  if rv:
   self.acquire()
   try:
    self.emit(record)
   finally:
    self.release()
  return rv

可以看到, Handler在處理record時, 會去加鎖,然后調(diào)用self.emit(record)方法去處理。

4.1 emit(record)

def emit(self, record):
  """
  Do whatever it takes to actually log the specified logging record.

  This version is intended to be implemented by subclasses and so
  raises a NotImplementedError.
  """
  raise NotImplementedError('emit must be implemented '
         'by Handler subclasses')

看到需要由子類去實現(xiàn),以StreamHandler為例子:

def emit(self, record):
  """
  Emit a record.

  If a formatter is specified, it is used to format the record.
  The record is then written to the stream with a trailing newline. If
  exception information is present, it is formatted using
  traceback.print_exception and appended to the stream. If the stream
  has an 'encoding' attribute, it is used to determine how to do the
  output to the stream.
  """
  try:
   msg = self.format(record)
   stream = self.stream
   stream.write(msg)
   stream.write(self.terminator)
   self.flush()
  except Exception:
   self.handleError(record)

4.2 Handler.format(record):

 def format(self, record):
  """
  Format the specified record.

  If a formatter is set, use it. Otherwise, use the default formatter
  for the module.
  """
  if self.formatter:
   fmt = self.formatter
  else:
   fmt = _defaultFormatter
  return fmt.format(record)

如果handler有自定義的formatter就用自定義的,如果沒有則用默認的Formatter的實例, 初始化元源碼為:

 def __init__(self, fmt=None, datefmt=None, style='%'):
  """
  Initialize the formatter with specified format strings.

  Initialize the formatter either with the specified format string, or a
  default as described above. Allow for specialized date formatting with
  the optional datefmt argument (if omitted, you get the ISO8601 format).

  Use a style parameter of '%', '{' or '$' to specify that you want to
  use one of %-formatting, :meth:`str.format` (``{}``) formatting or
  :class:`string.Template` formatting in your format string.

  .. versionchanged:: 3.2
   Added the ``style`` parameter.
  """
  if style not in _STYLES:
   raise ValueError('Style must be one of: %s' % ','.join(
        _STYLES.keys()))
  self._style = _STYLES[style][0](fmt)
  self._fmt = self._style._fmt
  self.datefmt = datefmt

有三個參數(shù):

  • fmt: 格式化模板
  • datefmt: 時間格式化參數(shù)
  • style: 日志格式化的樣式。

style有三種:

_STYLES = {
 '%': (PercentStyle, BASIC_FORMAT),
 '{': (StrFormatStyle, '{levelname}:{name}:{message}'),
 '$': (StringTemplateStyle, '${levelname}:${name}:${message}'),

可以看出對應(yīng)到:% 操作符的格式化, format方法的格式化以及Template的格式化。

Formatter的format方法源碼為:

 def format(self, record):
  """
  Format the specified record as text.
  The record's attribute dictionary is used as the operand to a
  string formatting operation which yields the returned string.
  Before formatting the dictionary, a couple of preparatory steps
  are carried out. The message attribute of the record is computed
  using LogRecord.getMessage(). If the formatting string uses the
  time (as determined by a call to usesTime(), formatTime() is
  called to format the event time. If there is exception information,
  it is formatted using formatException() and appended to the message.
  """
  record.message = record.getMessage()
  if self.usesTime():
   record.asctime = self.formatTime(record, self.datefmt)
  s = self.formatMessage(record)
  if record.exc_info:
   # Cache the traceback text to avoid converting it multiple times
   # (it's constant anyway)
   if not record.exc_text:
    record.exc_text = self.formatException(record.exc_info)
  if record.exc_text:
   if s[-1:] != "\n":
    s = s + "\n"
   s = s + record.exc_text
  if record.stack_info:
   if s[-1:] != "\n":
    s = s + "\n"
   s = s + self.formatStack(record.stack_info)

看到會調(diào)用record.getMessage(),這里僅僅是獲取我們需要的日志信息。

之后會調(diào)用s = self.formatMessage(record):

 def formatMessage(self, record):
  return self._style.format(record)

其實是調(diào)用了當(dāng)前style的format方法,以%這一類型為例PercentStyle:

class PercentStyle(object):

 default_format = '%(message)s'
 asctime_format = '%(asctime)s'
 asctime_search = '%(asctime)'

 def __init__(self, fmt):
  self._fmt = fmt or self.default_format

 def usesTime(self):
  return self._fmt.find(self.asctime_search) >= 0

 def format(self, record):
  return self._fmt % record.__dict__

從其中的format方法可以看出,是針對record的__dict__屬性中的所有參數(shù)進行格式化,這下,就清楚了之前的extra參數(shù)是干嘛用的了:可以在formatter中加入自己自定義的一些參數(shù),如固定的用戶信息等等。

之后,將最終的message flush到對應(yīng)的Stream里面去就行了,就是整個流程:


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

相關(guān)文章

  • 解決Keras中Embedding層masking與Concatenate層不可調(diào)和的問題

    解決Keras中Embedding層masking與Concatenate層不可調(diào)和的問題

    這篇文章主要介紹了解決Keras中Embedding層masking與Concatenate層不可調(diào)和的問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-06-06
  • 在python中創(chuàng)建表格的兩種方法實例

    在python中創(chuàng)建表格的兩種方法實例

    Python 是一種解釋型、面向?qū)ο蟆討B(tài)數(shù)據(jù)類型的高級程序設(shè)計語言,下面這篇文章主要給大家介紹了關(guān)于如何在python中創(chuàng)建表格的兩種方法,文中通過實例代碼介紹的非常詳細,需要的朋友可以參考下
    2022-01-01
  • opencv python截取圓形區(qū)域的實現(xiàn)

    opencv python截取圓形區(qū)域的實現(xiàn)

    本文主要介紹了opencv python截取圓形區(qū)域的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-08-08
  • Python下opencv使用hough變換檢測直線與圓

    Python下opencv使用hough變換檢測直線與圓

    在數(shù)字圖像中,往往存在著一些特殊形狀的幾何圖形,像檢測馬路邊一條直線,檢測人眼的圓形等等,有時我們需要把這些特定圖形檢測出來,本文就詳細的介紹了一下方法
    2021-06-06
  • python中將字典改造為對象的方法

    python中將字典改造為對象的方法

    這篇文章主要介紹了python中將字典改造為對象的方法,在實際項目中,當(dāng)使用json模塊加載一個深度很深的字典類型的json文件時,使用字典的訪問方式,將會出現(xiàn)很多中括號,即不直觀也不美觀,可以將這個字典轉(zhuǎn)化為對象,使得可以用.的方式訪問,需要的朋友可以參考下
    2023-11-11
  • Python?頁面解析Beautiful?Soup庫的使用方法

    Python?頁面解析Beautiful?Soup庫的使用方法

    Beautiful?Soup?簡稱?BS4(其中?4?表示版本號)是一個?Python?中常用的頁面解析庫,它可以從?HTML?或?XML?文檔中快速地提取指定的數(shù)據(jù),這篇文章主要介紹了springboot?集成?docsify?實現(xiàn)隨身文檔?,需要的朋友可以參考下
    2022-09-09
  • python目標(biāo)檢測非極大抑制NMS與Soft-NMS

    python目標(biāo)檢測非極大抑制NMS與Soft-NMS

    這篇文章主要weidajia?介紹了python目標(biāo)檢測非極大抑制NMS與Soft-NMS實現(xiàn)過程,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-05-05
  • 教你用Python寫一個植物大戰(zhàn)僵尸小游戲

    教你用Python寫一個植物大戰(zhàn)僵尸小游戲

    這篇文章主要介紹了教你用Python寫一個植物大戰(zhàn)僵尸小游戲,文中有非常詳細的代碼示例,對正在學(xué)習(xí)python的小伙伴們有非常好的幫助,需要的朋友可以參考下
    2021-04-04
  • Python部署web開發(fā)程序的幾種方法

    Python部署web開發(fā)程序的幾種方法

    本篇文章主要介紹了Python部署web開發(fā)程序的幾種方法,具有很好的參考價值。下面跟著小編一起來看下吧
    2017-05-05
  • 如何使用Python實現(xiàn)斐波那契數(shù)列

    如何使用Python實現(xiàn)斐波那契數(shù)列

    這篇文章主要介紹了如何使用Python實現(xiàn)斐波那契數(shù)列,斐波那契數(shù)列(Fibonacci)最早由印度數(shù)學(xué)家Gopala提出,而第一個真正研究斐波那契數(shù)列的是意大利數(shù)學(xué)家 Leonardo Fibonacci,需要的朋友可以參考下
    2019-07-07

最新評論

甘孜县| 广安市| 富民县| 广汉市| 乌什县| 鱼台县| 米泉市| 富川| 抚顺县| 扬州市| 蒙城县| 阿城市| 永康市| 承德市| 墨竹工卡县| 视频| 大石桥市| 汉川市| 海口市| 奇台县| 桂阳县| 田林县| 辽宁省| 谢通门县| 娄底市| 建平县| 泸定县| 宁城县| 夏河县| 武威市| 滨海县| 昭觉县| 滦南县| 津市市| 公主岭市| 西畴县| 黄骅市| 肥东县| 儋州市| 景宁| 濮阳市|