def test_tracer_reuse(): # GIVEN tracer A, B were initialized # WHEN tracer B explicitly reuses A config # THEN tracer B attributes should be equal to tracer A service_name = "booking" tracer_a = Tracer(disabled=True, service=service_name) tracer_b = Tracer() assert id(tracer_a) != id(tracer_b) assert tracer_a.__dict__.items() == tracer_b.__dict__.items()
def test_tracer_custom_metadata(mocker, dummy_response, provider_stub): put_metadata_mock = mocker.MagicMock() annotation_key = "Booking response" annotation_value = {"bookingStatus": "CONFIRMED"} provider = provider_stub(put_metadata_mock=put_metadata_mock) tracer = Tracer(provider=provider, service="booking") tracer.put_metadata(annotation_key, annotation_value) assert put_metadata_mock.call_count == 1 assert put_metadata_mock.call_args_list[0] == mocker.call( key=annotation_key, value=annotation_value, namespace="booking")
def test_tracer_custom_annotation(mocker, dummy_response, provider_stub): put_annotation_mock = mocker.MagicMock() annotation_key = "BookingId" annotation_value = "123456" provider = provider_stub(put_annotation_mock=put_annotation_mock) tracer = Tracer(provider=provider, service="booking") tracer.put_annotation(annotation_key, annotation_value) assert put_annotation_mock.call_count == 1 assert put_annotation_mock.call_args == mocker.call(key=annotation_key, value=annotation_value)
def test_tracer_patch(xray_patch_all_mock, xray_patch_mock, mocker): # GIVEN tracer is instantiated # WHEN default X-Ray provider client is mocked # THEN tracer should run just fine Tracer() assert xray_patch_all_mock.call_count == 1 modules = ["boto3"] Tracer(service="booking", patch_modules=modules) assert xray_patch_mock.call_count == 1 assert xray_patch_mock.call_args == mocker.call(modules)
def test_package_logger_format(stdout, capsys): set_package_logger(stream=stdout, formatter=JsonFormatter(formatter="test")) Tracer(disabled=True) output = json.loads(stdout.getvalue().split("\n")[0]) assert "test" in output["formatter"]
async def test_tracer_method_nested_async(mocker, dummy_response, provider_stub, in_subsegment_mock): provider = provider_stub( in_subsegment_async=in_subsegment_mock.in_subsegment) tracer = Tracer(provider=provider, service="booking") @tracer.capture_method async def greeting_2(name, message): return dummy_response @tracer.capture_method async def greeting(name, message): await greeting_2(name, message) return dummy_response await greeting(name="Foo", message="Bar") ( in_subsegment_greeting_call_args, in_subsegment_greeting2_call_args, ) = in_subsegment_mock.in_subsegment.call_args_list put_metadata_greeting2_call_args, put_metadata_greeting_call_args = in_subsegment_mock.put_metadata.call_args_list assert in_subsegment_mock.in_subsegment.call_count == 2 assert in_subsegment_greeting_call_args == mocker.call(name="## greeting") assert in_subsegment_greeting2_call_args == mocker.call( name="## greeting_2") assert in_subsegment_mock.put_metadata.call_count == 2 assert put_metadata_greeting2_call_args == mocker.call( key="greeting_2 response", value=dummy_response, namespace="booking") assert put_metadata_greeting_call_args == mocker.call( key="greeting response", value=dummy_response, namespace="booking")
def test_tracer_lambda_handler(mocker, dummy_response, xray_stub): put_metadata_mock = mocker.MagicMock() begin_subsegment_mock = mocker.MagicMock() end_subsegment_mock = mocker.MagicMock() xray_provider = xray_stub( put_metadata_mock=put_metadata_mock, begin_subsegment_mock=begin_subsegment_mock, end_subsegment_mock=end_subsegment_mock, ) tracer = Tracer(provider=xray_provider, service="booking") @tracer.capture_lambda_handler def handler(event, context): return dummy_response handler({}, mocker.MagicMock()) assert begin_subsegment_mock.call_count == 1 assert begin_subsegment_mock.call_args == mocker.call(name="## handler") assert end_subsegment_mock.call_count == 1 assert put_metadata_mock.call_args == mocker.call( key="lambda handler response", value=dummy_response, namespace="booking")
def test_package_logger(capsys): set_package_logger() Tracer(disabled=True) output = capsys.readouterr() assert "Tracing has been disabled" in output.out
def test_tracer_env_vars(monkeypatch): # GIVEN tracer disabled, is run without parameters # WHEN service is explicitly defined # THEN tracer should have use that service name service_name = "booking" monkeypatch.setenv("POWERTOOLS_SERVICE_NAME", service_name) tracer_env_var = Tracer(disabled=True) assert tracer_env_var.service == service_name tracer_explicit = Tracer(disabled=True, service=service_name) assert tracer_explicit.service == service_name monkeypatch.setenv("POWERTOOLS_TRACE_DISABLED", "true") tracer = Tracer() assert bool(tracer.disabled) is True
def test_capture_lambda_handler(dummy_response): # GIVEN tracer is disabled, and decorator is used # WHEN a lambda handler is run # THEN tracer should not raise an Exception tracer = Tracer(disabled=True) @tracer.capture_lambda_handler def handler(event, context): return dummy_response handler({}, {})
def test_tracer_lambda_emulator(monkeypatch, mocker, dummy_response): # GIVEN tracer is run locally # WHEN a lambda function is run through SAM CLI # THEN tracer should not raise an Exception monkeypatch.setenv("AWS_SAM_LOCAL", "true") tracer = Tracer() @tracer.capture_lambda_handler def handler(event, context): return dummy_response handler({}, mocker.MagicMock())
def test_tracer_method_empty_response_metadata(mocker, provider_stub): put_metadata_mock = mocker.MagicMock() provider = provider_stub(put_metadata_mock=put_metadata_mock) tracer = Tracer(provider=provider) @tracer.capture_method def greeting(name, message): return greeting(name="Foo", message="Bar") assert put_metadata_mock.call_count == 0
def test_capture_method(dummy_response): # GIVEN tracer is disabled, and method decorator is used # WHEN a function is run # THEN tracer should not raise an Exception tracer = Tracer(disabled=True) @tracer.capture_method def greeting(name, message): return dummy_response greeting(name="Foo", message="Bar")
def test_tracer_lambda_handler_empty_response_metadata(mocker, provider_stub): put_metadata_mock = mocker.MagicMock() provider = provider_stub(put_metadata_mock=put_metadata_mock) tracer = Tracer(provider=provider) @tracer.capture_lambda_handler def handler(event, context): return handler({}, mocker.MagicMock()) assert put_metadata_mock.call_count == 0
def test_tracer_metadata_disabled(dummy_response): # GIVEN tracer is disabled, and annotations/metadata are used # WHEN a lambda handler is run # THEN tracer should not raise an Exception and simply ignore tracer = Tracer(disabled=True) @tracer.capture_lambda_handler def handler(event, context): tracer.put_annotation("PaymentStatus", "SUCCESS") tracer.put_metadata("PaymentMetadata", "Metadata") return dummy_response handler({}, {})
async def test_tracer_method_exception_metadata_async(mocker, provider_stub, in_subsegment_mock): provider = provider_stub( in_subsegment_async=in_subsegment_mock.in_subsegment) tracer = Tracer(provider=provider, service="booking") @tracer.capture_method async def greeting(name, message): raise ValueError("test") with pytest.raises(ValueError): await greeting(name="Foo", message="Bar") put_metadata_mock_args = in_subsegment_mock.put_metadata.call_args[1] assert put_metadata_mock_args["key"] == "greeting error" assert put_metadata_mock_args["namespace"] == "booking"
async def test_tracer_method_nested_async_disabled(dummy_response): tracer = Tracer(service="booking", disabled=True) @tracer.capture_method async def greeting_2(name, message): return dummy_response @tracer.capture_method async def greeting(name, message): await greeting_2(name, message) return dummy_response ret = await greeting(name="Foo", message="Bar") assert ret == dummy_response
def test_tracer_lambda_handler_exception_metadata(mocker, provider_stub, in_subsegment_mock): provider = provider_stub(in_subsegment=in_subsegment_mock.in_subsegment) tracer = Tracer(provider=provider, service="booking") @tracer.capture_lambda_handler def handler(event, context): raise ValueError("test") with pytest.raises(ValueError): handler({}, mocker.MagicMock()) put_metadata_mock_args = in_subsegment_mock.put_metadata.call_args[1] assert put_metadata_mock_args["key"] == "booking error" assert put_metadata_mock_args["namespace"] == "booking"
def test_tracer_custom_annotation(mocker, dummy_response, xray_stub): put_annotation_mock = mocker.MagicMock() xray_provider = xray_stub(put_annotation_mock=put_annotation_mock) tracer = Tracer(provider=xray_provider, service="booking") annotation_key = "BookingId" annotation_value = "123456" @tracer.capture_lambda_handler def handler(event, context): tracer.put_annotation(annotation_key, annotation_value) return dummy_response handler({}, mocker.MagicMock()) assert put_annotation_mock.call_count == 1 assert put_annotation_mock.call_args == mocker.call(key=annotation_key, value=annotation_value)
def test_tracer_custom_metadata(mocker, dummy_response, xray_stub): put_metadata_mock = mocker.MagicMock() xray_provider = xray_stub(put_metadata_mock=put_metadata_mock) tracer = Tracer(provider=xray_provider, service="booking") annotation_key = "Booking response" annotation_value = {"bookingStatus": "CONFIRMED"} @tracer.capture_lambda_handler def handler(event, context): tracer.put_metadata(annotation_key, annotation_value) return dummy_response handler({}, mocker.MagicMock()) assert put_metadata_mock.call_count == 2 assert put_metadata_mock.call_args_list[0] == mocker.call( key=annotation_key, value=annotation_value, namespace="booking")
def test_tracer_lambda_handler(mocker, dummy_response, provider_stub, in_subsegment_mock): provider = provider_stub(in_subsegment=in_subsegment_mock.in_subsegment) tracer = Tracer(provider=provider, service="booking") @tracer.capture_lambda_handler def handler(event, context): return dummy_response handler({}, mocker.MagicMock()) assert in_subsegment_mock.in_subsegment.call_count == 1 assert in_subsegment_mock.in_subsegment.call_args == mocker.call( name="## handler") assert in_subsegment_mock.put_metadata.call_args == mocker.call( key="handler response", value=dummy_response, namespace="booking") assert in_subsegment_mock.put_annotation.call_count == 1 assert in_subsegment_mock.put_annotation.call_args == mocker.call( key="ColdStart", value=True)
def test_tracer_method_nested_sync(mocker): # GIVEN tracer is disabled, decorator is used # WHEN multiple sync functions are nested # THEN tracer should not raise a Runtime Error tracer = Tracer(disabled=True) @tracer.capture_method def func_1(): return 1 @tracer.capture_method def func_2(): return 2 @tracer.capture_method def sums_values(): return func_1() + func_2() sums_values()
def test_tracer_method(mocker, dummy_response, xray_stub): put_metadata_mock = mocker.MagicMock() put_annotation_mock = mocker.MagicMock() begin_subsegment_mock = mocker.MagicMock() end_subsegment_mock = mocker.MagicMock() xray_provider = xray_stub(put_metadata_mock, put_annotation_mock, begin_subsegment_mock, end_subsegment_mock) tracer = Tracer(provider=xray_provider, service="booking") @tracer.capture_method def greeting(name, message): return dummy_response greeting(name="Foo", message="Bar") assert begin_subsegment_mock.call_count == 1 assert begin_subsegment_mock.call_args == mocker.call(name="## greeting") assert end_subsegment_mock.call_count == 1 assert put_metadata_mock.call_args == mocker.call(key="greeting response", value=dummy_response, namespace="booking")
def test_tracer_with_exception(mocker): # GIVEN tracer is disabled, decorator is used # WHEN a lambda handler or method returns an Exception # THEN tracer should reraise the same Exception class CustomException(Exception): pass tracer = Tracer(disabled=True) @tracer.capture_lambda_handler def handler(event, context): raise CustomException("test") @tracer.capture_method def greeting(name, message): raise CustomException("test") with pytest.raises(CustomException): handler({}, {}) with pytest.raises(CustomException): greeting(name="Foo", message="Bar")
# 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. import gettext from ask_sdk_core.dispatch_components import AbstractRequestInterceptor from ask_sdk_core.handler_input import HandlerInput from ask_sdk_core.utils import get_locale from aws_lambda_powertools.logging import Logger from aws_lambda_powertools.tracing import Tracer # Logging/tracing configuration logger = Logger(service="i18n interceptor") tracer = Tracer(service="i18n interceptor") class LocalizationInterceptor(AbstractRequestInterceptor): """Request interceptor to handle multiple locales.""" def process(self, handler_input): """Parse locale information and add i18n manager to the request attributes.""" # type: (HandlerInput) -> None logger.debug("In LocalizationInterceptor") locale = get_locale(handler_input) logger.debug({"Locale": locale}) i18n = gettext.translation( "base", localedir="core/locales/", languages=[locale], fallback=True )
""" import os import boto3 import requests from aws_lambda_powertools.tracing import Tracer # pylint: disable=import-error from aws_lambda_powertools.logging.logger import Logger # pylint: disable=import-error API_URL = os.environ["API_URL"] ENVIRONMENT = os.environ["ENVIRONMENT"] TABLE_NAME = os.environ["TABLE_NAME"] dynamodb = boto3.resource("dynamodb") # pylint: disable=invalid-name table = dynamodb.Table(TABLE_NAME) # pylint: disable=invalid-name,no-member logger = Logger() # pylint: disable=invalid-name tracer = Tracer() # pylint: disable=invalid-name @tracer.capture_method def get_payment_token(order_id: str) -> str: """ Retrieve the paymentToken from DynamoDB """ response = table.get_item(Key={"orderId": order_id}) return response["Item"]["paymentToken"] @tracer.capture_method def update_payment_amount(payment_token: str, amount: int) -> None:
from typing import Dict, List, Optional import hermes.backend.dict from ask_sdk_core.exceptions import ApiClientException from ask_sdk_model.services import ApiClient, ApiClientRequest from aws_lambda_powertools.logging import Logger from aws_lambda_powertools.tracing import Tracer from marshmallow import ValidationError from .cache.bmemcached import Backend as BmemcachedBackend from .exceptions import GTFSDataError, NetworkDescriptionError, OperationMonitoringError from .model.line_stops import LineDetails from .model.passing_times import PassingTime, PointPassingTimes logger = Logger(service="STIB service") tracer = Tracer(service="STIB service") ENVIRONMENT = environ["env"] MEMCACHED_ENDPOINT = environ["cache_endpoint"] MEMCACHED_USERNAME = environ["cache_username"] MEMCACHED_PASSWORD = environ["cache_password"] @tracer.capture_method def initialize_cache() -> hermes.Hermes: if ENVIRONMENT == "Sandbox": logger.info( { "operation": "Setting Hermes caching backend", "environment": ENVIRONMENT.upper(), "backend": "Dictionary",
class Utils: def __init__(self): self.logger = Logger() self.tracer = Tracer() def set_trace_id(self, lambda_handler): def get_trace_id(raw_trace_id): for t in raw_trace_id.split(';'): if t.startswith('Root'): return t.split('=')[1] return None def decorate(event, context): if '_X_AMZN_TRACE_ID' in os.environ: if get_trace_id(os.environ['_X_AMZN_TRACE_ID']) is not None: os.environ['trace_id'] = get_trace_id( os.environ['_X_AMZN_TRACE_ID']) if 'trace_id' not in os.environ: START_TIME = time.time() HEX = hex(int(START_TIME))[2:] os.environ['trace_id'] = "0-{}-{}".format( HEX, str(binascii.hexlify(urandom(12)), 'utf-8')) self.logger.structure_logs(append=True, trace_id=os.environ['trace_id']) self.logger.info(os.environ.get('trace_id')) response = lambda_handler(event, context) return response return decorate def api_gateway_response(self, lambda_handler): def decorate(event, context): response = lambda_handler(event, context) if isinstance(response, tuple): body = response[0] status = response[1] else: body = response status = 200 if isinstance(body, Exception): if status == 200: status = 400 self.logger.exception(body) self.tracer.put_annotation("ErrorCode", body.__class__.__name__) self.tracer.put_annotation("ErrorMessage", "{}".format(body)) res = { "isBase64Encoded": False, "statusCode": status, 'headers': { "Access-Control-Allow-Origin": "*", "Content-Type": "application/json" }, 'body': json.dumps({ "Code": body.__class__.__name__, "Message": "{}".format(body), "TraceId": os.environ.get('trace_id') }) } else: if body is not None and isinstance(body, str) is False: body = json.dumps(body) res = { 'isBase64Encoded': False, 'statusCode': status, 'headers': { "Access-Control-Allow-Origin": "*", "Content-Type": "application/json" } } if body is not None: res['body'] = body return res return decorate
def __init__(self): self.logger = Logger() self.tracer = Tracer()
from typing import List, Optional from ask_sdk_core.dispatch_components import AbstractRequestHandler from ask_sdk_core.handler_input import HandlerInput from ask_sdk_core.utils import is_intent_name from ask_sdk_model import Response from aws_lambda_powertools.logging import Logger from aws_lambda_powertools.tracing import Tracer from ...data import data from ...service.model.passing_times import PassingTime # Logging/tracing configuration logger = Logger(service="Get arrival time intent handler") tracer = Tracer(service="Get arrival time intent handler") class GetArrivalTimesNoPrefsIntentHandler(AbstractRequestHandler): """Handler for get arrival time Intent: no available preferences scenario.""" def can_handle(self, handler_input): # type: (HandlerInput) -> bool # Extract persistent attributes and check if they are all present attr = handler_input.attributes_manager.persistent_attributes attributes_are_present = ("favorite_stop_id" in attr and "favorite_line_id" in attr) return not attributes_are_present and is_intent_name( "GetArrivalTimesIntent")(handler_input) def handle(self, handler_input):