18
18
19
19
import com .mongodb .MongoCommandException ;
20
20
import com .mongodb .RequestContext ;
21
+ import com .mongodb .connection .ClusterId ;
21
22
import com .mongodb .connection .ConnectionDescription ;
22
23
import com .mongodb .event .CommandListener ;
23
- import com .mongodb .internal .diagnostics .logging .Logger ;
24
+ import com .mongodb .internal .logging .StructuredLogMessage ;
25
+ import com .mongodb .internal .logging .StructuredLogMessage .Entry ;
26
+ import com .mongodb .internal .logging .StructuredLogger ;
24
27
import com .mongodb .lang .Nullable ;
25
28
import org .bson .BsonDocument ;
26
29
import org .bson .BsonInt32 ;
29
32
import org .bson .json .JsonMode ;
30
33
import org .bson .json .JsonWriter ;
31
34
import org .bson .json .JsonWriterSettings ;
35
+ import org .bson .types .ObjectId ;
32
36
33
37
import java .io .StringWriter ;
38
+ import java .util .ArrayList ;
39
+ import java .util .List ;
34
40
import java .util .Set ;
35
41
36
42
import static com .mongodb .assertions .Assertions .assertNotNull ;
37
43
import static com .mongodb .internal .connection .ProtocolHelper .sendCommandFailedEvent ;
38
44
import static com .mongodb .internal .connection .ProtocolHelper .sendCommandStartedEvent ;
39
45
import static com .mongodb .internal .connection .ProtocolHelper .sendCommandSucceededEvent ;
40
- import static java .lang .String .format ;
46
+ import static com .mongodb .internal .logging .StructuredLogMessage .Component .COMMAND ;
47
+ import static com .mongodb .internal .logging .StructuredLogMessage .Level .DEBUG ;
41
48
42
49
class LoggingCommandEventSender implements CommandEventSender {
43
50
private static final int MAX_COMMAND_DOCUMENT_LENGTH_TO_LOG = 1000 ;
51
+ private static final double NANOS_PER_MILLI = 1_000_000.0d ;
44
52
45
53
private final ConnectionDescription description ;
46
54
@ Nullable private final CommandListener commandListener ;
47
55
private final RequestContext requestContext ;
48
- private final Logger logger ;
56
+ private final StructuredLogger logger ;
49
57
private final long startTimeNanos ;
50
58
private final CommandMessage message ;
51
59
private final String commandName ;
@@ -55,7 +63,7 @@ class LoggingCommandEventSender implements CommandEventSender {
55
63
LoggingCommandEventSender (final Set <String > securitySensitiveCommands , final Set <String > securitySensitiveHelloCommands ,
56
64
final ConnectionDescription description ,
57
65
@ Nullable final CommandListener commandListener , final RequestContext requestContext , final CommandMessage message ,
58
- final ByteBufferBsonOutput bsonOutput , final Logger logger ) {
66
+ final ByteBufferBsonOutput bsonOutput , final StructuredLogger logger ) {
59
67
this .description = description ;
60
68
this .commandListener = commandListener ;
61
69
this .requestContext = requestContext ;
@@ -71,12 +79,17 @@ class LoggingCommandEventSender implements CommandEventSender {
71
79
@ Override
72
80
public void sendStartedEvent () {
73
81
if (loggingRequired ()) {
74
- String commandString = redactionRequired ? format ("{\" %s\" : ..." , commandName ) : getTruncatedJsonCommand ();
75
- // TODO: log RequestContext?
76
- logger .debug (
77
- format ("Sending command '%s' with request id %d to database %s on connection [%s] to server %s" ,
78
- commandString , message .getId (),
79
- message .getNamespace ().getDatabaseName (), description .getConnectionId (), description .getServerAddress ()));
82
+ List <Entry > entries = new ArrayList <>();
83
+ StringBuilder builder = new StringBuilder ("Command \" %s\" started on database %s" );
84
+ entries .add (new Entry ("commandName" , commandName ));
85
+ entries .add (new Entry ("databaseName" , message .getNamespace ().getDatabaseName ()));
86
+
87
+ appendCommonLogFragment (entries , builder );
88
+
89
+ builder .append (" Command: %s" );
90
+ entries .add (new Entry ("command" , redactionRequired ? "{}" : getTruncatedJsonCommand (commandDocument )));
91
+
92
+ logger .log (new StructuredLogMessage (COMMAND , DEBUG , "Command started" , getClusterId (), entries ), builder .toString ());
80
93
}
81
94
82
95
if (eventRequired ()) {
@@ -91,38 +104,27 @@ public void sendStartedEvent() {
91
104
commandDocument = null ;
92
105
}
93
106
94
- private String getTruncatedJsonCommand () {
95
- StringWriter writer = new StringWriter ();
96
-
97
- try (BsonReader bsonReader = commandDocument .asBsonReader ()) {
98
- JsonWriter jsonWriter = new JsonWriter (writer ,
99
- JsonWriterSettings .builder ().outputMode (JsonMode .RELAXED ).maxLength (MAX_COMMAND_DOCUMENT_LENGTH_TO_LOG ).build ());
100
-
101
- jsonWriter .pipe (bsonReader );
102
-
103
- if (jsonWriter .isTruncated ()) {
104
- writer .append (" ..." );
105
- }
106
-
107
- return writer .toString ();
108
- }
109
- }
110
107
111
108
@ Override
112
109
public void sendFailedEvent (final Throwable t ) {
113
110
Throwable commandEventException = t ;
114
111
if (t instanceof MongoCommandException && redactionRequired ) {
115
- commandEventException = new MongoCommandException (new BsonDocument (), description .getServerAddress ());
112
+ MongoCommandException originalCommandException = (MongoCommandException ) t ;
113
+ commandEventException = new MongoCommandException (new BsonDocument (), originalCommandException .getServerAddress ());
114
+ commandEventException .setStackTrace (t .getStackTrace ());
116
115
}
117
116
long elapsedTimeNanos = System .nanoTime () - startTimeNanos ;
118
117
119
118
if (loggingRequired ()) {
120
- logger .debug (
121
- format ("Execution of command with request id %d failed to complete successfully in %s ms on connection [%s] "
122
- + "to server %s" ,
123
- message .getId (), getElapsedTimeFormattedInMilliseconds (elapsedTimeNanos ), description .getConnectionId (),
124
- description .getServerAddress ()),
125
- commandEventException );
119
+ List <Entry > entries = new ArrayList <>();
120
+ StringBuilder builder = new StringBuilder ("Command \" %s\" failed in %.2f ms" );
121
+ entries .add (new Entry ("commandName" , commandName ));
122
+ entries .add (new Entry ("durationMS" , elapsedTimeNanos / NANOS_PER_MILLI ));
123
+
124
+ appendCommonLogFragment (entries , builder );
125
+
126
+ logger .log (new StructuredLogMessage (COMMAND , DEBUG , "Command failed" , getClusterId (), commandEventException , entries ),
127
+ builder .toString ());
126
128
}
127
129
128
130
if (eventRequired ()) {
@@ -133,53 +135,92 @@ public void sendFailedEvent(final Throwable t) {
133
135
134
136
@ Override
135
137
public void sendSucceededEvent (final ResponseBuffers responseBuffers ) {
136
- long elapsedTimeNanos = System .nanoTime () - startTimeNanos ;
137
-
138
- if (loggingRequired ()) {
139
- logger .debug (
140
- format ("Execution of command with request id %d completed successfully in %s ms on connection [%s] to server %s" ,
141
- message .getId (), getElapsedTimeFormattedInMilliseconds (elapsedTimeNanos ), description .getConnectionId (),
142
- description .getServerAddress ()));
143
- }
144
-
145
- if (eventRequired ()) {
146
- BsonDocument responseDocumentForEvent = redactionRequired
147
- ? new BsonDocument ()
148
- : responseBuffers .getResponseDocument (message .getId (), new RawBsonDocumentCodec ());
149
- sendCommandSucceededEvent (message , commandName , responseDocumentForEvent , description ,
150
- elapsedTimeNanos , commandListener , requestContext );
151
- }
138
+ sendSucceededEvent (responseBuffers .getResponseDocument (message .getId (), new RawBsonDocumentCodec ()));
152
139
}
153
140
154
141
@ Override
155
142
public void sendSucceededEventForOneWayCommand () {
143
+ sendSucceededEvent (new BsonDocument ("ok" , new BsonInt32 (1 )));
144
+ }
145
+
146
+ private void sendSucceededEvent (final BsonDocument reply ) {
156
147
long elapsedTimeNanos = System .nanoTime () - startTimeNanos ;
157
148
158
149
if (loggingRequired ()) {
159
- logger .debug (
160
- format ("Execution of one-way command with request id %d completed successfully in %s ms on connection [%s] "
161
- + "to server %s" ,
162
- message .getId (), getElapsedTimeFormattedInMilliseconds (elapsedTimeNanos ), description .getConnectionId (),
163
- description .getServerAddress ()));
150
+ List <Entry > entries = new ArrayList <>();
151
+ StringBuilder builder = new StringBuilder ("Command \" %s\" succeeded in %.2f ms" );
152
+ entries .add (new Entry ("commandName" , commandName ));
153
+ entries .add (new Entry ("durationMS" , elapsedTimeNanos / NANOS_PER_MILLI ));
154
+
155
+ appendCommonLogFragment (entries , builder );
156
+
157
+ builder .append (" Command reply: %s" );
158
+ BsonDocument responseDocumentForEvent = redactionRequired ? new BsonDocument () : reply ;
159
+ String replyString = redactionRequired ? "{}" : getTruncatedJsonCommand (responseDocumentForEvent );
160
+ entries .add (new Entry ("reply" , replyString ));
161
+
162
+ logger .log (new StructuredLogMessage (COMMAND , DEBUG , "Command succeeded" , getClusterId (), entries ),
163
+ builder .toString ());
164
164
}
165
165
166
166
if (eventRequired ()) {
167
- BsonDocument responseDocumentForEvent = new BsonDocument ( "ok" , new BsonInt32 ( 1 )) ;
167
+ BsonDocument responseDocumentForEvent = redactionRequired ? new BsonDocument () : reply ;
168
168
sendCommandSucceededEvent (message , commandName , responseDocumentForEvent , description ,
169
169
elapsedTimeNanos , commandListener , requestContext );
170
170
}
171
171
}
172
172
173
173
private boolean loggingRequired () {
174
- return logger .isDebugEnabled ();
174
+ return logger .isRequired (DEBUG , getClusterId ());
175
+ }
176
+
177
+
178
+ private ClusterId getClusterId () {
179
+ return description .getConnectionId ().getServerId ().getClusterId ();
175
180
}
176
181
177
182
private boolean eventRequired () {
178
183
return commandListener != null ;
179
184
}
180
185
181
- private String getElapsedTimeFormattedInMilliseconds (final long elapsedTimeNanos ) {
182
- return DecimalFormatHelper .format ("#0.00" , elapsedTimeNanos / 1000000.0 );
186
+ private void appendCommonLogFragment (final List <Entry > entries , final StringBuilder builder ) {
187
+ builder .append (" using a connection with driver-generated ID %d" );
188
+ entries .add (new Entry ("driverConnectionId" , description .getConnectionId ().getLocalValue ()));
189
+
190
+ Integer connectionServerValue = description .getConnectionId ().getServerValue ();
191
+ if (connectionServerValue != null ) {
192
+ builder .append (" and server-generated ID %d" );
193
+ entries .add (new Entry ("serverConnectionId" , connectionServerValue ));
194
+ }
195
+
196
+ builder .append (" to %s:%s" );
197
+ entries .add (new Entry ("serverHost" , description .getServerAddress ().getHost ()));
198
+ entries .add (new Entry ("serverPort" , description .getServerAddress ().getPort ()));
199
+
200
+ ObjectId descriptionServiceId = description .getServiceId ();
201
+ if (descriptionServiceId != null ) {
202
+ builder .append (" with service ID %s" );
203
+ entries .add (new Entry ("serviceId" , descriptionServiceId ));
204
+ }
205
+
206
+ builder .append (". The request ID is %s." );
207
+ entries .add (new Entry ("requestId" , message .getId ()));
183
208
}
184
209
210
+ private static String getTruncatedJsonCommand (final BsonDocument commandDocument ) {
211
+ StringWriter writer = new StringWriter ();
212
+
213
+ try (BsonReader bsonReader = commandDocument .asBsonReader ()) {
214
+ JsonWriter jsonWriter = new JsonWriter (writer ,
215
+ JsonWriterSettings .builder ().outputMode (JsonMode .RELAXED ).maxLength (MAX_COMMAND_DOCUMENT_LENGTH_TO_LOG ).build ());
216
+
217
+ jsonWriter .pipe (bsonReader );
218
+
219
+ if (jsonWriter .isTruncated ()) {
220
+ writer .append (" ..." );
221
+ }
222
+
223
+ return writer .toString ();
224
+ }
225
+ }
185
226
}
0 commit comments