opentracing.rst 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. ===========
  2. Opentracing
  3. ===========
  4. Background
  5. ----------
  6. Opentracing is semi-standard being addopted by a number of distributed tracing
  7. platforms. It is a standardised api for facilitating vendor agnostic tracing
  8. instrumentation. That is, we can use the opentracing api and select one of a
  9. number of tracer implementations to do the heavy lifting in the background.
  10. Our current selected implementation is Jaeger.
  11. Opentracing concepts can be found at
  12. https://opentracing.io/docs/overview/what-is-tracing/
  13. Python specific tracing concepts are at https://opentracing.io/guides/python/.
  14. Note that synapse wraps opentracing in a small library in order to make the
  15. opentracing dependency optional. That means that the access patterns are
  16. different to those demonstrated here. However, it is still usefull to know.
  17. Especially if opentracing is included as a full dependency in the future or if
  18. you are modifying synapse's opentracing lib.
  19. For more information about Jaeger's implementation see
  20. https://www.jaegertracing.io/docs/
  21. =================
  22. Setup opentracing
  23. =================
  24. To receive opentracing spans start up a Jaeger server using docker like so
  25. .. code-block:: bash
  26. docker run -d --name jaeger \ -e COLLECTOR_ZIPKIN_HTTP_PORT=9411 \
  27. -p 5775:5775/udp \
  28. -p 6831:6831/udp \
  29. -p 6832:6832/udp \
  30. -p 5778:5778 \
  31. -p 16686:16686 \
  32. -p 14268:14268 \
  33. -p 9411:9411 \
  34. jaegertracing/all-in-one:1.13
  35. Latest documentation is probably at
  36. https://www.jaegertracing.io/docs/1.13/getting-started/
  37. Enable opentracing in synapse
  38. -----------------------------
  39. Opentracing is not enabled by default. It must be enabled in the homeserver
  40. config by uncommenting the config options under ``opentracing``. For example:
  41. .. code-block:: yaml
  42. opentracing:
  43. # Enable / disable tracer
  44. tracer_enabled: true
  45. # The list of homeservers we wish to expose our current traces to.
  46. # The list is a list of regexes which are matched against the
  47. # servername of the homeserver
  48. homeserver_whitelist:
  49. - ".*"
  50. Homeserver whitelisting
  51. -----------------------
  52. The homeserver whitelist is configured using regex. A list of regexes can be
  53. given and their union will be compared when propagating any spans through a
  54. carrier. Most of the whitelist checks are encapsulated in the lib's injection
  55. and extraction method but be aware that using custom carriers or crossing
  56. unchartered waters will require the enforcement of this whitelist.
  57. ``logging/opentracing.py`` has a ``whitelisted_homeserver`` method which takes
  58. in a destination and compares it to the whitelist.
  59. ============================
  60. Using opentracing in synapse
  61. ============================
  62. Access to the opentracing api is mediated through the
  63. ``logging/opentracing.py`` lib. Opentracing is encapsulated such that
  64. no statefull spans from opentracing are used in synapses code. This allows
  65. opentracing to be easily disabled in synapse and thereby have opentracing as
  66. an optional dependency. This does however limit the number of modifyable spans
  67. at any point in the code to one. From here out references to opentracing refer
  68. to the lib implemented in synapse.
  69. Tracing
  70. -------
  71. In synapse it is not possible to start a non-active span. Spans can be started
  72. using the ``opentracing.start_active_span`` method. This returns a scope (see
  73. opentracing docs) which is a context manager that needs to be entered and
  74. exited. This is usually done by using ``with``.
  75. .. code-block:: python
  76. with start_active_span("operation name"):
  77. # Do something we want to tracer
  78. Forgetting to enter or exit a scope will result in some mysterious grevious log
  79. context errors.
  80. At anytime where there is an active span ``opentracing.set_tag`` can be used to
  81. set a tag on the current active span.
  82. Tracing functions
  83. -----------------
  84. Functions can be easily traced using decorators. There is a decorator for
  85. 'normal' function and for functions which are actually deferreds. The name of
  86. function becomes the operation name for the span.
  87. .. code-block:: python
  88. # Start a span using 'normal_function' as the operation name
  89. @trace
  90. def normal_function(*args, **kwargs):
  91. # Does all kinds of cool and expected things
  92. return something_usual_and_useful
  93. # Start a span using 'deferred_function' as the operation name
  94. @trace_deferred
  95. # Yes, there is a typo in the lib. I will fix this
  96. def deferred_function(*args, **kwargs):
  97. # We start
  98. yield we_wait
  99. # we finish
  100. defer.returnValue(something_usual_and_useful)
  101. Operation names can be explicitely set for functions by using
  102. ``trace_using_operation_name`` and
  103. ``trace_deferred_using_operation_name``
  104. .. code-block:: python
  105. @trace_using_operation_name("A *much* better operation name")
  106. def normal_function(*args, **kwargs):
  107. # Does all kinds of cool and expected things
  108. return something_usual_and_useful
  109. @trace_deferred_using_operation_name("An operation name that fixes the typo!")
  110. # Yes, there is a typo in the lib. I will fix this
  111. def deferred_function(*args, **kwargs):
  112. # We start
  113. yield we_wait
  114. # we finish
  115. defer.returnValue(something_usual_and_useful)
  116. Contexts and carriers
  117. ---------------------
  118. There are a selection of wrappers for injecting and extracting contexts from
  119. carriers provided. Unfortunately opentracing's standard three are not adequate
  120. in the majority of cases. Also note that the binnary encoding format mandated
  121. by opentracing is not actually implemented by Jaeger and it will silently noop.
  122. Please refer to the the end of ``logging/opentracing.py`` for the available
  123. injection and extraction methods.
  124. ==================
  125. Configuring Jaeger
  126. ==================
  127. Sampling strategies can be set as in this document:
  128. https://www.jaegertracing.io/docs/1.13/sampling/
  129. =======
  130. Gotchas
  131. =======
  132. - Checking whitelists on span propagation
  133. - Inserting pii
  134. - Forgetting to enter or exit a scope
  135. - Span source: make sure that the span you expect to be active across a
  136. function call really will be that one. Does the current function have more
  137. than one caller? Will all of those calling functions have be in a context
  138. with an active span?