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")) # 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) 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) # force_flush before function quit in case of Lambda freeze. self._tracer_provider.force_flush() return result
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", "") propagator = AwsXRayFormat() parent_context = propagator.extract({"X-Amzn-Trace-Id": xray_trace_id}) with tracer.start_as_current_span( name=orig_handler_name, context=parent_context, kind=SpanKind.SERVER ) as span: 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. tracer_provider = get_tracer_provider() tracer_provider.force_flush() return result
def _function_patch(self, original_func, _, args, kwargs): lambda_context = args[1] ctx_aws_request_id = lambda_context.aws_request_id orig_handler = os.environ.get("ORIG_HANDLER", os.environ.get("_HANDLER")) xray_trace_id = os.environ.get("_X_AMZN_TRACE_ID", "") propagator = AwsXRayFormat() parent_context = propagator.extract(DictGetter(), {TRACE_HEADER_KEY: xray_trace_id}) with self._tracer.start_as_current_span(orig_handler, context=parent_context, kind=SpanKind.CLIENT) 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) result = original_func(*args, **kwargs) # force_flush before function quit in case of Lambda freeze. self._tracer_provider.force_flush() return result
class AwsXRayPropagatorTest(unittest.TestCase): XRAY_PROPAGATOR = AwsXRayFormat() # Inject Tests def test_inject_into_non_sampled_context(self): carrier = CaseInsensitiveDict() AwsXRayPropagatorTest.XRAY_PROPAGATOR.inject( carrier, build_test_current_context(), ) injected_items = set(carrier.items()) expected_items = set( CaseInsensitiveDict({ TRACE_HEADER_KEY: "Root=1-8a3c60f7-d188f8fa79d48a391a778fa6;Parent=53995c3f42cd8ad8;Sampled=0" }).items()) self.assertEqual(injected_items, expected_items) def test_inject_into_sampled_context(self): carrier = CaseInsensitiveDict() AwsXRayPropagatorTest.XRAY_PROPAGATOR.inject( carrier, build_test_current_context( trace_flags=TraceFlags(TraceFlags.SAMPLED)), ) injected_items = set(carrier.items()) expected_items = set( CaseInsensitiveDict({ TRACE_HEADER_KEY: "Root=1-8a3c60f7-d188f8fa79d48a391a778fa6;Parent=53995c3f42cd8ad8;Sampled=1" }).items()) self.assertEqual(injected_items, expected_items) def test_inject_into_context_with_non_default_state(self): carrier = CaseInsensitiveDict() AwsXRayPropagatorTest.XRAY_PROPAGATOR.inject( carrier, build_test_current_context(trace_state=TraceState([("foo", "bar")])), ) # TODO: (NathanielRN) Assert trace state when the propagator supports it injected_items = set(carrier.items()) expected_items = set( CaseInsensitiveDict({ TRACE_HEADER_KEY: "Root=1-8a3c60f7-d188f8fa79d48a391a778fa6;Parent=53995c3f42cd8ad8;Sampled=0" }).items()) self.assertEqual(injected_items, expected_items) def test_inject_reported_fields_matches_carrier_fields(self): carrier = CaseInsensitiveDict() AwsXRayPropagatorTest.XRAY_PROPAGATOR.inject( carrier, build_test_current_context(), ) injected_keys = set(carrier.keys()) self.assertEqual(injected_keys, AwsXRayPropagatorTest.XRAY_PROPAGATOR.fields) # Extract Tests def test_extract_empty_carrier_from_invalid_context(self): context_with_extracted = AwsXRayPropagatorTest.XRAY_PROPAGATOR.extract( CaseInsensitiveDict()) self.assertEqual( get_nested_span_context(context_with_extracted), INVALID_SPAN_CONTEXT, ) def test_extract_not_sampled_context(self): context_with_extracted = AwsXRayPropagatorTest.XRAY_PROPAGATOR.extract( CaseInsensitiveDict({ TRACE_HEADER_KEY: "Root=1-8a3c60f7-d188f8fa79d48a391a778fa6;Parent=53995c3f42cd8ad8;Sampled=0" }), ) self.assertEqual( get_nested_span_context(context_with_extracted), build_test_span_context(), ) def test_extract_sampled_context(self): context_with_extracted = AwsXRayPropagatorTest.XRAY_PROPAGATOR.extract( CaseInsensitiveDict({ TRACE_HEADER_KEY: "Root=1-8a3c60f7-d188f8fa79d48a391a778fa6;Parent=53995c3f42cd8ad8;Sampled=1" }), ) self.assertEqual( get_nested_span_context(context_with_extracted), build_test_span_context( trace_flags=TraceFlags(TraceFlags.SAMPLED)), ) def test_extract_different_order(self): context_with_extracted = AwsXRayPropagatorTest.XRAY_PROPAGATOR.extract( CaseInsensitiveDict({ TRACE_HEADER_KEY: "Sampled=0;Parent=53995c3f42cd8ad8;Root=1-8a3c60f7-d188f8fa79d48a391a778fa6" }), ) self.assertEqual( get_nested_span_context(context_with_extracted), build_test_span_context(), ) def test_extract_with_additional_fields(self): context_with_extracted = AwsXRayPropagatorTest.XRAY_PROPAGATOR.extract( CaseInsensitiveDict({ TRACE_HEADER_KEY: "Root=1-8a3c60f7-d188f8fa79d48a391a778fa6;Parent=53995c3f42cd8ad8;Sampled=0;Foo=Bar" }), ) self.assertEqual( get_nested_span_context(context_with_extracted), build_test_span_context(), ) def test_extract_with_extra_whitespace(self): context_with_extracted = AwsXRayPropagatorTest.XRAY_PROPAGATOR.extract( CaseInsensitiveDict({ TRACE_HEADER_KEY: " Root = 1-8a3c60f7-d188f8fa79d48a391a778fa6 ; Parent = 53995c3f42cd8ad8 ; Sampled = 0 " }), ) self.assertEqual( get_nested_span_context(context_with_extracted), build_test_span_context(), ) def test_extract_invalid_xray_trace_header(self): context_with_extracted = AwsXRayPropagatorTest.XRAY_PROPAGATOR.extract( CaseInsensitiveDict({TRACE_HEADER_KEY: ""}), ) self.assertEqual( get_nested_span_context(context_with_extracted), INVALID_SPAN_CONTEXT, ) def test_extract_invalid_trace_id(self): context_with_extracted = AwsXRayPropagatorTest.XRAY_PROPAGATOR.extract( CaseInsensitiveDict({ TRACE_HEADER_KEY: "Root=1-12345678-abcdefghijklmnopqrstuvwx;Parent=53995c3f42cd8ad8;Sampled=0" }), ) self.assertEqual( get_nested_span_context(context_with_extracted), INVALID_SPAN_CONTEXT, ) def test_extract_invalid_trace_id_size(self): context_with_extracted = AwsXRayPropagatorTest.XRAY_PROPAGATOR.extract( CaseInsensitiveDict({ TRACE_HEADER_KEY: "Root=1-8a3c60f7-d188f8fa79d48a391a778fa600;Parent=53995c3f42cd8ad8;Sampled=0=" }), ) self.assertEqual( get_nested_span_context(context_with_extracted), INVALID_SPAN_CONTEXT, ) def test_extract_invalid_span_id(self): context_with_extracted = AwsXRayPropagatorTest.XRAY_PROPAGATOR.extract( CaseInsensitiveDict({ TRACE_HEADER_KEY: "Root=1-8a3c60f7-d188f8fa79d48a391a778fa6;Parent=abcdefghijklmnop;Sampled=0" }), ) self.assertEqual( get_nested_span_context(context_with_extracted), INVALID_SPAN_CONTEXT, ) def test_extract_invalid_span_id_size(self): context_with_extracted = AwsXRayPropagatorTest.XRAY_PROPAGATOR.extract( CaseInsensitiveDict({ TRACE_HEADER_KEY: "Root=1-8a3c60f7-d188f8fa79d48a391a778fa6;Parent=53995c3f42cd8ad800;Sampled=0" }), ) self.assertEqual( get_nested_span_context(context_with_extracted), INVALID_SPAN_CONTEXT, ) def test_extract_invalid_empty_sampled_flag(self): context_with_extracted = AwsXRayPropagatorTest.XRAY_PROPAGATOR.extract( CaseInsensitiveDict({ TRACE_HEADER_KEY: "Root=1-8a3c60f7-d188f8fa79d48a391a778fa6;Parent=53995c3f42cd8ad8;Sampled=" }), ) self.assertEqual( get_nested_span_context(context_with_extracted), INVALID_SPAN_CONTEXT, ) def test_extract_invalid_sampled_flag_size(self): context_with_extracted = AwsXRayPropagatorTest.XRAY_PROPAGATOR.extract( CaseInsensitiveDict({ TRACE_HEADER_KEY: "Root=1-8a3c60f7-d188f8fa79d48a391a778fa6;Parent=53995c3f42cd8ad8;Sampled=011" }), ) self.assertEqual( get_nested_span_context(context_with_extracted), INVALID_SPAN_CONTEXT, ) def test_extract_invalid_non_numeric_sampled_flag(self): context_with_extracted = AwsXRayPropagatorTest.XRAY_PROPAGATOR.extract( CaseInsensitiveDict({ TRACE_HEADER_KEY: "Root=1-8a3c60f7-d188f8fa79d48a391a778fa6;Parent=53995c3f42cd8ad8;Sampled=a" }), ) self.assertEqual( get_nested_span_context(context_with_extracted), INVALID_SPAN_CONTEXT, ) @patch("opentelemetry.sdk.extension.aws.trace." "propagation.aws_xray_format.trace") def test_fields(self, mock_trace): """Make sure the fields attribute returns the fields used in inject""" mock_trace.configure_mock( **{ "get_current_span.return_value": Mock( **{ "get_span_context.return_value": Mock(**{ "is_valid": True, "trace_id": 1, "span_id": 1 }) }) }) mock_setter = Mock() AwsXRayPropagatorTest.XRAY_PROPAGATOR.inject({}, setter=mock_setter) inject_fields = set() for call in mock_setter.mock_calls: inject_fields.add(call[1][1]) self.assertEqual(AwsXRayPropagatorTest.XRAY_PROPAGATOR.fields, inject_fields)
# 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. from requests.structures import CaseInsensitiveDict from opentelemetry.sdk.extension.aws.trace.propagation.aws_xray_format import ( TRACE_HEADER_KEY, AwsXRayFormat, ) XRAY_PROPAGATOR = AwsXRayFormat() def test_extract_single_header(benchmark): benchmark( XRAY_PROPAGATOR.extract, { TRACE_HEADER_KEY: "bdb5b63237ed38aea578af665aa5aa60-00000000000000000c32d953d73ad225" }, ) def test_inject_empty_context(benchmark): benchmark(XRAY_PROPAGATOR.inject, {}, setter=CaseInsensitiveDict.__setitem__)
class AwsXRayPropagatorTest(unittest.TestCase): carrier_setter = CaseInsensitiveDict.__setitem__ carrier_getter = DictGetter() XRAY_PROPAGATOR = AwsXRayFormat() # Inject Tests def test_inject_into_non_sampled_context(self): carrier = CaseInsensitiveDict() AwsXRayPropagatorTest.XRAY_PROPAGATOR.inject( AwsXRayPropagatorTest.carrier_setter, carrier, build_test_current_context(), ) injected_items = set(carrier.items()) expected_items = set( CaseInsensitiveDict( { TRACE_HEADER_KEY: "Root=1-8a3c60f7-d188f8fa79d48a391a778fa6;Parent=53995c3f42cd8ad8;Sampled=0" } ).items() ) self.assertEqual(injected_items, expected_items) def test_inject_into_sampled_context(self): carrier = CaseInsensitiveDict() AwsXRayPropagatorTest.XRAY_PROPAGATOR.inject( AwsXRayPropagatorTest.carrier_setter, carrier, build_test_current_context( trace_flags=TraceFlags(TraceFlags.SAMPLED) ), ) injected_items = set(carrier.items()) expected_items = set( CaseInsensitiveDict( { TRACE_HEADER_KEY: "Root=1-8a3c60f7-d188f8fa79d48a391a778fa6;Parent=53995c3f42cd8ad8;Sampled=1" } ).items() ) self.assertEqual(injected_items, expected_items) def test_inject_into_context_with_non_default_state(self): carrier = CaseInsensitiveDict() AwsXRayPropagatorTest.XRAY_PROPAGATOR.inject( AwsXRayPropagatorTest.carrier_setter, carrier, build_test_current_context(trace_state=TraceState({"foo": "bar"})), ) # TODO: (NathanielRN) Assert trace state when the propagator supports it injected_items = set(carrier.items()) expected_items = set( CaseInsensitiveDict( { TRACE_HEADER_KEY: "Root=1-8a3c60f7-d188f8fa79d48a391a778fa6;Parent=53995c3f42cd8ad8;Sampled=0" } ).items() ) self.assertEqual(injected_items, expected_items) def test_inject_reported_fields_matches_carrier_fields(self): carrier = CaseInsensitiveDict() AwsXRayPropagatorTest.XRAY_PROPAGATOR.inject( AwsXRayPropagatorTest.carrier_setter, carrier, build_test_current_context(), ) injected_keys = set(carrier.keys()) self.assertEqual( injected_keys, AwsXRayPropagatorTest.XRAY_PROPAGATOR.fields() ) # Extract Tests def test_extract_empty_carrier_from_invalid_context(self): context_with_extracted = AwsXRayPropagatorTest.XRAY_PROPAGATOR.extract( AwsXRayPropagatorTest.carrier_getter, CaseInsensitiveDict() ) self.assertEqual( get_nested_span_context(context_with_extracted), INVALID_SPAN_CONTEXT, ) def test_extract_not_sampled_context(self): context_with_extracted = AwsXRayPropagatorTest.XRAY_PROPAGATOR.extract( AwsXRayPropagatorTest.carrier_getter, CaseInsensitiveDict( { TRACE_HEADER_KEY: "Root=1-8a3c60f7-d188f8fa79d48a391a778fa6;Parent=53995c3f42cd8ad8;Sampled=0" } ), ) self.assertEqual( get_nested_span_context(context_with_extracted), build_test_span_context(), ) def test_extract_sampled_context(self): context_with_extracted = AwsXRayPropagatorTest.XRAY_PROPAGATOR.extract( AwsXRayPropagatorTest.carrier_getter, CaseInsensitiveDict( { TRACE_HEADER_KEY: "Root=1-8a3c60f7-d188f8fa79d48a391a778fa6;Parent=53995c3f42cd8ad8;Sampled=1" } ), ) self.assertEqual( get_nested_span_context(context_with_extracted), build_test_span_context( trace_flags=TraceFlags(TraceFlags.SAMPLED) ), ) def test_extract_different_order(self): context_with_extracted = AwsXRayPropagatorTest.XRAY_PROPAGATOR.extract( AwsXRayPropagatorTest.carrier_getter, CaseInsensitiveDict( { TRACE_HEADER_KEY: "Sampled=0;Parent=53995c3f42cd8ad8;Root=1-8a3c60f7-d188f8fa79d48a391a778fa6" } ), ) self.assertEqual( get_nested_span_context(context_with_extracted), build_test_span_context(), ) def test_extract_with_additional_fields(self): context_with_extracted = AwsXRayPropagatorTest.XRAY_PROPAGATOR.extract( AwsXRayPropagatorTest.carrier_getter, CaseInsensitiveDict( { TRACE_HEADER_KEY: "Root=1-8a3c60f7-d188f8fa79d48a391a778fa6;Parent=53995c3f42cd8ad8;Sampled=0;Foo=Bar" } ), ) self.assertEqual( get_nested_span_context(context_with_extracted), build_test_span_context(), ) def test_extract_with_extra_whitespace(self): context_with_extracted = AwsXRayPropagatorTest.XRAY_PROPAGATOR.extract( AwsXRayPropagatorTest.carrier_getter, CaseInsensitiveDict( { TRACE_HEADER_KEY: " Root = 1-8a3c60f7-d188f8fa79d48a391a778fa6 ; Parent = 53995c3f42cd8ad8 ; Sampled = 0 " } ), ) self.assertEqual( get_nested_span_context(context_with_extracted), build_test_span_context(), ) def test_extract_invalid_xray_trace_header(self): context_with_extracted = AwsXRayPropagatorTest.XRAY_PROPAGATOR.extract( AwsXRayPropagatorTest.carrier_getter, CaseInsensitiveDict({TRACE_HEADER_KEY: ""}), ) self.assertEqual( get_nested_span_context(context_with_extracted), INVALID_SPAN_CONTEXT, ) def test_extract_invalid_trace_id(self): context_with_extracted = AwsXRayPropagatorTest.XRAY_PROPAGATOR.extract( AwsXRayPropagatorTest.carrier_getter, CaseInsensitiveDict( { TRACE_HEADER_KEY: "Root=1-12345678-abcdefghijklmnopqrstuvwx;Parent=53995c3f42cd8ad8;Sampled=0" } ), ) self.assertEqual( get_nested_span_context(context_with_extracted), INVALID_SPAN_CONTEXT, ) def test_extract_invalid_trace_id_size(self): context_with_extracted = AwsXRayPropagatorTest.XRAY_PROPAGATOR.extract( AwsXRayPropagatorTest.carrier_getter, CaseInsensitiveDict( { TRACE_HEADER_KEY: "Root=1-8a3c60f7-d188f8fa79d48a391a778fa600;Parent=53995c3f42cd8ad8;Sampled=0=" } ), ) self.assertEqual( get_nested_span_context(context_with_extracted), INVALID_SPAN_CONTEXT, ) def test_extract_invalid_span_id(self): context_with_extracted = AwsXRayPropagatorTest.XRAY_PROPAGATOR.extract( AwsXRayPropagatorTest.carrier_getter, CaseInsensitiveDict( { TRACE_HEADER_KEY: "Root=1-8a3c60f7-d188f8fa79d48a391a778fa6;Parent=abcdefghijklmnop;Sampled=0" } ), ) self.assertEqual( get_nested_span_context(context_with_extracted), INVALID_SPAN_CONTEXT, ) def test_extract_invalid_span_id_size(self): context_with_extracted = AwsXRayPropagatorTest.XRAY_PROPAGATOR.extract( AwsXRayPropagatorTest.carrier_getter, CaseInsensitiveDict( { TRACE_HEADER_KEY: "Root=1-8a3c60f7-d188f8fa79d48a391a778fa6;Parent=53995c3f42cd8ad800;Sampled=0" } ), ) self.assertEqual( get_nested_span_context(context_with_extracted), INVALID_SPAN_CONTEXT, ) def test_extract_invalid_empty_sampled_flag(self): context_with_extracted = AwsXRayPropagatorTest.XRAY_PROPAGATOR.extract( AwsXRayPropagatorTest.carrier_getter, CaseInsensitiveDict( { TRACE_HEADER_KEY: "Root=1-8a3c60f7-d188f8fa79d48a391a778fa6;Parent=53995c3f42cd8ad8;Sampled=" } ), ) self.assertEqual( get_nested_span_context(context_with_extracted), INVALID_SPAN_CONTEXT, ) def test_extract_invalid_sampled_flag_size(self): context_with_extracted = AwsXRayPropagatorTest.XRAY_PROPAGATOR.extract( AwsXRayPropagatorTest.carrier_getter, CaseInsensitiveDict( { TRACE_HEADER_KEY: "Root=1-8a3c60f7-d188f8fa79d48a391a778fa6;Parent=53995c3f42cd8ad8;Sampled=011" } ), ) self.assertEqual( get_nested_span_context(context_with_extracted), INVALID_SPAN_CONTEXT, ) def test_extract_invalid_non_numeric_sampled_flag(self): context_with_extracted = AwsXRayPropagatorTest.XRAY_PROPAGATOR.extract( AwsXRayPropagatorTest.carrier_getter, CaseInsensitiveDict( { TRACE_HEADER_KEY: "Root=1-8a3c60f7-d188f8fa79d48a391a778fa6;Parent=53995c3f42cd8ad8;Sampled=a" } ), ) self.assertEqual( get_nested_span_context(context_with_extracted), INVALID_SPAN_CONTEXT, )