Skip to content
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

Add structured log messages to CMAP. #1114

Merged
merged 22 commits into from
May 19, 2023
Merged

Add structured log messages to CMAP. #1114

merged 22 commits into from
May 19, 2023

Conversation

vbabanin
Copy link
Member

@vbabanin vbabanin commented May 6, 2023

This pull request adds changes to logging in accordance with CMAP specification. The purpose of these changes is to introduce structured logging to the connection component, providing a uniform logging format across all drivers.

Additionally, this pull request removes unnecessary logging that is not widely used and therefore not necessary to maintain. This will help to simplify the codebase.

Furthermore, conditional logging statements have been improved for better readability. A special formatting approach has been introduced, allowing the omission of log sentences enclosed in conditionals when the corresponding value is null.

JAVA-4771
JAVA-4962
JAVA-4946

@@ -497,7 +506,24 @@ private void initClient(final BsonDocument entity, final String id,
MongoClientSettings clientSettings = clientSettingsBuilder.build();

if (entity.containsKey("observeLogMessages")) {
putEntity(id + "-logging-interceptor", new TestLoggingInterceptor(clientSettings.getApplicationName()), clientLoggingInterceptors);
Copy link
Member Author

@vbabanin vbabanin May 6, 2023

Choose a reason for hiding this comment

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

This change below has been added in accordance with the spec observeLogMessages

@vbabanin vbabanin requested review from stIncMale and jyemin May 6, 2023 01:51
@vbabanin vbabanin marked this pull request as ready for review May 8, 2023 15:28
@stIncMale
Copy link
Member

stIncMale commented May 9, 2023

The PR implements the spec changes from mongodb/specifications@d268119. As far as I understand, there are some changes in this commits that are either not reflected, or should be reflected differently in the PR:

  1. The directory source/connection-monitoring-and-pooling/tests/connection-monitoring-and-pooling/ was renamed to source/connection-monitoring-and-pooling/tests/cmap-format/, which means we need to rename driver-core/src/test/resources/connection-monitoring-and-pooling/ to driver-core/src/test/resources/connection-monitoring-and-pooling-cmap-format/.
  2. We need to replace all the .rst and .json files in the new driver directory driver-core/src/test/resources/connection-monitoring-and-pooling-cmap-format/ with those from source/connection-monitoring-and-pooling/tests/cmap-format/. Note that the link is to d268119c9d4354f60e59d2e798c3cb3ee5323a29.
    2.1. We need to update the corresponding test runner AbstractConnectionPoolTest to search for tests from the new place.
  3. The directory source/connection-monitoring-and-pooling/tests/logging/ was created, and it contains unified tests, which means we need to create driver-core/src/test/resources/unified-test-format/connection-monitoring-and-pooling-logging/.
  4. We need to copy all the .json files from source/connection-monitoring-and-pooling/tests/logging/ to driver-core/src/test/resources/unified-test-format/connection-monitoring-and-pooling-logging/. Note that the link is to d268119c9d4354f60e59d2e798c3cb3ee5323a29.
    4.1. We need to update the corresponding test runner ConnectionPoolLoggingTest to search for tests from the new place.

Copy link
Member

@stIncMale stIncMale left a comment

Choose a reason for hiding this comment

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

I have not reviewed DefaultConnectionPool. Will wait until the new formatting approach is implemented.

Copy link
Member

@stIncMale stIncMale left a comment

Choose a reason for hiding this comment

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

I have not reviewed DefaultConnectionPool. Will wait until the new formatting approach is implemented.

@vbabanin
Copy link
Member Author

vbabanin commented May 10, 2023

The PR implements the spec changes from mongodb/specifications@d268119. As far as I understand, there are some changes in this commits that are either not reflected, or should be reflected differently in the PR:

  1. The directory source/connection-monitoring-and-pooling/tests/connection-monitoring-and-pooling/ was renamed to source/connection-monitoring-and-pooling/tests/cmap-format/, which means we need to rename driver-core/src/test/resources/connection-monitoring-and-pooling/ to driver-core/src/test/resources/connection-monitoring-and-pooling-cmap-format/.
  2. We need to replace all the .rst and .json files in the new driver directory driver-core/src/test/resources/connection-monitoring-and-pooling-cmap-format/ with those from source/connection-monitoring-and-pooling/tests/cmap-format/. Note that the link is to d268119c9d4354f60e59d2e798c3cb3ee5323a29.
    2.1. We need to update the corresponding test runner AbstractConnectionPoolTest to search for tests from the new place.
  3. The directory source/connection-monitoring-and-pooling/tests/logging/ was created, and it contains unified tests, which means we need to create driver-core/src/test/resources/unified-test-format/connection-monitoring-and-pooling-logging/.
  4. We need to copy all the .json files from source/connection-monitoring-and-pooling/tests/logging/ to driver-core/src/test/resources/unified-test-format/connection-monitoring-and-pooling-logging/. Note that the link is to d268119c9d4354f60e59d2e798c3cb3ee5323a29.
    4.1. We need to update the corresponding test runner ConnectionPoolLoggingTest to search for tests from the new place.

That makes sense. We can create a subfolder for the tests in our driver as in the spec repo source/connection-monitoring-and-pooling/tests/logging/

The location for this subfolder would be:
driver-core/src/test/resources/unified-test-format/connection-monitoring-and-pooling/logging
As more unified tests are added to CMAP, we can categorize them into separate subfolders under the same CMAP umbrella, based on the type of tests, for better organization. What do you think?

@stIncMale
Copy link
Member

stIncMale commented May 10, 2023

The location for this subfolder would be:
driver-core/src/test/resources/unified-test-format/connection-monitoring-and-pooling/logging

As more unified tests are added to CMAP, we can categorize them into separate subfolders under the same CMAP umbrella, based on the type of tests, for better organization. What do you think?

The current naming schema is confusing / does not seem to exist: sometimes we use subfolders, as in

  • driver-core/src/test/resources/server-discovery-and-monitoring/errors
  • driver-core/src/test/resources/server-discovery-and-monitoring/rs

and sometimes we use plain structure with suffixes, as in

  • driver-core/src/test/resources/client-side-encryption-corpus
  • driver-core/src/test/resources/client-side-encryption-data

So yeah, this PR can use subfolders as they seem much better than suffixes.

@vbabanin vbabanin self-assigned this May 10, 2023
…d messages.

1. Add LogMessage abstraction over StructuredLogMessage and UnstructuredLogMessage to move interpolation logic to StructuredLogger and lazily construct messages.
2. Move repetitive log keys to an enum to improve code readability and maintainability.

JAVA-4771
JAVA-4962
String format = "Command \"{}\" succeeded in {} ms using a connection with driver-generated ID {}" +
"[ and server-generated ID {}] to {}:{}[ with service ID {}]. The requestID is {} and the " +
"operation ID is {}. Command reply: {}]";
return Stream.of(
Copy link
Member Author

Choose a reason for hiding this comment

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

You can see almost all the cases interpolation currently can handle

/**
* <p>This class is not part of the public API and may be removed or changed at any time</p>
*/
public final class LogMessage {
Copy link
Member Author

@vbabanin vbabanin May 12, 2023

Choose a reason for hiding this comment

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

GitHub shows changes as if this is a new class, but actually that is renamed StructuredLogMessage class to LogMessage.

The reason for this change is that by design and specification, StructuredLogMessage only allows non-null entry values. However, we also need to preserve null values when interpolating a message to indicate which parts should be omitted.

To capture all entries, both null and non-null, new wrapper class (LogMessage) was introduced that allows to contain all entries with their corresponding values. Additionally, StructuredLogMessage is an inner class of LogMessage, so that LogMessage can be converted to StructuredLogMessage using the toStructuredLogMessage method, which creates a null-free structured log message.

To handle message interpolation, UnstructuredLogMessage inner class class is introduced as well, which triggers interpolation logic lazily. Our Logger captures LogMessage and internally converts it to either an unstructured or structured log message.

At this time, we only emit unstructured logs to the user.

@vbabanin vbabanin requested a review from stIncMale May 12, 2023 18:02
* @return the interpolated string with the values from the entries collection filled in the placeholders.
* @throws NoSuchElementException – if the iteration has no more elements.
*/
public String interpolate() {
Copy link
Member Author

Choose a reason for hiding this comment

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

@katcharov this is interpolation logic we discussed. You are welcome to review

@stIncMale
Copy link
Member

Since this PR also implements JAVA-4962, let's add it to the PR description.

@stIncMale
Copy link
Member

I noticed that the connection-pool-options.json as you took it also contains the complete implementation of JAVA-4946. So let's add this ticket to the PR description, and close it with the others when the PR is merged.

@@ -473,10 +495,36 @@ private void connectionCreated(final ConnectionPoolListener connectionPoolListen
*/
private void connectionClosed(final ConnectionPoolListener connectionPoolListener, final ConnectionId connectionId,
final ConnectionClosedEvent.Reason reason) {
ClusterId clusterId = serverId.getClusterId();
if (STRUCTURED_LOGGER.isRequired(DEBUG, clusterId)) {
String errorReason = "There was a socket exception raised by this connection";
Copy link
Member Author

Choose a reason for hiding this comment

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

No explicit exception is thrown to provide a comprehensive explanation of the error. However, according to the specification, it is mandatory to supply an error description when the reason for closure is an ERROR. Please refer to the specification available at Spec.

In the getReasonForClosing method, there is a check if (connection.isClosed()) which returns an ERROR type. Consequently, a corresponding check was implemented in the getReasonStringForClosing method to elaborate in more detail on the cause of the connection closure. Therefore, the error message was derived from the getReasonStringForClosing.

@vbabanin vbabanin marked this pull request as draft May 17, 2023 07:06
@vbabanin
Copy link
Member Author

Additional tests will be added. Converted to draft

- Update LoggingInterceptor to accept LogMessage for capturing both structured and unstructured log messages during testing.
- Remove redundant methods.

JAVA-4771
JAVA-4962
@vbabanin vbabanin requested a review from stIncMale May 17, 2023 22:39
@vbabanin vbabanin marked this pull request as ready for review May 17, 2023 22:40
Copy link
Member

@stIncMale stIncMale left a comment

Choose a reason for hiding this comment

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

It'd be great to introduce a new type for message ID constants (a enum appears to be the best choice) instead of using String literals.

I approved, but static checks need to pass before merging.

StructuredLogMessage is an inner class, but does not use its embedded reference to the object which created it.  This reference makes the instances of the class larger, and may keep the reference to the creator object alive longer than necessary.

JAVA-4771
JAVA-4962
@vbabanin vbabanin requested a review from jyemin May 18, 2023 20:35
Copy link
Contributor

@jyemin jyemin left a comment

Choose a reason for hiding this comment

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

LGTM!

@vbabanin vbabanin merged commit 14dd356 into mongodb:master May 19, 2023
41 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
3 participants