Funktionierender Prototyp des Serious Games zur Vermittlung von Wissen zu Software-Engineering-Arbeitsmodellen.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

_logger.py 9.7KB

1 year ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269
  1. # -*- test-case-name: twisted.logger.test.test_logger -*-
  2. # Copyright (c) Twisted Matrix Laboratories.
  3. # See LICENSE for details.
  4. """
  5. Logger class.
  6. """
  7. from time import time
  8. from typing import Any, Optional, cast
  9. from twisted.python.compat import currentframe
  10. from twisted.python.failure import Failure
  11. from ._interfaces import ILogObserver, LogTrace
  12. from ._levels import InvalidLogLevelError, LogLevel
  13. class Logger:
  14. """
  15. A L{Logger} emits log messages to an observer. You should instantiate it
  16. as a class or module attribute, as documented in L{this module's
  17. documentation <twisted.logger>}.
  18. @ivar namespace: the namespace for this logger
  19. @ivar source: The object which is emitting events via this logger
  20. @ivar observer: The observer that this logger will send events to.
  21. """
  22. @staticmethod
  23. def _namespaceFromCallingContext() -> str:
  24. """
  25. Derive a namespace from the module containing the caller's caller.
  26. @return: the fully qualified python name of a module.
  27. """
  28. try:
  29. return cast(str, currentframe(2).f_globals["__name__"])
  30. except KeyError:
  31. return "<unknown>"
  32. def __init__(
  33. self,
  34. namespace: Optional[str] = None,
  35. source: Optional[object] = None,
  36. observer: Optional["ILogObserver"] = None,
  37. ) -> None:
  38. """
  39. @param namespace: The namespace for this logger. Uses a dotted
  40. notation, as used by python modules. If not L{None}, then the name
  41. of the module of the caller is used.
  42. @param source: The object which is emitting events via this
  43. logger; this is automatically set on instances of a class
  44. if this L{Logger} is an attribute of that class.
  45. @param observer: The observer that this logger will send events to.
  46. If L{None}, use the L{global log publisher <globalLogPublisher>}.
  47. """
  48. if namespace is None:
  49. namespace = self._namespaceFromCallingContext()
  50. self.namespace = namespace
  51. self.source = source
  52. if observer is None:
  53. from ._global import globalLogPublisher
  54. self.observer: ILogObserver = globalLogPublisher
  55. else:
  56. self.observer = observer
  57. def __get__(self, instance: object, owner: Optional[type] = None) -> "Logger":
  58. """
  59. When used as a descriptor, i.e.::
  60. # File: athing.py
  61. class Something:
  62. log = Logger()
  63. def hello(self):
  64. self.log.info("Hello")
  65. a L{Logger}'s namespace will be set to the name of the class it is
  66. declared on. In the above example, the namespace would be
  67. C{athing.Something}.
  68. Additionally, its source will be set to the actual object referring to
  69. the L{Logger}. In the above example, C{Something.log.source} would be
  70. C{Something}, and C{Something().log.source} would be an instance of
  71. C{Something}.
  72. """
  73. assert owner is not None
  74. if instance is None:
  75. source: Any = owner
  76. else:
  77. source = instance
  78. return self.__class__(
  79. ".".join([owner.__module__, owner.__name__]),
  80. source,
  81. observer=self.observer,
  82. )
  83. def __repr__(self) -> str:
  84. return f"<{self.__class__.__name__} {self.namespace!r}>"
  85. def emit(
  86. self, level: LogLevel, format: Optional[str] = None, **kwargs: object
  87. ) -> None:
  88. """
  89. Emit a log event to all log observers at the given level.
  90. @param level: a L{LogLevel}
  91. @param format: a message format using new-style (PEP 3101)
  92. formatting. The logging event (which is a L{dict}) is
  93. used to render this format string.
  94. @param kwargs: additional key/value pairs to include in the event.
  95. Note that values which are later mutated may result in
  96. non-deterministic behavior from observers that schedule work for
  97. later execution.
  98. """
  99. if level not in LogLevel.iterconstants():
  100. self.failure(
  101. "Got invalid log level {invalidLevel!r} in {logger}.emit().",
  102. Failure(InvalidLogLevelError(level)),
  103. invalidLevel=level,
  104. logger=self,
  105. )
  106. return
  107. event = kwargs
  108. event.update(
  109. log_logger=self,
  110. log_level=level,
  111. log_namespace=self.namespace,
  112. log_source=self.source,
  113. log_format=format,
  114. log_time=time(),
  115. )
  116. if "log_trace" in event:
  117. cast(LogTrace, event["log_trace"]).append((self, self.observer))
  118. self.observer(event)
  119. def failure(
  120. self,
  121. format: str,
  122. failure: Optional[Failure] = None,
  123. level: LogLevel = LogLevel.critical,
  124. **kwargs: object,
  125. ) -> None:
  126. """
  127. Log a failure and emit a traceback.
  128. For example::
  129. try:
  130. frob(knob)
  131. except Exception:
  132. log.failure("While frobbing {knob}", knob=knob)
  133. or::
  134. d = deferredFrob(knob)
  135. d.addErrback(lambda f: log.failure("While frobbing {knob}",
  136. f, knob=knob))
  137. This method is generally meant to capture unexpected exceptions in
  138. code; an exception that is caught and handled somehow should be logged,
  139. if appropriate, via L{Logger.error} instead. If some unknown exception
  140. occurs and your code doesn't know how to handle it, as in the above
  141. example, then this method provides a means to describe the failure in
  142. nerd-speak. This is done at L{LogLevel.critical} by default, since no
  143. corrective guidance can be offered to an user/administrator, and the
  144. impact of the condition is unknown.
  145. @param format: a message format using new-style (PEP 3101) formatting.
  146. The logging event (which is a L{dict}) is used to render this
  147. format string.
  148. @param failure: a L{Failure} to log. If L{None}, a L{Failure} is
  149. created from the exception in flight.
  150. @param level: a L{LogLevel} to use.
  151. @param kwargs: additional key/value pairs to include in the event.
  152. Note that values which are later mutated may result in
  153. non-deterministic behavior from observers that schedule work for
  154. later execution.
  155. """
  156. if failure is None:
  157. failure = Failure()
  158. self.emit(level, format, log_failure=failure, **kwargs)
  159. def debug(self, format: Optional[str] = None, **kwargs: object) -> None:
  160. """
  161. Emit a log event at log level L{LogLevel.debug}.
  162. @param format: a message format using new-style (PEP 3101) formatting.
  163. The logging event (which is a L{dict}) is used to render this
  164. format string.
  165. @param kwargs: additional key/value pairs to include in the event.
  166. Note that values which are later mutated may result in
  167. non-deterministic behavior from observers that schedule work for
  168. later execution.
  169. """
  170. self.emit(LogLevel.debug, format, **kwargs)
  171. def info(self, format: Optional[str] = None, **kwargs: object) -> None:
  172. """
  173. Emit a log event at log level L{LogLevel.info}.
  174. @param format: a message format using new-style (PEP 3101) formatting.
  175. The logging event (which is a L{dict}) is used to render this
  176. format string.
  177. @param kwargs: additional key/value pairs to include in the event.
  178. Note that values which are later mutated may result in
  179. non-deterministic behavior from observers that schedule work for
  180. later execution.
  181. """
  182. self.emit(LogLevel.info, format, **kwargs)
  183. def warn(self, format: Optional[str] = None, **kwargs: object) -> None:
  184. """
  185. Emit a log event at log level L{LogLevel.warn}.
  186. @param format: a message format using new-style (PEP 3101) formatting.
  187. The logging event (which is a L{dict}) is used to render this
  188. format string.
  189. @param kwargs: additional key/value pairs to include in the event.
  190. Note that values which are later mutated may result in
  191. non-deterministic behavior from observers that schedule work for
  192. later execution.
  193. """
  194. self.emit(LogLevel.warn, format, **kwargs)
  195. def error(self, format: Optional[str] = None, **kwargs: object) -> None:
  196. """
  197. Emit a log event at log level L{LogLevel.error}.
  198. @param format: a message format using new-style (PEP 3101) formatting.
  199. The logging event (which is a L{dict}) is used to render this
  200. format string.
  201. @param kwargs: additional key/value pairs to include in the event.
  202. Note that values which are later mutated may result in
  203. non-deterministic behavior from observers that schedule work for
  204. later execution.
  205. """
  206. self.emit(LogLevel.error, format, **kwargs)
  207. def critical(self, format: Optional[str] = None, **kwargs: object) -> None:
  208. """
  209. Emit a log event at log level L{LogLevel.critical}.
  210. @param format: a message format using new-style (PEP 3101) formatting.
  211. The logging event (which is a L{dict}) is used to render this
  212. format string.
  213. @param kwargs: additional key/value pairs to include in the event.
  214. Note that values which are later mutated may result in
  215. non-deterministic behavior from observers that schedule work for
  216. later execution.
  217. """
  218. self.emit(LogLevel.critical, format, **kwargs)
  219. _log = Logger()
  220. _loggerFor = lambda obj: _log.__get__(obj, obj.__class__)