Renan_Alonkin

Opencensus Middleware

Nov 13th, 2019
268
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 6.34 KB | None | 0 0
  1.  
  2. import logging
  3.  
  4. from starlette.requests import Request
  5. from google.rpc import code_pb2
  6. import sys
  7.  
  8. from opencensus.trace import span as span_module
  9. from opencensus.trace import stack_trace, status
  10. from opencensus.trace import tracer as tracer_module
  11. from opencensus.trace import utils
  12. from opencensus.trace.propagation import trace_context_http_header_format
  13. from opencensus.ext.azure.trace_exporter import AzureExporter
  14. from opencensus.ext.azure.log_exporter import AzureLogHandler
  15.  
  16. from opencensus.common import configuration
  17. from opencensus.trace import (
  18.     attributes_helper,
  19.     execution_context,
  20.     print_exporter,
  21.     samplers,
  22. )
  23.  
  24. HTTP_HOST = attributes_helper.COMMON_ATTRIBUTES['HTTP_HOST']
  25. HTTP_METHOD = attributes_helper.COMMON_ATTRIBUTES['HTTP_METHOD']
  26. HTTP_PATH = attributes_helper.COMMON_ATTRIBUTES['HTTP_PATH']
  27. HTTP_ROUTE = attributes_helper.COMMON_ATTRIBUTES['HTTP_ROUTE']
  28. HTTP_URL = attributes_helper.COMMON_ATTRIBUTES['HTTP_URL']
  29. HTTP_STATUS_CODE = attributes_helper.COMMON_ATTRIBUTES['HTTP_STATUS_CODE']
  30.  
  31. BLACKLIST_PATHS = 'BLACKLIST_PATHS'
  32. BLACKLIST_HOSTNAMES = 'BLACKLIST_HOSTNAMES'
  33.  
  34. connection_string = 'InstrumentationKey=##############################################'
  35.  
  36. # Logs are used to send error reports
  37. logger = logging.getLogger(__name__)
  38. logger.addHandler(AzureLogHandler(
  39.     connection_string=connection_string))
  40.  
  41. sampler = samplers.AlwaysOnSampler()
  42. exporter = AzureExporter(
  43.     connection_string=connection_string)
  44. propagator = trace_context_http_header_format.TraceContextPropagator()
  45.  
  46. class OpencensusMiddleware(object):
  47.  
  48.     def __init__(self, sampler=None, exporter=None, propagator=None):
  49.         self.sampler = sampler
  50.         self.exporter = exporter
  51.         self.propagator = propagator
  52.         self.tracer_instance = None
  53.         self.span_instance = None
  54.         self.init_app()
  55.  
  56.     def init_app(self):
  57.         if self.sampler is None:
  58.             self.sampler = samplers.ProbabilitySampler()
  59.  
  60.         if self.exporter is None:
  61.             self.exporter = print_exporter.PrintExporter()
  62.  
  63.         if self.propagator is None:
  64.             self.propagator = trace_context_http_header_format.TraceContextPropagator()
  65.  
  66.     def _before_request(self, request: Request):
  67.         """
  68.        This method sets the Tracer and creates the request Span.
  69.  
  70.        Args:
  71.        ---------
  72.            request: Request
  73.                An object with request's headers, values and body.  
  74.  
  75.        Return:
  76.        ---------
  77.  
  78.        """
  79.  
  80.         # Do not trace if the url is blacklisted
  81.         # --------------------- TODO review this later ---------------------
  82.         try:
  83.             span_context = self.propagator.from_headers(request.headers)
  84.             self.tracer_instance = tracer_module.Tracer(
  85.                 span_context=span_context,
  86.                 sampler=self.sampler,
  87.                 exporter=self.exporter,
  88.                 propagator=self.propagator)
  89.  
  90.             self.span_instance = self.tracer_instance.start_span()
  91.             self.span_instance.span_kind = span_module.SpanKind.SERVER
  92.             # Set the span name as the name of the current module name
  93.             self.span_instance.name = '[{}]{}'.format(
  94.                 request.method,
  95.                 request.url)
  96.             self.tracer_instance.add_attribute_to_current_span(
  97.                 HTTP_HOST, request.url.hostname
  98.             )
  99.             self.tracer_instance.add_attribute_to_current_span(
  100.                 HTTP_METHOD, request.method
  101.             )
  102.             self.tracer_instance.add_attribute_to_current_span(
  103.                 HTTP_PATH, request.url.path
  104.             )
  105.             self.tracer_instance.add_attribute_to_current_span(
  106.                 HTTP_URL, str(request.url)
  107.             )
  108.  
  109.         except Exception:  # pragma: NO COVER
  110.             logger.error('Failed to trace request', exc_info=True)
  111.  
  112.     def _after_request(self, response):
  113.         """
  114.        Sets the status code into the current Span.
  115.  
  116.        Args:
  117.        ---------
  118.            response: Response
  119.                An object with status code and prediction results.  
  120.  
  121.        Return:
  122.        ---------
  123.  
  124.        """
  125.         try:
  126.             self.tracer_instance.add_attribute_to_current_span(
  127.                 HTTP_STATUS_CODE,
  128.                 response.status_code
  129.             )
  130.         except Exception:  # pragma: NO COVER
  131.             logger.error('Failed to trace request', exc_info=True)
  132.         finally:
  133.             return response
  134.  
  135.     def _teardown_request(self, exception):
  136.         """
  137.        Inserts the response code and finishes the Span.
  138.  
  139.        Args:
  140.        ---------
  141.            exception: Exception
  142.                An object with request's headers, values and body.  
  143.  
  144.        Return:
  145.        ---------
  146.  
  147.        """
  148.         try:
  149.             self._throw_exceptions(
  150.                 span=self.span_instance, exception=exception)
  151.             self.tracer_instance.end_span()
  152.             self.tracer_instance.finish()
  153.         except Exception:  # pragma: NO COVER
  154.             logger.error('Failed to trace request', exc_info=True)
  155.  
  156.     def _throw_exceptions(self, span, exception):
  157.         """
  158.        Verify if exists an exception, assign it to a span and throws to Azure.
  159.  
  160.        Args:
  161.        ---------
  162.            span: Span
  163.                A time-span that threw an exception.
  164.            exception: Exception / HTTPException
  165.                Some error that needs to be thrown.
  166.  
  167.        Return:
  168.        ---------
  169.  
  170.        """
  171.         if exception is not None:
  172.             logger.exception(exception)
  173.             if span is not None:
  174.                 span.status = status.Status(
  175.                     code=code_pb2.UNKNOWN,
  176.                     message=str(exception)
  177.                 )
  178.                 # try attaching the stack trace to the span, only populated
  179.                 # if the app has 'PROPAGATE_EXCEPTIONS', 'DEBUG', or
  180.                 # 'TESTING' enabled
  181.                 exc_type, _, exc_traceback = sys.exc_info()
  182.                 if exc_traceback is not None:
  183.                     span.stack_trace = (
  184.                         stack_trace.StackTrace.from_traceback(
  185.                             exc_traceback
  186.                         )
  187.                     )
  188.  
  189.  
  190. opencensus_instance = OpencensusMiddleware(
  191.     sampler=sampler, exporter=exporter, propagator=propagator)
Add Comment
Please, Sign In to add comment