Skip to content

Commit

Permalink
Adding data base user attribute in Python EMF logs (#222)
Browse files Browse the repository at this point in the history
*Issue #, if available:*

*Description of changes:*
- Adding data base user attribute in Python EMF logs - db.user.
- Added unit test for data base user attribute
- Added contract-tests

Output of EMF log:
```
{
    “Environment”: “ECS”,
    “RemoteDbUser”: “myuser”, <- Added Data base user
    “RemoteService”: “mysql”,
    “Service”: “python-appsignals-auto-cwa”,
        …
    },
    “Latency”: {
        “Values”: [
            …
        ],
        “Counts”: [
            …
        ],
        …
    }
}
```

By submitting this pull request, I confirm that you can use, modify,
copy, and redistribute this contribution, under the terms of your
choice.
  • Loading branch information
ektabj authored Jul 3, 2024
1 parent 912dd93 commit 7a90ee5
Show file tree
Hide file tree
Showing 5 changed files with 59 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
AWS_SPAN_KIND: str = "aws.span.kind"
AWS_LOCAL_SERVICE: str = "aws.local.service"
AWS_LOCAL_OPERATION: str = "aws.local.operation"
AWS_REMOTE_DB_USER: str = "aws.remote.db.user"
AWS_REMOTE_SERVICE: str = "aws.remote.service"
AWS_REMOTE_OPERATION: str = "aws.remote.operation"
AWS_REMOTE_RESOURCE_TYPE: str = "aws.remote.resource.type"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
AWS_LOCAL_SERVICE,
AWS_QUEUE_NAME,
AWS_QUEUE_URL,
AWS_REMOTE_DB_USER,
AWS_REMOTE_OPERATION,
AWS_REMOTE_RESOURCE_IDENTIFIER,
AWS_REMOTE_RESOURCE_TYPE,
Expand Down Expand Up @@ -52,6 +53,7 @@
_DB_OPERATION: str = SpanAttributes.DB_OPERATION
_DB_STATEMENT: str = SpanAttributes.DB_STATEMENT
_DB_SYSTEM: str = SpanAttributes.DB_SYSTEM
_DB_USER: str = SpanAttributes.DB_USER
_FAAS_INVOKED_NAME: str = SpanAttributes.FAAS_INVOKED_NAME
_FAAS_TRIGGER: str = SpanAttributes.FAAS_TRIGGER
_GRAPHQL_OPERATION_TYPE: str = SpanAttributes.GRAPHQL_OPERATION_TYPE
Expand Down Expand Up @@ -126,6 +128,7 @@ def _generate_dependency_metric_attributes(span: ReadableSpan, resource: Resourc
_set_egress_operation(span, attributes)
_set_remote_service_and_operation(span, attributes)
_set_remote_type_and_identifier(span, attributes)
_set_remote_db_user(span, attributes)
_set_span_kind_for_dependency(span, attributes)
return attributes

Expand Down Expand Up @@ -451,6 +454,11 @@ def _escape_delimiters(input_str: str) -> Optional[str]:
return input_str.replace("^", "^^").replace("|", "^|")


def _set_remote_db_user(span: ReadableSpan, attributes: BoundedAttributes) -> None:
if is_db_span(span) and is_key_present(span, _DB_USER):
attributes[AWS_REMOTE_DB_USER] = span.attributes.get(_DB_USER)


def _set_span_kind_for_dependency(span: ReadableSpan, attributes: BoundedAttributes) -> None:
span_kind: str = span.kind.name
attributes[AWS_SPAN_KIND] = span_kind
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
AWS_LOCAL_SERVICE,
AWS_QUEUE_NAME,
AWS_QUEUE_URL,
AWS_REMOTE_DB_USER,
AWS_REMOTE_OPERATION,
AWS_REMOTE_RESOURCE_IDENTIFIER,
AWS_REMOTE_RESOURCE_TYPE,
Expand Down Expand Up @@ -773,6 +774,52 @@ def test_both_metric_when_local_root_consumer_process(self):
self.assertIsNotNone(service_attributes)
self.assertIsNotNone(dependency_attributes)

def test_db_user_attribute(self):
self._mock_attribute([SpanAttributes.DB_OPERATION, SpanAttributes.DB_USER], ["db_operation", "db_user"])
self.span_mock.kind = SpanKind.CLIENT

actual_attributes: Attributes = _GENERATOR.generate_metric_attributes_dict_from_span(
self.span_mock, self.resource
).get(DEPENDENCY_METRIC)
self.assertEqual(actual_attributes.get(AWS_REMOTE_OPERATION), "db_operation")
self.assertEqual(actual_attributes.get(AWS_REMOTE_DB_USER), "db_user")

def test_db_user_attribute_absent(self):
self._mock_attribute([SpanAttributes.DB_SYSTEM], ["db_system"])
self.span_mock.kind = SpanKind.CLIENT

actual_attributes: Attributes = _GENERATOR.generate_metric_attributes_dict_from_span(
self.span_mock, self.resource
).get(DEPENDENCY_METRIC)
self.assertIsNone(actual_attributes.get(AWS_REMOTE_DB_USER))

def test_db_user_attribute_not_present_in_service_metric_for_server_span(self):
self._mock_attribute([SpanAttributes.DB_USER, SpanAttributes.DB_SYSTEM], ["db_user", "db_system"])
self.span_mock.kind = SpanKind.SERVER

actual_attributes: Attributes = _GENERATOR.generate_metric_attributes_dict_from_span(
self.span_mock, self.resource
).get(SERVICE_METRIC)
self.assertIsNone(actual_attributes.get(AWS_REMOTE_DB_USER))

def test_db_user_attribute_with_different_values(self):
self._mock_attribute([SpanAttributes.DB_OPERATION, SpanAttributes.DB_USER], ["db_operation", "non_db_user"])
self.span_mock.kind = SpanKind.CLIENT

actual_attributes: Attributes = _GENERATOR.generate_metric_attributes_dict_from_span(
self.span_mock, self.resource
).get(DEPENDENCY_METRIC)
self.assertEqual(actual_attributes.get(AWS_REMOTE_DB_USER), "non_db_user")

def test_db_user_present_and_is_db_span_false(self):
self._mock_attribute([SpanAttributes.DB_USER], ["db_user"])
self.span_mock.kind = SpanKind.CLIENT

actual_attributes: Attributes = _GENERATOR.generate_metric_attributes_dict_from_span(
self.span_mock, self.resource
).get(DEPENDENCY_METRIC)
self.assertIsNone(actual_attributes.get(AWS_REMOTE_DB_USER))

def test_local_root_boto3_span(self):
self._update_resource_with_service_name()
self.parent_span_context.is_valid = False
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from amazon.utils.application_signals_constants import (
AWS_LOCAL_OPERATION,
AWS_LOCAL_SERVICE,
AWS_REMOTE_DB_USER,
AWS_REMOTE_OPERATION,
AWS_REMOTE_RESOURCE_IDENTIFIER,
AWS_REMOTE_RESOURCE_TYPE,
Expand Down Expand Up @@ -109,6 +110,7 @@ def _assert_aws_attributes(self, attributes_list: List[KeyValue], **kwargs) -> N
self._assert_str_attribute(attributes_dict, AWS_REMOTE_SERVICE, self.get_remote_service())
self._assert_str_attribute(attributes_dict, AWS_REMOTE_OPERATION, kwargs.get("sql_command"))
self._assert_str_attribute(attributes_dict, AWS_REMOTE_RESOURCE_TYPE, "DB::Connection")
self._assert_str_attribute(attributes_dict, AWS_REMOTE_DB_USER, DATABASE_USER)
self._assert_str_attribute(
attributes_dict, AWS_REMOTE_RESOURCE_IDENTIFIER, self.get_remote_resource_identifier()
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
# Attribute names
AWS_LOCAL_SERVICE: str = "aws.local.service"
AWS_LOCAL_OPERATION: str = "aws.local.operation"
AWS_REMOTE_DB_USER: str = "aws.remote.db.user"
AWS_REMOTE_SERVICE: str = "aws.remote.service"
AWS_REMOTE_OPERATION: str = "aws.remote.operation"
AWS_REMOTE_RESOURCE_TYPE: str = "aws.remote.resource.type"
Expand Down

0 comments on commit 7a90ee5

Please sign in to comment.