Skip to content

PYTHON-3472 - Add log messages to SDAM spec #1771

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
Aug 28, 2024

Conversation

NoahStapp
Copy link
Contributor

No description provided.

@mongodb-drivers-pr-bot mongodb-drivers-pr-bot bot requested a review from Jibola August 5, 2024 19:05
Jibola
Jibola previously approved these changes Aug 7, 2024
Copy link
Contributor

@Jibola Jibola left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall LGTM!

Left non-blocking comments.

@@ -16,7 +16,7 @@
"b:27017"
],
"minWireVersion": 0,
"maxWireVersion": 21
"maxWireVersion": 6
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Guessing this is just a spec requirement change?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes.

@@ -1804,14 +1818,28 @@ def check_events(self, spec):
else:
assert server_connection_id is None

def process_ignore_messages(self, ignore_logs, actual_logs):
final_logs = []
for log in actual_logs:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NIT: Thoughts on this potential optimization?

actual_log_messages = {actual_log["data"]["message"] for actual_log in actual_logs}
return list(filter(lambda log: log["data"]["message"] not in actual_log_messages))

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like this optimization but it does deviate from the spec's statement that "Matching rules used to match messages in ignoreMessages are identical to match rules used for messages matching". Is this a case where we need to stick closely to the spec, or can we do this much simpler way of matching?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point. I'll say let's not then.

The self.match_evaluator.match_result() function could be added in, but we lose readability so we'll keep it as is.

NoahStapp and others added 4 commits August 7, 2024 10:16
Co-authored-by: Jib <Jibzade@gmail.com>
Co-authored-by: Jib <Jibzade@gmail.com>
@NoahStapp NoahStapp requested a review from Jibola August 8, 2024 16:03
if self._publish:
assert self._listeners is not None
sd = self._server_description
# XXX: "awaited" could be incorrectly set to True in the rare case
# the pool checkout closes and recreates a connection.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment should move along with the awaited var.

serverHost=address[0],
serverPort=address[1],
awaited=awaited,
durationMS=round_trip_time,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here and elsewhere: round_trip_time is a float in seconds, but durationMS should be in milliseconds.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Still need to make this change in the other locations where durationMS is passed.

@NoahStapp NoahStapp requested a review from ShaneHarvey August 8, 2024 20:49
serverHost=address[0],
serverPort=address[1],
awaited=awaited,
durationMS=duration,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

durationMS needs to be in ms here too.

self._listeners.publish_server_heartbeat_started(address, awaited)

if self._cancel_context and self._cancel_context.cancelled:
await self._reset_connection()
async with self._pool.checkout() as conn:
if _SDAM_LOGGER.isEnabledFor(logging.DEBUG):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't this happen at the same point where publish_server_heartbeat_started is called?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In theory yes. However, we need a connection for the required logging information, and checking out the connection before publishing the heartbeat has a lot of side effects for other tests.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would expect driverConnectionId to be None on the initial started event. Does the spec not expect that?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member

@ShaneHarvey ShaneHarvey Aug 12, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm this was intended to be fixed in DRIVERS-2677. Let's go forward with the current approach for now since the spec is ambiguous.

@@ -1804,14 +1818,28 @@ def check_events(self, spec):
else:
assert server_connection_id is None

def process_ignore_messages(self, ignore_logs, actual_logs):
final_logs = []
for log in actual_logs:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point. I'll say let's not then.

The self.match_evaluator.match_result() function could be added in, but we lose readability so we'll keep it as is.

@NoahStapp NoahStapp requested a review from ShaneHarvey August 26, 2024 13:38
@ShaneHarvey
Copy link
Member

Is this pypy failure related?:

=================================== FAILURES ===================================
_ TestConnectionLoggingConnectionLogging.test_Create_a_client,_run_a_command,_and_close_the_client _

self = <test.test_connection_logging.TestConnectionLoggingConnectionLogging testMethod=test_Create_a_client,_run_a_command,_and_close_the_client>

    def test_case(self):
>       self.run_scenario(spec)

test/unified_format.py:2069: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
test/unified_format.py:2013: in run_scenario
    self._run_scenario(spec, uri)
test/unified_format.py:2043: in _run_scenario
    self.check_log_messages(spec["operations"], expect_log_messages)
test/unified_format.py:1939: in check_log_messages
    formatted_logs = format_logs(cm.records)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

log_list = [<LogRecord: pymongo.topology, 10, /home/runner/work/mongo-python-driver/mongo-python-driver/pymongo/logger.py, 100, "...66cddd96f2b922fd71bcd93c"}, "message": "Connection pool ready", "serverHost": "localhost", "serverPort": 27017}">, ...]

    def format_logs(log_list):
        client_to_log = defaultdict(list)
        for log in log_list:
            if log.module == "ocsp_support":
                continue
>           data = json_util.loads(log.message)
E           AttributeError: 'LogRecord' object has no attribute 'message'

test/unified_format.py:1926: AttributeError
------------------------------ Captured log call -------------------------------
DEBUG    pymongo.topology:logger.py:100 {"topologyId": {"$oid": "66cddd96f2b922fd71bcd93c"}, "driverConnectionId": 1, "serverConnectionId": 901, "serverHost": "localhost", "serverPort": 27017, "awaited": true, "message": "Server heartbeat started"}

@NoahStapp
Copy link
Contributor Author

Is this pypy failure related?:

=================================== FAILURES ===================================
_ TestConnectionLoggingConnectionLogging.test_Create_a_client,_run_a_command,_and_close_the_client _

self = <test.test_connection_logging.TestConnectionLoggingConnectionLogging testMethod=test_Create_a_client,_run_a_command,_and_close_the_client>

    def test_case(self):
>       self.run_scenario(spec)

test/unified_format.py:2069: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
test/unified_format.py:2013: in run_scenario
    self._run_scenario(spec, uri)
test/unified_format.py:2043: in _run_scenario
    self.check_log_messages(spec["operations"], expect_log_messages)
test/unified_format.py:1939: in check_log_messages
    formatted_logs = format_logs(cm.records)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

log_list = [<LogRecord: pymongo.topology, 10, /home/runner/work/mongo-python-driver/mongo-python-driver/pymongo/logger.py, 100, "...66cddd96f2b922fd71bcd93c"}, "message": "Connection pool ready", "serverHost": "localhost", "serverPort": 27017}">, ...]

    def format_logs(log_list):
        client_to_log = defaultdict(list)
        for log in log_list:
            if log.module == "ocsp_support":
                continue
>           data = json_util.loads(log.message)
E           AttributeError: 'LogRecord' object has no attribute 'message'

test/unified_format.py:1926: AttributeError
------------------------------ Captured log call -------------------------------
DEBUG    pymongo.topology:logger.py:100 {"topologyId": {"$oid": "66cddd96f2b922fd71bcd93c"}, "driverConnectionId": 1, "serverConnectionId": 901, "serverHost": "localhost", "serverPort": 27017, "awaited": true, "message": "Server heartbeat started"}

I wouldn't expect it to be related, but it doesn't appear to be failing on other PRs. According to the logging docs, LogRecord.message is set only when the formatter is called. We've seen this exact error before intermittently, but haven't tracked down the underlying cause.

@NoahStapp
Copy link
Contributor Author

Is this pypy failure related?:

=================================== FAILURES ===================================
_ TestConnectionLoggingConnectionLogging.test_Create_a_client,_run_a_command,_and_close_the_client _

self = <test.test_connection_logging.TestConnectionLoggingConnectionLogging testMethod=test_Create_a_client,_run_a_command,_and_close_the_client>

    def test_case(self):
>       self.run_scenario(spec)

test/unified_format.py:2069: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
test/unified_format.py:2013: in run_scenario
    self._run_scenario(spec, uri)
test/unified_format.py:2043: in _run_scenario
    self.check_log_messages(spec["operations"], expect_log_messages)
test/unified_format.py:1939: in check_log_messages
    formatted_logs = format_logs(cm.records)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

log_list = [<LogRecord: pymongo.topology, 10, /home/runner/work/mongo-python-driver/mongo-python-driver/pymongo/logger.py, 100, "...66cddd96f2b922fd71bcd93c"}, "message": "Connection pool ready", "serverHost": "localhost", "serverPort": 27017}">, ...]

    def format_logs(log_list):
        client_to_log = defaultdict(list)
        for log in log_list:
            if log.module == "ocsp_support":
                continue
>           data = json_util.loads(log.message)
E           AttributeError: 'LogRecord' object has no attribute 'message'

test/unified_format.py:1926: AttributeError
------------------------------ Captured log call -------------------------------
DEBUG    pymongo.topology:logger.py:100 {"topologyId": {"$oid": "66cddd96f2b922fd71bcd93c"}, "driverConnectionId": 1, "serverConnectionId": 901, "serverHost": "localhost", "serverPort": 27017, "awaited": true, "message": "Server heartbeat started"}

I wouldn't expect it to be related, but it doesn't appear to be failing on other PRs. According to the logging docs, LogRecord.message is set only when the formatter is called. We've seen this exact error before intermittently, but haven't tracked down the underlying cause.

I cannot reproduce this locally. Will keep an eye on it, and if it continues failing I'll open a ticket to investigate.

@NoahStapp NoahStapp merged commit c6967ab into mongodb:master Aug 28, 2024
30 of 34 checks passed
@NoahStapp NoahStapp deleted the PYTHON-3472 branch August 28, 2024 18:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants