log.py 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. """celery.log"""
  2. import os
  3. import sys
  4. import time
  5. import logging
  6. from celery.conf import LOG_FORMAT, DAEMON_LOG_LEVEL
  7. def setup_logger(loglevel=DAEMON_LOG_LEVEL, logfile=None, format=LOG_FORMAT,
  8. **kwargs):
  9. """Setup the ``multiprocessing`` logger. If ``logfile`` is not specified,
  10. ``stderr`` is used.
  11. Returns logger object.
  12. """
  13. import multiprocessing
  14. logger = multiprocessing.get_logger()
  15. logger.setLevel(loglevel)
  16. if logger.handlers:
  17. return logger
  18. if logfile:
  19. if hasattr(logfile, "write"):
  20. log_file_handler = logging.StreamHandler(logfile)
  21. else:
  22. log_file_handler = logging.FileHandler(logfile)
  23. formatter = logging.Formatter(format)
  24. log_file_handler.setFormatter(formatter)
  25. logger.addHandler(log_file_handler)
  26. else:
  27. multiprocessing.log_to_stderr()
  28. return logger
  29. def emergency_error(logfile, message):
  30. """Emergency error logging, for when there's no standard file
  31. descriptors open because the process has been daemonized or for
  32. some other reason."""
  33. logfh_needs_to_close = False
  34. if not logfile:
  35. logfile = sys.stderr
  36. if hasattr(logfile, "write"):
  37. logfh = logfile
  38. else:
  39. logfh = open(logfile, "a")
  40. logfh_needs_to_close = True
  41. logfh.write("[%(asctime)s: FATAL/%(pid)d]: %(message)s\n" % {
  42. "asctime": time.asctime(),
  43. "pid": os.getpid(),
  44. "message": message})
  45. if logfh_needs_to_close:
  46. logfh.close()
  47. def redirect_stdouts_to_logger(logger, loglevel=None):
  48. """Redirect :class:`sys.stdout` and :class:`sys.stderr` to a
  49. logging instance.
  50. :param logger: The :class:`logging.Logger` instance to redirect to.
  51. :param loglevel: The loglevel redirected messages will be logged as.
  52. """
  53. proxy = LoggingProxy(logger, loglevel)
  54. sys.stdout = proxy
  55. sys.stderr = proxy
  56. return proxy
  57. class LoggingProxy(object):
  58. """Forward file object to :class:`logging.Logger` instance.
  59. :param logger: The :class:`logging.Logger` instance to forward to.
  60. :param loglevel: Loglevel to use when writing messages.
  61. """
  62. mode = "w"
  63. name = None
  64. closed = False
  65. def __init__(self, logger, loglevel=logging.INFO):
  66. self.logger = logger
  67. self.loglevel = loglevel
  68. def write(self, data):
  69. """Write message to logging object."""
  70. if not self.closed:
  71. self.logger.log(self.loglevel, data)
  72. def writelines(self, sequence):
  73. """``writelines(sequence_of_strings) -> None``.
  74. Write the strings to the file.
  75. The sequence can be any iterable object producing strings.
  76. This is equivalent to calling :meth:`write` for each string.
  77. """
  78. map(self.write, sequence)
  79. def flush(self):
  80. """This object is not buffered so any :meth:`flush` requests
  81. are ignored."""
  82. pass
  83. def close(self):
  84. """When the object is closed, no write requests are forwarded to
  85. the logging object anymore."""
  86. self.closed = True
  87. def isatty(self):
  88. """Always returns ``False``. Just here for file support."""
  89. return False
  90. def fileno(self):
  91. return None