Format: text/x-python
⬇ Download File (2.3 KB)
   1  from __future__ import annotations
   2  
   3  import logging
   4  import sys
   5  import typing as t
   6  
   7  from werkzeug.local import LocalProxy
   8  
   9  from .globals import request
  10  
  11  if t.TYPE_CHECKING:  # pragma: no cover
  12      from .sansio.app import App
  13  
  14  
  15  @LocalProxy
  16  def wsgi_errors_stream() -> t.TextIO:
  17      """Find the most appropriate error stream for the application. If a request
  18      is active, log to ``wsgi.errors``, otherwise use ``sys.stderr``.
  19  
  20      If you configure your own :class:`logging.StreamHandler`, you may want to
  21      use this for the stream. If you are using file or dict configuration and
  22      can't import this directly, you can refer to it as
  23      ``ext://flask.logging.wsgi_errors_stream``.
  24      """
  25      if request:
  26          return request.environ["wsgi.errors"]  # type: ignore[no-any-return]
  27  
  28      return sys.stderr
  29  
  30  
  31  def has_level_handler(logger: logging.Logger) -> bool:
  32      """Check if there is a handler in the logging chain that will handle the
  33      given logger's :meth:`effective level <~logging.Logger.getEffectiveLevel>`.
  34      """
  35      level = logger.getEffectiveLevel()
  36      current = logger
  37  
  38      while current:
  39          if any(handler.level <= level for handler in current.handlers):
  40              return True
  41  
  42          if not current.propagate:
  43              break
  44  
  45          current = current.parent  # type: ignore
  46  
  47      return False
  48  
  49  
  50  #: Log messages to :func:`~flask.logging.wsgi_errors_stream` with the format
  51  #: ``[%(asctime)s] %(levelname)s in %(module)s: %(message)s``.
  52  default_handler = logging.StreamHandler(wsgi_errors_stream)  # type: ignore
  53  default_handler.setFormatter(
  54      logging.Formatter("[%(asctime)s] %(levelname)s in %(module)s: %(message)s")
  55  )
  56  
  57  
  58  def create_logger(app: App) -> logging.Logger:
  59      """Get the Flask app's logger and configure it if needed.
  60  
  61      The logger name will be the same as
  62      :attr:`app.import_name <flask.Flask.name>`.
  63  
  64      When :attr:`~flask.Flask.debug` is enabled, set the logger level to
  65      :data:`logging.DEBUG` if it is not set.
  66  
  67      If there is no handler for the logger's effective level, add a
  68      :class:`~logging.StreamHandler` for
  69      :func:`~flask.logging.wsgi_errors_stream` with a basic format.
  70      """
  71      logger = logging.getLogger(app.name)
  72  
  73      if app.debug and not logger.level:
  74          logger.setLevel(logging.DEBUG)
  75  
  76      if not has_level_handler(logger):
  77          logger.addHandler(default_handler)
  78  
  79      return logger
  80