From ce489dc28c87379190c8b886306bd4fe5d4a8169 Mon Sep 17 00:00:00 2001 From: "(Eliseo) Nathaniel Ruiz Nowell" Date: Fri, 2 Jul 2021 20:57:57 -0700 Subject: [PATCH 1/3] =?UTF-8?q?Update=20Python=C2=A0Sample=20Apps=20for=20?= =?UTF-8?q?Upstream=201.3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../instrumentation/aws_lambda/__init__.py | 6 ++- .../instrumentation/aws_lambda/package.py | 16 ++++++ .../src/otel/otel_sdk/requirements-nodeps.txt | 54 +++++++++---------- python/src/otel/otel_sdk/requirements.txt | 12 ++--- 4 files changed, 54 insertions(+), 34 deletions(-) create mode 100644 python/src/otel/otel_sdk/opentelemetry/instrumentation/aws_lambda/package.py diff --git a/python/src/otel/otel_sdk/opentelemetry/instrumentation/aws_lambda/__init__.py b/python/src/otel/otel_sdk/opentelemetry/instrumentation/aws_lambda/__init__.py index fc557f8493..725ab83588 100644 --- a/python/src/otel/otel_sdk/opentelemetry/instrumentation/aws_lambda/__init__.py +++ b/python/src/otel/otel_sdk/opentelemetry/instrumentation/aws_lambda/__init__.py @@ -47,13 +47,14 @@ def lambda_handler(event, context): import logging import os from importlib import import_module - +from typing import Collection from wrapt import wrap_function_wrapper # TODO: aws propagator from opentelemetry.sdk.extension.aws.trace.propagation.aws_xray_format import ( AwsXRayFormat, ) +from opentelemetry.instrumentation.aws_lambda.package import _instruments from opentelemetry.instrumentation.aws_lambda.version import __version__ from opentelemetry.instrumentation.instrumentor import BaseInstrumentor from opentelemetry.instrumentation.utils import unwrap @@ -63,6 +64,9 @@ def lambda_handler(event, context): class AwsLambdaInstrumentor(BaseInstrumentor): + def instrumentation_dependencies(self) -> Collection[str]: + return _instruments + def _instrument(self, **kwargs): self._tracer = get_tracer(__name__, __version__, kwargs.get("tracer_provider")) diff --git a/python/src/otel/otel_sdk/opentelemetry/instrumentation/aws_lambda/package.py b/python/src/otel/otel_sdk/opentelemetry/instrumentation/aws_lambda/package.py new file mode 100644 index 0000000000..1a38f1f3e5 --- /dev/null +++ b/python/src/otel/otel_sdk/opentelemetry/instrumentation/aws_lambda/package.py @@ -0,0 +1,16 @@ +# Copyright The OpenTelemetry Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +_instruments = ("not-applicable >= 0.1.0",) diff --git a/python/src/otel/otel_sdk/requirements-nodeps.txt b/python/src/otel/otel_sdk/requirements-nodeps.txt index 931e597059..69da5048c6 100644 --- a/python/src/otel/otel_sdk/requirements-nodeps.txt +++ b/python/src/otel/otel_sdk/requirements-nodeps.txt @@ -1,27 +1,27 @@ -opentelemetry-instrumentation-aiohttp-client==0.21b0 -opentelemetry-instrumentation-asgi==0.21b0 -opentelemetry-instrumentation-asyncpg==0.21b0 -opentelemetry-instrumentation-boto==0.21b0 -opentelemetry-instrumentation-botocore==0.21b0 -opentelemetry-instrumentation-celery==0.21b0 -opentelemetry-instrumentation-dbapi==0.21b0 -opentelemetry-instrumentation-django==0.21b0 -opentelemetry-instrumentation-elasticsearch==0.21b0 -opentelemetry-instrumentation-fastapi==0.21b0 -opentelemetry-instrumentation-falcon==0.21b0 -opentelemetry-instrumentation-flask==0.21b0 -opentelemetry-instrumentation-grpc==0.21b0 -opentelemetry-instrumentation-jinja2==0.21b0 -opentelemetry-instrumentation-mysql==0.21b0 -opentelemetry-instrumentation-psycopg2==0.21b0 -opentelemetry-instrumentation-pymemcache==0.21b0 -opentelemetry-instrumentation-pymongo==0.21b0 -opentelemetry-instrumentation-pymysql==0.21b0 -opentelemetry-instrumentation-pyramid==0.21b0 -opentelemetry-instrumentation-redis==0.21b0 -opentelemetry-instrumentation-requests==0.21b0 -opentelemetry-instrumentation-sqlalchemy==0.21b0 -opentelemetry-instrumentation-sqlite3==0.21b0 -opentelemetry-instrumentation-starlette==0.21b0 -opentelemetry-instrumentation-tornado==0.21b0 -opentelemetry-instrumentation-wsgi==0.21b0 \ No newline at end of file +opentelemetry-instrumentation-aiohttp-client==0.22b0 +opentelemetry-instrumentation-asgi==0.22b0 +opentelemetry-instrumentation-asyncpg==0.22b0 +opentelemetry-instrumentation-boto==0.22b0 +opentelemetry-instrumentation-botocore==0.22b0 +opentelemetry-instrumentation-celery==0.22b0 +opentelemetry-instrumentation-dbapi==0.22b0 +opentelemetry-instrumentation-django==0.22b0 +opentelemetry-instrumentation-elasticsearch==0.22b0 +opentelemetry-instrumentation-fastapi==0.22b0 +opentelemetry-instrumentation-falcon==0.22b0 +opentelemetry-instrumentation-flask==0.22b0 +opentelemetry-instrumentation-grpc==0.22b0 +opentelemetry-instrumentation-jinja2==0.22b0 +opentelemetry-instrumentation-mysql==0.22b0 +opentelemetry-instrumentation-psycopg2==0.22b0 +opentelemetry-instrumentation-pymemcache==0.22b0 +opentelemetry-instrumentation-pymongo==0.22b0 +opentelemetry-instrumentation-pymysql==0.22b0 +opentelemetry-instrumentation-pyramid==0.22b0 +opentelemetry-instrumentation-redis==0.22b0 +opentelemetry-instrumentation-requests==0.22b0 +opentelemetry-instrumentation-sqlalchemy==0.22b0 +opentelemetry-instrumentation-sqlite3==0.22b0 +opentelemetry-instrumentation-starlette==0.22b0 +opentelemetry-instrumentation-tornado==0.22b0 +opentelemetry-instrumentation-wsgi==0.22b0 \ No newline at end of file diff --git a/python/src/otel/otel_sdk/requirements.txt b/python/src/otel/otel_sdk/requirements.txt index b9f984f7f9..a93896c2c2 100644 --- a/python/src/otel/otel_sdk/requirements.txt +++ b/python/src/otel/otel_sdk/requirements.txt @@ -1,6 +1,6 @@ -opentelemetry-api==1.2.0 -opentelemetry-sdk==1.2.0 -opentelemetry-exporter-otlp==1.2.0 -opentelemetry-distro==0.21b0 -opentelemetry-instrumentation==0.21b0 -opentelemetry-sdk-extension-aws==0.21b0 \ No newline at end of file +opentelemetry-api==1.3.0 +opentelemetry-sdk==1.3.0 +opentelemetry-exporter-otlp==1.3.0 +opentelemetry-distro==0.22b0 +opentelemetry-instrumentation==0.22b0 +opentelemetry-sdk-extension-aws==0.22b0 \ No newline at end of file From ccced7ebfde7563afb23c000401cbb182655d90b Mon Sep 17 00:00:00 2001 From: "(Eliseo) Nathaniel Ruiz Nowell" Date: Fri, 2 Jul 2021 22:35:43 -0700 Subject: [PATCH 2/3] Skip dep check lets LambdaInstrumentor get called --- .../instrumentation/aws_lambda/__init__.py | 2 +- .../instrumentation/aws_lambda/package.py | 2 +- python/src/otel/otel_sdk/otel_wrapper.py | 2 +- python/src/otel/tests/test-requirements.txt | 10 +++++----- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/python/src/otel/otel_sdk/opentelemetry/instrumentation/aws_lambda/__init__.py b/python/src/otel/otel_sdk/opentelemetry/instrumentation/aws_lambda/__init__.py index 725ab83588..c1740e520a 100644 --- a/python/src/otel/otel_sdk/opentelemetry/instrumentation/aws_lambda/__init__.py +++ b/python/src/otel/otel_sdk/opentelemetry/instrumentation/aws_lambda/__init__.py @@ -30,7 +30,7 @@ ) # Enable instrumentation - AwsLambdaInstrumentor().instrument() + AwsLambdaInstrumentor().instrument(skip_dep_check=True) # Lambda function def lambda_handler(event, context): diff --git a/python/src/otel/otel_sdk/opentelemetry/instrumentation/aws_lambda/package.py b/python/src/otel/otel_sdk/opentelemetry/instrumentation/aws_lambda/package.py index 1a38f1f3e5..211727b883 100644 --- a/python/src/otel/otel_sdk/opentelemetry/instrumentation/aws_lambda/package.py +++ b/python/src/otel/otel_sdk/opentelemetry/instrumentation/aws_lambda/package.py @@ -13,4 +13,4 @@ # limitations under the License. -_instruments = ("not-applicable >= 0.1.0",) +_instruments = () diff --git a/python/src/otel/otel_sdk/otel_wrapper.py b/python/src/otel/otel_sdk/otel_wrapper.py index c0dd6f3e4b..3bf5975c72 100644 --- a/python/src/otel/otel_sdk/otel_wrapper.py +++ b/python/src/otel/otel_sdk/otel_wrapper.py @@ -74,7 +74,7 @@ class HandlerError(Exception): _load_configurators() _load_instrumentors() # TODO: move to python-contrib -AwsLambdaInstrumentor().instrument() +AwsLambdaInstrumentor().instrument(skip_dep_check=True) path = os.environ.get("ORIG_HANDLER", None) if path is None: diff --git a/python/src/otel/tests/test-requirements.txt b/python/src/otel/tests/test-requirements.txt index 9dc3242bdc..f6e7d4e89b 100644 --- a/python/src/otel/tests/test-requirements.txt +++ b/python/src/otel/tests/test-requirements.txt @@ -1,6 +1,6 @@ -opentelemetry-api==1.2.0 -opentelemetry-sdk==1.2.0 -opentelemetry-distro==0.21b0 -opentelemetry-instrumentation==0.21b0 -opentelemetry-sdk-extension-aws==0.21b0 +opentelemetry-api==1.3.0 +opentelemetry-sdk==1.3.0 +opentelemetry-distro==0.22b0 +opentelemetry-instrumentation==0.22b0 +opentelemetry-sdk-extension-aws==0.22b0 pytest \ No newline at end of file From 6ba9b00f3bee3be14cdcf66630a66d9e207257ae Mon Sep 17 00:00:00 2001 From: "(Eliseo) Nathaniel Ruiz Nowell" Date: Mon, 5 Jul 2021 10:09:33 -0700 Subject: [PATCH 3/3] Copy style of contrib instrumentations --- .../instrumentation/aws_lambda/__init__.py | 80 ++++++++++++------- 1 file changed, 51 insertions(+), 29 deletions(-) diff --git a/python/src/otel/otel_sdk/opentelemetry/instrumentation/aws_lambda/__init__.py b/python/src/otel/otel_sdk/opentelemetry/instrumentation/aws_lambda/__init__.py index c1740e520a..74643907f9 100644 --- a/python/src/otel/otel_sdk/opentelemetry/instrumentation/aws_lambda/__init__.py +++ b/python/src/otel/otel_sdk/opentelemetry/instrumentation/aws_lambda/__init__.py @@ -58,6 +58,7 @@ def lambda_handler(event, context): from opentelemetry.instrumentation.aws_lambda.version import __version__ from opentelemetry.instrumentation.instrumentor import BaseInstrumentor from opentelemetry.instrumentation.utils import unwrap +from opentelemetry.semconv.trace import SpanAttributes from opentelemetry.trace import SpanKind, get_tracer, get_tracer_provider logger = logging.getLogger(__name__) @@ -68,19 +69,25 @@ def instrumentation_dependencies(self) -> Collection[str]: return _instruments def _instrument(self, **kwargs): - self._tracer = get_tracer(__name__, __version__, kwargs.get("tracer_provider")) - - self._tracer_provider = get_tracer_provider() + """Instruments Lambda Handlers on AWS Lambda + + Args: + **kwargs: Optional arguments + ``tracer_provider``: a TracerProvider, defaults to global + """ + tracer = get_tracer( + __name__, __version__, kwargs.get("tracer_provider") + ) - lambda_handler = os.environ.get("ORIG_HANDLER", os.environ.get("_HANDLER")) + lambda_handler = os.environ.get( + "ORIG_HANDLER", os.environ.get("_HANDLER") + ) wrapped_names = lambda_handler.rsplit(".", 1) self._wrapped_module_name = wrapped_names[0] self._wrapped_function_name = wrapped_names[1] - wrap_function_wrapper( - self._wrapped_module_name, - self._wrapped_function_name, - self._functionPatch, + _instrument( + tracer, self._wrapped_module_name, self._wrapped_function_name ) def _uninstrument(self, **kwargs): @@ -89,35 +96,50 @@ def _uninstrument(self, **kwargs): self._wrapped_function_name, ) - def _functionPatch(self, original_func, instance, args, kwargs): - lambda_context = args[1] - ctx_aws_request_id = lambda_context.aws_request_id - ctx_invoked_function_arn = lambda_context.invoked_function_arn - orig_handler = os.environ.get("ORIG_HANDLER", os.environ.get("_HANDLER")) + +def _instrument(tracer, wrapped_module_name, wrapped_function_name): + def _instrumented_lambda_handler_call(call_wrapped, instance, args, kwargs): + orig_handler_name = ".".join( + [wrapped_module_name, wrapped_function_name] + ) # TODO: enable propagate from AWS by env variable xray_trace_id = os.environ.get("_X_AMZN_TRACE_ID", "") - - lambda_name = os.environ.get("AWS_LAMBDA_FUNCTION_NAME") - function_version = os.environ.get("AWS_LAMBDA_FUNCTION_VERSION") - propagator = AwsXRayFormat() parent_context = propagator.extract({"X-Amzn-Trace-Id": xray_trace_id}) - with self._tracer.start_as_current_span( - name=orig_handler, context=parent_context, kind=SpanKind.SERVER + with tracer.start_as_current_span( + name=orig_handler_name, context=parent_context, kind=SpanKind.SERVER ) as span: - # Refer: https://github.com/open-telemetry/opentelemetry-specification/blob/master/specification/trace/semantic_conventions/faas.md#example - span.set_attribute("faas.execution", ctx_aws_request_id) - span.set_attribute("faas.id", ctx_invoked_function_arn) - - # TODO: fix in Collector because they belong resource attrubutes - span.set_attribute("faas.name", lambda_name) - span.set_attribute("faas.version", function_version) - - result = original_func(*args, **kwargs) + if span.is_recording(): + lambda_context = args[1] + # Refer: https://github.com/open-telemetry/opentelemetry-specification/blob/master/specification/trace/semantic_conventions/faas.md#example + span.set_attribute( + SpanAttributes.FAAS_EXECUTION, lambda_context.aws_request_id + ) + span.set_attribute( + "faas.id", lambda_context.invoked_function_arn + ) + + # TODO: fix in Collector because they belong resource attrubutes + span.set_attribute( + "faas.name", os.environ.get("AWS_LAMBDA_FUNCTION_NAME") + ) + span.set_attribute( + "faas.version", + os.environ.get("AWS_LAMBDA_FUNCTION_VERSION"), + ) + + result = call_wrapped(*args, **kwargs) # force_flush before function quit in case of Lambda freeze. - self._tracer_provider.force_flush() + tracer_provider = get_tracer_provider() + tracer_provider.force_flush() return result + + wrap_function_wrapper( + wrapped_module_name, + wrapped_function_name, + _instrumented_lambda_handler_call, + )