diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index d39178473..47b839637 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -19,6 +19,11 @@ Please describe the tests that you ran to verify your changes. Provide instructi - [ ] Test A +# Does This PR Require a Core Repo Change? + +- [ ] Yes. - Link to PR: +- [ ] No. + # Checklist: See [contributing.md](https://github.com/open-telemetry/opentelemetry-python-contrib/blob/master/CONTRIBUTING.md) for styleguide, changelog guidelines, and more. diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index fc2c043d1..ab79b7047 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -6,7 +6,7 @@ on: - 'release/*' pull_request: env: - CORE_REPO_SHA: 47483865854c7adae7455f8441dab7f814f4ce2a + CORE_REPO_SHA: 3b813eb9921e709538dd1b07fa7a5f93600fbec1 jobs: build: diff --git a/.gitignore b/.gitignore index fa3e412d8..92e9ccd05 100644 --- a/.gitignore +++ b/.gitignore @@ -16,6 +16,7 @@ var sdist develop-eggs .installed.cfg +pyvenv.cfg lib lib64 __pycache__ diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e28d36567..c3176b51d 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -46,7 +46,7 @@ You can run: - `tox -e lint` to run lint checks on all code See -[`tox.ini`](https://github.com/open-telemetry/opentelemetry-python/blob/master/tox.ini) +[`tox.ini`](https://github.com/open-telemetry/opentelemetry-python-contrib/blob/master/tox.ini) for more detail on available tox commands. ## Pull Requests diff --git a/_template/README.rst b/_template/README.rst index 32fcbfe3e..7eb48e6b1 100644 --- a/_template/README.rst +++ b/_template/README.rst @@ -19,5 +19,5 @@ Installation References ---------- -* `OpenTelemetry / Tracing /.html>`_ +* `OpenTelemetry / Tracing /.html>`_ * `OpenTelemetry Project `_ diff --git a/exporter/opentelemetry-exporter-datadog/setup.cfg b/exporter/opentelemetry-exporter-datadog/setup.cfg index 45bf200ee..d40e6eb8a 100644 --- a/exporter/opentelemetry-exporter-datadog/setup.cfg +++ b/exporter/opentelemetry-exporter-datadog/setup.cfg @@ -19,7 +19,7 @@ long_description = file: README.rst long_description_content_type = text/x-rst author = OpenTelemetry Authors author_email = cncf-opentelemetry-contributors@lists.cncf.io -url = https://github.com/open-telemetry/opentelemetry-python/exporter/opentelemetry-exporter-datadog +url = https://github.com/open-telemetry/opentelemetry-python-contrib/exporter/opentelemetry-exporter-datadog platforms = any license = Apache-2.0 classifiers = diff --git a/instrumentation/opentelemetry-instrumentation-aiohttp-client/setup.cfg b/instrumentation/opentelemetry-instrumentation-aiohttp-client/setup.cfg index e0fcfbf4b..9a7b3866c 100644 --- a/instrumentation/opentelemetry-instrumentation-aiohttp-client/setup.cfg +++ b/instrumentation/opentelemetry-instrumentation-aiohttp-client/setup.cfg @@ -19,7 +19,7 @@ long_description = file: README.rst long_description_content_type = text/x-rst author = OpenTelemetry Authors author_email = cncf-opentelemetry-contributors@lists.cncf.io -url = https://github.com/open-telemetry/opentelemetry-python/instrumentation/opentelemetry-instrumentation-aiohttp-client +url = https://github.com/open-telemetry/opentelemetry-python-contrib/instrumentation/opentelemetry-instrumentation-aiohttp-client platforms = any license = Apache-2.0 classifiers = diff --git a/instrumentation/opentelemetry-instrumentation-aiopg/README.rst b/instrumentation/opentelemetry-instrumentation-aiopg/README.rst index f7a66579d..c616c6b96 100644 --- a/instrumentation/opentelemetry-instrumentation-aiopg/README.rst +++ b/instrumentation/opentelemetry-instrumentation-aiopg/README.rst @@ -17,5 +17,5 @@ Installation References ---------- -* `OpenTelemetry aiopg Instrumentation `_ +* `OpenTelemetry aiopg Instrumentation `_ * `OpenTelemetry Project `_ diff --git a/instrumentation/opentelemetry-instrumentation-aiopg/setup.cfg b/instrumentation/opentelemetry-instrumentation-aiopg/setup.cfg index c903180e9..ad12511bc 100644 --- a/instrumentation/opentelemetry-instrumentation-aiopg/setup.cfg +++ b/instrumentation/opentelemetry-instrumentation-aiopg/setup.cfg @@ -19,7 +19,7 @@ long_description = file: README.rst long_description_content_type = text/x-rst author = OpenTelemetry Authors author_email = cncf-opentelemetry-contributors@lists.cncf.io -url = https://github.com/open-telemetry/opentelemetry-python/tree/master/instrumentation/opentelemetry-instrumentation-aiopg +url = https://github.com/open-telemetry/opentelemetry-python-contrib/tree/master/instrumentation/opentelemetry-instrumentation-aiopg platforms = any license = Apache-2.0 classifiers = diff --git a/instrumentation/opentelemetry-instrumentation-aiopg/src/opentelemetry/instrumentation/aiopg/aiopg_integration.py b/instrumentation/opentelemetry-instrumentation-aiopg/src/opentelemetry/instrumentation/aiopg/aiopg_integration.py index 14f986da0..982423756 100644 --- a/instrumentation/opentelemetry-instrumentation-aiopg/src/opentelemetry/instrumentation/aiopg/aiopg_integration.py +++ b/instrumentation/opentelemetry-instrumentation-aiopg/src/opentelemetry/instrumentation/aiopg/aiopg_integration.py @@ -101,9 +101,16 @@ class AsyncTracedCursor(TracedCursor): *args: typing.Tuple[typing.Any, typing.Any], **kwargs: typing.Dict[typing.Any, typing.Any] ): + name = "" + if len(args) > 0 and args[0]: + name = args[0] + elif self._db_api_integration.database: + name = self._db_api_integration.database + else: + name = self._db_api_integration.name with self._db_api_integration.get_tracer().start_as_current_span( - self._db_api_integration.name, kind=SpanKind.CLIENT + name, kind=SpanKind.CLIENT ) as span: self._populate_span(span, *args) try: diff --git a/instrumentation/opentelemetry-instrumentation-aiopg/tests/test_aiopg_integration.py b/instrumentation/opentelemetry-instrumentation-aiopg/tests/test_aiopg_integration.py index 89e7cc05a..c6f771e1b 100644 --- a/instrumentation/opentelemetry-instrumentation-aiopg/tests/test_aiopg_integration.py +++ b/instrumentation/opentelemetry-instrumentation-aiopg/tests/test_aiopg_integration.py @@ -215,12 +215,12 @@ class TestAiopgIntegration(TestBase): spans_list = self.memory_exporter.get_finished_spans() self.assertEqual(len(spans_list), 1) span = spans_list[0] - self.assertEqual(span.name, "testcomponent.testdatabase") + self.assertEqual(span.name, "Test query") self.assertIs(span.kind, trace_api.SpanKind.CLIENT) self.assertEqual(span.attributes["component"], "testcomponent") - self.assertEqual(span.attributes["db.type"], "testtype") - self.assertEqual(span.attributes["db.instance"], "testdatabase") + self.assertEqual(span.attributes["db.system"], "testcomponent") + self.assertEqual(span.attributes["db.name"], "testdatabase") self.assertEqual(span.attributes["db.statement"], "Test query") self.assertEqual( span.attributes["db.statement.parameters"], @@ -230,7 +230,7 @@ class TestAiopgIntegration(TestBase): self.assertEqual(span.attributes["net.peer.name"], "testhost") self.assertEqual(span.attributes["net.peer.port"], 123) self.assertIs( - span.status.status_code, trace_api.status.StatusCode.UNSET, + span.status.status_code, trace_api.status.StatusCode.UNSET ) def test_span_not_recording(self): @@ -281,7 +281,7 @@ class TestAiopgIntegration(TestBase): span = spans_list[0] self.assertEqual(span.attributes["db.statement"], "Test query") self.assertIs( - span.status.status_code, trace_api.status.StatusCode.ERROR, + span.status.status_code, trace_api.status.StatusCode.ERROR ) self.assertEqual(span.status.description, "Test Exception") diff --git a/instrumentation/opentelemetry-instrumentation-asgi/setup.cfg b/instrumentation/opentelemetry-instrumentation-asgi/setup.cfg index dafb83794..207c757ca 100644 --- a/instrumentation/opentelemetry-instrumentation-asgi/setup.cfg +++ b/instrumentation/opentelemetry-instrumentation-asgi/setup.cfg @@ -19,7 +19,7 @@ long_description = file: README.rst long_description_content_type = text/x-rst author = OpenTelemetry Authors author_email = cncf-opentelemetry-contributors@lists.cncf.io -url = https://github.com/open-telemetry/opentelemetry-python/instrumentation/opentelemetry-instrumentation-asgi +url = https://github.com/open-telemetry/opentelemetry-python-contrib/instrumentation/opentelemetry-instrumentation-asgi platforms = any license = Apache-2.0 classifiers = diff --git a/instrumentation/opentelemetry-instrumentation-asyncpg/README.rst b/instrumentation/opentelemetry-instrumentation-asyncpg/README.rst index 33c60852c..27f9e0f9d 100644 --- a/instrumentation/opentelemetry-instrumentation-asyncpg/README.rst +++ b/instrumentation/opentelemetry-instrumentation-asyncpg/README.rst @@ -19,5 +19,5 @@ Installation References ---------- -* `OpenTelemetry asyncpg Instrumentation `_ +* `OpenTelemetry asyncpg Instrumentation `_ * `OpenTelemetry Project `_ diff --git a/instrumentation/opentelemetry-instrumentation-asyncpg/setup.cfg b/instrumentation/opentelemetry-instrumentation-asyncpg/setup.cfg index 0e0e32fc8..3c863b188 100644 --- a/instrumentation/opentelemetry-instrumentation-asyncpg/setup.cfg +++ b/instrumentation/opentelemetry-instrumentation-asyncpg/setup.cfg @@ -19,7 +19,7 @@ long_description = file: README.rst long_description_content_type = text/x-rst author = OpenTelemetry Authors author_email = cncf-opentelemetry-contributors@lists.cncf.io -url = https://github.com/open-telemetry/opentelemetry-python/instrumentation/opentelemetry-instrumentation-asyncpg +url = https://github.com/open-telemetry/opentelemetry-python-contrib/instrumentation/opentelemetry-instrumentation-asyncpg platforms = any license = Apache-2.0 classifiers = diff --git a/instrumentation/opentelemetry-instrumentation-boto/README.rst b/instrumentation/opentelemetry-instrumentation-boto/README.rst index 2b40321c0..bd962fb5f 100644 --- a/instrumentation/opentelemetry-instrumentation-boto/README.rst +++ b/instrumentation/opentelemetry-instrumentation-boto/README.rst @@ -19,5 +19,5 @@ Installation References ---------- -* `OpenTelemetry Boto Tracing `_ +* `OpenTelemetry Boto Tracing `_ * `OpenTelemetry Project `_ diff --git a/instrumentation/opentelemetry-instrumentation-boto/setup.cfg b/instrumentation/opentelemetry-instrumentation-boto/setup.cfg index fadbac4c5..e621830d3 100644 --- a/instrumentation/opentelemetry-instrumentation-boto/setup.cfg +++ b/instrumentation/opentelemetry-instrumentation-boto/setup.cfg @@ -19,7 +19,7 @@ long_description = file: README.rst long_description_content_type = text/x-rst author = OpenTelemetry Authors author_email = cncf-opentelemetry-contributors@lists.cncf.io -url = https://github.com/open-telemetry/opentelemetry-python/tree/master/instrumentation/opentelemetry-instrumentation-boto +url = https://github.com/open-telemetry/opentelemetry-python-contrib/tree/master/instrumentation/opentelemetry-instrumentation-boto platforms = any license = Apache-2.0 classifiers = diff --git a/instrumentation/opentelemetry-instrumentation-boto/src/opentelemetry/instrumentation/boto/__init__.py b/instrumentation/opentelemetry-instrumentation-boto/src/opentelemetry/instrumentation/boto/__init__.py index 57a6fb16f..58dee0ba7 100644 --- a/instrumentation/opentelemetry-instrumentation-boto/src/opentelemetry/instrumentation/boto/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-boto/src/opentelemetry/instrumentation/boto/__init__.py @@ -48,13 +48,15 @@ from boto.connection import AWSAuthConnection, AWSQueryConnection from wrapt import wrap_function_wrapper from opentelemetry.instrumentation.boto.version import __version__ -from opentelemetry.instrumentation.botocore import add_span_arg_tags, unwrap from opentelemetry.instrumentation.instrumentor import BaseInstrumentor +from opentelemetry.instrumentation.utils import unwrap from opentelemetry.sdk.trace import Resource from opentelemetry.trace import SpanKind, get_tracer logger = logging.getLogger(__name__) +SERVICE_PARAMS_BLOCK_LIST = {"s3": ["params.Body"]} + def _get_instance_region_name(instance): region = getattr(instance, "region", None) @@ -201,3 +203,50 @@ class BotoInstrumentor(BaseInstrumentor): args, kwargs, ) + + +def flatten_dict(dict_, sep=".", prefix=""): + """ + Returns a normalized dict of depth 1 with keys in order of embedding + """ + # NOTE: This should probably be in `opentelemetry.instrumentation.utils`. + # adapted from https://stackoverflow.com/a/19647596 + return ( + { + prefix + sep + k if prefix else k: v + for kk, vv in dict_.items() + for k, v in flatten_dict(vv, sep, kk).items() + } + if isinstance(dict_, dict) + else {prefix: dict_} + ) + + +def add_span_arg_tags(span, aws_service, args, args_names, args_traced): + def truncate_arg_value(value, max_len=1024): + """Truncate values which are bytes and greater than `max_len`. + Useful for parameters like "Body" in `put_object` operations. + """ + if isinstance(value, bytes) and len(value) > max_len: + return b"..." + + return value + + if not span.is_recording(): + return + + # Do not trace `Key Management Service` or `Secure Token Service` API calls + # over concerns of security leaks. + if aws_service not in {"kms", "sts"}: + tags = dict( + (name, value) + for (name, value) in zip(args_names, args) + if name in args_traced + ) + tags = flatten_dict(tags) + + for param_key, value in tags.items(): + if param_key in SERVICE_PARAMS_BLOCK_LIST.get(aws_service, {}): + continue + + span.set_attribute(param_key, truncate_arg_value(value)) diff --git a/instrumentation/opentelemetry-instrumentation-botocore/CHANGELOG.md b/instrumentation/opentelemetry-instrumentation-botocore/CHANGELOG.md index ea05e4d72..800f8487f 100644 --- a/instrumentation/opentelemetry-instrumentation-botocore/CHANGELOG.md +++ b/instrumentation/opentelemetry-instrumentation-botocore/CHANGELOG.md @@ -5,6 +5,8 @@ ([#181](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/181)) - Make botocore instrumentation check if instrumentation has been suppressed ([#182](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/182)) +- Botocore SpanKind as CLIENT and modify existing traced attributes + ([#150])(https://github.com/open-telemetry/opentelemetry-python-contrib/pull/150) ## Version 0.13b0 diff --git a/instrumentation/opentelemetry-instrumentation-botocore/README.rst b/instrumentation/opentelemetry-instrumentation-botocore/README.rst index 4f5eb9d9a..e2f44f262 100644 --- a/instrumentation/opentelemetry-instrumentation-botocore/README.rst +++ b/instrumentation/opentelemetry-instrumentation-botocore/README.rst @@ -19,5 +19,5 @@ Installation References ---------- -* `OpenTelemetry Botocore Tracing `_ +* `OpenTelemetry Botocore Tracing `_ * `OpenTelemetry Project `_ diff --git a/instrumentation/opentelemetry-instrumentation-botocore/setup.cfg b/instrumentation/opentelemetry-instrumentation-botocore/setup.cfg index 6bd0190ac..9fb198121 100644 --- a/instrumentation/opentelemetry-instrumentation-botocore/setup.cfg +++ b/instrumentation/opentelemetry-instrumentation-botocore/setup.cfg @@ -19,7 +19,7 @@ long_description = file: README.rst long_description_content_type = text/x-rst author = OpenTelemetry Authors author_email = cncf-opentelemetry-contributors@lists.cncf.io -url = https://github.com/open-telemetry/opentelemetry-python/tree/master/instrumentation/opentelemetry-instrumentation-botocore +url = https://github.com/open-telemetry/opentelemetry-python-contrib/tree/master/instrumentation/opentelemetry-instrumentation-botocore platforms = any license = Apache-2.0 classifiers = diff --git a/instrumentation/opentelemetry-instrumentation-botocore/src/opentelemetry/instrumentation/botocore/__init__.py b/instrumentation/opentelemetry-instrumentation-botocore/src/opentelemetry/instrumentation/botocore/__init__.py index 1dd1989c5..713a1e6a6 100644 --- a/instrumentation/opentelemetry-instrumentation-botocore/src/opentelemetry/instrumentation/botocore/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-botocore/src/opentelemetry/instrumentation/botocore/__init__.py @@ -49,12 +49,14 @@ API import logging from botocore.client import BaseClient +from botocore.exceptions import ClientError, ParamValidationError from wrapt import ObjectProxy, wrap_function_wrapper from opentelemetry import context as context_api from opentelemetry import propagators from opentelemetry.instrumentation.botocore.version import __version__ from opentelemetry.instrumentation.instrumentor import BaseInstrumentor +from opentelemetry.instrumentation.utils import unwrap from opentelemetry.sdk.trace import Resource from opentelemetry.trace import SpanKind, get_tracer @@ -70,15 +72,13 @@ def _patched_endpoint_prepare_request(wrapped, instance, args, kwargs): class BotocoreInstrumentor(BaseInstrumentor): - """A instrumentor for Botocore + """An instrumentor for Botocore. See `BaseInstrumentor` """ def _instrument(self, **kwargs): - # FIXME should the tracer provider be accessed via Configuration - # instead? # pylint: disable=attribute-defined-outside-init self._tracer = get_tracer( __name__, __version__, kwargs.get("tracer_provider") @@ -99,137 +99,66 @@ class BotocoreInstrumentor(BaseInstrumentor): def _uninstrument(self, **kwargs): unwrap(BaseClient, "_make_api_call") + # pylint: disable=too-many-branches def _patched_api_call(self, original_func, instance, args, kwargs): if context_api.get_value("suppress_instrumentation"): return original_func(*args, **kwargs) - endpoint_name = deep_getattr(instance, "_endpoint._endpoint_prefix") + # pylint: disable=protected-access + service_name = instance._service_model.service_name + operation_name, api_params = args + + error = None + result = None with self._tracer.start_as_current_span( - "{}.command".format(endpoint_name), kind=SpanKind.CONSUMER, + "{}".format(service_name), kind=SpanKind.CLIENT, ) as span: + if span.is_recording(): + span.set_attribute("aws.operation", operation_name) + span.set_attribute("aws.region", instance.meta.region_name) + span.set_attribute("aws.service", service_name) + if "QueueUrl" in api_params: + span.set_attribute("aws.queue_url", api_params["QueueUrl"]) + if "TableName" in api_params: + span.set_attribute( + "aws.table_name", api_params["TableName"] + ) - operation = None - if args and span.is_recording(): - operation = args[0] - span.resource = Resource( - attributes={ - "endpoint": endpoint_name, - "operation": operation.lower(), - } - ) + try: + result = original_func(*args, **kwargs) + except ClientError as ex: + error = ex - else: - span.resource = Resource( - attributes={"endpoint": endpoint_name} - ) - - add_span_arg_tags( - span, - endpoint_name, - args, - ("action", "params", "path", "verb"), - {"params", "path", "verb"}, - ) + if error: + result = error.response if span.is_recording(): - region_name = deep_getattr(instance, "meta.region_name") + if "ResponseMetadata" in result: + metadata = result["ResponseMetadata"] + req_id = None + if "RequestId" in metadata: + req_id = metadata["RequestId"] + elif "HTTPHeaders" in metadata: + headers = metadata["HTTPHeaders"] + if "x-amzn-RequestId" in headers: + req_id = headers["x-amzn-RequestId"] + elif "x-amz-request-id" in headers: + req_id = headers["x-amz-request-id"] + elif "x-amz-id-2" in headers: + req_id = headers["x-amz-id-2"] - meta = { - "aws.agent": "botocore", - "aws.operation": operation, - "aws.region": region_name, - } - for key, value in meta.items(): - span.set_attribute(key, value) + if req_id: + span.set_attribute( + "aws.request_id", req_id, + ) - result = original_func(*args, **kwargs) + if "HTTPStatusCode" in metadata: + span.set_attribute( + "http.status_code", metadata["HTTPStatusCode"], + ) - if span.is_recording(): - span.set_attribute( - "http.status_code", - result["ResponseMetadata"]["HTTPStatusCode"], - ) - span.set_attribute( - "retry_attempts", - result["ResponseMetadata"]["RetryAttempts"], - ) + if error: + raise error return result - - -def unwrap(obj, attr): - function = getattr(obj, attr, None) - if ( - function - and isinstance(function, ObjectProxy) - and hasattr(function, "__wrapped__") - ): - setattr(obj, attr, function.__wrapped__) - - -def add_span_arg_tags(span, endpoint_name, args, args_names, args_traced): - def truncate_arg_value(value, max_len=1024): - """Truncate values which are bytes and greater than `max_len`. - Useful for parameters like "Body" in `put_object` operations. - """ - if isinstance(value, bytes) and len(value) > max_len: - return b"..." - - return value - - def flatten_dict(dict_, sep=".", prefix=""): - """ - Returns a normalized dict of depth 1 with keys in order of embedding - """ - # adapted from https://stackoverflow.com/a/19647596 - return ( - { - prefix + sep + k if prefix else k: v - for kk, vv in dict_.items() - for k, v in flatten_dict(vv, sep, kk).items() - } - if isinstance(dict_, dict) - else {prefix: dict_} - ) - - if not span.is_recording(): - return - - if endpoint_name not in {"kms", "sts"}: - tags = dict( - (name, value) - for (name, value) in zip(args_names, args) - if name in args_traced - ) - tags = flatten_dict(tags) - for key, value in { - k: truncate_arg_value(v) - for k, v in tags.items() - if k not in {"s3": ["params.Body"]}.get(endpoint_name, []) - }.items(): - span.set_attribute(key, value) - - -def deep_getattr(obj, attr_string, default=None): - """ - Returns the attribute of ``obj`` at the dotted path given by - ``attr_string``, if no such attribute is reachable, returns ``default``. - - >>> deep_getattr(cass, "cluster") - >> deep_getattr(cass, "cluster.metadata.partitioner") - u"org.apache.cassandra.dht.Murmur3Partitioner" - - >>> deep_getattr(cass, "i.dont.exist", default="default") - "default" - """ - attrs = attr_string.split(".") - for attr in attrs: - try: - obj = getattr(obj, attr) - except AttributeError: - return default - - return obj diff --git a/instrumentation/opentelemetry-instrumentation-botocore/tests/test_botocore_instrumentation.py b/instrumentation/opentelemetry-instrumentation-botocore/tests/test_botocore_instrumentation.py index 8c1cb4c0c..23dc32d2d 100644 --- a/instrumentation/opentelemetry-instrumentation-botocore/tests/test_botocore_instrumentation.py +++ b/instrumentation/opentelemetry-instrumentation-botocore/tests/test_botocore_instrumentation.py @@ -17,29 +17,25 @@ from unittest.mock import Mock, patch import botocore.session from botocore.exceptions import ParamValidationError from moto import ( # pylint: disable=import-error + mock_dynamodb2, mock_ec2, mock_kinesis, mock_kms, mock_lambda, mock_s3, mock_sqs, + mock_sts, mock_xray, ) from opentelemetry import propagators +from opentelemetry import trace as trace_api from opentelemetry.context import attach, detach, set_value from opentelemetry.instrumentation.botocore import BotocoreInstrumentor -from opentelemetry.sdk.resources import Resource from opentelemetry.test.mock_textmap import MockTextMapPropagator from opentelemetry.test.test_base import TestBase -def assert_span_http_status_code(span, code): - """Assert on the span"s "http.status_code" tag""" - tag = span.attributes["http.status_code"] - assert tag == code, "%r != %r" % (tag, code) - - class TestBotocoreInstrumentor(TestBase): """Botocore integration testsuite""" @@ -66,20 +62,17 @@ class TestBotocoreInstrumentor(TestBase): assert spans span = spans[0] self.assertEqual(len(spans), 1) - self.assertEqual(span.attributes["aws.agent"], "botocore") - self.assertEqual(span.attributes["aws.region"], "us-west-2") - self.assertEqual(span.attributes["aws.operation"], "DescribeInstances") - assert_span_http_status_code(span, 200) self.assertEqual( - span.resource, - Resource( - attributes={ - "endpoint": "ec2", - "operation": "describeinstances", - } - ), + span.attributes, + { + "aws.operation": "DescribeInstances", + "aws.region": "us-west-2", + "aws.request_id": "fdcdcab1-ae5c-489e-9c33-4637c5dda355", + "aws.service": "ec2", + "http.status_code": 200, + }, ) - self.assertEqual(span.name, "ec2.command") + self.assertEqual(span.name, "ec2") @mock_ec2 def test_not_recording(self): @@ -117,13 +110,14 @@ class TestBotocoreInstrumentor(TestBase): assert spans span = spans[0] self.assertEqual(len(spans), 2) - self.assertEqual(span.attributes["aws.operation"], "ListBuckets") - assert_span_http_status_code(span, 200) self.assertEqual( - span.resource, - Resource( - attributes={"endpoint": "s3", "operation": "listbuckets"} - ), + span.attributes, + { + "aws.operation": "ListBuckets", + "aws.region": "us-west-2", + "aws.service": "s3", + "http.status_code": 200, + }, ) # testing for span error @@ -134,10 +128,15 @@ class TestBotocoreInstrumentor(TestBase): assert spans span = spans[2] self.assertEqual( - span.resource, - Resource( - attributes={"endpoint": "s3", "operation": "listobjects"} - ), + span.attributes, + { + "aws.operation": "ListObjects", + "aws.region": "us-west-2", + "aws.service": "s3", + }, + ) + self.assertIs( + span.status.status_code, trace_api.status.StatusCode.ERROR, ) # Comment test for issue 1088 @@ -148,29 +147,42 @@ class TestBotocoreInstrumentor(TestBase): location = {"LocationConstraint": "us-west-2"} s3.create_bucket(Bucket="mybucket", CreateBucketConfiguration=location) s3.put_object(**params) + s3.get_object(Bucket="mybucket", Key="foo") spans = self.memory_exporter.get_finished_spans() assert spans - span = spans[0] - self.assertEqual(len(spans), 2) - self.assertEqual(span.attributes["aws.operation"], "CreateBucket") - assert_span_http_status_code(span, 200) + self.assertEqual(len(spans), 3) + create_bucket_attributes = spans[0].attributes self.assertEqual( - span.resource, - Resource( - attributes={"endpoint": "s3", "operation": "createbucket"} - ), + create_bucket_attributes, + { + "aws.operation": "CreateBucket", + "aws.region": "us-west-2", + "aws.service": "s3", + "http.status_code": 200, + }, ) - self.assertEqual(spans[1].attributes["aws.operation"], "PutObject") + put_object_attributes = spans[1].attributes self.assertEqual( - spans[1].resource, - Resource(attributes={"endpoint": "s3", "operation": "putobject"}), - ) - self.assertEqual(spans[1].attributes["params.Key"], str(params["Key"])) - self.assertEqual( - spans[1].attributes["params.Bucket"], str(params["Bucket"]) + put_object_attributes, + { + "aws.operation": "PutObject", + "aws.region": "us-west-2", + "aws.service": "s3", + "http.status_code": 200, + }, ) self.assertTrue("params.Body" not in spans[1].attributes.keys()) + get_object_attributes = spans[2].attributes + self.assertEqual( + get_object_attributes, + { + "aws.operation": "GetObject", + "aws.region": "us-west-2", + "aws.service": "s3", + "http.status_code": 200, + }, + ) @mock_sqs def test_sqs_client(self): @@ -182,14 +194,62 @@ class TestBotocoreInstrumentor(TestBase): assert spans span = spans[0] self.assertEqual(len(spans), 1) - self.assertEqual(span.attributes["aws.region"], "us-east-1") - self.assertEqual(span.attributes["aws.operation"], "ListQueues") - assert_span_http_status_code(span, 200) + actual = span.attributes + self.assertRegex(actual["aws.request_id"], r"[A-Z0-9]{52}") + del actual["aws.request_id"] self.assertEqual( - span.resource, - Resource( - attributes={"endpoint": "sqs", "operation": "listqueues"} - ), + actual, + { + "aws.operation": "ListQueues", + "aws.region": "us-east-1", + "aws.service": "sqs", + "http.status_code": 200, + }, + ) + + @mock_sqs + def test_sqs_send_message(self): + sqs = self.session.create_client("sqs", region_name="us-east-1") + + test_queue_name = "test_queue_name" + + response = sqs.create_queue(QueueName=test_queue_name) + + sqs.send_message( + QueueUrl=response["QueueUrl"], MessageBody="Test SQS MESSAGE!" + ) + + spans = self.memory_exporter.get_finished_spans() + assert spans + self.assertEqual(len(spans), 2) + create_queue_attributes = spans[0].attributes + self.assertRegex( + create_queue_attributes["aws.request_id"], r"[A-Z0-9]{52}" + ) + del create_queue_attributes["aws.request_id"] + self.assertEqual( + create_queue_attributes, + { + "aws.operation": "CreateQueue", + "aws.region": "us-east-1", + "aws.service": "sqs", + "http.status_code": 200, + }, + ) + send_msg_attributes = spans[1].attributes + self.assertRegex( + send_msg_attributes["aws.request_id"], r"[A-Z0-9]{52}" + ) + del send_msg_attributes["aws.request_id"] + self.assertEqual( + send_msg_attributes, + { + "aws.operation": "SendMessage", + "aws.queue_url": response["QueueUrl"], + "aws.region": "us-east-1", + "aws.service": "sqs", + "http.status_code": 200, + }, ) @mock_kinesis @@ -204,14 +264,14 @@ class TestBotocoreInstrumentor(TestBase): assert spans span = spans[0] self.assertEqual(len(spans), 1) - self.assertEqual(span.attributes["aws.region"], "us-east-1") - self.assertEqual(span.attributes["aws.operation"], "ListStreams") - assert_span_http_status_code(span, 200) self.assertEqual( - span.resource, - Resource( - attributes={"endpoint": "kinesis", "operation": "liststreams"} - ), + span.attributes, + { + "aws.operation": "ListStreams", + "aws.region": "us-east-1", + "aws.service": "kinesis", + "http.status_code": 200, + }, ) @mock_kinesis @@ -249,14 +309,14 @@ class TestBotocoreInstrumentor(TestBase): assert spans span = spans[0] self.assertEqual(len(spans), 1) - self.assertEqual(span.attributes["aws.region"], "us-east-1") - self.assertEqual(span.attributes["aws.operation"], "ListFunctions") - assert_span_http_status_code(span, 200) self.assertEqual( - span.resource, - Resource( - attributes={"endpoint": "lambda", "operation": "listfunctions"} - ), + span.attributes, + { + "aws.operation": "ListFunctions", + "aws.region": "us-east-1", + "aws.service": "lambda", + "http.status_code": 200, + }, ) @mock_kms @@ -269,12 +329,38 @@ class TestBotocoreInstrumentor(TestBase): assert spans span = spans[0] self.assertEqual(len(spans), 1) - self.assertEqual(span.attributes["aws.region"], "us-east-1") - self.assertEqual(span.attributes["aws.operation"], "ListKeys") - assert_span_http_status_code(span, 200) self.assertEqual( - span.resource, - Resource(attributes={"endpoint": "kms", "operation": "listkeys"}), + span.attributes, + { + "aws.operation": "ListKeys", + "aws.region": "us-east-1", + "aws.service": "kms", + "http.status_code": 200, + }, + ) + + # checking for protection on kms against security leak + self.assertTrue("params" not in span.attributes.keys()) + + @mock_sts + def test_sts_client(self): + sts = self.session.create_client("sts", region_name="us-east-1") + + sts.get_caller_identity() + + spans = self.memory_exporter.get_finished_spans() + assert spans + span = spans[0] + self.assertEqual(len(spans), 1) + self.assertEqual( + span.attributes, + { + "aws.operation": "GetCallerIdentity", + "aws.region": "us-east-1", + "aws.request_id": "c6104cbe-af31-11e0-8154-cbc7ccf896c7", + "aws.service": "sts", + "http.status_code": 200, + }, ) # checking for protection on sts against security leak @@ -299,25 +385,19 @@ class TestBotocoreInstrumentor(TestBase): ec2.describe_instances() spans = self.memory_exporter.get_finished_spans() - assert spans - span = spans[0] self.assertEqual(len(spans), 1) - self.assertEqual(span.attributes["aws.agent"], "botocore") - self.assertEqual(span.attributes["aws.region"], "us-west-2") + span = spans[0] + describe_instances_attributes = spans[0].attributes self.assertEqual( - span.attributes["aws.operation"], "DescribeInstances" + describe_instances_attributes, + { + "aws.operation": "DescribeInstances", + "aws.region": "us-west-2", + "aws.request_id": "fdcdcab1-ae5c-489e-9c33-4637c5dda355", + "aws.service": "ec2", + "http.status_code": 200, + }, ) - assert_span_http_status_code(span, 200) - self.assertEqual( - span.resource, - Resource( - attributes={ - "endpoint": "ec2", - "operation": "describeinstances", - } - ), - ) - self.assertEqual(span.name, "ec2.command") self.assertIn(MockTextMapPropagator.TRACE_ID_KEY, headers) self.assertEqual( @@ -345,3 +425,74 @@ class TestBotocoreInstrumentor(TestBase): spans = self.memory_exporter.get_finished_spans() self.assertEqual(0, len(spans)) + + @mock_dynamodb2 + def test_dynamodb_client(self): + ddb = self.session.create_client("dynamodb", region_name="us-west-2") + + test_table_name = "test_table_name" + + ddb.create_table( + AttributeDefinitions=[ + {"AttributeName": "id", "AttributeType": "S"}, + ], + KeySchema=[{"AttributeName": "id", "KeyType": "HASH"}], + ProvisionedThroughput={ + "ReadCapacityUnits": 5, + "WriteCapacityUnits": 5, + }, + TableName=test_table_name, + ) + + ddb.put_item(TableName=test_table_name, Item={"id": {"S": "test_key"}}) + + ddb.get_item(TableName=test_table_name, Key={"id": {"S": "test_key"}}) + + spans = self.memory_exporter.get_finished_spans() + assert spans + self.assertEqual(len(spans), 3) + create_table_attributes = spans[0].attributes + self.assertRegex( + create_table_attributes["aws.request_id"], r"[A-Z0-9]{52}" + ) + del create_table_attributes["aws.request_id"] + self.assertEqual( + create_table_attributes, + { + "aws.operation": "CreateTable", + "aws.region": "us-west-2", + "aws.service": "dynamodb", + "aws.table_name": "test_table_name", + "http.status_code": 200, + }, + ) + put_item_attributes = spans[1].attributes + self.assertRegex( + put_item_attributes["aws.request_id"], r"[A-Z0-9]{52}" + ) + del put_item_attributes["aws.request_id"] + self.assertEqual( + put_item_attributes, + { + "aws.operation": "PutItem", + "aws.region": "us-west-2", + "aws.service": "dynamodb", + "aws.table_name": "test_table_name", + "http.status_code": 200, + }, + ) + get_item_attributes = spans[2].attributes + self.assertRegex( + get_item_attributes["aws.request_id"], r"[A-Z0-9]{52}" + ) + del get_item_attributes["aws.request_id"] + self.assertEqual( + get_item_attributes, + { + "aws.operation": "GetItem", + "aws.region": "us-west-2", + "aws.service": "dynamodb", + "aws.table_name": "test_table_name", + "http.status_code": 200, + }, + ) diff --git a/instrumentation/opentelemetry-instrumentation-celery/README.rst b/instrumentation/opentelemetry-instrumentation-celery/README.rst index 92e5a770a..19669c55d 100644 --- a/instrumentation/opentelemetry-instrumentation-celery/README.rst +++ b/instrumentation/opentelemetry-instrumentation-celery/README.rst @@ -63,6 +63,6 @@ accomplish this as shown in the example above. References ---------- -* `OpenTelemetry Celery Instrumentation `_ +* `OpenTelemetry Celery Instrumentation `_ * `OpenTelemetry Project `_ diff --git a/instrumentation/opentelemetry-instrumentation-celery/setup.cfg b/instrumentation/opentelemetry-instrumentation-celery/setup.cfg index d1f8866a9..b43dcd730 100644 --- a/instrumentation/opentelemetry-instrumentation-celery/setup.cfg +++ b/instrumentation/opentelemetry-instrumentation-celery/setup.cfg @@ -19,7 +19,7 @@ long_description = file: README.rst long_description_content_type = text/x-rst author = OpenTelemetry Authors author_email = cncf-opentelemetry-contributors@lists.cncf.io -url = https://github.com/open-telemetry/opentelemetry-python/tree/master/instrumentation/opentelemetry-instrumentation-celery +url = https://github.com/open-telemetry/opentelemetry-python-contrib/tree/master/instrumentation/opentelemetry-instrumentation-celery platforms = any license = Apache-2.0 classifiers = diff --git a/instrumentation/opentelemetry-instrumentation-dbapi/CHANGELOG.md b/instrumentation/opentelemetry-instrumentation-dbapi/CHANGELOG.md index 37f59c018..0c13891d8 100644 --- a/instrumentation/opentelemetry-instrumentation-dbapi/CHANGELOG.md +++ b/instrumentation/opentelemetry-instrumentation-dbapi/CHANGELOG.md @@ -2,7 +2,10 @@ ## Unreleased -Stop capturing query parameters by default +- Update dbapi and its dependant instrumentations to follow semantic conventions + ([#195](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/195)) + +- Stop capturing query parameters by default ([#156](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/156)) ## Version 0.13b0 diff --git a/instrumentation/opentelemetry-instrumentation-dbapi/README.rst b/instrumentation/opentelemetry-instrumentation-dbapi/README.rst index 5137a1c1f..3cc9add48 100644 --- a/instrumentation/opentelemetry-instrumentation-dbapi/README.rst +++ b/instrumentation/opentelemetry-instrumentation-dbapi/README.rst @@ -17,5 +17,5 @@ Installation References ---------- -* `OpenTelemetry Database API Instrumentation `_ +* `OpenTelemetry Database API Instrumentation `_ * `OpenTelemetry Project `_ diff --git a/instrumentation/opentelemetry-instrumentation-dbapi/setup.cfg b/instrumentation/opentelemetry-instrumentation-dbapi/setup.cfg index 7c4daa402..fa3bb2e01 100644 --- a/instrumentation/opentelemetry-instrumentation-dbapi/setup.cfg +++ b/instrumentation/opentelemetry-instrumentation-dbapi/setup.cfg @@ -19,7 +19,7 @@ long_description = file: README.rst long_description_content_type = text/x-rst author = OpenTelemetry Authors author_email = cncf-opentelemetry-contributors@lists.cncf.io -url = https://github.com/open-telemetry/opentelemetry-python/tree/master/instrumentation/opentelemetry-instrumentation-dbapi +url = https://github.com/open-telemetry/opentelemetry-python-contrib/tree/master/instrumentation/opentelemetry-instrumentation-dbapi platforms = any license = Apache-2.0 classifiers = diff --git a/instrumentation/opentelemetry-instrumentation-dbapi/src/opentelemetry/instrumentation/dbapi/__init__.py b/instrumentation/opentelemetry-instrumentation-dbapi/src/opentelemetry/instrumentation/dbapi/__init__.py index 5b120d3de..197f4ade4 100644 --- a/instrumentation/opentelemetry-instrumentation-dbapi/src/opentelemetry/instrumentation/dbapi/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-dbapi/src/opentelemetry/instrumentation/dbapi/__init__.py @@ -62,19 +62,19 @@ def trace_integration( capture_parameters: bool = False, ): """Integrate with DB API library. - https://www.python.org/dev/peps/pep-0249/ + https://www.python.org/dev/peps/pep-0249/ - Args: - connect_module: Module name where connect method is available. - connect_method_name: The connect method name. - database_component: Database driver name or database name "JDBI", - "jdbc", "odbc", "postgreSQL". - database_type: The Database type. For any SQL database, "sql". - connection_attributes: Attribute names for database, port, host and - user in Connection object. - tracer_provider: The :class:`opentelemetry.trace.TracerProvider` to - use. If ommited the current configured one is used. - capture_parameters: Configure if db.statement.parameters should be captured. + Args: + connect_module: Module name where connect method is available. + connect_method_name: The connect method name. + database_component: Database driver name or database name "JDBI", + "jdbc", "odbc", "postgreSQL". + database_type: The Database type. For any SQL database, "sql". + connection_attributes: Attribute names for database, port, host and + user in Connection object. + tracer_provider: The :class:`opentelemetry.trace.TracerProvider` to + use. If ommited the current configured one is used. + capture_parameters: Configure if db.statement.parameters should be captured. """ wrap_connect( __name__, @@ -101,18 +101,18 @@ def wrap_connect( capture_parameters: bool = False, ): """Integrate with DB API library. - https://www.python.org/dev/peps/pep-0249/ + https://www.python.org/dev/peps/pep-0249/ - Args: - tracer: The :class:`opentelemetry.trace.Tracer` to use. - connect_module: Module name where connect method is available. - connect_method_name: The connect method name. - database_component: Database driver name or database name "JDBI", - "jdbc", "odbc", "postgreSQL". - database_type: The Database type. For any SQL database, "sql". - connection_attributes: Attribute names for database, port, host and - user in Connection object. - capture_parameters: Configure if db.statement.parameters should be captured. + Args: + tracer: The :class:`opentelemetry.trace.Tracer` to use. + connect_module: Module name where connect method is available. + connect_method_name: The connect method name. + database_component: Database driver name or database name "JDBI", + "jdbc", "odbc", "postgreSQL". + database_type: The Database type. For any SQL database, "sql". + connection_attributes: Attribute names for database, port, host and + user in Connection object. + capture_parameters: Configure if db.statement.parameters should be captured. """ @@ -143,14 +143,14 @@ def wrap_connect( def unwrap_connect( - connect_module: typing.Callable[..., typing.Any], connect_method_name: str, + connect_module: typing.Callable[..., typing.Any], connect_method_name: str ): """Disable integration with DB API library. - https://www.python.org/dev/peps/pep-0249/ + https://www.python.org/dev/peps/pep-0249/ - Args: - connect_module: Module name where the connect method is available. - connect_method_name: The connect method name. + Args: + connect_module: Module name where the connect method is available. + connect_method_name: The connect method name. """ unwrap(connect_module, connect_method_name) @@ -251,8 +251,7 @@ class DatabaseApiIntegration: args: typing.Tuple[typing.Any, typing.Any], kwargs: typing.Dict[typing.Any, typing.Any], ): - """Add object proxy to connection object. - """ + """Add object proxy to connection object.""" connection = connect_method(*args, **kwargs) self.get_connection_attributes(connection) return get_traced_connection_proxy(connection, self) @@ -278,6 +277,9 @@ class DatabaseApiIntegration: self.database = self.database.decode(errors="ignore") self.name += "." + self.database user = self.connection_props.get("user") + # PyMySQL encodes this data + if user and isinstance(user, bytes): + user = user.decode() if user is not None: self.span_attributes["db.user"] = str(user) host = self.connection_props.get("host") @@ -325,8 +327,10 @@ class TracedCursor: span.set_attribute( "component", self._db_api_integration.database_component ) - span.set_attribute("db.type", self._db_api_integration.database_type) - span.set_attribute("db.instance", self._db_api_integration.database) + span.set_attribute( + "db.system", self._db_api_integration.database_component + ) + span.set_attribute("db.name", self._db_api_integration.database) span.set_attribute("db.statement", statement) for ( @@ -344,9 +348,16 @@ class TracedCursor: *args: typing.Tuple[typing.Any, typing.Any], **kwargs: typing.Dict[typing.Any, typing.Any] ): + name = "" + if args: + name = args[0] + elif self._db_api_integration.database: + name = self._db_api_integration.database + else: + name = self._db_api_integration.name with self._db_api_integration.get_tracer().start_as_current_span( - self._db_api_integration.name, kind=SpanKind.CLIENT + name, kind=SpanKind.CLIENT ) as span: self._populate_span(span, *args) try: diff --git a/instrumentation/opentelemetry-instrumentation-dbapi/tests/test_dbapi_integration.py b/instrumentation/opentelemetry-instrumentation-dbapi/tests/test_dbapi_integration.py index 40176363c..e69bf60c9 100644 --- a/instrumentation/opentelemetry-instrumentation-dbapi/tests/test_dbapi_integration.py +++ b/instrumentation/opentelemetry-instrumentation-dbapi/tests/test_dbapi_integration.py @@ -50,19 +50,19 @@ class TestDBApiIntegration(TestBase): spans_list = self.memory_exporter.get_finished_spans() self.assertEqual(len(spans_list), 1) span = spans_list[0] - self.assertEqual(span.name, "testcomponent.testdatabase") + self.assertEqual(span.name, "Test query") self.assertIs(span.kind, trace_api.SpanKind.CLIENT) self.assertEqual(span.attributes["component"], "testcomponent") - self.assertEqual(span.attributes["db.type"], "testtype") - self.assertEqual(span.attributes["db.instance"], "testdatabase") + self.assertEqual(span.attributes["db.system"], "testcomponent") + self.assertEqual(span.attributes["db.name"], "testdatabase") self.assertEqual(span.attributes["db.statement"], "Test query") self.assertFalse("db.statement.parameters" in span.attributes) self.assertEqual(span.attributes["db.user"], "testuser") self.assertEqual(span.attributes["net.peer.name"], "testhost") self.assertEqual(span.attributes["net.peer.port"], 123) self.assertIs( - span.status.status_code, trace_api.status.StatusCode.UNSET, + span.status.status_code, trace_api.status.StatusCode.UNSET ) def test_span_succeeded_with_capture_of_statement_parameters(self): @@ -93,12 +93,12 @@ class TestDBApiIntegration(TestBase): spans_list = self.memory_exporter.get_finished_spans() self.assertEqual(len(spans_list), 1) span = spans_list[0] - self.assertEqual(span.name, "testcomponent.testdatabase") + self.assertEqual(span.name, "Test query") self.assertIs(span.kind, trace_api.SpanKind.CLIENT) self.assertEqual(span.attributes["component"], "testcomponent") - self.assertEqual(span.attributes["db.type"], "testtype") - self.assertEqual(span.attributes["db.instance"], "testdatabase") + self.assertEqual(span.attributes["db.system"], "testcomponent") + self.assertEqual(span.attributes["db.name"], "testdatabase") self.assertEqual(span.attributes["db.statement"], "Test query") self.assertEqual( span.attributes["db.statement.parameters"], @@ -108,7 +108,7 @@ class TestDBApiIntegration(TestBase): self.assertEqual(span.attributes["net.peer.name"], "testhost") self.assertEqual(span.attributes["net.peer.port"], 123) self.assertIs( - span.status.status_code, trace_api.status.StatusCode.UNSET, + span.status.status_code, trace_api.status.StatusCode.UNSET ) def test_span_not_recording(self): @@ -159,7 +159,7 @@ class TestDBApiIntegration(TestBase): span = spans_list[0] self.assertEqual(span.attributes["db.statement"], "Test query") self.assertIs( - span.status.status_code, trace_api.status.StatusCode.ERROR, + span.status.status_code, trace_api.status.StatusCode.ERROR ) self.assertEqual(span.status.description, "Test Exception") diff --git a/instrumentation/opentelemetry-instrumentation-django/README.rst b/instrumentation/opentelemetry-instrumentation-django/README.rst index a2b98cabf..c6171fa44 100644 --- a/instrumentation/opentelemetry-instrumentation-django/README.rst +++ b/instrumentation/opentelemetry-instrumentation-django/README.rst @@ -49,5 +49,5 @@ References ---------- * `Django `_ -* `OpenTelemetry Instrumentation for Django `_ +* `OpenTelemetry Instrumentation for Django `_ * `OpenTelemetry Project `_ diff --git a/instrumentation/opentelemetry-instrumentation-django/setup.cfg b/instrumentation/opentelemetry-instrumentation-django/setup.cfg index 44a921283..ea1101681 100644 --- a/instrumentation/opentelemetry-instrumentation-django/setup.cfg +++ b/instrumentation/opentelemetry-instrumentation-django/setup.cfg @@ -19,7 +19,7 @@ long_description = file: README.rst long_description_content_type = text/x-rst author = OpenTelemetry Authors author_email = cncf-opentelemetry-contributors@lists.cncf.io -url = https://github.com/open-telemetry/opentelemetry-python/tree/master/instrumentation/opentelemetry-instrumentation-django +url = https://github.com/open-telemetry/opentelemetry-python-contrib/tree/master/instrumentation/opentelemetry-instrumentation-django platforms = any license = Apache-2.0 classifiers = diff --git a/instrumentation/opentelemetry-instrumentation-elasticsearch/README.rst b/instrumentation/opentelemetry-instrumentation-elasticsearch/README.rst index 9f898e783..f0719dbc8 100644 --- a/instrumentation/opentelemetry-instrumentation-elasticsearch/README.rst +++ b/instrumentation/opentelemetry-instrumentation-elasticsearch/README.rst @@ -19,5 +19,5 @@ Installation References ---------- -* `OpenTelemetry elasticsearch Integration `_ +* `OpenTelemetry elasticsearch Integration `_ * `OpenTelemetry Project `_ diff --git a/instrumentation/opentelemetry-instrumentation-elasticsearch/setup.cfg b/instrumentation/opentelemetry-instrumentation-elasticsearch/setup.cfg index b1ebcfe76..f2418ae10 100644 --- a/instrumentation/opentelemetry-instrumentation-elasticsearch/setup.cfg +++ b/instrumentation/opentelemetry-instrumentation-elasticsearch/setup.cfg @@ -19,7 +19,7 @@ long_description = file: README.rst long_description_content_type = text/x-rst author = OpenTelemetry Authors author_email = cncf-opentelemetry-contributors@lists.cncf.io -url = https://github.com/open-telemetry/opentelemetry-python/tree/master/instrumentation/opentelemetry-instrumentation-elasticsearch +url = https://github.com/open-telemetry/opentelemetry-python-contrib/tree/master/instrumentation/opentelemetry-instrumentation-elasticsearch platforms = any license = Apache-2.0 classifiers = diff --git a/instrumentation/opentelemetry-instrumentation-falcon/README.rst b/instrumentation/opentelemetry-instrumentation-falcon/README.rst index 8230deaf7..730e83f23 100644 --- a/instrumentation/opentelemetry-instrumentation-falcon/README.rst +++ b/instrumentation/opentelemetry-instrumentation-falcon/README.rst @@ -49,5 +49,5 @@ Falcon Request object reference: https://falcon.readthedocs.io/en/stable/api/req References ---------- -* `OpenTelemetry Falcon Instrumentation `_ +* `OpenTelemetry Falcon Instrumentation `_ * `OpenTelemetry Project `_ diff --git a/instrumentation/opentelemetry-instrumentation-falcon/setup.cfg b/instrumentation/opentelemetry-instrumentation-falcon/setup.cfg index 88e287c60..e4d706a0d 100644 --- a/instrumentation/opentelemetry-instrumentation-falcon/setup.cfg +++ b/instrumentation/opentelemetry-instrumentation-falcon/setup.cfg @@ -19,7 +19,7 @@ long_description = file: README.rst long_description_content_type = text/x-rst author = OpenTelemetry Authors author_email = cncf-opentelemetry-contributors@lists.cncf.io -url = https://github.com/open-telemetry/opentelemetry-python/tree/master/instrumentation/opentelemetry-instrumentation-falcon +url = https://github.com/open-telemetry/opentelemetry-python-contrib/tree/master/instrumentation/opentelemetry-instrumentation-falcon platforms = any license = Apache-2.0 classifiers = diff --git a/instrumentation/opentelemetry-instrumentation-fastapi/setup.cfg b/instrumentation/opentelemetry-instrumentation-fastapi/setup.cfg index d6b6bdc54..523c051e7 100644 --- a/instrumentation/opentelemetry-instrumentation-fastapi/setup.cfg +++ b/instrumentation/opentelemetry-instrumentation-fastapi/setup.cfg @@ -19,7 +19,7 @@ long_description = file: README.rst long_description_content_type = text/x-rst author = OpenTelemetry Authors author_email = cncf-opentelemetry-contributors@lists.cncf.io -url = https://github.com/open-telemetry/opentelemetry-python/tree/master/instrumentation/opentelemetry-instrumentation-fastapi +url = https://github.com/open-telemetry/opentelemetry-python-contrib/tree/master/instrumentation/opentelemetry-instrumentation-fastapi platforms = any license = Apache-2.0 classifiers = diff --git a/instrumentation/opentelemetry-instrumentation-flask/CHANGELOG.md b/instrumentation/opentelemetry-instrumentation-flask/CHANGELOG.md index 4c7e7a055..3ff39fb72 100644 --- a/instrumentation/opentelemetry-instrumentation-flask/CHANGELOG.md +++ b/instrumentation/opentelemetry-instrumentation-flask/CHANGELOG.md @@ -2,6 +2,9 @@ ## Unreleased +- Add span name callback + ([#152](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/152)) + ## Version 0.15b0 Released 2020-11-02 diff --git a/instrumentation/opentelemetry-instrumentation-flask/README.rst b/instrumentation/opentelemetry-instrumentation-flask/README.rst index f79d8fd60..7502ed08f 100644 --- a/instrumentation/opentelemetry-instrumentation-flask/README.rst +++ b/instrumentation/opentelemetry-instrumentation-flask/README.rst @@ -34,5 +34,5 @@ will exclude requests such as ``https://site/client/123/info`` and ``https://sit References ---------- -* `OpenTelemetry Flask Instrumentation `_ +* `OpenTelemetry Flask Instrumentation `_ * `OpenTelemetry Project `_ diff --git a/instrumentation/opentelemetry-instrumentation-flask/setup.cfg b/instrumentation/opentelemetry-instrumentation-flask/setup.cfg index 2e9f943ce..df48d5985 100644 --- a/instrumentation/opentelemetry-instrumentation-flask/setup.cfg +++ b/instrumentation/opentelemetry-instrumentation-flask/setup.cfg @@ -19,7 +19,7 @@ long_description = file: README.rst long_description_content_type = text/x-rst author = OpenTelemetry Authors author_email = cncf-opentelemetry-contributors@lists.cncf.io -url = https://github.com/open-telemetry/opentelemetry-python/tree/master/instrumentation/opentelemetry-instrumentation-flask +url = https://github.com/open-telemetry/opentelemetry-python-contrib/tree/master/instrumentation/opentelemetry-instrumentation-flask platforms = any license = Apache-2.0 classifiers = diff --git a/instrumentation/opentelemetry-instrumentation-flask/src/opentelemetry/instrumentation/flask/__init__.py b/instrumentation/opentelemetry-instrumentation-flask/src/opentelemetry/instrumentation/flask/__init__.py index 1235b09a3..bfc1b3d79 100644 --- a/instrumentation/opentelemetry-instrumentation-flask/src/opentelemetry/instrumentation/flask/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-flask/src/opentelemetry/instrumentation/flask/__init__.py @@ -20,7 +20,7 @@ This library builds on the OpenTelemetry WSGI middleware to track web requests in Flask applications. In addition to opentelemetry-instrumentation-wsgi, it supports flask-specific features such as: -* The Flask endpoint name is used as the Span name. +* The Flask url rule pattern is used as the Span name. * The ``http.route`` Span attribute is set so that one can see which URL rule matched a request. @@ -75,6 +75,15 @@ def get_excluded_urls(): _excluded_urls = get_excluded_urls() +def get_default_span_name(): + span_name = "" + try: + span_name = flask.request.url_rule.rule + except AttributeError: + span_name = otel_wsgi.get_default_span_name(flask.request.environ) + return span_name + + def _rewrapped_app(wsgi_app): def _wrapped_app(environ, start_response): # We want to measure the time for route matching, etc. @@ -105,43 +114,40 @@ def _rewrapped_app(wsgi_app): return _wrapped_app -def _before_request(): - if _excluded_urls.url_disabled(flask.request.url): - return +def _wrapped_before_request(name_callback): + def _before_request(): + if _excluded_urls.url_disabled(flask.request.url): + return - environ = flask.request.environ - span_name = None - try: - span_name = flask.request.url_rule.rule - except AttributeError: - pass - if span_name is None: - span_name = otel_wsgi.get_default_span_name(environ) - token = context.attach( - propagators.extract(otel_wsgi.carrier_getter, environ) - ) + environ = flask.request.environ + span_name = name_callback() + token = context.attach( + propagators.extract(otel_wsgi.carrier_getter, environ) + ) - tracer = trace.get_tracer(__name__, __version__) + tracer = trace.get_tracer(__name__, __version__) - span = tracer.start_span( - span_name, - kind=trace.SpanKind.SERVER, - start_time=environ.get(_ENVIRON_STARTTIME_KEY), - ) - if span.is_recording(): - attributes = otel_wsgi.collect_request_attributes(environ) - if flask.request.url_rule: - # For 404 that result from no route found, etc, we - # don't have a url_rule. - attributes["http.route"] = flask.request.url_rule.rule - for key, value in attributes.items(): - span.set_attribute(key, value) + span = tracer.start_span( + span_name, + kind=trace.SpanKind.SERVER, + start_time=environ.get(_ENVIRON_STARTTIME_KEY), + ) + if span.is_recording(): + attributes = otel_wsgi.collect_request_attributes(environ) + if flask.request.url_rule: + # For 404 that result from no route found, etc, we + # don't have a url_rule. + attributes["http.route"] = flask.request.url_rule.rule + for key, value in attributes.items(): + span.set_attribute(key, value) - activation = tracer.use_span(span, end_on_exit=True) - activation.__enter__() - environ[_ENVIRON_ACTIVATION_KEY] = activation - environ[_ENVIRON_SPAN_KEY] = span - environ[_ENVIRON_TOKEN] = token + activation = tracer.use_span(span, end_on_exit=True) + activation.__enter__() + environ[_ENVIRON_ACTIVATION_KEY] = activation + environ[_ENVIRON_SPAN_KEY] = span + environ[_ENVIRON_TOKEN] = token + + return _before_request def _teardown_request(exc): @@ -167,12 +173,19 @@ def _teardown_request(exc): class _InstrumentedFlask(flask.Flask): + + name_callback = get_default_span_name + def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self._original_wsgi_ = self.wsgi_app self.wsgi_app = _rewrapped_app(self.wsgi_app) + _before_request = _wrapped_before_request( + _InstrumentedFlask.name_callback + ) + self._before_request = _before_request self.before_request(_before_request) self.teardown_request(_teardown_request) @@ -186,9 +199,14 @@ class FlaskInstrumentor(BaseInstrumentor): def _instrument(self, **kwargs): self._original_flask = flask.Flask + name_callback = kwargs.get("name_callback") + if callable(name_callback): + _InstrumentedFlask.name_callback = name_callback flask.Flask = _InstrumentedFlask - def instrument_app(self, app): # pylint: disable=no-self-use + def instrument_app( + self, app, name_callback=get_default_span_name + ): # pylint: disable=no-self-use if not hasattr(app, "_is_instrumented"): app._is_instrumented = False @@ -196,6 +214,8 @@ class FlaskInstrumentor(BaseInstrumentor): app._original_wsgi_app = app.wsgi_app app.wsgi_app = _rewrapped_app(app.wsgi_app) + _before_request = _wrapped_before_request(name_callback) + app._before_request = _before_request app.before_request(_before_request) app.teardown_request(_teardown_request) app._is_instrumented = True @@ -215,7 +235,7 @@ class FlaskInstrumentor(BaseInstrumentor): app.wsgi_app = app._original_wsgi_app # FIXME add support for other Flask blueprints that are not None - app.before_request_funcs[None].remove(_before_request) + app.before_request_funcs[None].remove(app._before_request) app.teardown_request_funcs[None].remove(_teardown_request) del app._original_wsgi_app diff --git a/instrumentation/opentelemetry-instrumentation-flask/tests/test_programmatic.py b/instrumentation/opentelemetry-instrumentation-flask/tests/test_programmatic.py index a90789052..0bed5d20d 100644 --- a/instrumentation/opentelemetry-instrumentation-flask/tests/test_programmatic.py +++ b/instrumentation/opentelemetry-instrumentation-flask/tests/test_programmatic.py @@ -178,3 +178,63 @@ class TestProgrammatic(InstrumentationTest, TestBase, WsgiTestBase): self.client.get("/excluded_noarg2") span_list = self.memory_exporter.get_finished_spans() self.assertEqual(len(span_list), 1) + + +class TestProgrammaticCustomSpanName( + InstrumentationTest, TestBase, WsgiTestBase +): + def setUp(self): + super().setUp() + + def custom_span_name(): + return "flask-custom-span-name" + + self.app = Flask(__name__) + + FlaskInstrumentor().instrument_app( + self.app, name_callback=custom_span_name + ) + + self._common_initialization() + + def tearDown(self): + super().tearDown() + with self.disable_logging(): + FlaskInstrumentor().uninstrument_app(self.app) + + def test_custom_span_name(self): + self.client.get("/hello/123") + + span_list = self.memory_exporter.get_finished_spans() + self.assertEqual(len(span_list), 1) + self.assertEqual(span_list[0].name, "flask-custom-span-name") + + +class TestProgrammaticCustomSpanNameCallbackWithoutApp( + InstrumentationTest, TestBase, WsgiTestBase +): + def setUp(self): + super().setUp() + + def custom_span_name(): + return "instrument-without-app" + + FlaskInstrumentor().instrument(name_callback=custom_span_name) + # pylint: disable=import-outside-toplevel,reimported,redefined-outer-name + from flask import Flask + + self.app = Flask(__name__) + + self._common_initialization() + + def tearDown(self): + super().tearDown() + with self.disable_logging(): + FlaskInstrumentor().uninstrument() + + def test_custom_span_name(self): + self.client.get("/hello/123") + + span_list = self.memory_exporter.get_finished_spans() + self.assertEqual(len(span_list), 1) + self.assertEqual(span_list[0].name, "instrument-without-app") diff --git a/instrumentation/opentelemetry-instrumentation-grpc/setup.cfg b/instrumentation/opentelemetry-instrumentation-grpc/setup.cfg index d1d3ff52d..1d052eac6 100644 --- a/instrumentation/opentelemetry-instrumentation-grpc/setup.cfg +++ b/instrumentation/opentelemetry-instrumentation-grpc/setup.cfg @@ -19,7 +19,7 @@ long_description = file: README.rst long_description_content_type = text/x-rst author = OpenTelemetry Authors author_email = cncf-opentelemetry-contributors@lists.cncf.io -url = https://github.com/open-telemetry/opentelemetry-python/tree/master/instrumentation/opentelemetry-instrumentation-grpc +url = https://github.com/open-telemetry/opentelemetry-python-contrib/tree/master/instrumentation/opentelemetry-instrumentation-grpc platforms = any license = Apache-2.0 classifiers = diff --git a/instrumentation/opentelemetry-instrumentation-grpc/src/opentelemetry/instrumentation/grpc/_client.py b/instrumentation/opentelemetry-instrumentation-grpc/src/opentelemetry/instrumentation/grpc/_client.py index f8a72931f..55317fa2d 100644 --- a/instrumentation/opentelemetry-instrumentation-grpc/src/opentelemetry/instrumentation/grpc/_client.py +++ b/instrumentation/opentelemetry-instrumentation-grpc/src/opentelemetry/instrumentation/grpc/_client.py @@ -87,13 +87,17 @@ class OpenTelemetryClientInterceptor( def __init__(self, tracer, exporter, interval): self._tracer = tracer - self._meter = None + self._accumulator = None if exporter and interval: - self._meter = metrics.get_meter(__name__) + self._accumulator = metrics.get_meter(__name__) self.controller = PushController( - meter=self._meter, exporter=exporter, interval=interval + accumulator=self._accumulator, + exporter=exporter, + interval=interval, ) - self._metrics_recorder = TimedMetricRecorder(self._meter, "client") + self._metrics_recorder = TimedMetricRecorder( + self._accumulator, "client", + ) def _start_span(self, method): return self._tracer.start_as_current_span( diff --git a/instrumentation/opentelemetry-instrumentation-jinja2/README.rst b/instrumentation/opentelemetry-instrumentation-jinja2/README.rst index c74faeb32..24ecc66a8 100644 --- a/instrumentation/opentelemetry-instrumentation-jinja2/README.rst +++ b/instrumentation/opentelemetry-instrumentation-jinja2/README.rst @@ -17,5 +17,5 @@ Installation References ---------- -* `OpenTelemetry jinja2 integration `_ +* `OpenTelemetry jinja2 integration `_ * `OpenTelemetry Project `_ diff --git a/instrumentation/opentelemetry-instrumentation-jinja2/setup.cfg b/instrumentation/opentelemetry-instrumentation-jinja2/setup.cfg index 08f46ae10..23ec0795d 100644 --- a/instrumentation/opentelemetry-instrumentation-jinja2/setup.cfg +++ b/instrumentation/opentelemetry-instrumentation-jinja2/setup.cfg @@ -19,7 +19,7 @@ long_description = file: README.rst long_description_content_type = text/x-rst author = OpenTelemetry Authors author_email = cncf-opentelemetry-contributors@lists.cncf.io -url = https://github.com/open-telemetry/opentelemetry-python/tree/master/instrumentation/opentelemetry-instrumentation-jinja2 +url = https://github.com/open-telemetry/opentelemetry-python-contrib/tree/master/instrumentation/opentelemetry-instrumentation-jinja2 platforms = any license = Apache-2.0 classifiers = diff --git a/instrumentation/opentelemetry-instrumentation-mysql/README.rst b/instrumentation/opentelemetry-instrumentation-mysql/README.rst index 9558f64bd..44860ef5e 100644 --- a/instrumentation/opentelemetry-instrumentation-mysql/README.rst +++ b/instrumentation/opentelemetry-instrumentation-mysql/README.rst @@ -20,6 +20,6 @@ Installation References ---------- -* `OpenTelemetry MySQL Instrumentation `_ +* `OpenTelemetry MySQL Instrumentation `_ * `OpenTelemetry Project `_ diff --git a/instrumentation/opentelemetry-instrumentation-mysql/setup.cfg b/instrumentation/opentelemetry-instrumentation-mysql/setup.cfg index ff9984a0c..f2d7d7e2a 100644 --- a/instrumentation/opentelemetry-instrumentation-mysql/setup.cfg +++ b/instrumentation/opentelemetry-instrumentation-mysql/setup.cfg @@ -19,7 +19,7 @@ long_description = file: README.rst long_description_content_type = text/x-rst author = OpenTelemetry Authors author_email = cncf-opentelemetry-contributors@lists.cncf.io -url = https://github.com/open-telemetry/opentelemetry-python/tree/master/instrumentation/opentelemetry-instrumentation-mysql +url = https://github.com/open-telemetry/opentelemetry-python-contrib/tree/master/instrumentation/opentelemetry-instrumentation-mysql platforms = any license = Apache-2.0 classifiers = diff --git a/instrumentation/opentelemetry-instrumentation-psycopg2/README.rst b/instrumentation/opentelemetry-instrumentation-psycopg2/README.rst index 3ab1025ea..bdb35fb20 100644 --- a/instrumentation/opentelemetry-instrumentation-psycopg2/README.rst +++ b/instrumentation/opentelemetry-instrumentation-psycopg2/README.rst @@ -16,5 +16,5 @@ Installation References ---------- -* `OpenTelemetry Psycopg Instrumentation `_ +* `OpenTelemetry Psycopg Instrumentation `_ * `OpenTelemetry Project `_ diff --git a/instrumentation/opentelemetry-instrumentation-psycopg2/setup.cfg b/instrumentation/opentelemetry-instrumentation-psycopg2/setup.cfg index db98bf125..441e1cbfa 100644 --- a/instrumentation/opentelemetry-instrumentation-psycopg2/setup.cfg +++ b/instrumentation/opentelemetry-instrumentation-psycopg2/setup.cfg @@ -19,7 +19,7 @@ long_description = file: README.rst long_description_content_type = text/x-rst author = OpenTelemetry Authors author_email = cncf-opentelemetry-contributors@lists.cncf.io -url = https://github.com/open-telemetry/opentelemetry-python/tree/master/instrumentation/opentelemetry-instrumentation-psycopg2 +url = https://github.com/open-telemetry/opentelemetry-python-contrib/tree/master/instrumentation/opentelemetry-instrumentation-psycopg2 platforms = any license = Apache-2.0 classifiers = diff --git a/instrumentation/opentelemetry-instrumentation-pymemcache/README.rst b/instrumentation/opentelemetry-instrumentation-pymemcache/README.rst index f126f4246..29ae0b2ee 100644 --- a/instrumentation/opentelemetry-instrumentation-pymemcache/README.rst +++ b/instrumentation/opentelemetry-instrumentation-pymemcache/README.rst @@ -16,5 +16,5 @@ Installation References ---------- -* `OpenTelemetry Pymemcache Instrumentation `_ +* `OpenTelemetry Pymemcache Instrumentation `_ * `OpenTelemetry Project `_ diff --git a/instrumentation/opentelemetry-instrumentation-pymemcache/setup.cfg b/instrumentation/opentelemetry-instrumentation-pymemcache/setup.cfg index c352ba903..4df8dd702 100644 --- a/instrumentation/opentelemetry-instrumentation-pymemcache/setup.cfg +++ b/instrumentation/opentelemetry-instrumentation-pymemcache/setup.cfg @@ -19,7 +19,7 @@ long_description = file: README.rst long_description_content_type = text/x-rst author = OpenTelemetry Authors author_email = cncf-opentelemetry-contributors@lists.cncf.io -url = https://github.com/open-telemetry/opentelemetry-python/instrumentation/opentelemetry-instrumentation-pymemcache +url = https://github.com/open-telemetry/opentelemetry-python-contrib/instrumentation/opentelemetry-instrumentation-pymemcache platforms = any license = Apache-2.0 classifiers = diff --git a/instrumentation/opentelemetry-instrumentation-pymongo/CHANGELOG.md b/instrumentation/opentelemetry-instrumentation-pymongo/CHANGELOG.md index 30e36e004..05716f473 100644 --- a/instrumentation/opentelemetry-instrumentation-pymongo/CHANGELOG.md +++ b/instrumentation/opentelemetry-instrumentation-pymongo/CHANGELOG.md @@ -2,6 +2,9 @@ ## Unreleased +- Update pymongo instrumentation to follow semantic conventions +([#203](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/203)) + ## Version 0.14b0 Released 2020-10-13 diff --git a/instrumentation/opentelemetry-instrumentation-pymongo/README.rst b/instrumentation/opentelemetry-instrumentation-pymongo/README.rst index 7791810e9..23ca2c9aa 100644 --- a/instrumentation/opentelemetry-instrumentation-pymongo/README.rst +++ b/instrumentation/opentelemetry-instrumentation-pymongo/README.rst @@ -16,6 +16,6 @@ Installation References ---------- -* `OpenTelemetry pymongo Instrumentation `_ +* `OpenTelemetry pymongo Instrumentation `_ * `OpenTelemetry Project `_ diff --git a/instrumentation/opentelemetry-instrumentation-pymongo/setup.cfg b/instrumentation/opentelemetry-instrumentation-pymongo/setup.cfg index 6ccf6f100..225886c45 100644 --- a/instrumentation/opentelemetry-instrumentation-pymongo/setup.cfg +++ b/instrumentation/opentelemetry-instrumentation-pymongo/setup.cfg @@ -19,7 +19,7 @@ long_description = file: README.rst long_description_content_type = text/x-rst author = OpenTelemetry Authors author_email = cncf-opentelemetry-contributors@lists.cncf.io -url = https://github.com/open-telemetry/opentelemetry-python/tree/master/instrumentation/opentelemetry-instrumentation-pymongo +url = https://github.com/open-telemetry/opentelemetry-python-contrib/tree/master/instrumentation/opentelemetry-instrumentation-pymongo platforms = any license = Apache-2.0 classifiers = diff --git a/instrumentation/opentelemetry-instrumentation-pymongo/src/opentelemetry/instrumentation/pymongo/__init__.py b/instrumentation/opentelemetry-instrumentation-pymongo/src/opentelemetry/instrumentation/pymongo/__init__.py index 434984ec3..abcbe0d63 100644 --- a/instrumentation/opentelemetry-instrumentation-pymongo/src/opentelemetry/instrumentation/pymongo/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-pymongo/src/opentelemetry/instrumentation/pymongo/__init__.py @@ -46,7 +46,6 @@ from opentelemetry.trace import SpanKind, get_tracer from opentelemetry.trace.status import Status, StatusCode DATABASE_TYPE = "mongodb" -COMMAND_ATTRIBUTES = ["filter", "sort", "skip", "limit", "pipeline"] class CommandTracer(monitoring.CommandListener): @@ -60,7 +59,7 @@ class CommandTracer(monitoring.CommandListener): if not self.is_enabled: return command = event.command.get(event.command_name, "") - name = DATABASE_TYPE + "." + event.command_name + name = event.command_name statement = event.command_name if command: name += "." + str(command) @@ -69,23 +68,13 @@ class CommandTracer(monitoring.CommandListener): try: span = self._tracer.start_span(name, kind=SpanKind.CLIENT) if span.is_recording(): - span.set_attribute("component", DATABASE_TYPE) - span.set_attribute("db.type", DATABASE_TYPE) - span.set_attribute("db.instance", event.database_name) + span.set_attribute("db.system", DATABASE_TYPE) + span.set_attribute("db.name", event.database_name) span.set_attribute("db.statement", statement) if event.connection_id is not None: span.set_attribute("net.peer.name", event.connection_id[0]) span.set_attribute("net.peer.port", event.connection_id[1]) - # pymongo specific, not specified by spec - span.set_attribute("db.mongo.operation_id", event.operation_id) - span.set_attribute("db.mongo.request_id", event.request_id) - - for attr in COMMAND_ATTRIBUTES: - _attr = event.command.get(attr) - if _attr is not None: - span.set_attribute("db.mongo." + attr, str(_attr)) - # Add Span to dictionary self._span_dict[_get_span_dict_key(event)] = span except Exception as ex: # noqa pylint: disable=broad-except @@ -101,10 +90,6 @@ class CommandTracer(monitoring.CommandListener): span = self._pop_span(event) if span is None: return - if span.is_recording(): - span.set_attribute( - "db.mongo.duration_micros", event.duration_micros - ) span.end() def failed(self, event: monitoring.CommandFailedEvent): @@ -115,9 +100,6 @@ class CommandTracer(monitoring.CommandListener): if span is None: return if span.is_recording(): - span.set_attribute( - "db.mongo.duration_micros", event.duration_micros - ) span.set_status(Status(StatusCode.ERROR, event.failure)) span.end() diff --git a/instrumentation/opentelemetry-instrumentation-pymongo/tests/test_pymongo.py b/instrumentation/opentelemetry-instrumentation-pymongo/tests/test_pymongo.py index a3bb7b222..bfd3d8f52 100644 --- a/instrumentation/opentelemetry-instrumentation-pymongo/tests/test_pymongo.py +++ b/instrumentation/opentelemetry-instrumentation-pymongo/tests/test_pymongo.py @@ -39,10 +39,6 @@ class TestPymongo(TestBase): def test_started(self): command_attrs = { - "filter": "filter", - "sort": "sort", - "limit": "limit", - "pipeline": "pipeline", "command_name": "find", } command_tracer = CommandTracer(self.tracer) @@ -55,24 +51,12 @@ class TestPymongo(TestBase): # pylint: disable=protected-access span = command_tracer._pop_span(mock_event) self.assertIs(span.kind, trace_api.SpanKind.CLIENT) - self.assertEqual(span.name, "mongodb.command_name.find") - self.assertEqual(span.attributes["component"], "mongodb") - self.assertEqual(span.attributes["db.type"], "mongodb") - self.assertEqual(span.attributes["db.instance"], "database_name") + self.assertEqual(span.name, "command_name.find") + self.assertEqual(span.attributes["db.system"], "mongodb") + self.assertEqual(span.attributes["db.name"], "database_name") self.assertEqual(span.attributes["db.statement"], "command_name find") self.assertEqual(span.attributes["net.peer.name"], "test.com") self.assertEqual(span.attributes["net.peer.port"], "1234") - self.assertEqual( - span.attributes["db.mongo.operation_id"], "operation_id" - ) - self.assertEqual( - span.attributes["db.mongo.request_id"], "test_request_id" - ) - - self.assertEqual(span.attributes["db.mongo.filter"], "filter") - self.assertEqual(span.attributes["db.mongo.sort"], "sort") - self.assertEqual(span.attributes["db.mongo.limit"], "limit") - self.assertEqual(span.attributes["db.mongo.pipeline"], "pipeline") def test_succeeded(self): mock_event = MockEvent({}) @@ -82,9 +66,6 @@ class TestPymongo(TestBase): spans_list = self.memory_exporter.get_finished_spans() self.assertEqual(len(spans_list), 1) span = spans_list[0] - self.assertEqual( - span.attributes["db.mongo.duration_micros"], "duration_micros" - ) self.assertIs( span.status.status_code, trace_api.status.StatusCode.UNSET ) @@ -116,9 +97,6 @@ class TestPymongo(TestBase): self.assertEqual(len(spans_list), 1) span = spans_list[0] - self.assertEqual( - span.attributes["db.mongo.duration_micros"], "duration_micros" - ) self.assertIs( span.status.status_code, trace_api.status.StatusCode.ERROR, ) @@ -139,13 +117,9 @@ class TestPymongo(TestBase): first_span = spans_list[0] second_span = spans_list[1] - self.assertEqual(first_span.attributes["db.mongo.request_id"], "first") self.assertIs( first_span.status.status_code, trace_api.status.StatusCode.UNSET, ) - self.assertEqual( - second_span.attributes["db.mongo.request_id"], "second" - ) self.assertIs( second_span.status.status_code, trace_api.status.StatusCode.ERROR, ) @@ -165,7 +139,7 @@ class TestPymongo(TestBase): self.assertEqual(len(spans_list), 1) span = spans_list[0] - self.assertEqual(span.name, "mongodb.command_name.123") + self.assertEqual(span.name, "command_name.123") class MockCommand: diff --git a/instrumentation/opentelemetry-instrumentation-pymysql/README.rst b/instrumentation/opentelemetry-instrumentation-pymysql/README.rst index 0b566d2a9..9fc22b04f 100644 --- a/instrumentation/opentelemetry-instrumentation-pymysql/README.rst +++ b/instrumentation/opentelemetry-instrumentation-pymysql/README.rst @@ -16,5 +16,5 @@ Installation References ---------- -* `OpenTelemetry PyMySQL Instrumentation `_ +* `OpenTelemetry PyMySQL Instrumentation `_ * `OpenTelemetry Project `_ diff --git a/instrumentation/opentelemetry-instrumentation-pymysql/setup.cfg b/instrumentation/opentelemetry-instrumentation-pymysql/setup.cfg index b84fe20d5..f54651fc3 100644 --- a/instrumentation/opentelemetry-instrumentation-pymysql/setup.cfg +++ b/instrumentation/opentelemetry-instrumentation-pymysql/setup.cfg @@ -19,7 +19,7 @@ long_description = file: README.rst long_description_content_type = text/x-rst author = OpenTelemetry Authors author_email = cncf-opentelemetry-contributors@lists.cncf.io -url = https://github.com/open-telemetry/opentelemetry-python/tree/master/instrumentation/opentelemetry-instrumentation-pymysql +url = https://github.com/open-telemetry/opentelemetry-python-contrib/tree/master/instrumentation/opentelemetry-instrumentation-pymysql platforms = any license = Apache-2.0 classifiers = diff --git a/instrumentation/opentelemetry-instrumentation-pyramid/README.rst b/instrumentation/opentelemetry-instrumentation-pyramid/README.rst index 931486773..811715a9d 100644 --- a/instrumentation/opentelemetry-instrumentation-pyramid/README.rst +++ b/instrumentation/opentelemetry-instrumentation-pyramid/README.rst @@ -27,6 +27,6 @@ will exclude requests such as ``https://site/client/123/info`` and ``https://sit References ---------- -* `OpenTelemetry Pyramid Instrumentation `_ +* `OpenTelemetry Pyramid Instrumentation `_ * `OpenTelemetry Project `_ diff --git a/instrumentation/opentelemetry-instrumentation-pyramid/setup.cfg b/instrumentation/opentelemetry-instrumentation-pyramid/setup.cfg index 44db6be96..e7bb5b747 100644 --- a/instrumentation/opentelemetry-instrumentation-pyramid/setup.cfg +++ b/instrumentation/opentelemetry-instrumentation-pyramid/setup.cfg @@ -19,7 +19,7 @@ long_description = file: README.rst long_description_content_type = text/x-rst author = OpenTelemetry Authors author_email = cncf-opentelemetry-contributors@lists.cncf.io -url = https://github.com/open-telemetry/opentelemetry-python/tree/master/instrumentation/opentelemetry-instrumentation-pyramid +url = https://github.com/open-telemetry/opentelemetry-python-contrib/tree/master/instrumentation/opentelemetry-instrumentation-pyramid platforms = any license = Apache-2.0 classifiers = diff --git a/instrumentation/opentelemetry-instrumentation-redis/CHANGELOG.md b/instrumentation/opentelemetry-instrumentation-redis/CHANGELOG.md index 8f2d5f7e8..5924a131e 100644 --- a/instrumentation/opentelemetry-instrumentation-redis/CHANGELOG.md +++ b/instrumentation/opentelemetry-instrumentation-redis/CHANGELOG.md @@ -2,6 +2,9 @@ ## Unreleased +- Update redis instrumentation to follow semantic conventions + ([#184](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/184)) + ## Version 0.13b0 Released 2020-09-17 diff --git a/instrumentation/opentelemetry-instrumentation-redis/README.rst b/instrumentation/opentelemetry-instrumentation-redis/README.rst index 1a071ad0f..5e230ae88 100644 --- a/instrumentation/opentelemetry-instrumentation-redis/README.rst +++ b/instrumentation/opentelemetry-instrumentation-redis/README.rst @@ -19,5 +19,5 @@ Installation References ---------- -* `OpenTelemetry Redis Instrumentation `_ +* `OpenTelemetry Redis Instrumentation `_ * `OpenTelemetry Project `_ diff --git a/instrumentation/opentelemetry-instrumentation-redis/setup.cfg b/instrumentation/opentelemetry-instrumentation-redis/setup.cfg index 186e167de..55ff9df8b 100644 --- a/instrumentation/opentelemetry-instrumentation-redis/setup.cfg +++ b/instrumentation/opentelemetry-instrumentation-redis/setup.cfg @@ -19,7 +19,7 @@ long_description = file: README.rst long_description_content_type = text/x-rst author = OpenTelemetry Authors author_email = cncf-opentelemetry-contributors@lists.cncf.io -url = https://github.com/open-telemetry/opentelemetry-python/tree/master/instrumentation/opentelemetry-instrumentation-redis +url = https://github.com/open-telemetry/opentelemetry-python-contrib/tree/master/instrumentation/opentelemetry-instrumentation-redis platforms = any license = Apache-2.0 classifiers = diff --git a/instrumentation/opentelemetry-instrumentation-redis/src/opentelemetry/instrumentation/redis/__init__.py b/instrumentation/opentelemetry-instrumentation-redis/src/opentelemetry/instrumentation/redis/__init__.py index 6cf59a4a0..5bf83242c 100644 --- a/instrumentation/opentelemetry-instrumentation-redis/src/opentelemetry/instrumentation/redis/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-redis/src/opentelemetry/instrumentation/redis/__init__.py @@ -56,7 +56,6 @@ from opentelemetry.instrumentation.utils import unwrap _DEFAULT_SERVICE = "redis" _RAWCMD = "db.statement" -_CMD = "redis.command" def _set_connection_attributes(span, conn): @@ -71,8 +70,13 @@ def _set_connection_attributes(span, conn): def _traced_execute_command(func, instance, args, kwargs): tracer = getattr(redis, "_opentelemetry_tracer") query = _format_command_args(args) + name = "" + if len(args) > 0 and args[0]: + name = args[0] + else: + name = instance.connection_pool.connection_kwargs.get("db", 0) with tracer.start_as_current_span( - _CMD, kind=trace.SpanKind.CLIENT + name, kind=trace.SpanKind.CLIENT ) as span: if span.is_recording(): span.set_attribute("service", tracer.instrumentation_info.name) @@ -88,8 +92,10 @@ def _traced_execute_pipeline(func, instance, args, kwargs): cmds = [_format_command_args(c) for c, _ in instance.command_stack] resource = "\n".join(cmds) + span_name = " ".join([args[0] for args, _ in instance.command_stack]) + with tracer.start_as_current_span( - _CMD, kind=trace.SpanKind.CLIENT + span_name, kind=trace.SpanKind.CLIENT ) as span: if span.is_recording(): span.set_attribute("service", tracer.instrumentation_info.name) diff --git a/instrumentation/opentelemetry-instrumentation-redis/src/opentelemetry/instrumentation/redis/util.py b/instrumentation/opentelemetry-instrumentation-redis/src/opentelemetry/instrumentation/redis/util.py index 289513408..f2ac71a36 100644 --- a/instrumentation/opentelemetry-instrumentation-redis/src/opentelemetry/instrumentation/redis/util.py +++ b/instrumentation/opentelemetry-instrumentation-redis/src/opentelemetry/instrumentation/redis/util.py @@ -20,15 +20,16 @@ Some utils used by the redis integration def _extract_conn_attributes(conn_kwargs): """ Transform redis conn info into dict """ attributes = { - "db.type": "redis", - "db.instance": conn_kwargs.get("db", 0), + "db.system": "redis", + "db.name": conn_kwargs.get("db", 0), } try: - attributes["db.url"] = "redis://{}:{}".format( - conn_kwargs["host"], conn_kwargs["port"] - ) + attributes["net.peer.name"] = conn_kwargs["host"] + attributes["net.peer.ip"] = conn_kwargs["port"] + attributes["net.transport"] = "IP.TCP" except KeyError: - pass # don't include url attribute + attributes["net.peer.name"] = conn_kwargs["path"] + attributes["net.transport"] = "Unix" return attributes diff --git a/instrumentation/opentelemetry-instrumentation-redis/tests/test_redis.py b/instrumentation/opentelemetry-instrumentation-redis/tests/test_redis.py index 3e07ac725..0ca99bead 100644 --- a/instrumentation/opentelemetry-instrumentation-redis/tests/test_redis.py +++ b/instrumentation/opentelemetry-instrumentation-redis/tests/test_redis.py @@ -31,7 +31,7 @@ class TestRedis(TestBase): spans = self.memory_exporter.get_finished_spans() self.assertEqual(len(spans), 1) span = spans[0] - self.assertEqual(span.name, "redis.command") + self.assertEqual(span.name, "GET") self.assertEqual(span.kind, SpanKind.CLIENT) def test_not_recording(self): diff --git a/instrumentation/opentelemetry-instrumentation-requests/README.rst b/instrumentation/opentelemetry-instrumentation-requests/README.rst index d4944d352..0b614b22b 100644 --- a/instrumentation/opentelemetry-instrumentation-requests/README.rst +++ b/instrumentation/opentelemetry-instrumentation-requests/README.rst @@ -19,5 +19,5 @@ Installation References ---------- -* `OpenTelemetry requests Instrumentation `_ +* `OpenTelemetry requests Instrumentation `_ * `OpenTelemetry Project `_ diff --git a/instrumentation/opentelemetry-instrumentation-requests/setup.cfg b/instrumentation/opentelemetry-instrumentation-requests/setup.cfg index 8aaec6e84..fbd0e1694 100644 --- a/instrumentation/opentelemetry-instrumentation-requests/setup.cfg +++ b/instrumentation/opentelemetry-instrumentation-requests/setup.cfg @@ -19,7 +19,7 @@ long_description = file: README.rst long_description_content_type = text/x-rst author = OpenTelemetry Authors author_email = cncf-opentelemetry-contributors@lists.cncf.io -url = https://github.com/open-telemetry/opentelemetry-python/tree/master/instrumentation/opentelemetry-instrumentation-requests +url = https://github.com/open-telemetry/opentelemetry-python-contrib/tree/master/instrumentation/opentelemetry-instrumentation-requests platforms = any license = Apache-2.0 classifiers = diff --git a/instrumentation/opentelemetry-instrumentation-sklearn/README.rst b/instrumentation/opentelemetry-instrumentation-sklearn/README.rst index 20679b101..f1658cfcf 100644 --- a/instrumentation/opentelemetry-instrumentation-sklearn/README.rst +++ b/instrumentation/opentelemetry-instrumentation-sklearn/README.rst @@ -19,5 +19,5 @@ Installation References ---------- -* `OpenTelemetry sklearn Instrumentation `_ +* `OpenTelemetry sklearn Instrumentation `_ * `OpenTelemetry Project `_ diff --git a/instrumentation/opentelemetry-instrumentation-sqlalchemy/README.rst b/instrumentation/opentelemetry-instrumentation-sqlalchemy/README.rst index f29cbe9ff..f33cf8679 100644 --- a/instrumentation/opentelemetry-instrumentation-sqlalchemy/README.rst +++ b/instrumentation/opentelemetry-instrumentation-sqlalchemy/README.rst @@ -20,5 +20,5 @@ References ---------- * `SQLAlchemy Project `_ -* `OpenTelemetry SQLAlchemy Tracing `_ +* `OpenTelemetry SQLAlchemy Tracing `_ * `OpenTelemetry Project `_ \ No newline at end of file diff --git a/instrumentation/opentelemetry-instrumentation-sqlalchemy/setup.cfg b/instrumentation/opentelemetry-instrumentation-sqlalchemy/setup.cfg index c6b44013c..e819b37f6 100644 --- a/instrumentation/opentelemetry-instrumentation-sqlalchemy/setup.cfg +++ b/instrumentation/opentelemetry-instrumentation-sqlalchemy/setup.cfg @@ -19,7 +19,7 @@ long_description = file: README.rst long_description_content_type = text/x-rst author = OpenTelemetry Authors author_email = cncf-opentelemetry-contributors@lists.cncf.io -url = https://github.com/open-telemetry/opentelemetry-python/tree/master/instrumentation/opentelemetry-instrumentation-sqlalchemy +url = https://github.com/open-telemetry/opentelemetry-python-contrib/tree/master/instrumentation/opentelemetry-instrumentation-sqlalchemy platforms = any license = Apache-2.0 classifiers = diff --git a/instrumentation/opentelemetry-instrumentation-sqlite3/README.rst b/instrumentation/opentelemetry-instrumentation-sqlite3/README.rst index 0d2aa2dd9..0d842dcdb 100644 --- a/instrumentation/opentelemetry-instrumentation-sqlite3/README.rst +++ b/instrumentation/opentelemetry-instrumentation-sqlite3/README.rst @@ -16,6 +16,6 @@ Installation References ---------- -* `OpenTelemetry SQLite3 Instrumentation `_ +* `OpenTelemetry SQLite3 Instrumentation `_ * `OpenTelemetry Project `_ diff --git a/instrumentation/opentelemetry-instrumentation-sqlite3/setup.cfg b/instrumentation/opentelemetry-instrumentation-sqlite3/setup.cfg index d8145be39..8d802d762 100644 --- a/instrumentation/opentelemetry-instrumentation-sqlite3/setup.cfg +++ b/instrumentation/opentelemetry-instrumentation-sqlite3/setup.cfg @@ -19,7 +19,7 @@ long_description = file: README.rst long_description_content_type = text/x-rst author = OpenTelemetry Authors author_email = cncf-opentelemetry-contributors@lists.cncf.io -url = https://github.com/open-telemetry/opentelemetry-python/tree/master/instrumentation/opentelemetry-instrumentation-sqlite3 +url = https://github.com/open-telemetry/opentelemetry-python-contrib/tree/master/instrumentation/opentelemetry-instrumentation-sqlite3 platforms = any license = Apache-2.0 classifiers = diff --git a/instrumentation/opentelemetry-instrumentation-sqlite3/src/opentelemetry/instrumentation/sqlite3/__init__.py b/instrumentation/opentelemetry-instrumentation-sqlite3/src/opentelemetry/instrumentation/sqlite3/__init__.py index 986b0c621..bad033b29 100644 --- a/instrumentation/opentelemetry-instrumentation-sqlite3/src/opentelemetry/instrumentation/sqlite3/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-sqlite3/src/opentelemetry/instrumentation/sqlite3/__init__.py @@ -51,7 +51,7 @@ class SQLite3Instrumentor(BaseInstrumentor): # No useful attributes of sqlite3 connection object _CONNECTION_ATTRIBUTES = {} - _DATABASE_COMPONENT = "sqlite3" + _DATABASE_COMPONENT = "sqlite" _DATABASE_TYPE = "sql" def _instrument(self, **kwargs): diff --git a/instrumentation/opentelemetry-instrumentation-sqlite3/tests/test_sqlite3.py b/instrumentation/opentelemetry-instrumentation-sqlite3/tests/test_sqlite3.py index 0e385cf3e..a4fc88706 100644 --- a/instrumentation/opentelemetry-instrumentation-sqlite3/tests/test_sqlite3.py +++ b/instrumentation/opentelemetry-instrumentation-sqlite3/tests/test_sqlite3.py @@ -37,7 +37,7 @@ class TestSQLite3(TestBase): if cls._connection: cls._connection.close() - def validate_spans(self): + def validate_spans(self, span_name): spans = self.memory_exporter.get_finished_spans() self.assertEqual(len(spans), 2) for span in spans: @@ -50,34 +50,30 @@ class TestSQLite3(TestBase): self.assertIsNotNone(root_span) self.assertIsNotNone(child_span) self.assertEqual(root_span.name, "rootSpan") - self.assertEqual(child_span.name, "sqlite3") + self.assertEqual(child_span.name, span_name) self.assertIsNotNone(child_span.parent) self.assertIs(child_span.parent, root_span.get_span_context()) self.assertIs(child_span.kind, trace_api.SpanKind.CLIENT) def test_execute(self): - """Should create a child span for execute method - """ + """Should create a child span for execute method""" + stmt = "CREATE TABLE IF NOT EXISTS test (id integer)" with self._tracer.start_as_current_span("rootSpan"): - self._cursor.execute( - "CREATE TABLE IF NOT EXISTS test (id integer)" - ) - self.validate_spans() + self._cursor.execute(stmt) + self.validate_spans(stmt) def test_executemany(self): - """Should create a child span for executemany - """ + """Should create a child span for executemany""" + stmt = "INSERT INTO test (id) VALUES (?)" with self._tracer.start_as_current_span("rootSpan"): data = [("1",), ("2",), ("3",)] - stmt = "INSERT INTO test (id) VALUES (?)" self._cursor.executemany(stmt, data) - self.validate_spans() + self.validate_spans(stmt) def test_callproc(self): - """Should create a child span for callproc - """ + """Should create a child span for callproc""" with self._tracer.start_as_current_span("rootSpan"), self.assertRaises( Exception ): self._cursor.callproc("test", ()) - self.validate_spans() + self.validate_spans("test") diff --git a/instrumentation/opentelemetry-instrumentation-starlette/setup.cfg b/instrumentation/opentelemetry-instrumentation-starlette/setup.cfg index 04b1f3cbe..93395eb47 100644 --- a/instrumentation/opentelemetry-instrumentation-starlette/setup.cfg +++ b/instrumentation/opentelemetry-instrumentation-starlette/setup.cfg @@ -19,7 +19,7 @@ long_description = file: README.rst long_description_content_type = text/x-rst author = OpenTelemetry Authors author_email = cncf-opentelemetry-contributors@lists.cncf.io -url = https://github.com/open-telemetry/opentelemetry-python/tree/master/instrumentation/opentelemetry-instrumentation-starlette +url = https://github.com/open-telemetry/opentelemetry-python-contrib/tree/master/instrumentation/opentelemetry-instrumentation-starlette platforms = any license = Apache-2.0 classifiers = diff --git a/instrumentation/opentelemetry-instrumentation-system-metrics/README.rst b/instrumentation/opentelemetry-instrumentation-system-metrics/README.rst index fc984256b..7a6c65b59 100644 --- a/instrumentation/opentelemetry-instrumentation-system-metrics/README.rst +++ b/instrumentation/opentelemetry-instrumentation-system-metrics/README.rst @@ -19,6 +19,6 @@ Installation References ---------- -* `OpenTelemetry System Metrics Instrumentation `_ +* `OpenTelemetry System Metrics Instrumentation `_ * `OpenTelemetry Project `_ diff --git a/instrumentation/opentelemetry-instrumentation-system-metrics/setup.cfg b/instrumentation/opentelemetry-instrumentation-system-metrics/setup.cfg index f8c27e54d..01daaa444 100644 --- a/instrumentation/opentelemetry-instrumentation-system-metrics/setup.cfg +++ b/instrumentation/opentelemetry-instrumentation-system-metrics/setup.cfg @@ -19,7 +19,7 @@ long_description = file: README.rst long_description_content_type = text/x-rst author = OpenTelemetry Authors author_email = cncf-opentelemetry-contributors@lists.cncf.io -url = https://github.com/open-telemetry/opentelemetry-python/tree/master/instrumentation/opentelemetry-instrumentation-system-metrics +url = https://github.com/open-telemetry/opentelemetry-python-contrib/tree/master/instrumentation/opentelemetry-instrumentation-system-metrics platforms = any license = Apache-2.0 classifiers = diff --git a/instrumentation/opentelemetry-instrumentation-system-metrics/src/opentelemetry/instrumentation/system_metrics/__init__.py b/instrumentation/opentelemetry-instrumentation-system-metrics/src/opentelemetry/instrumentation/system_metrics/__init__.py index 2b453dbd7..cedc79113 100644 --- a/instrumentation/opentelemetry-instrumentation-system-metrics/src/opentelemetry/instrumentation/system_metrics/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-system-metrics/src/opentelemetry/instrumentation/system_metrics/__init__.py @@ -92,9 +92,9 @@ class SystemMetrics: config: typing.Optional[typing.Dict[str, typing.List[str]]] = None, ): self._labels = {} if labels is None else labels - self.meter = metrics.get_meter(__name__) + self.accumulator = metrics.get_meter(__name__) self.controller = PushController( - meter=self.meter, exporter=exporter, interval=interval + accumulator=self.accumulator, exporter=exporter, interval=interval ) self._python_implementation = python_implementation().lower() if config is None: @@ -155,7 +155,7 @@ class SystemMetrics: self._runtime_cpu_time_labels = self._labels.copy() self._runtime_gc_count_labels = self._labels.copy() - self.meter.register_sumobserver( + self.accumulator.register_sumobserver( callback=self._get_system_cpu_time, name="system.cpu.time", description="System CPU time", @@ -163,7 +163,7 @@ class SystemMetrics: value_type=float, ) - self.meter.register_valueobserver( + self.accumulator.register_valueobserver( callback=self._get_system_cpu_utilization, name="system.cpu.utilization", description="System CPU utilization", @@ -171,7 +171,7 @@ class SystemMetrics: value_type=float, ) - self.meter.register_valueobserver( + self.accumulator.register_valueobserver( callback=self._get_system_memory_usage, name="system.memory.usage", description="System memory usage", @@ -179,7 +179,7 @@ class SystemMetrics: value_type=int, ) - self.meter.register_valueobserver( + self.accumulator.register_valueobserver( callback=self._get_system_memory_utilization, name="system.memory.utilization", description="System memory utilization", @@ -187,7 +187,7 @@ class SystemMetrics: value_type=float, ) - self.meter.register_valueobserver( + self.accumulator.register_valueobserver( callback=self._get_system_swap_usage, name="system.swap.usage", description="System swap usage", @@ -195,7 +195,7 @@ class SystemMetrics: value_type=int, ) - self.meter.register_valueobserver( + self.accumulator.register_valueobserver( callback=self._get_system_swap_utilization, name="system.swap.utilization", description="System swap utilization", @@ -203,7 +203,7 @@ class SystemMetrics: value_type=float, ) - # self.meter.register_sumobserver( + # self.accumulator.register_sumobserver( # callback=self._get_system_swap_page_faults, # name="system.swap.page_faults", # description="System swap page faults", @@ -211,7 +211,7 @@ class SystemMetrics: # value_type=int, # ) - # self.meter.register_sumobserver( + # self.accumulator.register_sumobserver( # callback=self._get_system_swap_page_operations, # name="system.swap.page_operations", # description="System swap page operations", @@ -219,7 +219,7 @@ class SystemMetrics: # value_type=int, # ) - self.meter.register_sumobserver( + self.accumulator.register_sumobserver( callback=self._get_system_disk_io, name="system.disk.io", description="System disk IO", @@ -227,7 +227,7 @@ class SystemMetrics: value_type=int, ) - self.meter.register_sumobserver( + self.accumulator.register_sumobserver( callback=self._get_system_disk_operations, name="system.disk.operations", description="System disk operations", @@ -235,7 +235,7 @@ class SystemMetrics: value_type=int, ) - self.meter.register_sumobserver( + self.accumulator.register_sumobserver( callback=self._get_system_disk_time, name="system.disk.time", description="System disk time", @@ -243,7 +243,7 @@ class SystemMetrics: value_type=float, ) - self.meter.register_sumobserver( + self.accumulator.register_sumobserver( callback=self._get_system_disk_merged, name="system.disk.merged", description="System disk merged", @@ -251,7 +251,7 @@ class SystemMetrics: value_type=int, ) - # self.meter.register_valueobserver( + # self.accumulator.register_valueobserver( # callback=self._get_system_filesystem_usage, # name="system.filesystem.usage", # description="System filesystem usage", @@ -259,7 +259,7 @@ class SystemMetrics: # value_type=int, # ) - # self.meter.register_valueobserver( + # self.accumulator.register_valueobserver( # callback=self._get_system_filesystem_utilization, # name="system.filesystem.utilization", # description="System filesystem utilization", @@ -267,7 +267,7 @@ class SystemMetrics: # value_type=float, # ) - self.meter.register_sumobserver( + self.accumulator.register_sumobserver( callback=self._get_system_network_dropped_packets, name="system.network.dropped_packets", description="System network dropped_packets", @@ -275,7 +275,7 @@ class SystemMetrics: value_type=int, ) - self.meter.register_sumobserver( + self.accumulator.register_sumobserver( callback=self._get_system_network_packets, name="system.network.packets", description="System network packets", @@ -283,7 +283,7 @@ class SystemMetrics: value_type=int, ) - self.meter.register_sumobserver( + self.accumulator.register_sumobserver( callback=self._get_system_network_errors, name="system.network.errors", description="System network errors", @@ -291,7 +291,7 @@ class SystemMetrics: value_type=int, ) - self.meter.register_sumobserver( + self.accumulator.register_sumobserver( callback=self._get_system_network_io, name="system.network.io", description="System network io", @@ -299,7 +299,7 @@ class SystemMetrics: value_type=int, ) - self.meter.register_updownsumobserver( + self.accumulator.register_updownsumobserver( callback=self._get_system_network_connections, name="system.network.connections", description="System network connections", @@ -307,7 +307,7 @@ class SystemMetrics: value_type=int, ) - self.meter.register_sumobserver( + self.accumulator.register_sumobserver( callback=self._get_runtime_memory, name="runtime.{}.memory".format(self._python_implementation), description="Runtime {} memory".format( @@ -317,7 +317,7 @@ class SystemMetrics: value_type=int, ) - self.meter.register_sumobserver( + self.accumulator.register_sumobserver( callback=self._get_runtime_cpu_time, name="runtime.{}.cpu_time".format(self._python_implementation), description="Runtime {} CPU time".format( @@ -327,7 +327,7 @@ class SystemMetrics: value_type=float, ) - self.meter.register_sumobserver( + self.accumulator.register_sumobserver( callback=self._get_runtime_gc_count, name="runtime.{}.gc_count".format(self._python_implementation), description="Runtime {} GC count".format( diff --git a/instrumentation/opentelemetry-instrumentation-tornado/README.rst b/instrumentation/opentelemetry-instrumentation-tornado/README.rst index 088c7f0e8..1d9e92335 100644 --- a/instrumentation/opentelemetry-instrumentation-tornado/README.rst +++ b/instrumentation/opentelemetry-instrumentation-tornado/README.rst @@ -47,5 +47,5 @@ will extract path_info and content_type attributes from every traced request and References ---------- -* `OpenTelemetry Tornado Instrumentation `_ +* `OpenTelemetry Tornado Instrumentation `_ * `OpenTelemetry Project `_ diff --git a/instrumentation/opentelemetry-instrumentation-tornado/setup.cfg b/instrumentation/opentelemetry-instrumentation-tornado/setup.cfg index 889eb0e97..c0feeba3a 100644 --- a/instrumentation/opentelemetry-instrumentation-tornado/setup.cfg +++ b/instrumentation/opentelemetry-instrumentation-tornado/setup.cfg @@ -19,7 +19,7 @@ long_description = file: README.rst long_description_content_type = text/x-rst author = OpenTelemetry Authors author_email = cncf-opentelemetry-contributors@lists.cncf.io -url = https://github.com/open-telemetry/opentelemetry-python/tree/master/instrumentation/opentelemetry-instrumentation-tornado +url = https://github.com/open-telemetry/opentelemetry-python-contrib/tree/master/instrumentation/opentelemetry-instrumentation-tornado platforms = any license = Apache-2.0 classifiers = diff --git a/instrumentation/opentelemetry-instrumentation-wsgi/README.rst b/instrumentation/opentelemetry-instrumentation-wsgi/README.rst index ac39dac0c..c3f06bfed 100644 --- a/instrumentation/opentelemetry-instrumentation-wsgi/README.rst +++ b/instrumentation/opentelemetry-instrumentation-wsgi/README.rst @@ -21,6 +21,6 @@ Installation References ---------- -* `OpenTelemetry WSGI Middleware `_ +* `OpenTelemetry WSGI Middleware `_ * `OpenTelemetry Project `_ * `WSGI `_ diff --git a/instrumentation/opentelemetry-instrumentation-wsgi/setup.cfg b/instrumentation/opentelemetry-instrumentation-wsgi/setup.cfg index 585a51341..8d656592e 100644 --- a/instrumentation/opentelemetry-instrumentation-wsgi/setup.cfg +++ b/instrumentation/opentelemetry-instrumentation-wsgi/setup.cfg @@ -19,7 +19,7 @@ long_description = file: README.rst long_description_content_type = text/x-rst author = OpenTelemetry Authors author_email = cncf-opentelemetry-contributors@lists.cncf.io -url = https://github.com/open-telemetry/opentelemetry-python/tree/master/instrumentation/opentelemetry-instrumentation-wsgi +url = https://github.com/open-telemetry/opentelemetry-python-contrib/tree/master/instrumentation/opentelemetry-instrumentation-wsgi platforms = any license = Apache-2.0 classifiers = diff --git a/sdk-extension/opentelemetry-sdk-extension-aws/CHANGELOG.md b/sdk-extension/opentelemetry-sdk-extension-aws/CHANGELOG.md index 7a82dad1c..406feb500 100644 --- a/sdk-extension/opentelemetry-sdk-extension-aws/CHANGELOG.md +++ b/sdk-extension/opentelemetry-sdk-extension-aws/CHANGELOG.md @@ -2,5 +2,9 @@ ## Unreleased +- Fix typo for installing OTel SDK in docs + ([#200](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/200)) +- Import missing components for docs + ([#198](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/198)) - Provide components needed to Configure OTel SDK for Tracing with AWS X-Ray ([#130](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/130)) diff --git a/sdk-extension/opentelemetry-sdk-extension-aws/README.rst b/sdk-extension/opentelemetry-sdk-extension-aws/README.rst index 8fd5b683d..2c74a6527 100644 --- a/sdk-extension/opentelemetry-sdk-extension-aws/README.rst +++ b/sdk-extension/opentelemetry-sdk-extension-aws/README.rst @@ -24,9 +24,19 @@ Usage (AWS X-Ray IDs Generator) Configure the OTel SDK TracerProvider with the provided custom IDs Generator to make spans compatible with the AWS X-Ray backend tracing service. +Install the OpenTelemetry SDK package. + +:: + + pip install opentelemetry-sdk + +Next, use the provided `AwsXRayIdsGenerator` to initialize the `TracerProvider`. + .. code-block:: python + import opentelemetry.trace as trace from opentelemetry.sdk.extension.aws.trace import AwsXRayIdsGenerator + from opentelemetry.sdk.trace import TracerProvider trace.set_tracer_provider( TracerProvider(ids_generator=AwsXRayIdsGenerator()) @@ -36,14 +46,25 @@ make spans compatible with the AWS X-Ray backend tracing service. Usage (AWS X-Ray Propagator) ---------------------------- -Set this environment variable to have the OTel SDK use the provided AWS X-Ray -Propagator: +Use the provided AWS X-Ray Propagator to inject the necessary context into +traces sent to external systems. + +This can be done by either setting this environment variable: :: export OTEL_PROPAGATORS = aws_xray +Or by setting this propagator in your instrumented application: + +.. code-block:: python + + from opentelemetry import propagators + from opentelemetry.sdk.extension.aws.trace.propagation.aws_xray_format import AwsXRayFormat + + propagators.set_global_textmap(AwsXRayFormat()) + References ---------- diff --git a/tests/opentelemetry-docker-tests/tests/check_availability.py b/tests/opentelemetry-docker-tests/tests/check_availability.py index 308257219..0e066610c 100644 --- a/tests/opentelemetry-docker-tests/tests/check_availability.py +++ b/tests/opentelemetry-docker-tests/tests/check_availability.py @@ -24,16 +24,16 @@ MONGODB_COLLECTION_NAME = "test" MONGODB_DB_NAME = os.getenv("MONGODB_DB_NAME", "opentelemetry-tests") MONGODB_HOST = os.getenv("MONGODB_HOST", "localhost") MONGODB_PORT = int(os.getenv("MONGODB_PORT", "27017")) -MYSQL_DB_NAME = os.getenv("MYSQL_DB_NAME ", "opentelemetry-tests") -MYSQL_HOST = os.getenv("MYSQL_HOST ", "localhost") -MYSQL_PORT = int(os.getenv("MYSQL_PORT ", "3306")) -MYSQL_USER = os.getenv("MYSQL_USER ", "testuser") -MYSQL_PASSWORD = os.getenv("MYSQL_PASSWORD ", "testpassword") +MYSQL_DB_NAME = os.getenv("MYSQL_DB_NAME", "opentelemetry-tests") +MYSQL_HOST = os.getenv("MYSQL_HOST", "localhost") +MYSQL_PORT = int(os.getenv("MYSQL_PORT", "3306")) +MYSQL_USER = os.getenv("MYSQL_USER", "testuser") +MYSQL_PASSWORD = os.getenv("MYSQL_PASSWORD", "testpassword") POSTGRES_DB_NAME = os.getenv("POSTGRESQL_DB_NAME", "opentelemetry-tests") POSTGRES_HOST = os.getenv("POSTGRESQL_HOST", "localhost") -POSTGRES_PASSWORD = os.getenv("POSTGRESQL_HOST", "testpassword") +POSTGRES_PASSWORD = os.getenv("POSTGRESQL_PASSWORD", "testpassword") POSTGRES_PORT = int(os.getenv("POSTGRESQL_PORT", "5432")) -POSTGRES_USER = os.getenv("POSTGRESQL_HOST", "testuser") +POSTGRES_USER = os.getenv("POSTGRESQL_USER", "testuser") REDIS_HOST = os.getenv("REDIS_HOST", "localhost") REDIS_PORT = int(os.getenv("REDIS_PORT ", "6379")) RETRY_COUNT = 8 diff --git a/tests/opentelemetry-docker-tests/tests/mysql/test_mysql_functional.py b/tests/opentelemetry-docker-tests/tests/mysql/test_mysql_functional.py index fc237fe12..ec6eed313 100644 --- a/tests/opentelemetry-docker-tests/tests/mysql/test_mysql_functional.py +++ b/tests/opentelemetry-docker-tests/tests/mysql/test_mysql_functional.py @@ -20,11 +20,11 @@ from opentelemetry import trace as trace_api from opentelemetry.instrumentation.mysql import MySQLInstrumentor from opentelemetry.test.test_base import TestBase -MYSQL_USER = os.getenv("MYSQL_USER ", "testuser") -MYSQL_PASSWORD = os.getenv("MYSQL_PASSWORD ", "testpassword") -MYSQL_HOST = os.getenv("MYSQL_HOST ", "localhost") -MYSQL_PORT = int(os.getenv("MYSQL_PORT ", "3306")) -MYSQL_DB_NAME = os.getenv("MYSQL_DB_NAME ", "opentelemetry-tests") +MYSQL_USER = os.getenv("MYSQL_USER", "testuser") +MYSQL_PASSWORD = os.getenv("MYSQL_PASSWORD", "testpassword") +MYSQL_HOST = os.getenv("MYSQL_HOST", "localhost") +MYSQL_PORT = int(os.getenv("MYSQL_PORT", "3306")) +MYSQL_DB_NAME = os.getenv("MYSQL_DB_NAME", "opentelemetry-tests") class TestFunctionalMysql(TestBase): @@ -53,7 +53,7 @@ class TestFunctionalMysql(TestBase): ) self._cursor = self._connection.cursor() - def validate_spans(self): + def validate_spans(self, span_name): spans = self.memory_exporter.get_finished_spans() self.assertEqual(len(spans), 2) for span in spans: @@ -66,42 +66,47 @@ class TestFunctionalMysql(TestBase): self.assertIsNotNone(root_span) self.assertIsNotNone(db_span) self.assertEqual(root_span.name, "rootSpan") - self.assertEqual(db_span.name, "mysql.opentelemetry-tests") + self.assertEqual(db_span.name, span_name) self.assertIsNotNone(db_span.parent) self.assertIs(db_span.parent, root_span.get_span_context()) self.assertIs(db_span.kind, trace_api.SpanKind.CLIENT) - self.assertEqual(db_span.attributes["db.instance"], MYSQL_DB_NAME) + self.assertEqual(db_span.attributes["db.system"], "mysql") + self.assertEqual(db_span.attributes["db.name"], MYSQL_DB_NAME) + self.assertEqual(db_span.attributes["db.user"], MYSQL_USER) self.assertEqual(db_span.attributes["net.peer.name"], MYSQL_HOST) self.assertEqual(db_span.attributes["net.peer.port"], MYSQL_PORT) def test_execute(self): """Should create a child span for execute""" + stmt = "CREATE TABLE IF NOT EXISTS test (id INT)" with self._tracer.start_as_current_span("rootSpan"): - self._cursor.execute("CREATE TABLE IF NOT EXISTS test (id INT)") - self.validate_spans() + self._cursor.execute(stmt) + self.validate_spans(stmt) def test_execute_with_connection_context_manager(self): """Should create a child span for execute with connection context""" + stmt = "CREATE TABLE IF NOT EXISTS test (id INT)" with self._tracer.start_as_current_span("rootSpan"): with self._connection as conn: cursor = conn.cursor() - cursor.execute("CREATE TABLE IF NOT EXISTS test (id INT)") - self.validate_spans() + cursor.execute(stmt) + self.validate_spans(stmt) def test_execute_with_cursor_context_manager(self): """Should create a child span for execute with cursor context""" + stmt = "CREATE TABLE IF NOT EXISTS test (id INT)" with self._tracer.start_as_current_span("rootSpan"): with self._connection.cursor() as cursor: - cursor.execute("CREATE TABLE IF NOT EXISTS test (id INT)") - self.validate_spans() + cursor.execute(stmt) + self.validate_spans(stmt) def test_executemany(self): """Should create a child span for executemany""" + stmt = "INSERT INTO test (id) VALUES (%s)" with self._tracer.start_as_current_span("rootSpan"): data = (("1",), ("2",), ("3",)) - stmt = "INSERT INTO test (id) VALUES (%s)" self._cursor.executemany(stmt, data) - self.validate_spans() + self.validate_spans(stmt) def test_callproc(self): """Should create a child span for callproc""" @@ -109,4 +114,4 @@ class TestFunctionalMysql(TestBase): Exception ): self._cursor.callproc("test", ()) - self.validate_spans() + self.validate_spans("test") diff --git a/tests/opentelemetry-docker-tests/tests/postgres/test_aiopg_functional.py b/tests/opentelemetry-docker-tests/tests/postgres/test_aiopg_functional.py index d76cd702e..030aecc66 100644 --- a/tests/opentelemetry-docker-tests/tests/postgres/test_aiopg_functional.py +++ b/tests/opentelemetry-docker-tests/tests/postgres/test_aiopg_functional.py @@ -22,11 +22,11 @@ from opentelemetry import trace as trace_api from opentelemetry.instrumentation.aiopg import AiopgInstrumentor from opentelemetry.test.test_base import TestBase -POSTGRES_HOST = os.getenv("POSTGRESQL_HOST ", "localhost") -POSTGRES_PORT = int(os.getenv("POSTGRESQL_PORT ", "5432")) -POSTGRES_DB_NAME = os.getenv("POSTGRESQL_DB_NAME ", "opentelemetry-tests") -POSTGRES_PASSWORD = os.getenv("POSTGRESQL_HOST ", "testpassword") -POSTGRES_USER = os.getenv("POSTGRESQL_HOST ", "testuser") +POSTGRES_HOST = os.getenv("POSTGRESQL_HOST", "localhost") +POSTGRES_PORT = int(os.getenv("POSTGRESQL_PORT", "5432")) +POSTGRES_DB_NAME = os.getenv("POSTGRESQL_DB_NAME", "opentelemetry-tests") +POSTGRES_PASSWORD = os.getenv("POSTGRESQL_PASSWORD", "testpassword") +POSTGRES_USER = os.getenv("POSTGRESQL_USER", "testuser") def async_call(coro): @@ -61,7 +61,7 @@ class TestFunctionalAiopgConnect(TestBase): cls._connection.close() AiopgInstrumentor().uninstrument() - def validate_spans(self): + def validate_spans(self, span_name): spans = self.memory_exporter.get_finished_spans() self.assertEqual(len(spans), 2) for span in spans: @@ -74,34 +74,31 @@ class TestFunctionalAiopgConnect(TestBase): self.assertIsNotNone(root_span) self.assertIsNotNone(child_span) self.assertEqual(root_span.name, "rootSpan") - self.assertEqual(child_span.name, "postgresql.opentelemetry-tests") + self.assertEqual(child_span.name, span_name) self.assertIsNotNone(child_span.parent) self.assertIs(child_span.parent, root_span.get_span_context()) self.assertIs(child_span.kind, trace_api.SpanKind.CLIENT) - self.assertEqual( - child_span.attributes["db.instance"], POSTGRES_DB_NAME - ) + self.assertEqual(child_span.attributes["db.system"], "postgresql") + self.assertEqual(child_span.attributes["db.name"], POSTGRES_DB_NAME) + self.assertEqual(child_span.attributes["db.user"], POSTGRES_USER) self.assertEqual(child_span.attributes["net.peer.name"], POSTGRES_HOST) self.assertEqual(child_span.attributes["net.peer.port"], POSTGRES_PORT) def test_execute(self): """Should create a child span for execute method""" + stmt = "CREATE TABLE IF NOT EXISTS test (id integer)" with self._tracer.start_as_current_span("rootSpan"): - async_call( - self._cursor.execute( - "CREATE TABLE IF NOT EXISTS test (id integer)" - ) - ) - self.validate_spans() + async_call(self._cursor.execute(stmt)) + self.validate_spans(stmt) def test_executemany(self): """Should create a child span for executemany""" + stmt = "INSERT INTO test (id) VALUES (%s)" with pytest.raises(psycopg2.ProgrammingError): with self._tracer.start_as_current_span("rootSpan"): data = (("1",), ("2",), ("3",)) - stmt = "INSERT INTO test (id) VALUES (%s)" async_call(self._cursor.executemany(stmt, data)) - self.validate_spans() + self.validate_spans(stmt) def test_callproc(self): """Should create a child span for callproc""" @@ -109,7 +106,7 @@ class TestFunctionalAiopgConnect(TestBase): Exception ): async_call(self._cursor.callproc("test", ())) - self.validate_spans() + self.validate_spans("test") class TestFunctionalAiopgCreatePool(TestBase): @@ -142,7 +139,7 @@ class TestFunctionalAiopgCreatePool(TestBase): cls._pool.close() AiopgInstrumentor().uninstrument() - def validate_spans(self): + def validate_spans(self, span_name): spans = self.memory_exporter.get_finished_spans() self.assertEqual(len(spans), 2) for span in spans: @@ -155,34 +152,31 @@ class TestFunctionalAiopgCreatePool(TestBase): self.assertIsNotNone(root_span) self.assertIsNotNone(child_span) self.assertEqual(root_span.name, "rootSpan") - self.assertEqual(child_span.name, "postgresql.opentelemetry-tests") + self.assertEqual(child_span.name, span_name) self.assertIsNotNone(child_span.parent) self.assertIs(child_span.parent, root_span.get_span_context()) self.assertIs(child_span.kind, trace_api.SpanKind.CLIENT) - self.assertEqual( - child_span.attributes["db.instance"], POSTGRES_DB_NAME - ) + self.assertEqual(child_span.attributes["db.system"], "postgresql") + self.assertEqual(child_span.attributes["db.name"], POSTGRES_DB_NAME) + self.assertEqual(child_span.attributes["db.user"], POSTGRES_USER) self.assertEqual(child_span.attributes["net.peer.name"], POSTGRES_HOST) self.assertEqual(child_span.attributes["net.peer.port"], POSTGRES_PORT) def test_execute(self): """Should create a child span for execute method""" + stmt = "CREATE TABLE IF NOT EXISTS test (id integer)" with self._tracer.start_as_current_span("rootSpan"): - async_call( - self._cursor.execute( - "CREATE TABLE IF NOT EXISTS test (id integer)" - ) - ) - self.validate_spans() + async_call(self._cursor.execute(stmt)) + self.validate_spans(stmt) def test_executemany(self): """Should create a child span for executemany""" + stmt = "INSERT INTO test (id) VALUES (%s)" with pytest.raises(psycopg2.ProgrammingError): with self._tracer.start_as_current_span("rootSpan"): data = (("1",), ("2",), ("3",)) - stmt = "INSERT INTO test (id) VALUES (%s)" async_call(self._cursor.executemany(stmt, data)) - self.validate_spans() + self.validate_spans(stmt) def test_callproc(self): """Should create a child span for callproc""" @@ -190,4 +184,4 @@ class TestFunctionalAiopgCreatePool(TestBase): Exception ): async_call(self._cursor.callproc("test", ())) - self.validate_spans() + self.validate_spans("test") diff --git a/tests/opentelemetry-docker-tests/tests/postgres/test_psycopg_functional.py b/tests/opentelemetry-docker-tests/tests/postgres/test_psycopg_functional.py index 28db4c064..76116dfd2 100644 --- a/tests/opentelemetry-docker-tests/tests/postgres/test_psycopg_functional.py +++ b/tests/opentelemetry-docker-tests/tests/postgres/test_psycopg_functional.py @@ -20,11 +20,11 @@ from opentelemetry import trace as trace_api from opentelemetry.instrumentation.psycopg2 import Psycopg2Instrumentor from opentelemetry.test.test_base import TestBase -POSTGRES_HOST = os.getenv("POSTGRESQL_HOST ", "localhost") -POSTGRES_PORT = int(os.getenv("POSTGRESQL_PORT ", "5432")) -POSTGRES_DB_NAME = os.getenv("POSTGRESQL_DB_NAME ", "opentelemetry-tests") -POSTGRES_PASSWORD = os.getenv("POSTGRESQL_HOST ", "testpassword") -POSTGRES_USER = os.getenv("POSTGRESQL_HOST ", "testuser") +POSTGRES_HOST = os.getenv("POSTGRESQL_HOST", "localhost") +POSTGRES_PORT = int(os.getenv("POSTGRESQL_PORT", "5432")) +POSTGRES_DB_NAME = os.getenv("POSTGRESQL_DB_NAME", "opentelemetry-tests") +POSTGRES_PASSWORD = os.getenv("POSTGRESQL_PASSWORD", "testpassword") +POSTGRES_USER = os.getenv("POSTGRESQL_USER", "testuser") class TestFunctionalPsycopg(TestBase): @@ -53,7 +53,7 @@ class TestFunctionalPsycopg(TestBase): cls._connection.close() Psycopg2Instrumentor().uninstrument() - def validate_spans(self): + def validate_spans(self, span_name): spans = self.memory_exporter.get_finished_spans() self.assertEqual(len(spans), 2) for span in spans: @@ -66,47 +66,48 @@ class TestFunctionalPsycopg(TestBase): self.assertIsNotNone(root_span) self.assertIsNotNone(child_span) self.assertEqual(root_span.name, "rootSpan") - self.assertEqual(child_span.name, "postgresql.opentelemetry-tests") + self.assertEqual(child_span.name, span_name) self.assertIsNotNone(child_span.parent) self.assertIs(child_span.parent, root_span.get_span_context()) self.assertIs(child_span.kind, trace_api.SpanKind.CLIENT) - self.assertEqual( - child_span.attributes["db.instance"], POSTGRES_DB_NAME - ) + self.assertEqual(child_span.attributes["db.system"], "postgresql") + self.assertEqual(child_span.attributes["db.name"], POSTGRES_DB_NAME) + self.assertEqual(child_span.attributes["db.user"], POSTGRES_USER) self.assertEqual(child_span.attributes["net.peer.name"], POSTGRES_HOST) self.assertEqual(child_span.attributes["net.peer.port"], POSTGRES_PORT) def test_execute(self): """Should create a child span for execute method""" + stmt = "CREATE TABLE IF NOT EXISTS test (id integer)" with self._tracer.start_as_current_span("rootSpan"): - self._cursor.execute( - "CREATE TABLE IF NOT EXISTS test (id integer)" - ) - self.validate_spans() + self._cursor.execute(stmt) + self.validate_spans(stmt) def test_execute_with_connection_context_manager(self): """Should create a child span for execute with connection context""" + stmt = "CREATE TABLE IF NOT EXISTS test (id INT)" with self._tracer.start_as_current_span("rootSpan"): with self._connection as conn: cursor = conn.cursor() - cursor.execute("CREATE TABLE IF NOT EXISTS test (id INT)") - self.validate_spans() + cursor.execute(stmt) + self.validate_spans(stmt) def test_execute_with_cursor_context_manager(self): """Should create a child span for execute with cursor context""" + stmt = "CREATE TABLE IF NOT EXISTS test (id INT)" with self._tracer.start_as_current_span("rootSpan"): with self._connection.cursor() as cursor: - cursor.execute("CREATE TABLE IF NOT EXISTS test (id INT)") - self.validate_spans() + cursor.execute(stmt) + self.validate_spans(stmt) self.assertTrue(cursor.closed) def test_executemany(self): """Should create a child span for executemany""" + stmt = "INSERT INTO test (id) VALUES (%s)" with self._tracer.start_as_current_span("rootSpan"): data = (("1",), ("2",), ("3",)) - stmt = "INSERT INTO test (id) VALUES (%s)" self._cursor.executemany(stmt, data) - self.validate_spans() + self.validate_spans(stmt) def test_callproc(self): """Should create a child span for callproc""" @@ -114,4 +115,4 @@ class TestFunctionalPsycopg(TestBase): Exception ): self._cursor.callproc("test", ()) - self.validate_spans() + self.validate_spans("test") diff --git a/tests/opentelemetry-docker-tests/tests/pymongo/test_pymongo_functional.py b/tests/opentelemetry-docker-tests/tests/pymongo/test_pymongo_functional.py index 577477a2a..d662014f1 100644 --- a/tests/opentelemetry-docker-tests/tests/pymongo/test_pymongo_functional.py +++ b/tests/opentelemetry-docker-tests/tests/pymongo/test_pymongo_functional.py @@ -20,9 +20,9 @@ from opentelemetry import trace as trace_api from opentelemetry.instrumentation.pymongo import PymongoInstrumentor from opentelemetry.test.test_base import TestBase -MONGODB_HOST = os.getenv("MONGODB_HOST ", "localhost") -MONGODB_PORT = int(os.getenv("MONGODB_PORT ", "27017")) -MONGODB_DB_NAME = os.getenv("MONGODB_DB_NAME ", "opentelemetry-tests") +MONGODB_HOST = os.getenv("MONGODB_HOST", "localhost") +MONGODB_PORT = int(os.getenv("MONGODB_PORT", "27017")) +MONGODB_DB_NAME = os.getenv("MONGODB_DB_NAME", "opentelemetry-tests") MONGODB_COLLECTION_NAME = "test" @@ -53,9 +53,7 @@ class TestFunctionalPymongo(TestBase): self.assertIsNotNone(pymongo_span.parent) self.assertIs(pymongo_span.parent, root_span.get_span_context()) self.assertIs(pymongo_span.kind, trace_api.SpanKind.CLIENT) - self.assertEqual( - pymongo_span.attributes["db.instance"], MONGODB_DB_NAME - ) + self.assertEqual(pymongo_span.attributes["db.name"], MONGODB_DB_NAME) self.assertEqual( pymongo_span.attributes["net.peer.name"], MONGODB_HOST ) diff --git a/tests/opentelemetry-docker-tests/tests/pymysql/test_pymysql_functional.py b/tests/opentelemetry-docker-tests/tests/pymysql/test_pymysql_functional.py index 7c0902555..b8e440480 100644 --- a/tests/opentelemetry-docker-tests/tests/pymysql/test_pymysql_functional.py +++ b/tests/opentelemetry-docker-tests/tests/pymysql/test_pymysql_functional.py @@ -20,11 +20,11 @@ from opentelemetry import trace as trace_api from opentelemetry.instrumentation.pymysql import PyMySQLInstrumentor from opentelemetry.test.test_base import TestBase -MYSQL_USER = os.getenv("MYSQL_USER ", "testuser") -MYSQL_PASSWORD = os.getenv("MYSQL_PASSWORD ", "testpassword") -MYSQL_HOST = os.getenv("MYSQL_HOST ", "localhost") -MYSQL_PORT = int(os.getenv("MYSQL_PORT ", "3306")) -MYSQL_DB_NAME = os.getenv("MYSQL_DB_NAME ", "opentelemetry-tests") +MYSQL_USER = os.getenv("MYSQL_USER", "testuser") +MYSQL_PASSWORD = os.getenv("MYSQL_PASSWORD", "testpassword") +MYSQL_HOST = os.getenv("MYSQL_HOST", "localhost") +MYSQL_PORT = int(os.getenv("MYSQL_PORT", "3306")) +MYSQL_DB_NAME = os.getenv("MYSQL_DB_NAME", "opentelemetry-tests") class TestFunctionalPyMysql(TestBase): @@ -50,7 +50,7 @@ class TestFunctionalPyMysql(TestBase): cls._connection.close() PyMySQLInstrumentor().uninstrument() - def validate_spans(self): + def validate_spans(self, span_name): spans = self.memory_exporter.get_finished_spans() self.assertEqual(len(spans), 2) for span in spans: @@ -63,34 +63,38 @@ class TestFunctionalPyMysql(TestBase): self.assertIsNotNone(root_span) self.assertIsNotNone(db_span) self.assertEqual(root_span.name, "rootSpan") - self.assertEqual(db_span.name, "mysql.opentelemetry-tests") + self.assertEqual(db_span.name, span_name) self.assertIsNotNone(db_span.parent) self.assertIs(db_span.parent, root_span.get_span_context()) self.assertIs(db_span.kind, trace_api.SpanKind.CLIENT) - self.assertEqual(db_span.attributes["db.instance"], MYSQL_DB_NAME) + self.assertEqual(db_span.attributes["db.system"], "mysql") + self.assertEqual(db_span.attributes["db.name"], MYSQL_DB_NAME) + self.assertEqual(db_span.attributes["db.user"], MYSQL_USER) self.assertEqual(db_span.attributes["net.peer.name"], MYSQL_HOST) self.assertEqual(db_span.attributes["net.peer.port"], MYSQL_PORT) def test_execute(self): """Should create a child span for execute""" + stmt = "CREATE TABLE IF NOT EXISTS test (id INT)" with self._tracer.start_as_current_span("rootSpan"): - self._cursor.execute("CREATE TABLE IF NOT EXISTS test (id INT)") - self.validate_spans() + self._cursor.execute(stmt) + self.validate_spans(stmt) def test_execute_with_cursor_context_manager(self): """Should create a child span for execute with cursor context""" + stmt = "CREATE TABLE IF NOT EXISTS test (id INT)" with self._tracer.start_as_current_span("rootSpan"): with self._connection.cursor() as cursor: - cursor.execute("CREATE TABLE IF NOT EXISTS test (id INT)") - self.validate_spans() + cursor.execute(stmt) + self.validate_spans(stmt) def test_executemany(self): """Should create a child span for executemany""" + stmt = "INSERT INTO test (id) VALUES (%s)" with self._tracer.start_as_current_span("rootSpan"): data = (("1",), ("2",), ("3",)) - stmt = "INSERT INTO test (id) VALUES (%s)" self._cursor.executemany(stmt, data) - self.validate_spans() + self.validate_spans(stmt) def test_callproc(self): """Should create a child span for callproc""" @@ -98,4 +102,4 @@ class TestFunctionalPyMysql(TestBase): Exception ): self._cursor.callproc("test", ()) - self.validate_spans() + self.validate_spans("test") diff --git a/tests/opentelemetry-docker-tests/tests/redis/test_redis_functional.py b/tests/opentelemetry-docker-tests/tests/redis/test_redis_functional.py index 8bdc12010..b893a33b6 100644 --- a/tests/opentelemetry-docker-tests/tests/redis/test_redis_functional.py +++ b/tests/opentelemetry-docker-tests/tests/redis/test_redis_functional.py @@ -33,14 +33,13 @@ class TestRedisInstrument(TestBase): super().tearDown() RedisInstrumentor().uninstrument() - def _check_span(self, span): + def _check_span(self, span, name): self.assertEqual(span.attributes["service"], self.test_service) - self.assertEqual(span.name, "redis.command") + self.assertEqual(span.name, name) self.assertIs(span.status.status_code, trace.status.StatusCode.UNSET) - self.assertEqual(span.attributes.get("db.instance"), 0) - self.assertEqual( - span.attributes.get("db.url"), "redis://localhost:6379" - ) + self.assertEqual(span.attributes.get("db.name"), 0) + self.assertEqual(span.attributes["net.peer.name"], "localhost") + self.assertEqual(span.attributes["net.peer.ip"], 6379) def test_long_command(self): self.redis_client.mget(*range(1000)) @@ -48,7 +47,7 @@ class TestRedisInstrument(TestBase): spans = self.memory_exporter.get_finished_spans() self.assertEqual(len(spans), 1) span = spans[0] - self._check_span(span) + self._check_span(span, "MGET") self.assertTrue( span.attributes.get("db.statement").startswith("MGET 0 1 2 3") ) @@ -59,7 +58,7 @@ class TestRedisInstrument(TestBase): spans = self.memory_exporter.get_finished_spans() self.assertEqual(len(spans), 1) span = spans[0] - self._check_span(span) + self._check_span(span, "GET") self.assertEqual(span.attributes.get("db.statement"), "GET cheese") self.assertEqual(span.attributes.get("redis.args_length"), 2) @@ -73,7 +72,7 @@ class TestRedisInstrument(TestBase): spans = self.memory_exporter.get_finished_spans() self.assertEqual(len(spans), 1) span = spans[0] - self._check_span(span) + self._check_span(span, "SET RPUSH HGETALL") self.assertEqual( span.attributes.get("db.statement"), "SET blah 32\nRPUSH foo éé\nHGETALL xxx", @@ -91,7 +90,7 @@ class TestRedisInstrument(TestBase): # single span for the whole pipeline self.assertEqual(len(spans), 2) span = spans[0] - self._check_span(span) + self._check_span(span, "SET") self.assertEqual(span.attributes.get("db.statement"), "SET b 2") def test_parent(self): @@ -115,4 +114,4 @@ class TestRedisInstrument(TestBase): self.assertEqual( child_span.attributes.get("service"), self.test_service ) - self.assertEqual(child_span.name, "redis.command") + self.assertEqual(child_span.name, "GET")