Skip to content

Commit

Permalink
Update Python Sample Apps for Upstream 1.3 (open-telemetry#110)
Browse files Browse the repository at this point in the history
* Update Python Sample Apps for Upstream 1.3

* Skip dep check lets LambdaInstrumentor get called

* Copy style of contrib instrumentations
  • Loading branch information
NathanielRN authored and garrettwegan committed Jul 19, 2021
1 parent 9f98a3a commit c868338
Show file tree
Hide file tree
Showing 6 changed files with 112 additions and 70 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
)
# Enable instrumentation
AwsLambdaInstrumentor().instrument()
AwsLambdaInstrumentor().instrument(skip_dep_check=True)
# Lambda function
def lambda_handler(event, context):
Expand All @@ -47,36 +47,47 @@ 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
from opentelemetry.semconv.trace import SpanAttributes
from opentelemetry.trace import SpanKind, get_tracer, get_tracer_provider

logger = logging.getLogger(__name__)


class AwsLambdaInstrumentor(BaseInstrumentor):
def _instrument(self, **kwargs):
self._tracer = get_tracer(__name__, __version__, kwargs.get("tracer_provider"))
def instrumentation_dependencies(self) -> Collection[str]:
return _instruments

self._tracer_provider = get_tracer_provider()
def _instrument(self, **kwargs):
"""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):
Expand All @@ -85,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,
)
Original file line number Diff line number Diff line change
@@ -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 = ()
2 changes: 1 addition & 1 deletion python/src/otel/otel_sdk/otel_wrapper.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
54 changes: 27 additions & 27 deletions python/src/otel/otel_sdk/requirements-nodeps.txt
Original file line number Diff line number Diff line change
@@ -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
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
12 changes: 6 additions & 6 deletions python/src/otel/otel_sdk/requirements.txt
Original file line number Diff line number Diff line change
@@ -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
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
10 changes: 5 additions & 5 deletions python/src/otel/tests/test-requirements.txt
Original file line number Diff line number Diff line change
@@ -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

0 comments on commit c868338

Please sign in to comment.