_file.py 2.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677
  1. # -*- test-case-name: twisted.logger.test.test_file -*-
  2. # Copyright (c) Twisted Matrix Laboratories.
  3. # See LICENSE for details.
  4. """
  5. File log observer.
  6. """
  7. from typing import IO, Any, Callable, Optional
  8. from zope.interface import implementer
  9. from twisted.python.compat import ioType
  10. from ._format import formatEventAsClassicLogText, formatTime, timeFormatRFC3339
  11. from ._interfaces import ILogObserver, LogEvent
  12. @implementer(ILogObserver)
  13. class FileLogObserver:
  14. """
  15. Log observer that writes to a file-like object.
  16. """
  17. def __init__(
  18. self, outFile: IO[Any], formatEvent: Callable[[LogEvent], Optional[str]]
  19. ) -> None:
  20. """
  21. @param outFile: A file-like object. Ideally one should be passed which
  22. accepts text data. Otherwise, UTF-8 L{bytes} will be used.
  23. @param formatEvent: A callable that formats an event.
  24. """
  25. if ioType(outFile) is not str:
  26. self._encoding: Optional[str] = "utf-8"
  27. else:
  28. self._encoding = None
  29. self._outFile = outFile
  30. self.formatEvent = formatEvent
  31. def __call__(self, event: LogEvent) -> None:
  32. """
  33. Write event to file.
  34. @param event: An event.
  35. """
  36. text = self.formatEvent(event)
  37. if text:
  38. if self._encoding is None:
  39. self._outFile.write(text)
  40. else:
  41. self._outFile.write(text.encode(self._encoding))
  42. self._outFile.flush()
  43. def textFileLogObserver(
  44. outFile: IO[Any], timeFormat: Optional[str] = timeFormatRFC3339
  45. ) -> FileLogObserver:
  46. """
  47. Create a L{FileLogObserver} that emits text to a specified (writable)
  48. file-like object.
  49. @param outFile: A file-like object. Ideally one should be passed which
  50. accepts text data. Otherwise, UTF-8 L{bytes} will be used.
  51. @param timeFormat: The format to use when adding timestamp prefixes to
  52. logged events. If L{None}, or for events with no C{"log_timestamp"}
  53. key, the default timestamp prefix of C{"-"} is used.
  54. @return: A file log observer.
  55. """
  56. def formatEvent(event: LogEvent) -> Optional[str]:
  57. return formatEventAsClassicLogText(
  58. event, formatTime=lambda e: formatTime(e, timeFormat)
  59. )
  60. return FileLogObserver(outFile, formatEvent)