_legacy.py 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. # -*- test-case-name: twisted.logger.test.test_legacy -*-
  2. # Copyright (c) Twisted Matrix Laboratories.
  3. # See LICENSE for details.
  4. """
  5. Integration with L{twisted.python.log}.
  6. """
  7. from zope.interface import implementer
  8. from ._levels import LogLevel
  9. from ._format import formatEvent
  10. from ._observer import ILogObserver
  11. from ._stdlib import fromStdlibLogLevelMapping, StringifiableFromEvent
  12. @implementer(ILogObserver)
  13. class LegacyLogObserverWrapper(object):
  14. """
  15. L{ILogObserver} that wraps an L{twisted.python.log.ILogObserver}.
  16. Received (new-style) events are modified prior to forwarding to
  17. the legacy observer to ensure compatibility with observers that
  18. expect legacy events.
  19. """
  20. def __init__(self, legacyObserver):
  21. """
  22. @param legacyObserver: a legacy observer to which this observer will
  23. forward events.
  24. @type legacyObserver: L{twisted.python.log.ILogObserver}
  25. """
  26. self.legacyObserver = legacyObserver
  27. def __repr__(self):
  28. return (
  29. "{self.__class__.__name__}({self.legacyObserver})"
  30. .format(self=self)
  31. )
  32. def __call__(self, event):
  33. """
  34. Forward events to the legacy observer after editing them to
  35. ensure compatibility.
  36. @param event: an event
  37. @type event: L{dict}
  38. """
  39. # The "message" key is required by textFromEventDict()
  40. if "message" not in event:
  41. event["message"] = ()
  42. if "time" not in event:
  43. event["time"] = event["log_time"]
  44. if "system" not in event:
  45. event["system"] = event.get("log_system", "-")
  46. # Format new style -> old style
  47. if "format" not in event and event.get("log_format", None) is not None:
  48. # Create an object that implements __str__() in order to defer the
  49. # work of formatting until it's needed by a legacy log observer.
  50. event["format"] = "%(log_legacy)s"
  51. event["log_legacy"] = StringifiableFromEvent(event.copy())
  52. # In the old-style system, the 'message' key always holds a tuple
  53. # of messages. If we find the 'message' key here to not be a
  54. # tuple, it has been passed as new-style parameter. We drop it
  55. # here because we render it using the old-style 'format' key,
  56. # which otherwise doesn't get precedence, and the original event
  57. # has been copied above.
  58. if not isinstance(event["message"], tuple):
  59. event["message"] = ()
  60. # From log.failure() -> isError blah blah
  61. if "log_failure" in event:
  62. if "failure" not in event:
  63. event["failure"] = event["log_failure"]
  64. if "isError" not in event:
  65. event["isError"] = 1
  66. if "why" not in event:
  67. event["why"] = formatEvent(event)
  68. elif "isError" not in event:
  69. if event["log_level"] in (LogLevel.error, LogLevel.critical):
  70. event["isError"] = 1
  71. else:
  72. event["isError"] = 0
  73. self.legacyObserver(event)
  74. def publishToNewObserver(observer, eventDict, textFromEventDict):
  75. """
  76. Publish an old-style (L{twisted.python.log}) event to a new-style
  77. (L{twisted.logger}) observer.
  78. @note: It's possible that a new-style event was sent to a
  79. L{LegacyLogObserverWrapper}, and may now be getting sent back to a
  80. new-style observer. In this case, it's already a new-style event,
  81. adapted to also look like an old-style event, and we don't need to
  82. tweak it again to be a new-style event, hence the checks for
  83. already-defined new-style keys.
  84. @param observer: A new-style observer to handle this event.
  85. @type observer: L{ILogObserver}
  86. @param eventDict: An L{old-style <twisted.python.log>}, log event.
  87. @type eventDict: L{dict}
  88. @param textFromEventDict: callable that can format an old-style event as a
  89. string. Passed here rather than imported to avoid circular dependency.
  90. @type textFromEventDict: 1-arg L{callable} taking L{dict} returning L{str}
  91. @return: L{None}
  92. """
  93. if "log_time" not in eventDict:
  94. eventDict["log_time"] = eventDict["time"]
  95. if "log_format" not in eventDict:
  96. text = textFromEventDict(eventDict)
  97. if text is not None:
  98. eventDict["log_text"] = text
  99. eventDict["log_format"] = u"{log_text}"
  100. if "log_level" not in eventDict:
  101. if "logLevel" in eventDict:
  102. try:
  103. level = fromStdlibLogLevelMapping[eventDict["logLevel"]]
  104. except KeyError:
  105. level = None
  106. elif "isError" in eventDict:
  107. if eventDict["isError"]:
  108. level = LogLevel.critical
  109. else:
  110. level = LogLevel.info
  111. else:
  112. level = LogLevel.info
  113. if level is not None:
  114. eventDict["log_level"] = level
  115. if "log_namespace" not in eventDict:
  116. eventDict["log_namespace"] = u"log_legacy"
  117. if "log_system" not in eventDict and "system" in eventDict:
  118. eventDict["log_system"] = eventDict["system"]
  119. observer(eventDict)