@@ -275,31 +275,39 @@ type WriteError struct {
275
275
276
276
Code int
277
277
Message string
278
+ Details bson.Raw
278
279
}
279
280
280
- func (we WriteError ) Error () string { return we .Message }
281
+ func (we WriteError ) Error () string {
282
+ msg := we .Message
283
+ if len (we .Details ) > 0 {
284
+ msg = fmt .Sprintf ("%s: %s" , msg , we .Details .String ())
285
+ }
286
+ return msg
287
+ }
281
288
282
289
// WriteErrors is a group of write errors that occurred during execution of a write operation.
283
290
type WriteErrors []WriteError
284
291
285
292
// Error implements the error interface.
286
293
func (we WriteErrors ) Error () string {
287
- var buf bytes.Buffer
288
- fmt .Fprint (& buf , "write errors: [" )
289
- for idx , err := range we {
290
- if idx != 0 {
291
- fmt .Fprintf (& buf , ", " )
292
- }
293
- fmt .Fprintf (& buf , "{%s}" , err )
294
+ errs := make ([]error , len (we ))
295
+ for i := 0 ; i < len (we ); i ++ {
296
+ errs [i ] = we [i ]
294
297
}
295
- fmt . Fprint ( & buf , "]" )
296
- return buf . String ( )
298
+ // WriteErrors isn't returned from batch operations, but we can still use the same formatter.
299
+ return "write errors: " + joinBatchErrors ( errs )
297
300
}
298
301
299
302
func writeErrorsFromDriverWriteErrors (errs driver.WriteErrors ) WriteErrors {
300
303
wes := make (WriteErrors , 0 , len (errs ))
301
304
for _ , err := range errs {
302
- wes = append (wes , WriteError {Index : int (err .Index ), Code : int (err .Code ), Message : err .Message })
305
+ wes = append (wes , WriteError {
306
+ Index : int (err .Index ),
307
+ Code : int (err .Code ),
308
+ Message : err .Message ,
309
+ Details : bson .Raw (err .Details ),
310
+ })
303
311
}
304
312
return wes
305
313
}
@@ -336,11 +344,21 @@ type WriteException struct {
336
344
337
345
// Error implements the error interface.
338
346
func (mwe WriteException ) Error () string {
339
- var buf bytes.Buffer
340
- fmt .Fprint (& buf , "multiple write errors: [" )
341
- fmt .Fprintf (& buf , "{%s}, " , mwe .WriteErrors )
342
- fmt .Fprintf (& buf , "{%s}]" , mwe .WriteConcernError )
343
- return buf .String ()
347
+ causes := make ([]string , 0 , 2 )
348
+ if mwe .WriteConcernError != nil {
349
+ causes = append (causes , "write concern error: " + mwe .WriteConcernError .Error ())
350
+ }
351
+ if len (mwe .WriteErrors ) > 0 {
352
+ // The WriteErrors error message already starts with "write errors:", so don't add it to the
353
+ // error message again.
354
+ causes = append (causes , mwe .WriteErrors .Error ())
355
+ }
356
+
357
+ message := "write exception: "
358
+ if len (causes ) == 0 {
359
+ return message + "no causes"
360
+ }
361
+ return message + strings .Join (causes , ", " )
344
362
}
345
363
346
364
// HasErrorCode returns true if the error has the specified code.
@@ -420,9 +438,7 @@ type BulkWriteError struct {
420
438
421
439
// Error implements the error interface.
422
440
func (bwe BulkWriteError ) Error () string {
423
- var buf bytes.Buffer
424
- fmt .Fprintf (& buf , "{%s}" , bwe .WriteError )
425
- return buf .String ()
441
+ return bwe .WriteError .Error ()
426
442
}
427
443
428
444
// BulkWriteException is the error type returned by BulkWrite and InsertMany operations.
@@ -439,11 +455,23 @@ type BulkWriteException struct {
439
455
440
456
// Error implements the error interface.
441
457
func (bwe BulkWriteException ) Error () string {
442
- var buf bytes.Buffer
443
- fmt .Fprint (& buf , "bulk write error: [" )
444
- fmt .Fprintf (& buf , "{%s}, " , bwe .WriteErrors )
445
- fmt .Fprintf (& buf , "{%s}]" , bwe .WriteConcernError )
446
- return buf .String ()
458
+ causes := make ([]string , 0 , 2 )
459
+ if bwe .WriteConcernError != nil {
460
+ causes = append (causes , "write concern error: " + bwe .WriteConcernError .Error ())
461
+ }
462
+ if len (bwe .WriteErrors ) > 0 {
463
+ errs := make ([]error , len (bwe .WriteErrors ))
464
+ for i := 0 ; i < len (bwe .WriteErrors ); i ++ {
465
+ errs [i ] = & bwe .WriteErrors [i ]
466
+ }
467
+ causes = append (causes , "write errors: " + joinBatchErrors (errs ))
468
+ }
469
+
470
+ message := "bulk write exception: "
471
+ if len (causes ) == 0 {
472
+ return message + "no causes"
473
+ }
474
+ return "bulk write exception: " + strings .Join (causes , ", " )
447
475
}
448
476
449
477
// HasErrorCode returns true if any of the errors have the specified code.
@@ -539,3 +567,34 @@ func processWriteError(err error) (returnResult, error) {
539
567
return rrAll , nil
540
568
}
541
569
}
570
+
571
+ // batchErrorsTargetLength is the target length of error messages returned by batch operation
572
+ // error types. Try to limit batch error messages to 2kb to prevent problems when printing error
573
+ // messages from large batch operations.
574
+ const batchErrorsTargetLength = 2000
575
+
576
+ // joinBatchErrors appends messages from the given errors to a comma-separated string. If the
577
+ // string exceeds 2kb, it stops appending error messages and appends the message "+N more errors..."
578
+ // to the end.
579
+ //
580
+ // Example format:
581
+ // "[message 1, message 2, +8 more errors...]"
582
+ func joinBatchErrors (errs []error ) string {
583
+ var buf bytes.Buffer
584
+ fmt .Fprint (& buf , "[" )
585
+ for idx , err := range errs {
586
+ if idx != 0 {
587
+ fmt .Fprint (& buf , ", " )
588
+ }
589
+ // If the error message has exceeded the target error message length, stop appending errors
590
+ // to the message and append the number of remaining errors instead.
591
+ if buf .Len () > batchErrorsTargetLength {
592
+ fmt .Fprintf (& buf , "+%d more errors..." , len (errs )- idx )
593
+ break
594
+ }
595
+ fmt .Fprint (& buf , err .Error ())
596
+ }
597
+ fmt .Fprint (& buf , "]" )
598
+
599
+ return buf .String ()
600
+ }
0 commit comments