def test_s3_put(self): s3 = self.session.create_client("s3", region_name="us-west-2") Pin(service=self.TEST_SERVICE, tracer=self.tracer).onto(s3) params = { "Bucket": "mybucket", "CreateBucketConfiguration": { "LocationConstraint": "us-west-2", }, } s3.create_bucket(**params) params = dict(Key="foo", Bucket="mybucket", Body=b"bar") s3.put_object(**params) spans = self.get_spans() assert spans span = spans[0] self.assertEqual(len(spans), 2) self.assertEqual(span.get_tag("aws.operation"), "CreateBucket") assert_is_measured(span) assert_span_http_status_code(span, 200) self.assertEqual(span.service, "test-botocore-tracing.s3") self.assertEqual(span.resource, "s3.createbucket") self.assertEqual(spans[1].get_tag("aws.operation"), "PutObject") self.assertEqual(spans[1].resource, "s3.putobject") self.assertEqual(spans[1].get_tag("params.Key"), stringify(params["Key"])) self.assertEqual(spans[1].get_tag("params.Bucket"), stringify(params["Bucket"])) # confirm blacklisted self.assertIsNone(spans[1].get_tag("params.Body"))
def test_s3_put(self): params = dict(Key="foo", Bucket="mybucket", Body=b"bar") with aiobotocore_client("s3", self.tracer) as s3: yield from s3.create_bucket(Bucket="mybucket") yield from s3.put_object(**params) spans = [trace[0] for trace in self.pop_traces()] assert spans self.assertEqual(len(spans), 2) self.assertEqual(spans[0].get_tag("aws.operation"), "CreateBucket") assert_is_measured(spans[0]) assert_span_http_status_code(spans[0], 200) self.assertEqual(spans[0].service, "aws.s3") self.assertEqual(spans[0].resource, "s3.createbucket") assert_is_measured(spans[1]) self.assertEqual(spans[1].get_tag("aws.operation"), "PutObject") self.assertEqual(spans[1].resource, "s3.putobject") self.assertEqual(spans[1].get_tag("params.Key"), stringify(params["Key"])) self.assertEqual(spans[1].get_tag("params.Bucket"), stringify(params["Bucket"])) self.assertIsNone(spans[1].get_tag("params.Body"))
def _handle_error(span, response_error, status_code): # response_error should be a grpc.Future and so we expect to have cancelled(), # exception() and traceback() methods if a computation has resulted in an # exception being raised if ( not callable(getattr(response_error, "cancelled", None)) and not callable(getattr(response_error, "exception", None)) and not callable(getattr(response_error, "traceback", None)) ): return if response_error.cancelled(): # handle cancelled futures separately to avoid raising grpc.FutureCancelledError span.error = 1 exc_val = to_unicode(response_error.details()) span._set_str_tag(ERROR_MSG, exc_val) span._set_str_tag(ERROR_TYPE, status_code) return exception = response_error.exception() traceback = response_error.traceback() if exception is not None and traceback is not None: span.error = 1 if isinstance(exception, grpc.RpcError): # handle internal gRPC exceptions separately to get status code and # details as tags properly exc_val = to_unicode(response_error.details()) span._set_str_tag(ERROR_MSG, exc_val) span._set_str_tag(ERROR_TYPE, status_code) span._set_str_tag(ERROR_STACK, stringify(traceback)) else: exc_type = type(exception) span.set_exc_info(exc_type, exception, traceback) status_code = to_unicode(response_error.code())
def test_set_http_meta(span, int_config, method, url, status_code, status_msg, query, request_headers): int_config.http.trace_headers(["my-header"]) int_config.trace_query_string = True trace_utils.set_http_meta( span, int_config, method=method, url=url, status_code=status_code, status_msg=status_msg, query=query, request_headers=request_headers, ) if method is not None: assert span.get_tag(http.METHOD) == method else: assert http.METHOD not in span.get_tags() if url is not None: assert span.get_tag(http.URL) == stringify(url) else: assert http.URL not in span.get_tags() if status_code is not None: assert span.get_tag(http.STATUS_CODE) == str(status_code) if 500 <= int(status_code) < 600: assert span.error == 1 else: assert span.error == 0 else: assert http.STATUS_CODE not in span.get_tags() if status_msg is not None: assert span.get_tag(http.STATUS_MSG) == stringify(status_msg) if query is not None and int_config.trace_query_string: assert span.get_tag(http.QUERY_STRING) == query if request_headers is not None: for header, value in request_headers.items(): tag = "http.request.headers." + header assert span.get_tag(tag) == value
async def test_s3_put(tracer): params = dict(Key="foo", Bucket="mybucket", Body=b"bar") with aiobotocore_client("s3", tracer) as s3: await s3.create_bucket(Bucket="mybucket") await s3.put_object(**params) spans = [trace[0] for trace in tracer.pop_traces()] assert spans assert len(spans) == 2 assert spans[0].get_tag("aws.operation") == "CreateBucket" assert_is_measured(spans[0]) assert_span_http_status_code(spans[0], 200) assert spans[0].service == "aws.s3" assert spans[0].resource == "s3.createbucket" assert_is_measured(spans[1]) assert spans[1].get_tag("aws.operation") == "PutObject" assert spans[1].resource == "s3.putobject" assert spans[1].get_tag("params.Key") == stringify(params["Key"]) assert spans[1].get_tag("params.Bucket") == stringify(params["Bucket"]) assert spans[1].get_tag("params.Body") is None
class PyMySQLCore(object): """PyMySQL test case reuses the connection across tests""" conn = None DB_INFO = { "out.host": MYSQL_CONFIG.get("host"), } if PY2: DB_INFO.update({ "db.user": MYSQL_CONFIG.get("user"), "db.name": MYSQL_CONFIG.get("database") }) else: DB_INFO.update({ "db.user": stringify(bytes(MYSQL_CONFIG.get("user"), encoding="utf-8")), "db.name": stringify(bytes(MYSQL_CONFIG.get("database"), encoding="utf-8")), }) def setUp(self): super(PyMySQLCore, self).setUp() patch() def tearDown(self): super(PyMySQLCore, self).tearDown() if self.conn and not self.conn._closed: self.conn.close() unpatch() def _get_conn_tracer(self): # implement me pass def test_simple_query(self): conn, tracer = self._get_conn_tracer() cursor = conn.cursor() # PyMySQL returns back the rowcount instead of a cursor rowcount = cursor.execute("SELECT 1") assert rowcount == 1 rows = cursor.fetchall() assert len(rows) == 1 spans = tracer.pop() assert len(spans) == 1 span = spans[0] assert_is_measured(span) assert span.service == "pymysql" assert span.name == "pymysql.query" assert span.span_type == "sql" assert span.error == 0 assert span.get_metric("out.port") == MYSQL_CONFIG.get("port") meta = {} meta.update(self.DB_INFO) assert_dict_issuperset(span.get_tags(), meta) def test_simple_query_fetchall(self): with self.override_config("pymysql", dict(trace_fetch_methods=True)): conn, tracer = self._get_conn_tracer() cursor = conn.cursor() cursor.execute("SELECT 1") rows = cursor.fetchall() assert len(rows) == 1 spans = tracer.pop() assert len(spans) == 2 span = spans[0] assert_is_measured(span) assert span.service == "pymysql" assert span.name == "pymysql.query" assert span.span_type == "sql" assert span.error == 0 assert span.get_metric("out.port") == MYSQL_CONFIG.get("port") meta = {} meta.update(self.DB_INFO) assert_dict_issuperset(span.get_tags(), meta) fetch_span = spans[1] assert fetch_span.name == "pymysql.query.fetchall" def test_query_with_several_rows(self): conn, tracer = self._get_conn_tracer() cursor = conn.cursor() query = "SELECT n FROM (SELECT 42 n UNION SELECT 421 UNION SELECT 4210) m" cursor.execute(query) rows = cursor.fetchall() assert len(rows) == 3 spans = tracer.pop() assert len(spans) == 1 self.assertEqual(spans[0].name, "pymysql.query") def test_query_with_several_rows_fetchall(self): with self.override_config("pymysql", dict(trace_fetch_methods=True)): conn, tracer = self._get_conn_tracer() cursor = conn.cursor() query = "SELECT n FROM (SELECT 42 n UNION SELECT 421 UNION SELECT 4210) m" cursor.execute(query) rows = cursor.fetchall() assert len(rows) == 3 spans = tracer.pop() assert len(spans) == 2 fetch_span = spans[1] assert fetch_span.name == "pymysql.query.fetchall" def test_query_many(self): # tests that the executemany method is correctly wrapped. conn, tracer = self._get_conn_tracer() tracer.enabled = False cursor = conn.cursor() cursor.execute(""" create table if not exists dummy ( dummy_key VARCHAR(32) PRIMARY KEY, dummy_value TEXT NOT NULL)""") tracer.enabled = True stmt = "INSERT INTO dummy (dummy_key, dummy_value) VALUES (%s, %s)" data = [("foo", "this is foo"), ("bar", "this is bar")] # PyMySQL `executemany()` returns the rowcount rowcount = cursor.executemany(stmt, data) assert rowcount == 2 query = "SELECT dummy_key, dummy_value FROM dummy ORDER BY dummy_key" cursor.execute(query) rows = cursor.fetchall() assert len(rows) == 2 assert rows[0][0] == "bar" assert rows[0][1] == "this is bar" assert rows[1][0] == "foo" assert rows[1][1] == "this is foo" spans = tracer.pop() assert len(spans) == 2 cursor.execute("drop table if exists dummy") def test_query_many_fetchall(self): with self.override_config("pymysql", dict(trace_fetch_methods=True)): # tests that the executemany method is correctly wrapped. conn, tracer = self._get_conn_tracer() tracer.enabled = False cursor = conn.cursor() cursor.execute(""" create table if not exists dummy ( dummy_key VARCHAR(32) PRIMARY KEY, dummy_value TEXT NOT NULL)""") tracer.enabled = True stmt = "INSERT INTO dummy (dummy_key, dummy_value) VALUES (%s, %s)" data = [("foo", "this is foo"), ("bar", "this is bar")] cursor.executemany(stmt, data) query = "SELECT dummy_key, dummy_value FROM dummy ORDER BY dummy_key" cursor.execute(query) rows = cursor.fetchall() assert len(rows) == 2 assert rows[0][0] == "bar" assert rows[0][1] == "this is bar" assert rows[1][0] == "foo" assert rows[1][1] == "this is foo" spans = tracer.pop() assert len(spans) == 3 cursor.execute("drop table if exists dummy") fetch_span = spans[2] assert fetch_span.name == "pymysql.query.fetchall" def test_query_proc(self): conn, tracer = self._get_conn_tracer() # create a procedure tracer.enabled = False cursor = conn.cursor() cursor.execute("DROP PROCEDURE IF EXISTS sp_sum") cursor.execute(""" CREATE PROCEDURE sp_sum (IN p1 INTEGER, IN p2 INTEGER, OUT p3 INTEGER) BEGIN SET p3 := p1 + p2; END;""") tracer.enabled = True proc = "sp_sum" data = (40, 2, None) # spans[len(spans) - 2] cursor.callproc(proc, data) # spans[len(spans) - 1] cursor.execute(""" SELECT @_sp_sum_0, @_sp_sum_1, @_sp_sum_2 """) output = cursor.fetchone() assert len(output) == 3 assert output[2] == 42 spans = tracer.pop() assert spans, spans # number of spans depends on PyMySQL implementation details, # typically, internal calls to execute, but at least we # can expect the last closed span to be our proc. span = spans[len(spans) - 2] assert_is_measured(span) assert span.service == "pymysql" assert span.name == "pymysql.query" assert span.span_type == "sql" assert span.error == 0 assert span.get_metric("out.port") == MYSQL_CONFIG.get("port") meta = {} meta.update(self.DB_INFO) assert_dict_issuperset(span.get_tags(), meta) def test_simple_query_ot(self): """OpenTracing version of test_simple_query.""" conn, tracer = self._get_conn_tracer() ot_tracer = init_tracer("mysql_svc", tracer) with ot_tracer.start_active_span("mysql_op"): cursor = conn.cursor() cursor.execute("SELECT 1") rows = cursor.fetchall() assert len(rows) == 1 spans = tracer.pop() assert len(spans) == 2 ot_span, dd_span = spans # confirm parenting assert ot_span.parent_id is None assert dd_span.parent_id == ot_span.span_id assert ot_span.service == "mysql_svc" assert ot_span.name == "mysql_op" assert_is_measured(dd_span) assert dd_span.service == "pymysql" assert dd_span.name == "pymysql.query" assert dd_span.span_type == "sql" assert dd_span.error == 0 assert dd_span.get_metric("out.port") == MYSQL_CONFIG.get("port") meta = {} meta.update(self.DB_INFO) assert_dict_issuperset(dd_span.get_tags(), meta) def test_simple_query_ot_fetchall(self): """OpenTracing version of test_simple_query.""" with self.override_config("pymysql", dict(trace_fetch_methods=True)): conn, tracer = self._get_conn_tracer() ot_tracer = init_tracer("mysql_svc", tracer) with ot_tracer.start_active_span("mysql_op"): cursor = conn.cursor() cursor.execute("SELECT 1") rows = cursor.fetchall() assert len(rows) == 1 spans = tracer.pop() assert len(spans) == 3 ot_span, dd_span, fetch_span = spans # confirm parenting assert ot_span.parent_id is None assert dd_span.parent_id == ot_span.span_id assert ot_span.service == "mysql_svc" assert ot_span.name == "mysql_op" assert_is_measured(dd_span) assert dd_span.service == "pymysql" assert dd_span.name == "pymysql.query" assert dd_span.span_type == "sql" assert dd_span.error == 0 assert dd_span.get_metric("out.port") == MYSQL_CONFIG.get("port") meta = {} meta.update(self.DB_INFO) assert_dict_issuperset(dd_span.get_tags(), meta) assert fetch_span.name == "pymysql.query.fetchall" def test_commit(self): conn, tracer = self._get_conn_tracer() conn.commit() spans = tracer.pop() assert len(spans) == 1 span = spans[0] assert span.service == "pymysql" assert span.name == "pymysql.connection.commit" def test_rollback(self): conn, tracer = self._get_conn_tracer() conn.rollback() spans = tracer.pop() assert len(spans) == 1 span = spans[0] assert span.service == "pymysql" assert span.name == "pymysql.connection.rollback" def test_analytics_default(self): conn, tracer = self._get_conn_tracer() cursor = conn.cursor() cursor.execute("SELECT 1") rows = cursor.fetchall() assert len(rows) == 1 spans = tracer.pop() self.assertEqual(len(spans), 1) span = spans[0] self.assertIsNone(span.get_metric(ANALYTICS_SAMPLE_RATE_KEY)) def test_analytics_with_rate(self): with self.override_config( "pymysql", dict(analytics_enabled=True, analytics_sample_rate=0.5)): conn, tracer = self._get_conn_tracer() cursor = conn.cursor() cursor.execute("SELECT 1") rows = cursor.fetchall() assert len(rows) == 1 spans = tracer.pop() self.assertEqual(len(spans), 1) span = spans[0] self.assertEqual(span.get_metric(ANALYTICS_SAMPLE_RATE_KEY), 0.5) def test_analytics_without_rate(self): with self.override_config("pymysql", dict(analytics_enabled=True)): conn, tracer = self._get_conn_tracer() cursor = conn.cursor() cursor.execute("SELECT 1") rows = cursor.fetchall() assert len(rows) == 1 spans = tracer.pop() self.assertEqual(len(spans), 1) span = spans[0] self.assertEqual(span.get_metric(ANALYTICS_SAMPLE_RATE_KEY), 1.0)