_loggers.py 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. # This file is dual licensed under the terms of the Apache License, Version
  2. # 2.0, and the MIT License. See the LICENSE file in the root of this
  3. # repository for complete details.
  4. """
  5. Logger wrapper and helper class.
  6. """
  7. from __future__ import absolute_import, division, print_function
  8. import sys
  9. import threading
  10. from structlog._utils import until_not_interrupted
  11. class PrintLoggerFactory(object):
  12. """
  13. Produce :class:`PrintLogger`\ s.
  14. To be used with :func:`structlog.configure`\ 's `logger_factory`.
  15. :param file file: File to print to. (default: stdout)
  16. Positional arguments are silently ignored.
  17. .. versionadded:: 0.4.0
  18. """
  19. def __init__(self, file=None):
  20. self._file = file
  21. def __call__(self, *args):
  22. return PrintLogger(self._file)
  23. WRITE_LOCKS = {}
  24. class PrintLogger(object):
  25. """
  26. Print events into a file.
  27. :param file file: File to print to. (default: stdout)
  28. >>> from structlog import PrintLogger
  29. >>> PrintLogger().msg('hello')
  30. hello
  31. Useful if you just capture your stdout with tools like `runit
  32. <http://smarden.org/runit/>`_ or if you `forward your stderr to syslog
  33. <https://hynek.me/articles/taking-some-pain-out-of-python-logging/>`_.
  34. Also very useful for testing and examples since logging is finicky in
  35. doctests.
  36. """
  37. def __init__(self, file=None):
  38. self._file = file or sys.stdout
  39. self._write = self._file.write
  40. self._flush = self._file.flush
  41. lock = WRITE_LOCKS.get(self._file)
  42. if lock is None:
  43. lock = threading.Lock()
  44. WRITE_LOCKS[self._file] = lock
  45. self._lock = lock
  46. def __repr__(self):
  47. return '<PrintLogger(file={0!r})>'.format(self._file)
  48. def msg(self, message):
  49. """
  50. Print *message*.
  51. """
  52. with self._lock:
  53. until_not_interrupted(self._write, message + '\n')
  54. until_not_interrupted(self._flush)
  55. log = debug = info = warn = warning = msg
  56. failure = err = error = critical = exception = msg
  57. class ReturnLoggerFactory(object):
  58. """
  59. Produce and cache :class:`ReturnLogger`\ s.
  60. To be used with :func:`structlog.configure`\ 's `logger_factory`.
  61. Positional arguments are silently ignored.
  62. .. versionadded:: 0.4.0
  63. """
  64. def __init__(self):
  65. self._logger = ReturnLogger()
  66. def __call__(self, *args):
  67. return self._logger
  68. class ReturnLogger(object):
  69. """
  70. Return the arguments that it's called with.
  71. >>> from structlog import ReturnLogger
  72. >>> ReturnLogger().msg('hello')
  73. 'hello'
  74. >>> ReturnLogger().msg('hello', when='again')
  75. (('hello',), {'when': 'again'})
  76. Useful for unit tests.
  77. .. versionchanged:: 0.3.0
  78. Allow for arbitrary arguments and keyword arguments to be passed in.
  79. """
  80. def msg(self, *args, **kw):
  81. """
  82. Return tuple of ``args, kw`` or just ``args[0]`` if only one arg passed
  83. """
  84. # Slightly convoluted for backwards compatibility.
  85. if len(args) == 1 and not kw:
  86. return args[0]
  87. else:
  88. return args, kw
  89. log = debug = info = warn = warning = msg
  90. failure = err = error = critical = exception = msg