def add_attr_to_trace(key, value): """Add an attribute to the current span if tracing is enabled.""" if not execution_context: return tracer = execution_context.get_opencensus_tracer() tracer.add_attribute_to_current_span( attribute_key=key, attribute_value=value)
def stop_trace(): """Stop the current trace.""" if not execution_context: return execution_context.set_current_span(None) tracer = execution_context.get_opencensus_tracer() tracer.tracer = noop_tracer.NoopTracer() tracer.span_context = SpanContext(trace_options=trace_options.TraceOptions(0)) tracer.sampler = always_off.AlwaysOffSampler()
def perform_request(self, method, url, headers=None, params=None, body=None): span_name = 'es.{}'.format(url) tracer = execution_context.get_opencensus_tracer() with tracer.span(name=span_name) as span: span.add_attribute('elasticsearch.url', url) span.add_attribute('elasticsearch.method', method) if body: span.add_attribute('elasticsearch.statement', str(body)) if params: span.add_attribute('elasticsearch.params', str(params)) if headers: span.add_attribute('elasticsearch.headers', str(headers)) return super(TracingTransport, self).perform_request(method, url, headers, params, body)
def _after_request(self, response): """A function to be run after each request. See: http://flask.pocoo.org/docs/0.12/api/#flask.Flask.after_request """ # Do not trace if the url is blacklisted if utils.disable_tracing_url(flask.request.url, self.blacklist_paths): return response try: tracer = execution_context.get_opencensus_tracer() tracer.add_attribute_to_current_span(HTTP_STATUS_CODE, str(response.status_code)) tracer.end_span() tracer.finish() except Exception: # pragma: NO COVER log.error('Failed to trace request', exc_info=True) finally: return response
def template_test(): # Sleep for a random time to imitate a random processing time time.sleep(random.uniform(0, 0.5)) # Keyword that gets passed in will be concatenated to the final output string. output_string = app.config['keyword'] # If there is no endpoint, return the output string. url = app.config['endpoint'] if url == "": return output_string, 200 # Endpoint is the next service to send string to. data = {'body': output_string} # [START trace_context_header] trace_context_header = propagator.to_header( execution_context.get_opencensus_tracer().span_context) response = requests.get( url, params=data, headers={'X-Cloud-Trace-Context': trace_context_header}) # [END trace_context_header] return response.text + app.config['keyword']
def test_header_is_none(self): app = self.create_app() flask_middleware.FlaskMiddleware(app=app) context = app.test_request_context( path='/') with context: app.preprocess_request() tracer = execution_context.get_opencensus_tracer() self.assertIsNotNone(tracer) span = tracer.current_span() expected_attributes = { '/http/url': u'http://localhost/', '/http/method': 'GET', } self.assertEqual(span.attributes, expected_attributes) assert isinstance(span.parent_span, base.NullContextManager)
def test__before_request_blacklist(self): flask_trace_header = 'X_CLOUD_TRACE_CONTEXT' trace_id = '2dd43a1d6b2549c6bc2a1a54c2fc0b05' span_id = '6e0c63257de34c92' flask_trace_id = '{}/{}'.format(trace_id, span_id) app = self.create_app() flask_middleware.FlaskMiddleware(app=app) context = app.test_request_context( path='/_ah/health', headers={flask_trace_header: flask_trace_id}) with context: app.preprocess_request() tracer = execution_context.get_opencensus_tracer() assert isinstance(tracer, noop_tracer.NoopTracer) span = tracer.current_span() assert isinstance(span, base.NullContextManager)
def call(query, *args, **kwargs): _tracer = execution_context.get_opencensus_tracer() if _tracer is not None: # Note that although get_opencensus_tracer() returns a NoopTracer # if no thread local has been set, set_opencensus_tracer() does NOT # protect against setting None to the thread local - be defensive # here _span = _tracer.start_span() _span.name = '{}.query'.format(MODULE_NAME) _tracer.add_attribute_to_current_span( '{}/query'.format(MODULE_NAME), query) _tracer.add_attribute_to_current_span( '{}/cursor/method/name'.format(MODULE_NAME), query_func.__name__) result = query_func(query, *args, **kwargs) if _tracer is not None: _tracer.end_span() return result
def test__after_request_invalid_url(self): flask_trace_header = 'traceparent' trace_id = '2dd43a1d6b2549c6bc2a1a54c2fc0b05' span_id = '6e0c63257de34c92' flask_trace_id = '00-{}-{}-00'.format(trace_id, span_id) app = self.create_app() flask_middleware.FlaskMiddleware( app=app, sampler=samplers.AlwaysOnSampler() ) context = app.test_request_context( path='/this-url-does-not-exist', headers={flask_trace_header: flask_trace_id} ) with context: app.preprocess_request() tracer = execution_context.get_opencensus_tracer() self.assertIsNotNone(tracer) span = tracer.current_span() try: rv = app.dispatch_request() except NotFound as e: rv = app.handle_user_exception(e) app.finalize_request(rv) # http.route should not be set expected_attributes = { 'http.host': u'localhost', 'http.method': u'GET', 'http.path': u'/this-url-does-not-exist', 'http.url': u'http://localhost/this-url-does-not-exist', 'http.status_code': 404 } self.assertEqual(span.attributes, expected_attributes) assert isinstance(span.parent_span, base.NullContextManager)
def test__before_request(self): pyramid_trace_header = 'X-Cloud-Trace-Context' trace_id = '2dd43a1d6b2549c6bc2a1a54c2fc0b05' span_id = '6e0c63257de34c92' pyramid_trace_id = '{}/{}'.format(trace_id, span_id) response = Response() def dummy_handler(request): return response mock_registry = mock.Mock(spec=Registry) mock_registry.settings = {} middleware = pyramid_middleware.OpenCensusTweenFactory( dummy_handler, mock_registry, ) request = DummyRequest( registry=mock_registry, path='/', headers={pyramid_trace_header: pyramid_trace_id}, ) middleware._before_request(request) tracer = execution_context.get_opencensus_tracer() self.assertIsNotNone(tracer) span = tracer.current_span() expected_attributes = { '/http/url': u'/', '/http/method': 'GET', } self.assertEqual(span.attributes, expected_attributes) self.assertEqual(span.parent_span.span_id, span_id) span_context = tracer.span_context self.assertEqual(span_context.trace_id, trace_id)
def get_log_attrs(): """Get logging attributes from the opencensus context. :rtype: :class:`LogAttrs` :return: The current span's trace ID, span ID, and sampling decision. """ try: tracer = execution_context.get_opencensus_tracer() if tracer is None: raise RuntimeError except Exception: # noqa _meta_logger.error("Failed to get opencensus tracer") return ATTR_DEFAULTS try: trace_id = tracer.span_context.trace_id if trace_id is None: trace_id = ATTR_DEFAULTS.trace_id except Exception: # noqa _meta_logger.error("Failed to get opencensus trace ID") trace_id = ATTR_DEFAULTS.trace_id try: span_id = tracer.span_context.span_id if span_id is None: span_id = ATTR_DEFAULTS.span_id except Exception: # noqa _meta_logger.error("Failed to get opencensus span ID") span_id = ATTR_DEFAULTS.span_id try: sampling_decision = tracer.span_context.trace_options.get_enabled() if sampling_decision is None: sampling_decision = ATTR_DEFAULTS.sampling_decision except AttributeError: sampling_decision = ATTR_DEFAULTS.sampling_decision except Exception: # noqa _meta_logger.error("Failed to get opencensus sampling decision") sampling_decision = ATTR_DEFAULTS.sampling_decision return LogAttrs(trace_id, span_id, sampling_decision)
def call(self, method, url, body, headers, *args, **kwargs): _tracer = execution_context.get_opencensus_tracer() _span = _tracer.start_span() _span.name = '[httplib]{}'.format(request_func.__name__) # Add the request url to attributes _tracer.add_attribute_to_current_span(HTTP_URL, url) # Add the request method to attributes _tracer.add_attribute_to_current_span(HTTP_METHOD, method) # Store the current span id to thread local. execution_context.set_opencensus_attr( 'httplib/current_span_id', _span.span_id) try: headers = headers.copy() headers.update(_tracer.propagator.to_headers( _span.context_tracer.span_context)) except Exception: # pragma: NO COVER pass return request_func(self, method, url, body, headers, *args, **kwargs)
def GetFebStats(self, request, context): with get_opencensus_tracer().span(name="GetFebStats") as span: boxscores = request.boxscores # TODO: Add tenants when distributing the computations result = self.league_handler.export_boxscores(boxscores) response = feb_stats_pb2.GetFebStatsResponse() response.sheet = result response.teams.extend( [str(t) for t in self.league_handler.league.teams]) span.add_annotation( "League", name=str(self.league_handler.league.name), season=str(self.league_handler.league.season), number_of_teams=str(len(self.league_handler.league.teams)), number_of_games=str(len(self.league_handler.league.games)), ) self.league_handler.clean_league() return response
def format(self, record): context = execution_context.get_opencensus_tracer().span_context structured = { "message": super().format(record), "time": datetime.fromtimestamp(record.created, timezone.utc).isoformat(), "severity": record.levelname, "logging.googleapis.com/trace": "projects/%s/traces/%s" % (PROJECT_ID, context.trace_id), "logging.googleapis.com/sourceLocation": { "file": record.filename, "line": record.lineno, "function": record.funcName } } if context.span_id: structured["logging.googleapis.com/spanId"] = context.span_id return json.dumps(structured)
def call(self, *args, **kwargs): # Check if request was sent from an exporter. If so, do not wrap. if execution_context.is_exporter(): return response_func(self, *args, **kwargs) _tracer = execution_context.get_opencensus_tracer() current_span_id = execution_context.get_opencensus_attr( 'httplib/current_span_id') span = _tracer.current_span() # No corresponding request span is found, request not traced. if not span or span.span_id != current_span_id: return response_func(self, *args, **kwargs) result = response_func(self, *args, **kwargs) # Add the status code to attributes _tracer.add_attribute_to_current_span(HTTP_STATUS_CODE, result.status) _tracer.end_span() return result
def test_intercept_handler_no_metadata(self): patch = mock.patch( 'opencensus.trace.ext.grpc.server_interceptor.tracer_module.Tracer', MockTracer) mock_context = mock.Mock() mock_context.invocation_metadata = mock.Mock(return_value=None) interceptor = server_interceptor.OpenCensusServerInterceptor( None, None) with patch: interceptor.intercept_handler( mock.Mock(), mock.Mock() ).unary_unary(mock.Mock(), mock_context) expected_attributes = { '/component': 'grpc', } self.assertEqual( execution_context.get_opencensus_tracer().current_span().attributes, expected_attributes)
def _after_request(self, response): """A function to be run after each request. See: http://flask.pocoo.org/docs/0.12/api/#flask.Flask.after_request """ # Do not trace if the url is in the exclude list if utils.disable_tracing_url(flask.request.url, self.excludelist_paths): return response try: tracer = execution_context.get_opencensus_tracer() url_rule = flask.request.url_rule if url_rule is not None: tracer.add_attribute_to_current_span(HTTP_ROUTE, url_rule.rule) tracer.add_attribute_to_current_span(HTTP_STATUS_CODE, response.status_code) except Exception: # pragma: NO COVER log.error('Failed to trace request', exc_info=True) finally: return response
def test_intercept_handler(self): current_span = mock.Mock() mock_tracer = MockTracer(None, None, None) patch = mock.patch( 'opencensus.trace.ext.grpc.server_interceptor.tracer_module.Tracer', MockTracer) mock_details = mock.Mock() mock_details.invocation_metadata = (('test_key', b'test_value'), ) interceptor = server_interceptor.OpenCensusServerInterceptor( None, None) with patch: interceptor.intercept_handler(mock.Mock(), mock_details) expected_attributes = { '/component': 'grpc', } self.assertEqual( execution_context.get_opencensus_tracer().current_span.attributes, expected_attributes)
def test_header_is_none(self): from opencensus.trace import execution_context app = self.create_app() flask_middleware.FlaskMiddleware(app=app) context = app.test_request_context(path='/') with context: app.preprocess_request() tracer = execution_context.get_opencensus_tracer() self.assertIsNotNone(tracer) span = tracer.current_span() expected_labels = { '/http/url': u'http://localhost/', '/http/method': 'GET', } self.assertEqual(span.labels, expected_labels) self.assertIsNone(span.parent_span_id)
def wrap_session_request(wrapped, instance, args, kwargs): """Wrap the session function to trace it.""" method = kwargs.get('method') or args[0] url = kwargs.get('url') or args[1] _tracer = execution_context.get_opencensus_tracer() _span = _tracer.start_span() _span.name = '[requests]{}'.format(method) _span.span_kind = span_module.SpanKind.CLIENT # Add the requests url to attributes _tracer.add_attribute_to_current_span('requests/url', url) result = wrapped(*args, **kwargs) # Add the status code to attributes _tracer.add_attribute_to_current_span('requests/status_code', str(result.status_code)) _tracer.end_span() return result
def _finish_tracing_callback(future): tracer = execution_context.get_opencensus_tracer() status_code = None exc = future.exception() if exc: error = True if isinstance(exc, HTTPError): status_code = exc.code if status_code < 500: error = False if error: tracer.add_attribute_to_current_span(ERROR_MESSAGE, str(exc.message)) else: status_code = future.result().code if status_code is not None: tracer.add_attribute_to_current_span(HTTP_STATUS_CODE, str(status_code)) tracer.end_span()
def call(query, *args, **kwargs): _tracer = execution_context.get_opencensus_tracer() _span = None if _tracer is not None: # Note that although get_opencensus_tracer() returns a NoopTracer # if no thread local has been set, set_opencensus_tracer() does NOT # protect against setting None to the thread local - be defensive # here _span = _tracer.start_span() try: (sql_command, subcommand, *_) = query.split(maxsplit=2) if "COUNT(*)" == subcommand: _span.name = '{}.COUNT'.format(MODULE_NAME) else: _span.name = '{}.{}'.format(MODULE_NAME, sql_command) except: _span.name = '{}.OTHER'.format(MODULE_NAME) logger.warning("Could not parse SQL statement for detailed tracing", exc_info=True) _span.span_kind = span_module.SpanKind.CLIENT _tracer.add_attribute_to_current_span("component", MODULE_NAME) _tracer.add_attribute_to_current_span("db.type", "sql") _tracer.add_attribute_to_current_span( 'db.statement', query) _tracer.add_attribute_to_current_span( 'db.cursor.method.name', query_func.__name__) try: result = query_func(query, *args, **kwargs) except Exception as exc: if _span is not None: status = status_module.Status.from_exception(exc) _span.set_status(status) raise if _tracer is not None: _tracer.end_span() return result
def test__after_request_blacklist(self): from opencensus.trace import execution_context from opencensus.trace.tracers import base from opencensus.trace.tracers import noop_tracer from opencensus.trace.ext.pyramid import pyramid_middleware pyramid_trace_header = 'X_CLOUD_TRACE_CONTEXT' trace_id = '2dd43a1d6b2549c6bc2a1a54c2fc0b05' span_id = 1234 pyramid_trace_id = '{}/{}'.format(trace_id, span_id) response = Response() def dummy_handler(request): return response mock_registry = mock.Mock(spec=Registry) mock_registry.settings = {} middleware = pyramid_middleware.OpenCensusTweenFactory( dummy_handler, mock_registry, ) request = DummyRequest( registry=mock_registry, path='/_ah/health', headers={pyramid_trace_header: pyramid_trace_id}, ) middleware._before_request(request) tracer = execution_context.get_opencensus_tracer() assert isinstance(tracer, noop_tracer.NoopTracer) span = tracer.current_span() middleware._after_request(request, response) assert isinstance(span, base.NullContextManager)
def wrap_session_request(wrapped, instance, args, kwargs): """Wrap the session function to trace it.""" method = kwargs.get('method') or args[0] url = kwargs.get('url') or args[1] blacklist_hostnames = execution_context.get_opencensus_attr( 'blacklist_hostnames') parsed_url = urlparse(url) if parsed_url.port is None: dest_url = parsed_url.hostname else: dest_url = '{}:{}'.format(parsed_url.hostname, parsed_url.port) if utils.disable_tracing_hostname(dest_url, blacklist_hostnames): return wrapped(*args, **kwargs) _tracer = execution_context.get_opencensus_tracer() _span = _tracer.start_span() _span.name = '[requests]{}'.format(method) _span.span_kind = span_module.SpanKind.CLIENT try: tracer_headers = _tracer.propagator.to_headers( _tracer.span_context) kwargs.setdefault('headers', {}).update( tracer_headers) except Exception: # pragma: NO COVER pass # Add the requests url to attributes _tracer.add_attribute_to_current_span(HTTP_URL, url) result = wrapped(*args, **kwargs) # Add the status code to attributes _tracer.add_attribute_to_current_span( HTTP_STATUS_CODE, str(result.status_code)) _tracer.end_span() return result
async def request_started(self, request, query_string, parsed_query, operation_name, variables, context, request_context): self.query_string = query_string self.document = parsed_query tracer = execution_context.get_opencensus_tracer() tracer.start_span('gql') async def on_request_ended(errors): op_name = self.operation_name or '' document = request_context.get('document', None) signature = get_signature(request_context, operation_name, document, query_string) tracer = execution_context.get_opencensus_tracer() if SIGNATURE_HASH_KEY not in request_context: request_context[SIGNATURE_HASH_KEY] = compute(signature) tracer.current_span().name = 'gql[{}]'.format(request_context[SIGNATURE_HASH_KEY][0:12]) tracer.add_attribute_to_current_span('gql_operation_name', op_name) tracer.add_attribute_to_current_span('signature', signature) tracer.end_span() return on_request_ended
def test__before_request_blacklist(self): flask_trace_header = 'traceparent' trace_id = '2dd43a1d6b2549c6bc2a1a54c2fc0b05' span_id = '6e0c63257de34c92' flask_trace_id = '00-{}-{}-00'.format(trace_id, span_id) app = self.create_app() # Use the AlwaysOnSampler here to prove that the blacklist takes # precedence over the sampler flask_middleware.FlaskMiddleware(app=app, sampler=samplers.AlwaysOnSampler()) context = app.test_request_context( path='/_ah/health', headers={flask_trace_header: flask_trace_id}) with context: app.preprocess_request() tracer = execution_context.get_opencensus_tracer() assert isinstance(tracer, noop_tracer.NoopTracer) span = tracer.current_span() assert isinstance(span, BlankSpan)
def fft(x): # retrieve the stored tracer tracer = execution_context.get_opencensus_tracer() with tracer.span(name="fft") as span_fft: # tag the span with the signal being processed span_fft.add_attribute("x", ' '.join(str(x_i) for x_i in x)) n = len(x) t = exp(-2 * pi * 1j / n) if n > 1: even = fft(x[::2]) odd = fft(x[1::2]) x = even + odd for k in range(n // 2): x_k = x[k] x[k] = x_k + t**k * x[k + n // 2] x[k + n // 2] = x_k - t**k * x[k + n // 2] return x
def home(): locations = [] # Setup custom tracer # Get the Tracer object tracer = execution_context.get_opencensus_tracer() # Name should be descriptive with tracer.span(name="datastore.query()") as span: kind = "Hive" locations = [] for latlng in datastore_client.query(kind=kind).fetch(): locations.append({ 'loc': { "lat": latlng["LatLng"]['latitude'], "lon": latlng["LatLng"]['longitude'], }, "description": gettext("Authored by %(Firstname)s %(Familyname)s", Firstname=latlng['Firstname'], Familyname=latlng['Familyname']) }) location_count = len(locations) logger.debug("Found %d HiveLocation entries for map." % location_count) # Add info into our trace # Annotation: https://opencensus.io/tracing/span/time_events/annotation/ # Status: https://opencensus.io/tracing/span/status/ # For annotation first param is description, additional are freeform attributes span.add_annotation("Query all hive locations from datastore", kind=kind, count=location_count) if location_count > 0: span.status = Status(0, "Found %d hive locations." % location_count) else: # Not found span.status = Status(5, "Zero locations found.") return render_template("mymap.html", hive_locations=locations)
def trace_and_record_stats_with_key_and_value(method_name, fn, key, value, *args, **kwargs): __TRACER = execution_context.get_opencensus_tracer( ) or noop_tracer.NoopTracer() __STATS_RECORDER = stats.stats.stats_recorder start_time = time.time() tags = tag_map.TagMap() tags.insert(key_method, tag_value.TagValue(method_name)) mm = __STATS_RECORDER.new_measurement_map() with __TRACER.span(name=method_name) as span: try: return fn(*args, **kwargs) except Exception as e: span.status = Status.from_exception(e) tags.insert(key_status, "ERROR") tags.insert(key_error, e.__str__()) # Re-raise that exception after we've extracted the error. raise e else: tags.insert(key_status, "OK") finally: latency_ms = (time.time() - start_time) * 1e3 mm.measure_float_put(m_latency_ms, latency_ms) key_lengths = heuristical_lengths(key) value_lengths = heuristical_lengths(value) for key_length in key_lengths: mm.measure_int_put(m_key_length, key_length) for value_length in value_lengths: mm.measure_int_put(m_value_length, value_length) mm.record(tags)
def test_header_encoding(self): # The test is for detecting the encoding compatibility issue in # Python2 and Python3 and what flask does for encoding the headers. # This test case is expected to fail at the check_trace_id method # in SpanContext because it cannot match the pattern for trace_id, # And a new trace_id will generate for the context. flask_trace_header = 'traceparent' trace_id = "你好" span_id = '6e0c63257de34c92' flask_trace_id = '00-{}-{}-00'.format(trace_id, span_id) app = self.create_app() flask_middleware.FlaskMiddleware(app=app, sampler=samplers.AlwaysOnSampler()) context = app.test_request_context( path='/wiki/Rabbit', headers={flask_trace_header: flask_trace_id}) with context: app.preprocess_request() tracer = execution_context.get_opencensus_tracer() self.assertIsNotNone(tracer) span = tracer.current_span() expected_attributes = { 'http.host': u'localhost', 'http.method': u'GET', 'http.path': u'/wiki/Rabbit', 'http.url': u'http://localhost/wiki/Rabbit', } self.assertEqual(span.attributes, expected_attributes) assert isinstance(span.parent_span, base.NullContextManager) span_context = tracer.span_context self.assertNotEqual(span_context.trace_id, trace_id)
def home(request): _tracer = execution_context.get_opencensus_tracer() if _tracer is not None: headers = _tracer.propagator.to_headers(_tracer.span_context) else: headers = {} print(headers) response = requests.get('http://127.0.0.1:8081/', headers=headers) response.raise_for_status() weather = response.json() if isinstance(request.user, AnonymousUser): user = '******' else: user = request.user.get_username() users_count = auth.get_user_model().objects.count() return JsonResponse( dict( message='Hello, World!', weather_weather=weather['weather'][0], weather_location=weather['name'], user=user, users_count=users_count, ))
def main(): sampler = always_on.AlwaysOnSampler() exporter = print_exporter.PrintExporter() tracer = Tracer(sampler=sampler, exporter=exporter) with tracer.span(name='root'): tracer.add_attribute_to_current_span(attribute_key='example key', attribute_value='example value') function_to_trace() with tracer.span(name='child'): function_to_trace() # Get the current tracer tracer = execution_context.get_opencensus_tracer() # Explicitly create spans tracer.start_span() # Get current span execution_context.get_current_span() # Explicitly end span tracer.end_span()
def get_bg_trace(self, func): """Prepare the module_name and return a tracer.""" if not hasattr(self, 'module_name'): self.module_name = func.__module__.split('.')[-1] return execution_context.get_opencensus_tracer()
def tracer(*args, **kwargs): tracer = execution_context.get_opencensus_tracer() with tracer.span(name="%s" % (func.__name__)): return func(*args, **kwargs)