def test_tracer_reuse_configuration(service_name):
    # GIVEN tracer A is initialized
    tracer_a = Tracer(disabled=True, service=service_name)
    # WHEN tracer B is initialized afterwards
    tracer_b = Tracer()

    # THEN tracer B attributes should be equal to tracer A
    assert tracer_a.__dict__.items() == tracer_b.__dict__.items()
Beispiel #2
0
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_explicit_service(monkeypatch, service_name):
    # GIVEN tracer is disabled
    # WHEN service is explicitly defined
    tracer_explicit = Tracer(disabled=True, service=service_name)
    assert tracer_explicit.service == service_name

    monkeypatch.setenv("POWERTOOLS_TRACE_DISABLED", "true")
    tracer = Tracer()

    # THEN tracer should have use that service name
    assert tracer.service == service_name
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_tracer_custom_annotation(mocker, dummy_response, provider_stub):
    # GIVEN Tracer is initialized
    put_annotation_mock = mocker.MagicMock()
    provider = provider_stub(put_annotation_mock=put_annotation_mock)
    tracer = Tracer(provider=provider)

    # WHEN put_metadata is used
    annotation_key = "BookingId"
    annotation_value = "123456"
    tracer.put_annotation(annotation_key, annotation_value)

    # THEN we should have an annotation as expected
    assert put_annotation_mock.call_count == 1
    assert put_annotation_mock.call_args == mocker.call(key=annotation_key, value=annotation_value)
Beispiel #8
0
def test_tracer_custom_metadata(mocker, dummy_response, provider_stub):
    # GIVEN Tracer is initialized with booking as the service name
    put_metadata_mock = mocker.MagicMock()
    provider = provider_stub(put_metadata_mock=put_metadata_mock)
    tracer = Tracer(provider=provider, service="booking")

    # WHEN put_metadata is used
    annotation_key = "Booking response"
    annotation_value = {"bookingStatus": "CONFIRMED"}
    tracer.put_metadata(annotation_key, annotation_value)

    # THEN we should have metadata expected and booking as namespace
    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_autopatch(patch_mock):
    # GIVEN tracer is initialized
    # WHEN auto_patch hasn't been explicitly disabled
    Tracer(disabled=True)

    # THEN tracer should patch all modules
    assert patch_mock.call_count == 1
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_yield_from_context_manager(mocker, provider_stub, in_subsegment_mock):
    # GIVEN tracer is initialized
    provider = provider_stub(in_subsegment=in_subsegment_mock.in_subsegment)
    tracer = Tracer(provider=provider, service="booking")

    # WHEN capture_method decorator is used on a context manager
    @tracer.capture_method
    @contextlib.contextmanager
    def yield_with_capture():
        yield "test result"

    @tracer.capture_lambda_handler
    def handler(event, context):
        response = []
        with yield_with_capture() as yielded_value:
            response.append(yielded_value)

        return response

    result = handler({}, {})

    # THEN we should have a subsegment named after the method name
    # and add its response as trace metadata
    handler_trace, yield_function_trace = in_subsegment_mock.in_subsegment.call_args_list

    assert "test result" in in_subsegment_mock.put_metadata.call_args[1]["value"]
    assert in_subsegment_mock.in_subsegment.call_count == 2
    assert handler_trace == mocker.call(name="## handler")
    assert yield_function_trace == mocker.call(name="## yield_with_capture")
    assert "test result" in result
Beispiel #12
0
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_yield_with_capture():
    # GIVEN tracer method decorator is used
    tracer = Tracer(disabled=True)

    # WHEN capture_method decorator is applied to a context manager
    @tracer.capture_method
    @contextlib.contextmanager
    def yield_with_capture():
        yield "testresult"

    # Or WHEN capture_method decorator is applied to a generator function
    @tracer.capture_method
    def generator_func():
        yield "testresult2"

    @tracer.capture_lambda_handler
    def handler(event, context):
        result = []
        with yield_with_capture() as yielded_value:
            result.append(yielded_value)

        gen = generator_func()

        result.append(next(gen))

        return result

    # THEN no exception is thrown, and the functions properly return values
    result = handler({}, {})
    assert "testresult" in result
    assert "testresult2" in result
def test_tracer_no_autopatch(patch_mock):
    # GIVEN tracer is initialized
    # WHEN auto_patch is disabled
    Tracer(disabled=True, auto_patch=False)

    # THEN tracer should not patch any module
    assert patch_mock.call_count == 0
def test_tracer_yield_from_generator(mocker, provider_stub, in_subsegment_mock):
    # GIVEN tracer is initialized
    provider = provider_stub(in_subsegment=in_subsegment_mock.in_subsegment)
    tracer = Tracer(provider=provider, service="booking")

    # WHEN capture_method decorator is used on a generator function
    @tracer.capture_method
    def generator_fn():
        yield "test result"

    @tracer.capture_lambda_handler
    def handler(event, context):
        gen = generator_fn()
        response = list(gen)

        return response

    result = handler({}, {})

    # THEN we should have a subsegment named after the method name
    # and add its response as trace metadata
    handler_trace, generator_fn_trace = in_subsegment_mock.in_subsegment.call_args_list

    assert "test result" in in_subsegment_mock.put_metadata.call_args[1]["value"]
    assert in_subsegment_mock.in_subsegment.call_count == 2
    assert handler_trace == mocker.call(name="## handler")
    assert generator_fn_trace == mocker.call(name="## generator_fn")
    assert "test result" in result
async def test_tracer_method_nested_async(mocker, dummy_response, provider_stub, in_subsegment_mock):
    # GIVEN tracer is initialized
    provider = provider_stub(in_subsegment_async=in_subsegment_mock.in_subsegment)
    tracer = Tracer(provider=provider, service="booking")

    # WHEN capture_method decorator is used for nested async methods
    @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

    # THEN we should add metadata for each response like we would for a sync decorated method
    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"
    )
Beispiel #17
0
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"]
Beispiel #18
0
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_tracer_service_env_var(monkeypatch, service_name):
    # GIVEN tracer is run without parameters
    # WHEN service is implicitly defined via env var
    monkeypatch.setenv("POWERTOOLS_SERVICE_NAME", service_name)
    tracer = Tracer(disabled=True)

    # THEN tracer should have use that service name
    assert tracer.service == service_name
def test_tracer_patch_modules(xray_patch_mock, mocker):
    # GIVEN tracer is initialized with a list of modules to patch
    modules = ["boto3"]

    # WHEN modules are supported by X-Ray
    Tracer(service="booking", patch_modules=modules)

    # THEN tracer should run just fine
    assert xray_patch_mock.call_count == 1
    assert xray_patch_mock.call_args == mocker.call(modules)
def test_capture_method(dummy_response):
    # GIVEN tracer method decorator is used
    tracer = Tracer(disabled=True)

    # WHEN a function is run
    @tracer.capture_method
    def greeting(name, message):
        return dummy_response

    # THEN tracer should not raise an Exception
    greeting(name="Foo", message="Bar")
def test_capture_lambda_handler(dummy_response):
    # GIVEN tracer lambda handler decorator is used
    tracer = Tracer(disabled=True)

    # WHEN a lambda handler is run
    @tracer.capture_lambda_handler
    def handler(event, context):
        return dummy_response

    # THEN tracer should not raise an Exception
    handler({}, {})
def test_tracer_chalice_cli_mode(monkeypatch, dummy_response):
    # GIVEN tracer runs locally
    monkeypatch.setenv("AWS_CHALICE_CLI_MODE", "true")
    tracer = Tracer()

    # WHEN a lambda function is run through the Chalice CLI.
    @tracer.capture_lambda_handler
    def handler(event, context):
        return dummy_response

    # THEN tracer should run in disabled mode, and not raise an Exception
    handler({}, {})
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_lambda_emulator(monkeypatch, dummy_response):
    # GIVEN tracer runs locally
    monkeypatch.setenv("AWS_SAM_LOCAL", "true")
    tracer = Tracer()

    # WHEN a lambda function is run through SAM CLI
    @tracer.capture_lambda_handler
    def handler(event, context):
        return dummy_response

    # THEN tracer should run in disabled mode, and not raise an Exception
    handler({}, {})
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_package_logger_stream(stdout):
    # GIVEN package logger "aws_lambda_powertools" is explicitly set with no params
    set_package_logger(stream=stdout)

    # WHEN Tracer is initialized in disabled mode
    Tracer(disabled=True)

    # THEN Tracer debug log statement should be logged
    output = stdout.getvalue()
    logger = logging.getLogger("aws_lambda_powertools")
    assert "Tracing has been disabled" in output
    assert logger.level == logging.DEBUG
Beispiel #28
0
def test_tracer_lambda_emulator(monkeypatch, 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({}, {})
    monkeypatch.delenv("AWS_SAM_LOCAL")
def test_tracer_metadata_disabled(dummy_response):
    # GIVEN tracer is disabled, and annotations/metadata are used
    tracer = Tracer(disabled=True)

    # WHEN a lambda handler is run
    @tracer.capture_lambda_handler
    def handler(event, context):
        tracer.put_annotation("PaymentStatus", "SUCCESS")
        tracer.put_metadata("PaymentMetadata", "Metadata")
        return dummy_response

    # THEN tracer should not raise any Exception
    handler({}, {})
def test_tracer_method_override_response_as_metadata(provider_stub, in_subsegment_mock):
    # GIVEN tracer is initialized
    provider = provider_stub(in_subsegment=in_subsegment_mock.in_subsegment)
    tracer = Tracer(provider=provider, auto_patch=False)

    # WHEN capture_method decorator is used with capture_response set to False
    @tracer.capture_method(capture_response=False)
    def greeting(name, message):
        return "response"

    greeting(name="Foo", message="Bar")

    # THEN we should not add any metadata
    assert in_subsegment_mock.put_metadata.call_count == 0