async def r1(): Context.new() Context.logging.push(a=1) Context.track('test', 1.0) assert Context.logging.flat == {'a': 1} assert Context.current().tracking['test'].count == 1 await sub() # changes made by sub should be visible assert Context.logging.flat == {'a': 2} assert Context.current().tracking['test'].count == 2
async def r2(): # should be a separate context from r1 Context.new() Context.logging.push(a=3) Context.track('test', 1.0) assert Context.logging.flat == {'a': 3} assert Context.current().tracking['test'].count == 1
async def sub(): # should be same context as r1 assert Context.logging.flat == {'a': 1} Context.logging.push(a=2) Context.track('test', 1.0) assert Context.logging.flat == {'a': 2} assert Context.current().tracking['test'].count == 2
def test_metric_hook_user_name(context, get_breadcrumbs): r = mock_response(view='view') Context.current().metric_api_name = 'api' Context.current().metric_host_name = 'service' talisker.requests.metrics_response_hook(r) assert context.statsd[0] == 'requests.count.service.api:1|c' assert context.statsd[1] == ( 'requests.latency.service.api.200:1000.000000|ms') breadcrumbs = get_breadcrumbs() if breadcrumbs is not None: assert breadcrumbs[0]['type'] == 'http' assert breadcrumbs[0]['category'] == 'requests' assert breadcrumbs[0]['data']['url'] == 'http://example.com/' assert breadcrumbs[0]['data']['host'] == 'example.com' assert breadcrumbs[0]['data']['view'] == 'view' assert breadcrumbs[0]['data']['method'] == 'GET' assert breadcrumbs[0]['data']['status_code'] == 200 assert breadcrumbs[0]['data']['duration_ms'] == 1000.0
def request(method, url, **kwargs): ctx = Context.current() try: ctx.metric_api_name = kwargs.pop('metric_api_name', None) ctx.metric_host_name = kwargs.pop('metric_host_name', None) return func(method, url, **kwargs) finally: # some requests errors can cause the context to be lost, and we # should never fail due to this. try: del ctx.metric_api_name del ctx.metric_host_name except Exception: pass
def send(request, **kwargs): rid = Context.request_id if rid and config.id_header not in request.headers: request.headers[config.id_header] = rid ctx_deadline = Context.current().deadline if ctx_deadline: deadline = datetime.utcfromtimestamp(ctx_deadline) formatted = deadline.isoformat() + 'Z' request.headers[config.deadline_header] = formatted if Context.debug: request.headers[DEBUG_HEADER] = '1' try: return func(request, **kwargs) except Exception as e: record_request(request, None, e) raise
def record_request(request, response=None, exc=None): metadata = collect_metadata(request, response) if response: Context.track('http', metadata['duration_ms']) if exc: metadata.update(get_errno_fields(exc)) talisker.sentry.record_breadcrumb( type='http', category='requests', data=metadata, ) labels = { 'host': metadata['host'], 'view': metadata.get('view', 'unknown'), } ctx = Context.current() metric_api_name = getattr(ctx, 'metric_api_name', None) metric_host_name = getattr(ctx, 'metric_host_name', None) if metric_api_name is not None: labels['view'] = metric_api_name if metric_host_name is not None: labels['host'] = metric_host_name labels['host'] = labels['host'].replace('.', '-') RequestsMetric.count.inc(**labels) if response is None: # likely connection errors logger.exception('http request failure', extra=metadata) labels['type'] = 'connection' labels['status'] = metadata.get('errno', 'unknown') RequestsMetric.errors.inc(**labels) else: logger.info('http request', extra=metadata) labels['status'] = metadata['status_code'] RequestsMetric.latency.observe(metadata['duration_ms'], **labels) if metadata['status_code'] >= 500: labels['type'] = 'http' RequestsMetric.errors.inc(**labels)
def app(environ, _start_response): contexts.append(Context.current()) _start_response('200 OK', [('Content-Type', 'text/plain')]) return [b'OK']