Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support logging exception stack traces when the last argument is Throwable #3960

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
92 changes: 72 additions & 20 deletions reactor-core/src/main/java/reactor/util/Loggers.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2016-2022 VMware Inc. or its affiliates, All Rights Reserved.
* Copyright (c) 2016-2025 VMware Inc. or its affiliates, All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -18,6 +18,7 @@

import java.io.PrintStream;
import java.lang.ref.WeakReference;
import java.util.Arrays;
import java.util.Map;
import java.util.Objects;
import java.util.WeakHashMap;
Expand Down Expand Up @@ -353,7 +354,7 @@ public void trace(String msg) {

@Override
public void trace(String format, Object... arguments) {
logger.log(Level.FINEST, format(format, arguments));
logWithOptionalThrowable(Level.FINEST, format, arguments);
}

@Override
Expand All @@ -373,7 +374,7 @@ public void debug(String msg) {

@Override
public void debug(String format, Object... arguments) {
logger.log(Level.FINE, format(format, arguments));
logWithOptionalThrowable(Level.FINE, format, arguments);
}

@Override
Expand All @@ -393,7 +394,7 @@ public void info(String msg) {

@Override
public void info(String format, Object... arguments) {
logger.log(Level.INFO, format(format, arguments));
logWithOptionalThrowable(Level.INFO, format, arguments);
}

@Override
Expand All @@ -413,7 +414,7 @@ public void warn(String msg) {

@Override
public void warn(String format, Object... arguments) {
logger.log(Level.WARNING, format(format, arguments));
logWithOptionalThrowable(Level.WARNING, format, arguments);
}

@Override
Expand All @@ -433,7 +434,7 @@ public void error(String msg) {

@Override
public void error(String format, Object... arguments) {
logger.log(Level.SEVERE, format(format, arguments));
logWithOptionalThrowable(Level.SEVERE, format, arguments);
}

@Override
Expand All @@ -454,6 +455,24 @@ final String format(@Nullable String from, @Nullable Object... arguments){
}
return null;
}

private void logWithOptionalThrowable(Level level, String format, Object... arguments) {
if(isLastElementThrowable(arguments)) {
int lastIndex = arguments.length - 1;
Object[] args = Arrays.copyOfRange(arguments, 0, lastIndex);
Throwable t = (Throwable) arguments[lastIndex];

logger.log(level, format(format, args), t);
return;
}

logger.log(level, format(format, arguments));
}
Comment on lines +459 to +470
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In JdkLogger, if the last arguments are Throwable type, stacktrace is also logged.


private boolean isLastElementThrowable(Object... arguments) {
int length = arguments.length;
return length > 0 && arguments[length - 1] instanceof Throwable;
}
Comment on lines +472 to +475
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Checks whether the last argements are of type Throwable.

}

private static class JdkLoggerFactory implements Function<String, Logger> {
Expand Down Expand Up @@ -507,6 +526,39 @@ final String format(@Nullable String from, @Nullable Object... arguments){
return null;
}

private synchronized void logWithOptionalThrowable(String level, String format, Object... arguments) {
if(isLastElementThrowable(arguments)) {
int lastIndex = arguments.length - 1;
Object[] args = Arrays.copyOfRange(arguments, 0, lastIndex);
Throwable t = (Throwable) arguments[lastIndex];

this.log.format("[%s] (%s) %s\n", level.toUpperCase(), Thread.currentThread().getName(), format(format, args));
t.printStackTrace(this.log);
return;
}

this.log.format("[%s] (%s) %s\n", level.toUpperCase(), Thread.currentThread().getName(), format(format, arguments));
}
Comment on lines +529 to +541
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In ConsoleLogger, if the last argument is of type Throwable, it also prints a stack trace.
(only use for TRACE, DEBUG, INFO level)


private synchronized void logErrorWithOptionalThrowable(String level, String format, Object... arguments) {
if(isLastElementThrowable(arguments)) {
int lastIndex = arguments.length - 1;
Object[] args = Arrays.copyOfRange(arguments, 0, lastIndex);
Throwable t = (Throwable) arguments[lastIndex];

this.err.format("[%s] (%s) %s\n", level.toUpperCase(), Thread.currentThread().getName(), format(format, args));
t.printStackTrace(this.err);
return;
}

this.err.format("[%s] (%s) %s\n", level.toUpperCase(), Thread.currentThread().getName(), format(format, arguments));
}
Comment on lines +543 to +555
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In ConsoleLogger, if the last arguments are Throwable type, it also prints a stack trace with the err PrintStream.
(only use for WARN, ERROR level)


private boolean isLastElementThrowable(Object... arguments) {
int length = arguments.length;
return length > 0 && arguments[length - 1] instanceof Throwable;
}
Comment on lines +557 to +560
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Checks whether the last argements are of type Throwable.


@Override
public boolean isTraceEnabled() {
return identifier.verbose;
Expand All @@ -521,11 +573,11 @@ public synchronized void trace(String msg) {
}

@Override
public synchronized void trace(String format, Object... arguments) {
public void trace(String format, Object... arguments) {
if (!identifier.verbose) {
return;
}
this.log.format("[TRACE] (%s) %s\n", Thread.currentThread().getName(), format(format, arguments));
logWithOptionalThrowable("TRACE", format, arguments);
}
@Override
public synchronized void trace(String msg, Throwable t) {
Expand All @@ -550,11 +602,11 @@ public synchronized void debug(String msg) {
}

@Override
public synchronized void debug(String format, Object... arguments) {
public void debug(String format, Object... arguments) {
if (!identifier.verbose) {
return;
}
this.log.format("[DEBUG] (%s) %s\n", Thread.currentThread().getName(), format(format, arguments));
logWithOptionalThrowable("DEBUG", format, arguments);
}

@Override
Expand All @@ -573,17 +625,17 @@ public boolean isInfoEnabled() {

@Override
public synchronized void info(String msg) {
this.log.format("[ INFO] (%s) %s\n", Thread.currentThread().getName(), msg);
this.log.format("[INFO] (%s) %s\n", Thread.currentThread().getName(), msg);
}

@Override
public synchronized void info(String format, Object... arguments) {
this.log.format("[ INFO] (%s) %s\n", Thread.currentThread().getName(), format(format, arguments));
public void info(String format, Object... arguments) {
logWithOptionalThrowable("INFO", format, arguments);
}

@Override
public synchronized void info(String msg, Throwable t) {
this.log.format("[ INFO] (%s) %s - %s\n", Thread.currentThread().getName(), msg, t);
this.log.format("[INFO] (%s) %s - %s\n", Thread.currentThread().getName(), msg, t);
t.printStackTrace(this.log);
}

Expand All @@ -594,17 +646,17 @@ public boolean isWarnEnabled() {

@Override
public synchronized void warn(String msg) {
this.err.format("[ WARN] (%s) %s\n", Thread.currentThread().getName(), msg);
this.err.format("[WARN] (%s) %s\n", Thread.currentThread().getName(), msg);
}

@Override
public synchronized void warn(String format, Object... arguments) {
this.err.format("[ WARN] (%s) %s\n", Thread.currentThread().getName(), format(format, arguments));
public void warn(String format, Object... arguments) {
logErrorWithOptionalThrowable("WARN", format, arguments);
}

@Override
public synchronized void warn(String msg, Throwable t) {
this.err.format("[ WARN] (%s) %s - %s\n", Thread.currentThread().getName(), msg, t);
this.err.format("[WARN] (%s) %s - %s\n", Thread.currentThread().getName(), msg, t);
t.printStackTrace(this.err);
}

Expand All @@ -619,8 +671,8 @@ public synchronized void error(String msg) {
}

@Override
public synchronized void error(String format, Object... arguments) {
this.err.format("[ERROR] (%s) %s\n", Thread.currentThread().getName(), format(format, arguments));
public void error(String format, Object... arguments) {
logErrorWithOptionalThrowable("ERROR", format, arguments);
}

@Override
Expand Down