def test_handles_batched_traces(self): t1 = Trace('test', 1, 2) t2 = Trace('test2', 3, 4) cs1 = Annotation.client_send(1) cs2 = Annotation.client_send(2) cr1 = Annotation.client_recv(3) cr2 = Annotation.client_recv(4) self.tracer.record([(t1, [cs1, cr1]), (t2, [cs2, cr2])]) self.assertEqual(self.scribe.log.call_count, 1) args = self.scribe.log.mock_calls[0][1] self.assertEqual('restkin', args[0]) entries = args[1] self.assertEqual(len(entries), 1) self.assertEqual( json.loads(entries[0]), [{'trace_id': '0000000000000001', 'span_id': '0000000000000002', 'name': 'test', 'annotations': [ {'type': 'timestamp', 'value': 1, 'key': 'cs'}, {'type': 'timestamp', 'value': 3, 'key': 'cr'}]}, {'trace_id': '0000000000000003', 'span_id': '0000000000000004', 'name': 'test2', 'annotations': [ {'type': 'timestamp', 'value': 2, 'key': 'cs'}, {'type': 'timestamp', 'value': 4, 'key': 'cr'}]}])
def test_handles_batched_traces(self): t1 = self.trace t2 = Trace('test2', 3, 4) cs1 = Annotation.client_send(1) cs2 = Annotation.client_send(2) cr1 = Annotation.client_recv(3) cr2 = Annotation.client_recv(4) self.tracer.record([(t1, [cs1, cr1]), (t2, [cs2, cr2])]) self.assertEqual(self.agent.request.call_count, 1) args = self.agent.request.mock_calls[0][1] self.assertEqual(('POST', 'http://trace.it', Headers({})), args[:3]) bodyProducer = args[3] return self.assertBodyEquals( bodyProducer, [{'trace_id': '0000000000000001', 'span_id': '0000000000000002', 'name': 'test', 'annotations': [ {'type': 'timestamp', 'value': 1, 'key': 'cs'}, {'type': 'timestamp', 'value': 3, 'key': 'cr'} ]}, {'trace_id': '0000000000000003', 'span_id': '0000000000000004', 'name': 'test2', 'annotations': [ {'type': 'timestamp', 'value': 2, 'key': 'cs'}, {'type': 'timestamp', 'value': 4, 'key': 'cr'} ]}])
def test_handles_batched_traces(self): t1 = Trace('test', 1, 2) t2 = Trace('test2', 3, 4) cs1 = Annotation.client_send(1) cs2 = Annotation.client_send(2) cr1 = Annotation.client_recv(3) cr2 = Annotation.client_recv(4) self.tracer.record([(t1, [cs1, cr1]), (t2, [cs2, cr2])]) self.assertEqual(self.scribe.log.call_count, 1) args = self.scribe.log.mock_calls[0][1] self.assertEqual('restkin', args[0]) entries = args[1] self.assertEqual(len(entries), 1) self.assertEqual(json.loads(entries[0]), [{ 'trace_id': '0000000000000001', 'span_id': '0000000000000002', 'name': 'test', 'annotations': [{ 'type': 'timestamp', 'value': 1, 'key': 'cs' }, { 'type': 'timestamp', 'value': 3, 'key': 'cr' }] }, { 'trace_id': '0000000000000003', 'span_id': '0000000000000004', 'name': 'test2', 'annotations': [{ 'type': 'timestamp', 'value': 2, 'key': 'cs' }, { 'type': 'timestamp', 'value': 4, 'key': 'cr' }] }])
def test_handles_batched_traces(self): t1 = self.trace t2 = Trace('test2', 3, 4) cs1 = Annotation.client_send(1) cs2 = Annotation.client_send(2) cr1 = Annotation.client_recv(3) cr2 = Annotation.client_recv(4) self.tracer.record([(t1, [cs1, cr1]), (t2, [cs2, cr2])]) self.assertEqual(self.agent.request.call_count, 1) args = self.agent.request.mock_calls[0][1] self.assertEqual(('POST', 'http://trace.it', Headers({})), args[:3]) bodyProducer = args[3] return self.assertBodyEquals(bodyProducer, [{ 'trace_id': '0000000000000001', 'span_id': '0000000000000002', 'name': 'test', 'annotations': [{ 'type': 'timestamp', 'value': 1, 'key': 'cs' }, { 'type': 'timestamp', 'value': 3, 'key': 'cr' }] }, { 'trace_id': '0000000000000003', 'span_id': '0000000000000004', 'name': 'test2', 'annotations': [{ 'type': 'timestamp', 'value': 2, 'key': 'cs' }, { 'type': 'timestamp', 'value': 4, 'key': 'cr' }] }])
def fetch(self, request, *args, **kwargs): method, url = _request_info(request) ZipkinTracer.record(Annotation.string('Url', url)) ZipkinTracer.record(Annotation.client_send()) response = super(HTTPClient, self).fetch(request, *args, **kwargs) ZipkinTracer.record(Annotation.client_recv()) return response
def test_record_invokes_tracer(self): tracer = mock.Mock() t = Trace('test_trace', trace_id=1, span_id=1, tracers=[tracer]) annotation = Annotation.client_send(timestamp=0) t.record(annotation) tracer.record.assert_called_with([(t, (annotation,))])
def test_record_invokes_tracer(self): tracer = mock.Mock() t = Trace('test_trace', trace_id=1, span_id=1, tracers=[tracer]) annotation = Annotation.client_send(timestamp=0) t.record(annotation) tracer.record.assert_called_with([(t, (annotation, ))])
def test_handles_batched_traces(self): tracer = EndAnnotationTracer(self.tracer) t1 = Trace('test1', tracers=[tracer]) t2 = Trace('test2', tracers=[tracer]) cs1 = Annotation.client_send() cs2 = Annotation.client_send() cr1 = Annotation.client_recv() cr2 = Annotation.client_recv() tracer.record([(t1, [cs1, cr1]), (t2, [cs2, cr2])]) self.assertEqual(self.tracer.record.call_count, 2) self.tracer.record.assert_any_call([(t1, [cs1, cr1])]) self.tracer.record.assert_any_call([(t2, [cs2, cr2])])
def test_logs_to_scribe_immediately(self): tracer = RawZipkinTracer(self.scribe) t = Trace('test_raw_zipkin', 1, 2, tracers=[tracer]) t.record(Annotation.client_send(1)) self.scribe.log.assert_called_once_with('zipkin', [ 'CgABAAAAAAAAAAELAAMAAAAPdGVzdF9yYXdfemlwa2luCgAEAAAAAAAAAAIPAAY' 'MAAAAAQoAAQAA\nAAAAAAABCwACAAAAAmNzAA8ACAwAAAAAAA==' ])
def test_logs_to_scribe_immediately(self): tracer = RawZipkinTracer(self.scribe) t = Trace('test_raw_zipkin', 1, 2, tracers=[tracer]) t.record(Annotation.client_send(1)) self.scribe.log.assert_called_once_with( 'zipkin', ['CgABAAAAAAAAAAELAAMAAAAPdGVzdF9yYXdfemlwa2luCgAEAAAAAAAAAAIPAAY' 'MAAAAAQoAAQAA\nAAAAAAABCwACAAAAAmNzAA8ACAwAAAAAAA=='])
def test_traces_buffered_until_max_idle_time(self): completed_trace = (Trace('completed'), [Annotation.client_send(1), Annotation.client_recv(2)]) self.tracer.record([completed_trace]) self.assertEqual(self.record_function.call_count, 0) self.clock.advance(10) self.assertEqual(self.record_function.call_count, 1)
def fetch(self, request, callback=None, **kwargs): """Executes a request, asynchronously returning an `HTTPResponse`. The request may be either a string URL or an `HTTPRequest` object. If it is a string, we construct an `HTTPRequest` using any additional kwargs: ``HTTPRequest(request, **kwargs)`` This method returns a `.Future` whose result is an `HTTPResponse`. The ``Future`` wil raise an `HTTPError` if the request returned a non-200 response code. If a ``callback`` is given, it will be invoked with the `HTTPResponse`. In the callback interface, `HTTPError` is not automatically raised. Instead, you must check the response's ``error`` attribute or call its `~HTTPResponse.rethrow` method. """ if not isinstance(request, HTTPRequest): request = HTTPRequest(url=request, **kwargs) # We may modify this (to add Host, Accept-Encoding, etc), # so make sure we don't modify the caller's object. This is also # where normal dicts get converted to HTTPHeaders objects. request.headers = httputil.HTTPHeaders(request.headers) if options.client_trace: request.trace.record(Annotation.client_send()) request = _RequestProxy(request, self.defaults) future = TracebackFuture() if callback is not None: callback = stack_context.wrap(callback) def handle_future(future): exc = future.exception() if isinstance(exc, HTTPError) and exc.response is not None: response = exc.response elif exc is not None: response = HTTPResponse(request, 599, error=exc, request_time=time.time() - request.start_time) else: response = future.result() self.io_loop.add_callback(callback, response) future.add_done_callback(handle_future) def handle_response(response): if response.error: future.set_exception(response.error) else: future.set_result(response) if options.client_trace: request.trace.record(Annotation.client_recv()) self.fetch_impl(request, handle_response) return future
def test_handles_batched_traces(self): tracer = RawZipkinTracer(self.scribe) t1 = Trace('test_raw_zipkin', 1, 2, tracers=[tracer]) cs1 = Annotation.client_send(1) t2 = Trace('test_raw_zipkin', 1, 2, tracers=[tracer]) cs2 = Annotation.client_send(1) cr2 = Annotation.client_recv(2) tracer.record([(t1, [cs1]), (t2, [cs2, cr2])]) self.scribe.log.assert_called_once_with( 'zipkin', ['CgABAAAAAAAAAAELAAMAAAAPdGVzdF9yYXdfemlwa2luCgAEAAAAAAAAAAIPAAY' 'MAAAAAQoAAQAA\nAAAAAAABCwACAAAAAmNzAA8ACAwAAAAAAA==', 'CgABAAAAAAAAAAELAAMAAAAPdGVzdF9yYXdfemlwa2luCgAEAAAAAAAAAAIPAAY' 'MAAAAAgoAAQAA\nAAAAAAABCwACAAAAAmNzAAoAAQAAAAAAAAACCwACAAAAAmNy' 'AA8ACAwAAAAAAA=='])
def fetch(self, request, callback, *args, **kwargs): method, url = _request_info(request) ZipkinTracer.record(Annotation.string('Url', url)) ZipkinTracer.record(Annotation.client_send()) def wrapper(request, callback, response, *args): ZipkinTracer.record(Annotation.client_recv()) callback(response) super(AsyncHTTPClient, self).fetch( request, functools.partial(wrapper, request, callback), *args, **kwargs)
def test_writes_trace(self): t = Trace('test', 1, 2, tracers=[self.tracer]) t.record(Annotation.client_send(1)) self.assertEqual( json.loads(self.destination.getvalue()), [{'trace_id': '0000000000000001', 'span_id': '0000000000000002', 'name': 'test', 'annotations': [ {'type': 'timestamp', 'value': 1, 'key': 'cs'}]}])
def test_handles_batched_traces(self): tracer = RawZipkinTracer(self.scribe) t1 = Trace('test_raw_zipkin', 1, 2, tracers=[tracer]) cs1 = Annotation.client_send(1) t2 = Trace('test_raw_zipkin', 1, 2, tracers=[tracer]) cs2 = Annotation.client_send(1) cr2 = Annotation.client_recv(2) tracer.record([(t1, [cs1]), (t2, [cs2, cr2])]) self.scribe.log.assert_called_once_with('zipkin', [ 'CgABAAAAAAAAAAELAAMAAAAPdGVzdF9yYXdfemlwa2luCgAEAAAAAAAAAAIPAAY' 'MAAAAAQoAAQAA\nAAAAAAABCwACAAAAAmNzAA8ACAwAAAAAAA==', 'CgABAAAAAAAAAAELAAMAAAAPdGVzdF9yYXdfemlwa2luCgAEAAAAAAAAAAIPAAY' 'MAAAAAgoAAQAA\nAAAAAAABCwACAAAAAmNzAAoAAQAAAAAAAAACCwACAAAAAmNy' 'AA8ACAwAAAAAAA==' ])
def test_logs_to_scribe_with_non_default_category(self): tracer = RawZipkinTracer(self.scribe, 'not-zipkin') t = Trace('test_raw_zipkin', 1, 2, tracers=[tracer]) t.record(Annotation.client_send(1), Annotation.client_recv(2)) self.scribe.log.assert_called_once_with( 'not-zipkin', ['CgABAAAAAAAAAAELAAMAAAAPdGVzdF9yYXdfemlwa2luCgAEAAAAAAAAAAIPAAY' 'MAAAAAgoAAQAA\nAAAAAAABCwACAAAAAmNzAAoAAQAAAAAAAAACCwACAAAAAmNy' 'AA8ACAwAAAAAAA=='])
def test_logs_to_scribe_with_non_default_category(self): tracer = RawZipkinTracer(self.scribe, 'not-zipkin') t = Trace('test_raw_zipkin', 1, 2, tracers=[tracer]) t.record(Annotation.client_send(1), Annotation.client_recv(2)) self.scribe.log.assert_called_once_with('not-zipkin', [ 'CgABAAAAAAAAAAELAAMAAAAPdGVzdF9yYXdfemlwa2luCgAEAAAAAAAAAAIPAAY' 'MAAAAAgoAAQAA\nAAAAAAABCwACAAAAAmNzAAoAAQAAAAAAAAACCwACAAAAAmNy' 'AA8ACAwAAAAAAA==' ])
def test_delegates_on_end_annotation(self): tracer = EndAnnotationTracer(self.tracer) t = Trace('test_delegation', tracers=[tracer]) cs = Annotation.client_send() ce = Annotation.client_recv() t.record(cs) t.record(ce) self.tracer.record.assert_called_once_with([(t, [cs, ce])])
def test_record_sets_annotation_endpoint(self): tracer = mock.Mock() web_endpoint = Endpoint('127.0.0.1', 8080, 'web') t = Trace('test_trace', trace_id=1, span_id=1, tracers=[tracer]) t.set_endpoint(web_endpoint) annotation = Annotation.client_send(timestamp=1) t.record(annotation) tracer.record.assert_called_with([(t, (annotation, ))]) self.assertEqual(annotation.endpoint, web_endpoint)
def test_traces_buffered_until_max_idle_time(self): completed_trace = (Trace('completed'), [ Annotation.client_send(1), Annotation.client_recv(2) ]) self.tracer.record([completed_trace]) self.assertEqual(self.record_function.call_count, 0) self.clock.advance(10) self.assertEqual(self.record_function.call_count, 1)
def test_record_sets_annotation_endpoint(self): tracer = mock.Mock() web_endpoint = Endpoint('127.0.0.1', 8080, 'web') t = Trace('test_trace', trace_id=1, span_id=1, tracers=[tracer]) t.set_endpoint(web_endpoint) annotation = Annotation.client_send(timestamp=1) t.record(annotation) tracer.record.assert_called_with([(t, (annotation,))]) self.assertEqual(annotation.endpoint, web_endpoint)
def request(self, method, uri, headers=None, bodyProducer=None): """ Send a client request following HTTP redirects. @see: L{Agent.request}. """ if self._parent_trace is None: trace = Trace(method) else: trace = self._parent_trace.child(method) if self._endpoint is not None: trace.set_endpoint(self._endpoint) if headers is None: headers = Headers({}) # These headers are based on the headers used by finagle's tracing # http Codec. # # https://github.com/twitter/finagle/blob/master/finagle-http/ # # Currently not implemented are X-B3-Sampled and X-B3-Flags # Tryfer's underlying Trace implementation has no notion of a Sampled # trace and I haven't figured out what flags are for. headers.setRawHeaders('X-B3-TraceId', [hex_str(trace.trace_id)]) headers.setRawHeaders('X-B3-SpanId', [hex_str(trace.span_id)]) if trace.parent_span_id is not None: headers.setRawHeaders('X-B3-ParentSpanId', [hex_str(trace.parent_span_id)]) # Similar to the headers above we use the annotation 'http.uri' for # because that is the standard set forth in the finagle http Codec. trace.record(Annotation.string('http.uri', uri)) trace.record(Annotation.client_send()) def _finished(resp): # TODO: It may be advantageous here to return a wrapped response # whose deliverBody can wrap it's protocol and record when the # application has finished reading the contents. trace.record(Annotation.string( 'http.responsecode', '{0} {1}'.format(resp.code, resp.phrase))) trace.record(Annotation.client_recv()) return resp d = self._agent.request(method, uri, headers, bodyProducer) d.addBoth(_finished) return d
def fetch(self, request, callback=None, **kwargs): """Executes a request, asynchronously returning an `HTTPResponse`. The request may be either a string URL or an `HTTPRequest` object. If it is a string, we construct an `HTTPRequest` using any additional kwargs: ``HTTPRequest(request, **kwargs)`` This method returns a `.Future` whose result is an `HTTPResponse`. The ``Future`` wil raise an `HTTPError` if the request returned a non-200 response code. If a ``callback`` is given, it will be invoked with the `HTTPResponse`. In the callback interface, `HTTPError` is not automatically raised. Instead, you must check the response's ``error`` attribute or call its `~HTTPResponse.rethrow` method. """ if not isinstance(request, HTTPRequest): request = HTTPRequest(url=request, **kwargs) # We may modify this (to add Host, Accept-Encoding, etc), # so make sure we don't modify the caller's object. This is also # where normal dicts get converted to HTTPHeaders objects. request.headers = httputil.HTTPHeaders(request.headers) if options.client_trace: request.trace.record(Annotation.client_send()) request = _RequestProxy(request, self.defaults) future = TracebackFuture() if callback is not None: callback = stack_context.wrap(callback) def handle_future(future): exc = future.exception() if isinstance(exc, HTTPError) and exc.response is not None: response = exc.response elif exc is not None: response = HTTPResponse( request, 599, error=exc, request_time=time.time() - request.start_time) else: response = future.result() self.io_loop.add_callback(callback, response) future.add_done_callback(handle_future) def handle_response(response): if response.error: future.set_exception(response.error) else: future.set_result(response) if options.client_trace: request.trace.record(Annotation.client_recv()) self.fetch_impl(request, handle_response) return future
def request(self, method, uri, headers=None, bodyProducer=None): """ Send a client request following HTTP redirects. @see: L{Agent.request}. """ if self._parent_trace is None: trace = Trace(method) else: trace = self._parent_trace.child(method) if self._endpoint is not None: trace.set_endpoint(self._endpoint) if headers is None: headers = Headers({}) # These headers are based on the headers used by finagle's tracing # http Codec. # # https://github.com/twitter/finagle/blob/master/finagle-http/ # # Currently not implemented are X-B3-Sampled and X-B3-Flags # Tryfer's underlying Trace implementation has no notion of a Sampled # trace and I haven't figured out what flags are for. headers.setRawHeaders('X-B3-TraceId', [hex_str(trace.trace_id)]) headers.setRawHeaders('X-B3-SpanId', [hex_str(trace.span_id)]) if trace.parent_span_id is not None: headers.setRawHeaders('X-B3-ParentSpanId', [hex_str(trace.parent_span_id)]) # Similar to the headers above we use the annotation 'http.uri' for # because that is the standard set forth in the finagle http Codec. trace.record(Annotation.string('http.uri', uri)) trace.record(Annotation.client_send()) def _finished(resp): # TODO: It may be advantageous here to return a wrapped response # whose deliverBody can wrap it's protocol and record when the # application has finished reading the contents. trace.record( Annotation.string('http.responsecode', '{0} {1}'.format(resp.code, resp.phrase))) trace.record(Annotation.client_recv()) return resp d = self._agent.request(method, uri, headers, bodyProducer) d.addBoth(_finished) return d
def test_non_default_end(self): tracer = EndAnnotationTracer(self.tracer, end_annotations=['timeout']) t = Trace('test_non-default', tracers=[tracer]) cs = Annotation.client_send() t.record(cs) timeout = Annotation.timestamp('timeout') t.record(timeout) self.tracer.record.assert_called_once_with([(t, [cs, timeout])])
def test_traces_bufferred_until_max_traces(self): completed_traces = [ (Trace('completed'), [Annotation.client_send(1), Annotation.client_recv(2)]) for x in xrange(50)] self.tracer.record(completed_traces[:10]) self.clock.advance(1) self.assertEqual(self.record_function.call_count, 0) self.tracer.record(completed_traces[10:]) self.clock.advance(1) self.assertEqual(self.record_function.call_count, 1)
def test_traces_bufferred_until_max_traces(self): completed_traces = [ (Trace('completed'), [Annotation.client_send(1), Annotation.client_recv(2)]) for x in xrange(50) ] self.tracer.record(completed_traces[:10]) self.clock.advance(1) self.assertEqual(self.record_function.call_count, 0) self.tracer.record(completed_traces[10:]) self.clock.advance(1) self.assertEqual(self.record_function.call_count, 1)
def test_writes_trace(self): t = Trace('test', 1, 2, tracers=[self.tracer]) t.record(Annotation.client_send(1)) self.assertEqual( json.loads(self.destination.getvalue()), [{ 'trace_id': '0000000000000001', 'span_id': '0000000000000002', 'name': 'test', 'annotations': [{ 'type': 'timestamp', 'value': 1, 'key': 'cs' }] }])
def test_posts_immediately(self): self.trace.record(Annotation.client_send(1)) self.assertEqual(self.agent.request.call_count, 1) args = self.agent.request.mock_calls[0][1] self.assertEqual(('POST', 'http://trace.it', Headers({})), args[:3]) bodyProducer = args[3] return self.assertBodyEquals( bodyProducer, [{'trace_id': '0000000000000001', 'span_id': '0000000000000002', 'name': 'test', 'annotations': [ {'type': 'timestamp', 'value': 1, 'key': 'cs'} ]}])
def test_traces_immediately(self): t = Trace('test', 1, 2, tracers=[self.tracer]) t.record(Annotation.client_send(1)) self.assertEqual(self.scribe.log.call_count, 1) args = self.scribe.log.mock_calls[0][1] self.assertEqual('restkin', args[0]) entries = args[1] self.assertEqual(len(entries), 1) self.assertEqual( json.loads(entries[0]), [{'trace_id': '0000000000000001', 'span_id': '0000000000000002', 'name': 'test', 'annotations': [ {'type': 'timestamp', 'value': 1, 'key': 'cs'}]}])
def test_posts_immediately(self): self.trace.record(Annotation.client_send(1)) self.assertEqual(self.agent.request.call_count, 1) args = self.agent.request.mock_calls[0][1] self.assertEqual(('POST', 'http://trace.it', Headers({})), args[:3]) bodyProducer = args[3] return self.assertBodyEquals( bodyProducer, [{ 'trace_id': '0000000000000001', 'span_id': '0000000000000002', 'name': 'test', 'annotations': [{ 'type': 'timestamp', 'value': 1, 'key': 'cs' }] }])
def test_traces_immediately(self): t = Trace('test', 1, 2, tracers=[self.tracer]) t.record(Annotation.client_send(1)) self.assertEqual(self.scribe.log.call_count, 1) args = self.scribe.log.mock_calls[0][1] self.assertEqual('restkin', args[0]) entries = args[1] self.assertEqual(len(entries), 1) self.assertEqual( json.loads(entries[0]), [{ 'trace_id': '0000000000000001', 'span_id': '0000000000000002', 'name': 'test', 'annotations': [{ 'type': 'timestamp', 'value': 1, 'key': 'cs' }] }])
def test_client_send(self): a = Annotation.client_send() self.assertEqual(a.value, 1000000) self.assertEqual(a.name, 'cs') self.assertEqual(a.annotation_type, 'timestamp')
def test_no_unfinished_traces(self): unfinished_trace = (Trace('unfinished'), [Annotation.client_send(1)]) self.tracer.record([unfinished_trace]) self.assertEqual(self.record_function.call_count, 0)
def process(self, data): msg = json.loads(data) if msg["frontend_name"] == "haproxy_monitoring": return frontend = FE_OR_BE.search(msg["frontend_name"]).group(2) backend = FE_OR_BE.search(msg["backend_name"]).group(2) server = SERVER_SUB.sub("_", msg["server_name"]) # Consider server received to be the accept_date plus the time to # receive request headers. accept = parse_date_micro(msg["accept_date"]) request = int(msg["time_request"]) * 1000 if request < 0: request = 0 sr = accept + request ctrace = Trace(msg["http_verb"], trace_id=int_or_none(msg.get("zipkin_trace_id")), span_id=int_or_none(msg.get("zipkin_next_span_id")), parent_span_id=int_or_none(msg.get("zipkin_span_id")), tracers=self.tracers) # There's an assumption here and in the server endpoint that the 'host' # parsed by Logstash from the syslog message is the same host as the # service is running on. endpoint = Endpoint(msg["host"], 0, backend) ctrace.set_endpoint(endpoint) # For client sent we consider the time in queue plus backend connect # time (which is the time to get the SYN/ACK from the backend). queue = int(msg["time_queue"]) * 1000 if queue < 0: queue = 0 connect = int(msg["time_backend_connect"]) * 1000 if connect < 0: connect = 0 cs = sr + queue + connect ctrace.record(Annotation.client_send(cs)) ctrace.record(Annotation.string('haproxy.backend.server_name', server)) # Record response time in ms into an annotation since it doesn't fit # anywhere in zipkin. response = int(msg["time_backend_response"]) * 1000 if response < 0: response = 0 ctrace.record(Annotation.string("haproxy.backend.time", str(response))) ctrace.record(Annotation.string("haproxy.backend.queue", msg["backend_queue"])) # Apache sends the duration in microseconds already. For haproxy we # have to convert from ms. duration = int(msg["time_duration"]) if msg["program"] == "haproxy": duration = duration * 1000 if duration < 0: duration = 0 # Assume client response time to be the same as the request duration # minus a microsecond, just to keep ordering. ss = sr + duration cr = ss - 1 ctrace.record(Annotation.client_recv(cr)) # The top-level span is generally Apache. We record the parent span id # as '-' there if the parent span id is missing so convert to None. parent_span_id = msg.get("zipkin_parent_span_id") if parent_span_id is not None and parent_span_id == "-": parent_span_id = None strace = Trace(msg["http_verb"], trace_id=int_or_none(msg.get("zipkin_trace_id")), span_id=int_or_none(msg.get("zipkin_span_id")), parent_span_id=int_or_none(parent_span_id), tracers=self.tracers) endpoint = Endpoint(msg["host"], 0, frontend) strace.set_endpoint(endpoint) strace.record(Annotation.server_recv(sr)) strace.record(Annotation.string('http.uri', msg["http_request"])) strace.record(Annotation.string( 'http.responsecode', msg["http_status_code"])) strace.record(Annotation.server_send(ss))