def __init__(self, tracer, service, engine): self.tracer = tracer self.engine = engine self.vendor = sqlx.normalize_vendor(engine.name) self.service = service or self.vendor self.name = "%s.query" % self.vendor # set the service info. self.tracer.set_service_info(service=self.service, app=self.vendor, app_type=sqlx.APP_TYPE) self._span_buffer = ThreadLocalSpanBuffer() listen(engine, 'before_cursor_execute', self._before_cur_exec) listen(engine, 'after_cursor_execute', self._after_cur_exec) listen(engine, 'dbapi_error', self._dbapi_error)
class EngineTracer(object): def __init__(self, tracer, service, engine): self.tracer = tracer self.engine = engine self.vendor = sqlx.normalize_vendor(engine.name) self.service = service or self.vendor self.name = "%s.query" % self.vendor # set the service info. self.tracer.set_service_info( service=self.service, app=self.vendor, app_type=sqlx.APP_TYPE) self._span_buffer = ThreadLocalSpanBuffer() listen(engine, 'before_cursor_execute', self._before_cur_exec) listen(engine, 'after_cursor_execute', self._after_cur_exec) listen(engine, 'dbapi_error', self._dbapi_error) def _before_cur_exec(self, conn, cursor, statement, *args): self._span_buffer.pop() # should always be empty span = self.tracer.trace( self.name, service=self.service, span_type=sqlx.TYPE, resource=statement) # keep the unnormalized query span.set_tag(sqlx.QUERY, statement) if not _set_tags_from_url(span, conn.engine.url): _set_tags_from_cursor(span, self.vendor, cursor) self._span_buffer.set(span) def _after_cur_exec(self, conn, cursor, statement, *args): span = self._span_buffer.pop() if not span: return try: if cursor and cursor.rowcount >= 0: span.set_tag(sqlx.ROWS, cursor.rowcount) finally: span.finish() def _dbapi_error(self, conn, cursor, statement, *args): span = self._span_buffer.pop() if not span: return try: span.set_traceback() finally: span.finish()
def test_thread_local_buffer(self): # the internal buffer must be thread-safe tb = ThreadLocalSpanBuffer() def _set_get(): eq_(tb.get(), None) span = Span(tracer=None, name='client.testing') tb.set(span) eq_(span, tb.get()) threads = [threading.Thread(target=_set_get) for _ in range(20)] for t in threads: t.daemon = True t.start() for t in threads: t.join()
class TraceMiddleware(object): def __init__(self, tracer, service="falcon"): self.tracer = tracer self.service = service self.buffer = ThreadLocalSpanBuffer() def process_request(self, req, resp): self.buffer.pop() # we should never really have anything here. span = self.tracer.trace( "falcon.request", service=self.service, span_type=httpx.TYPE, ) span.set_tag(httpx.METHOD, req.method) span.set_tag(httpx.URL, req.url) self.buffer.set(span) def process_resource(self, req, resp, resource, params): span = self.buffer.get() if not span: return # unexpected span.resource = "%s %s" % (req.method, _name(resource)) def process_response(self, req, resp, resource): span = self.buffer.pop() if not span: return # unexpected status = httpx.normalize_status_code(resp.status) # FIXME[matt] falcon does not map errors or unmatched routes # to proper status codes, so we we have to try to infer them # here. See https://github.com/falconry/falcon/issues/606 if resource is None: span.resource = "%s 404" % req.method status = '404' # If we have an active unhandled error, treat it as a 500 span.set_traceback() err_msg = span.get_tag(errx.ERROR_MSG) if err_msg and not _is_404(err_msg): status = '500' span.set_tag(httpx.STATUS_CODE, status) span.finish()
def tearDown(self): # undo gevent monkey patching reload(thread); reload(threading) from ddtrace.buffer import ThreadLocalSpanBuffer from ddtrace import tracer; tracer.span_buffer = ThreadLocalSpanBuffer()
def __init__(self, tracer, service="falcon"): self.tracer = tracer self.service = service self.buffer = ThreadLocalSpanBuffer()