logging.py 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. # -*- coding: utf-8 -*-
  2. """
  3. flask.logging
  4. ~~~~~~~~~~~~~
  5. :copyright: 2010 Pallets
  6. :license: BSD-3-Clause
  7. """
  8. from __future__ import absolute_import
  9. import logging
  10. import sys
  11. import warnings
  12. from werkzeug.local import LocalProxy
  13. from .globals import request
  14. @LocalProxy
  15. def wsgi_errors_stream():
  16. """Find the most appropriate error stream for the application. If a request
  17. is active, log to ``wsgi.errors``, otherwise use ``sys.stderr``.
  18. If you configure your own :class:`logging.StreamHandler`, you may want to
  19. use this for the stream. If you are using file or dict configuration and
  20. can't import this directly, you can refer to it as
  21. ``ext://flask.logging.wsgi_errors_stream``.
  22. """
  23. return request.environ["wsgi.errors"] if request else sys.stderr
  24. def has_level_handler(logger):
  25. """Check if there is a handler in the logging chain that will handle the
  26. given logger's :meth:`effective level <~logging.Logger.getEffectiveLevel>`.
  27. """
  28. level = logger.getEffectiveLevel()
  29. current = logger
  30. while current:
  31. if any(handler.level <= level for handler in current.handlers):
  32. return True
  33. if not current.propagate:
  34. break
  35. current = current.parent
  36. return False
  37. #: Log messages to :func:`~flask.logging.wsgi_errors_stream` with the format
  38. #: ``[%(asctime)s] %(levelname)s in %(module)s: %(message)s``.
  39. default_handler = logging.StreamHandler(wsgi_errors_stream)
  40. default_handler.setFormatter(
  41. logging.Formatter("[%(asctime)s] %(levelname)s in %(module)s: %(message)s")
  42. )
  43. def _has_config(logger):
  44. """Decide if a logger has direct configuration applied by checking
  45. its properties against the defaults.
  46. :param logger: The :class:`~logging.Logger` to inspect.
  47. """
  48. return (
  49. logger.level != logging.NOTSET
  50. or logger.handlers
  51. or logger.filters
  52. or not logger.propagate
  53. )
  54. def create_logger(app):
  55. """Get the the Flask apps's logger and configure it if needed.
  56. The logger name will be the same as
  57. :attr:`app.import_name <flask.Flask.name>`.
  58. When :attr:`~flask.Flask.debug` is enabled, set the logger level to
  59. :data:`logging.DEBUG` if it is not set.
  60. If there is no handler for the logger's effective level, add a
  61. :class:`~logging.StreamHandler` for
  62. :func:`~flask.logging.wsgi_errors_stream` with a basic format.
  63. """
  64. logger = logging.getLogger(app.name)
  65. # 1.1.0 changes name of logger, warn if config is detected for old
  66. # name and not new name
  67. for old_name in ("flask.app", "flask"):
  68. old_logger = logging.getLogger(old_name)
  69. if _has_config(old_logger) and not _has_config(logger):
  70. warnings.warn(
  71. "'app.logger' is named '{name}' for this application,"
  72. " but configuration was found for '{old_name}', which"
  73. " no longer has an effect. The logging configuration"
  74. " should be moved to '{name}'.".format(name=app.name, old_name=old_name)
  75. )
  76. break
  77. if app.debug and not logger.level:
  78. logger.setLevel(logging.DEBUG)
  79. if not has_level_handler(logger):
  80. logger.addHandler(default_handler)
  81. return logger