11/*
2- * Copyright (c) 2016-2022 VMware Inc. or its affiliates, All Rights Reserved.
2+ * Copyright (c) 2016-2025 VMware Inc. or its affiliates, All Rights Reserved.
33 *
44 * Licensed under the Apache License, Version 2.0 (the "License");
55 * you may not use this file except in compliance with the License.
@@ -353,7 +353,7 @@ public void trace(String msg) {
353353
354354 @ Override
355355 public void trace (String format , Object ... arguments ) {
356- logger . log (Level .FINEST , format ( format , arguments ) );
356+ logWithPotentialThrowable (Level .FINEST , format , arguments );
357357 }
358358
359359 @ Override
@@ -373,7 +373,7 @@ public void debug(String msg) {
373373
374374 @ Override
375375 public void debug (String format , Object ... arguments ) {
376- logger . log (Level .FINE , format ( format , arguments ) );
376+ logWithPotentialThrowable (Level .FINE , format , arguments );
377377 }
378378
379379 @ Override
@@ -393,7 +393,7 @@ public void info(String msg) {
393393
394394 @ Override
395395 public void info (String format , Object ... arguments ) {
396- logger . log (Level .INFO , format ( format , arguments ) );
396+ logWithPotentialThrowable (Level .INFO , format , arguments );
397397 }
398398
399399 @ Override
@@ -413,7 +413,7 @@ public void warn(String msg) {
413413
414414 @ Override
415415 public void warn (String format , Object ... arguments ) {
416- logger . log (Level .WARNING , format ( format , arguments ) );
416+ logWithPotentialThrowable (Level .WARNING , format , arguments );
417417 }
418418
419419 @ Override
@@ -433,7 +433,7 @@ public void error(String msg) {
433433
434434 @ Override
435435 public void error (String format , Object ... arguments ) {
436- logger . log (Level .SEVERE , format ( format , arguments ) );
436+ logWithPotentialThrowable (Level .SEVERE , format , arguments );
437437 }
438438
439439 @ Override
@@ -442,18 +442,52 @@ public void error(String msg, Throwable t) {
442442 }
443443
444444 @ Nullable
445- final String format (@ Nullable String from , @ Nullable Object ... arguments ){
446- if (from != null ) {
445+ private String format (@ Nullable String from , @ Nullable Object [] arguments ) {
446+ return format (from , arguments , false );
447+ }
448+
449+ @ Nullable
450+ private String format (@ Nullable String from , @ Nullable Object [] arguments , boolean skipLast ) {
451+ if (from != null ) {
447452 String computed = from ;
448453 if (arguments != null && arguments .length != 0 ) {
449- for (Object argument : arguments ) {
450- computed = computed .replaceFirst ("\\ {\\ }" , Matcher .quoteReplacement (String .valueOf (argument )));
454+ int lastIndex = arguments .length ;
455+ if (skipLast ) {
456+ --lastIndex ;
457+ }
458+
459+ for (int index = 0 ; index < lastIndex ; ++index ) {
460+ computed = computed .replaceFirst ("\\ {\\ }" , Matcher .quoteReplacement (String .valueOf (arguments [index ])));
451461 }
452462 }
453463 return computed ;
454464 }
455465 return null ;
456466 }
467+
468+ private void logWithPotentialThrowable (Level level , String format , Object ... arguments ) {
469+ Throwable t = getPotentialThrowable (arguments );
470+ if (t != null ) {
471+ logger .log (level , format (format , arguments , true ), t );
472+ return ;
473+ }
474+
475+ logger .log (level , format (format , arguments ));
476+ }
477+
478+ @ Nullable
479+ private Throwable getPotentialThrowable (Object ... arguments ) {
480+ if (arguments == null ) {
481+ return null ;
482+ }
483+
484+ int length = arguments .length ;
485+ if (length > 0 && arguments [length - 1 ] instanceof Throwable ) {
486+ return (Throwable ) arguments [length - 1 ];
487+ }
488+
489+ return null ;
490+ }
457491 }
458492
459493 private static class JdkLoggerFactory implements Function <String , Logger > {
@@ -494,19 +528,64 @@ public String getName() {
494528 }
495529
496530 @ Nullable
497- final String format (@ Nullable String from , @ Nullable Object ... arguments ){
498- if (from != null ) {
531+ private String format (@ Nullable String from , @ Nullable Object [] arguments ) {
532+ return format (from , arguments , false );
533+ }
534+
535+ @ Nullable
536+ private String format (@ Nullable String from , @ Nullable Object [] arguments , boolean skipLast ) {
537+ if (from != null ) {
499538 String computed = from ;
500539 if (arguments != null && arguments .length != 0 ) {
501- for (Object argument : arguments ) {
502- computed = computed .replaceFirst ("\\ {\\ }" , Matcher .quoteReplacement (String .valueOf (argument )));
540+ int lastIndex = arguments .length ;
541+ if (skipLast ) {
542+ --lastIndex ;
543+ }
544+
545+ for (int index = 0 ; index < lastIndex ; ++index ) {
546+ computed = computed .replaceFirst ("\\ {\\ }" , Matcher .quoteReplacement (String .valueOf (arguments [index ])));
503547 }
504548 }
505549 return computed ;
506550 }
507551 return null ;
508552 }
509553
554+ private synchronized void logWithPotentialThrowable (PrintStream logger , String level , String format , Object ... arguments ) {
555+ Throwable t = getPotentialThrowable (arguments );
556+ if (t != null ) {
557+ logger .format (
558+ "[%s] (%s) %s\n " ,
559+ level .toUpperCase (),
560+ Thread .currentThread ().getName (),
561+ format (format , arguments , true )
562+ );
563+ t .printStackTrace (logger );
564+ return ;
565+ }
566+
567+ logger .format (
568+ "[%s] (%s) %s\n " ,
569+ level .toUpperCase (),
570+ Thread .currentThread ().getName (),
571+ format (format , arguments )
572+ );
573+ }
574+
575+ @ Nullable
576+ private static Throwable getPotentialThrowable (Object ... arguments ) {
577+ if (arguments == null ) {
578+ return null ;
579+ }
580+
581+ int length = arguments .length ;
582+ if (length > 0 && arguments [length - 1 ] instanceof Throwable ) {
583+ return (Throwable ) arguments [length - 1 ];
584+ }
585+
586+ return null ;
587+ }
588+
510589 @ Override
511590 public boolean isTraceEnabled () {
512591 return identifier .verbose ;
@@ -521,12 +600,13 @@ public synchronized void trace(String msg) {
521600 }
522601
523602 @ Override
524- public synchronized void trace (String format , Object ... arguments ) {
603+ public void trace (String format , Object ... arguments ) {
525604 if (!identifier .verbose ) {
526605 return ;
527606 }
528- this .log . format ( "[ TRACE] (%s) %s \n " , Thread . currentThread (). getName (), format ( format , arguments ) );
607+ logWithPotentialThrowable ( this .log , " TRACE" , format , arguments );
529608 }
609+
530610 @ Override
531611 public synchronized void trace (String msg , Throwable t ) {
532612 if (!identifier .verbose ) {
@@ -550,11 +630,11 @@ public synchronized void debug(String msg) {
550630 }
551631
552632 @ Override
553- public synchronized void debug (String format , Object ... arguments ) {
633+ public void debug (String format , Object ... arguments ) {
554634 if (!identifier .verbose ) {
555635 return ;
556636 }
557- this .log . format ( "[ DEBUG] (%s) %s \n " , Thread . currentThread (). getName (), format ( format , arguments ) );
637+ logWithPotentialThrowable ( this .log , " DEBUG" , format , arguments );
558638 }
559639
560640 @ Override
@@ -577,8 +657,8 @@ public synchronized void info(String msg) {
577657 }
578658
579659 @ Override
580- public synchronized void info (String format , Object ... arguments ) {
581- this .log . format ( "[ INFO] (%s) %s \n " , Thread . currentThread (). getName (), format ( format , arguments ) );
660+ public void info (String format , Object ... arguments ) {
661+ logWithPotentialThrowable ( this .log , " INFO" , format , arguments );
582662 }
583663
584664 @ Override
@@ -598,8 +678,8 @@ public synchronized void warn(String msg) {
598678 }
599679
600680 @ Override
601- public synchronized void warn (String format , Object ... arguments ) {
602- this .err . format ( "[ WARN] (%s) %s \n " , Thread . currentThread (). getName (), format ( format , arguments ) );
681+ public void warn (String format , Object ... arguments ) {
682+ logWithPotentialThrowable ( this .err , " WARN" , format , arguments );
603683 }
604684
605685 @ Override
@@ -619,8 +699,8 @@ public synchronized void error(String msg) {
619699 }
620700
621701 @ Override
622- public synchronized void error (String format , Object ... arguments ) {
623- this .err . format ( "[ ERROR] (%s) %s \n " , Thread . currentThread (). getName (), format ( format , arguments ) );
702+ public void error (String format , Object ... arguments ) {
703+ logWithPotentialThrowable ( this .err , " ERROR" , format , arguments );
624704 }
625705
626706 @ Override
0 commit comments