@@ -13,7 +13,8 @@ use serde::{Deserialize, Serialize};
13
13
use thiserror:: Error ;
14
14
15
15
use crate :: {
16
- bson:: { Bson , Document } ,
16
+ bson:: { doc, rawdoc, Bson , Document , RawDocumentBuf } ,
17
+ cmap:: RawCommandResponse ,
17
18
options:: ServerAddress ,
18
19
sdam:: { ServerType , TopologyVersion } ,
19
20
} ;
@@ -52,20 +53,32 @@ pub type Result<T> = std::result::Result<T, Error>;
52
53
#[ derive( Clone , Debug , Error ) ]
53
54
#[ cfg_attr(
54
55
test,
55
- error( "Kind: {kind}, labels: {labels:?}, source: {source:?}, backtrace: {bt}" )
56
+ error(
57
+ "Kind: {kind}, labels: {labels:?}, source: {source:?}, backtrace: {bt}, server response: \
58
+ {server_response:?}"
59
+ )
56
60
) ]
57
61
#[ cfg_attr(
58
62
not( test) ,
59
- error( "Kind: {kind}, labels: {labels:?}, source: {source:?}" )
63
+ error(
64
+ "Kind: {kind}, labels: {labels:?}, source: {source:?}, server response: \
65
+ {server_response:?}"
66
+ )
60
67
) ]
61
68
#[ non_exhaustive]
62
69
pub struct Error {
63
70
/// The type of error that occurred.
64
71
pub kind : Box < ErrorKind > ,
72
+
65
73
labels : HashSet < String > ,
74
+
66
75
pub ( crate ) wire_version : Option < i32 > ,
76
+
67
77
#[ source]
68
78
pub ( crate ) source : Option < Box < Error > > ,
79
+
80
+ pub ( crate ) server_response : Option < Box < RawDocumentBuf > > ,
81
+
69
82
#[ cfg( test) ]
70
83
bt : Arc < std:: backtrace:: Backtrace > ,
71
84
}
@@ -99,6 +112,7 @@ impl Error {
99
112
labels,
100
113
wire_version : None ,
101
114
source : None ,
115
+ server_response : None ,
102
116
#[ cfg( test) ]
103
117
bt : Arc :: new ( std:: backtrace:: Backtrace :: capture ( ) ) ,
104
118
}
@@ -288,6 +302,20 @@ impl Error {
288
302
self . labels . insert ( label) ;
289
303
}
290
304
305
+ /// The full response returned from the server. This can be used to inspect error fields that
306
+ /// are not represented in the `Error` type.
307
+ pub fn server_response ( & self ) -> Option < & RawDocumentBuf > {
308
+ self . server_response . as_deref ( )
309
+ }
310
+
311
+ /// Adds the server's response to this error if it is not already present.
312
+ pub ( crate ) fn with_server_response ( mut self , response : & RawCommandResponse ) -> Self {
313
+ if self . server_response . is_none ( ) {
314
+ self . server_response = Some ( Box :: new ( response. raw_body ( ) . to_owned ( ) ) ) ;
315
+ }
316
+ self
317
+ }
318
+
291
319
#[ cfg( feature = "dns-resolver" ) ]
292
320
pub ( crate ) fn from_resolve_error ( error : hickory_resolver:: error:: ResolveError ) -> Self {
293
321
ErrorKind :: DnsResolve {
@@ -496,6 +524,10 @@ impl Error {
496
524
source. redact ( ) ;
497
525
}
498
526
527
+ if self . server_response . is_some ( ) {
528
+ self . server_response = Some ( Box :: new ( rawdoc ! { "redacted" : true } ) ) ;
529
+ }
530
+
499
531
// This is intentionally written without a catch-all branch so that if new error
500
532
// kinds are added we remember to reason about whether they need to be redacted.
501
533
match * self . kind {
0 commit comments