@@ -13,7 +13,8 @@ use serde::{Deserialize, Serialize};
1313use thiserror:: Error ;
1414
1515use crate :: {
16- bson:: { Bson , Document } ,
16+ bson:: { doc, rawdoc, Bson , Document , RawDocumentBuf } ,
17+ cmap:: RawCommandResponse ,
1718 options:: ServerAddress ,
1819 sdam:: { ServerType , TopologyVersion } ,
1920} ;
@@ -52,20 +53,32 @@ pub type Result<T> = std::result::Result<T, Error>;
5253#[ derive( Clone , Debug , Error ) ]
5354#[ cfg_attr(
5455 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+ )
5660) ]
5761#[ cfg_attr(
5862 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+ )
6067) ]
6168#[ non_exhaustive]
6269pub struct Error {
6370 /// The type of error that occurred.
6471 pub kind : Box < ErrorKind > ,
72+
6573 labels : HashSet < String > ,
74+
6675 pub ( crate ) wire_version : Option < i32 > ,
76+
6777 #[ source]
6878 pub ( crate ) source : Option < Box < Error > > ,
79+
80+ pub ( crate ) server_response : Option < Box < RawDocumentBuf > > ,
81+
6982 #[ cfg( test) ]
7083 bt : Arc < std:: backtrace:: Backtrace > ,
7184}
@@ -99,6 +112,7 @@ impl Error {
99112 labels,
100113 wire_version : None ,
101114 source : None ,
115+ server_response : None ,
102116 #[ cfg( test) ]
103117 bt : Arc :: new ( std:: backtrace:: Backtrace :: capture ( ) ) ,
104118 }
@@ -288,6 +302,20 @@ impl Error {
288302 self . labels . insert ( label) ;
289303 }
290304
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+
291319 #[ cfg( feature = "dns-resolver" ) ]
292320 pub ( crate ) fn from_resolve_error ( error : hickory_resolver:: error:: ResolveError ) -> Self {
293321 ErrorKind :: DnsResolve {
@@ -496,6 +524,10 @@ impl Error {
496524 source. redact ( ) ;
497525 }
498526
527+ if self . server_response . is_some ( ) {
528+ self . server_response = Some ( Box :: new ( rawdoc ! { "redacted" : true } ) ) ;
529+ }
530+
499531 // This is intentionally written without a catch-all branch so that if new error
500532 // kinds are added we remember to reason about whether they need to be redacted.
501533 match * self . kind {
0 commit comments