Não pode escolher mais do que 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.
 
 
 
 
 
 

172 linhas
5.7 KiB

  1. # Copyright 2019 The Matrix.org Foundation C.I.C.
  2. #
  3. # Licensed under the Apache License, Version 2.0 (the "License");
  4. # you may not use this file except in compliance with the License.
  5. # You may obtain a copy of the License at
  6. #
  7. # http://www.apache.org/licenses/LICENSE-2.0
  8. #
  9. # Unless required by applicable law or agreed to in writing, software
  10. # distributed under the License is distributed on an "AS IS" BASIS,
  11. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. # See the License for the specific language governing permissions and
  13. # limitations under the License.import logging
  14. import logging
  15. from types import TracebackType
  16. from typing import Optional, Type
  17. from opentracing import Scope, ScopeManager, Span
  18. import twisted
  19. from synapse.logging.context import (
  20. LoggingContext,
  21. current_context,
  22. nested_logging_context,
  23. )
  24. logger = logging.getLogger(__name__)
  25. class LogContextScopeManager(ScopeManager):
  26. """
  27. The LogContextScopeManager tracks the active scope in opentracing
  28. by using the log contexts which are native to synapse. This is so
  29. that the basic opentracing api can be used across twisted defereds.
  30. It would be nice just to use opentracing's ContextVarsScopeManager,
  31. but currently that doesn't work due to https://twistedmatrix.com/trac/ticket/10301.
  32. """
  33. def __init__(self) -> None:
  34. pass
  35. @property
  36. def active(self) -> Optional[Scope]:
  37. """
  38. Returns the currently active Scope which can be used to access the
  39. currently active Scope.span.
  40. If there is a non-null Scope, its wrapped Span
  41. becomes an implicit parent of any newly-created Span at
  42. Tracer.start_active_span() time.
  43. Return:
  44. The Scope that is active, or None if not available.
  45. """
  46. ctx = current_context()
  47. return ctx.scope
  48. def activate(self, span: Span, finish_on_close: bool) -> Scope:
  49. """
  50. Makes a Span active.
  51. Args
  52. span: the span that should become active.
  53. finish_on_close: whether Span should be automatically finished when
  54. Scope.close() is called.
  55. Returns:
  56. Scope to control the end of the active period for
  57. *span*. It is a programming error to neglect to call
  58. Scope.close() on the returned instance.
  59. """
  60. ctx = current_context()
  61. if not ctx:
  62. logger.error("Tried to activate scope outside of loggingcontext")
  63. return Scope(None, span) # type: ignore[arg-type]
  64. if ctx.scope is not None:
  65. # start a new logging context as a child of the existing one.
  66. # Doing so -- rather than updating the existing logcontext -- means that
  67. # creating several concurrent spans under the same logcontext works
  68. # correctly.
  69. ctx = nested_logging_context("")
  70. enter_logcontext = True
  71. else:
  72. # if there is no span currently associated with the current logcontext, we
  73. # just store the scope in it.
  74. #
  75. # This feels a bit dubious, but it does hack around a problem where a
  76. # span outlasts its parent logcontext (which would otherwise lead to
  77. # "Re-starting finished log context" errors).
  78. enter_logcontext = False
  79. scope = _LogContextScope(self, span, ctx, enter_logcontext, finish_on_close)
  80. ctx.scope = scope
  81. if enter_logcontext:
  82. ctx.__enter__()
  83. return scope
  84. class _LogContextScope(Scope):
  85. """
  86. A custom opentracing scope, associated with a LogContext
  87. * filters out _DefGen_Return exceptions which arise from calling
  88. `defer.returnValue` in Twisted code
  89. * When the scope is closed, the logcontext's active scope is reset to None.
  90. and - if enter_logcontext was set - the logcontext is finished too.
  91. """
  92. def __init__(
  93. self,
  94. manager: LogContextScopeManager,
  95. span: Span,
  96. logcontext: LoggingContext,
  97. enter_logcontext: bool,
  98. finish_on_close: bool,
  99. ):
  100. """
  101. Args:
  102. manager:
  103. the manager that is responsible for this scope.
  104. span:
  105. the opentracing span which this scope represents the local
  106. lifetime for.
  107. logcontext:
  108. the log context to which this scope is attached.
  109. enter_logcontext:
  110. if True the log context will be exited when the scope is finished
  111. finish_on_close:
  112. if True finish the span when the scope is closed
  113. """
  114. super().__init__(manager, span)
  115. self.logcontext = logcontext
  116. self._finish_on_close = finish_on_close
  117. self._enter_logcontext = enter_logcontext
  118. def __exit__(
  119. self,
  120. exc_type: Optional[Type[BaseException]],
  121. value: Optional[BaseException],
  122. traceback: Optional[TracebackType],
  123. ) -> None:
  124. if exc_type == twisted.internet.defer._DefGen_Return:
  125. # filter out defer.returnValue() calls
  126. exc_type = value = traceback = None
  127. super().__exit__(exc_type, value, traceback)
  128. def __str__(self) -> str:
  129. return f"Scope<{self.span}>"
  130. def close(self) -> None:
  131. active_scope = self.manager.active
  132. if active_scope is not self:
  133. logger.error(
  134. "Closing scope %s which is not the currently-active one %s",
  135. self,
  136. active_scope,
  137. )
  138. if self._finish_on_close:
  139. self.span.finish()
  140. self.logcontext.scope = None
  141. if self._enter_logcontext:
  142. self.logcontext.__exit__(None, None, None)