diff --git a/pom.xml b/pom.xml index ff191017d620..9d85456a4b17 100644 --- a/pom.xml +++ b/pom.xml @@ -105,7 +105,6 @@ - org.apache.maven.plugins diff --git a/sdk/core/azure-core/pom.xml b/sdk/core/azure-core/pom.xml index 993266270689..29c7eaf4c347 100644 --- a/sdk/core/azure-core/pom.xml +++ b/sdk/core/azure-core/pom.xml @@ -120,12 +120,12 @@ 2.2 test - - org.slf4j - slf4j-simple - 1.7.25 - test - + + + + + + org.mockito mockito-core diff --git a/sdk/core/azure-core/src/main/java/com/azure/core/util/logging/ClientLogger.java b/sdk/core/azure-core/src/main/java/com/azure/core/util/logging/ClientLogger.java index 0938669d75a2..5e084a6997bf 100644 --- a/sdk/core/azure-core/src/main/java/com/azure/core/util/logging/ClientLogger.java +++ b/sdk/core/azure-core/src/main/java/com/azure/core/util/logging/ClientLogger.java @@ -5,11 +5,11 @@ import com.azure.core.util.Configuration; import com.azure.core.util.CoreUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import java.util.Arrays; import java.util.Objects; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.slf4j.helpers.NOPLogger; import static com.azure.core.implementation.LoggingUtil.getEnvironmentLoggingLevel; @@ -36,6 +36,7 @@ */ public class ClientLogger { private final Logger logger; + private final java.util.logging.Logger defaultLogger; /** * Retrieves a logger for the passed class using the {@link LoggerFactory}. @@ -50,9 +51,13 @@ public ClientLogger(Class clazz) { * Retrieves a logger for the passed class name using the {@link LoggerFactory}. * * @param className Class name creating the logger. + * @throws RuntimeException it is an error. */ public ClientLogger(String className) { logger = LoggerFactory.getLogger(className); + System.setProperty("java.util.logging.config.file", + ClientLogger.class.getClassLoader().getResource("logging.properties").getPath()); + defaultLogger = java.util.logging.Logger.getLogger(className); } /** @@ -131,10 +136,9 @@ public void error(String format, Object... args) { * @param args Arguments for the message, if an exception is being logged last argument is the throwable. */ private void log(LogLevel logLevel, String format, Object... args) { - LogLevel environmentLoggingLevel = getEnvironmentLoggingLevel(); - - if (canLogAtLevel(logLevel, environmentLoggingLevel)) { - performLogging(logLevel, environmentLoggingLevel, false, format, args); + LogLevel rootLogLevel = loadSystemLogLevel(); + if (canLogAtLevel(logLevel, rootLogLevel)) { + performLogging(logLevel, rootLogLevel, false, format, args); } } @@ -162,34 +166,23 @@ public RuntimeException logExceptionAsError(RuntimeException runtimeException) { private RuntimeException logException(RuntimeException runtimeException, LogLevel logLevel) { Objects.requireNonNull(runtimeException, "'runtimeException' cannot be null."); + LogLevel rootLogLevel = loadSystemLogLevel(); - LogLevel environmentLoggingLevel = getEnvironmentLoggingLevel(); - - if (canLogAtLevel(logLevel, environmentLoggingLevel)) { - performLogging(logLevel, environmentLoggingLevel, true, runtimeException.getMessage(), runtimeException); + if (canLogAtLevel(logLevel, rootLogLevel)) { + performLogging(logLevel, rootLogLevel, true, runtimeException.getMessage(), runtimeException); } return runtimeException; } - /** - * Determines if the environment and logger support logging at the given log level. - * - * @param logLevel The {@link LogLevel} being validated as supported. - * @return Flag indicating if the environment and logger support logging at the given log level. - */ - public boolean canLogAtLevel(LogLevel logLevel) { - return canLogAtLevel(logLevel, getEnvironmentLoggingLevel()); - } - /* * Performs the logging. * * @param format formattable message. * @param args Arguments for the message, if an exception is being logged last argument is the throwable. */ - private void performLogging(LogLevel logLevel, LogLevel environmentLogLevel, boolean isExceptionLogging, - String format, Object... args) { + private void performLogging(LogLevel logLevel, LogLevel rootLogLevel, + boolean isExceptionLogging, String format, Object... args) { // If the logging level is less granular than verbose remove the potential throwable from the args. String throwableMessage = ""; if (doesArgsHaveThrowable(args)) { @@ -207,11 +200,55 @@ private void performLogging(LogLevel logLevel, LogLevel environmentLogLevel, boo * Environment is logging at a level higher than verbose, strip out the throwable as it would log its * stack trace which is only expected when logging at a verbose level. */ - if (environmentLogLevel.getLogLevel() > LogLevel.VERBOSE.getLogLevel()) { + if (rootLogLevel.getLogLevel() > LogLevel.VERBOSE.getLogLevel()) { args = removeThrowable(args); } } + boolean isFromEnv = isLogFromEnv(); + printInPlace(isFromEnv, throwableMessage, logLevel, format, args); + + } + + private void printInPlace(boolean isFromEnv, String throwableMessage, LogLevel logLevel, String format, + Object... args) { + if (isFromEnv) { + printFromDefaultLogger(throwableMessage, logLevel, format, args); + } else { + printFromLogger(throwableMessage, logLevel, format, args); + } + } + private void printFromDefaultLogger(String throwableMessage, LogLevel logLevel, String format, Object... args) { + switch (logLevel) { + case VERBOSE: + defaultLogger.log(java.util.logging.Level.FINE, format, args); + break; + case INFORMATIONAL: + defaultLogger.log(java.util.logging.Level.INFO, format, args); + break; + case WARNING: + if (!CoreUtils.isNullOrEmpty(throwableMessage)) { + format += System.lineSeparator() + throwableMessage; + } + defaultLogger.log(java.util.logging.Level.WARNING, format, args); + break; + case ERROR: + if (!CoreUtils.isNullOrEmpty(throwableMessage)) { + format += System.lineSeparator() + throwableMessage; + } + defaultLogger.log(java.util.logging.Level.SEVERE, format, args); + break; + default: + // Don't do anything, this state shouldn't be possible. + break; + } + } + + private boolean isLogFromEnv() { + return logger instanceof NOPLogger; + } + + private void printFromLogger(String throwableMessage, LogLevel logLevel, String format, Object... args) { switch (logLevel) { case VERBOSE: logger.debug(format, args); @@ -237,37 +274,44 @@ private void performLogging(LogLevel logLevel, LogLevel environmentLogLevel, boo } } - /* - * Determines if the environment and logger support logging at the given log level. + /** + * Determines if the app or environment logger support logging at the given log level. * * @param logLevel Logging level for the log message. - * @param environmentLoggingLevel Logging level the environment is set to support. * @return Flag indicating if the environment and logger are configured to support logging at the given log level. */ - private boolean canLogAtLevel(LogLevel logLevel, LogLevel environmentLoggingLevel) { - // Do not log if logLevel is null is not set. - if (logLevel == null) { - return false; - } + public boolean canLogAtLevel(LogLevel logLevel) { + LogLevel rootLogLevel = loadSystemLogLevel(); + return canLogAtLevel(logLevel, rootLogLevel); + } - // Attempting to log at a level not supported by the environment. - if (logLevel.getLogLevel() < environmentLoggingLevel.getLogLevel()) { - return false; - } + private boolean canLogAtLevel(LogLevel logLevel, LogLevel allowedLogLevel) { + // Attempting to log at a level not supported by the SLF4J configuration or env variable. + return logLevel.getLogLevel() >= allowedLogLevel.getLogLevel(); + } - // Determine if the logger configuration supports logging at the level. - switch (logLevel) { - case VERBOSE: - return logger.isDebugEnabled(); - case INFORMATIONAL: - return logger.isInfoEnabled(); - case WARNING: - return logger.isWarnEnabled(); - case ERROR: - return logger.isErrorEnabled(); - default: - return false; + /** + * Checking the system log with the preference order of slf4j and environment variable. + * + * @return The log level. + */ + private LogLevel loadSystemLogLevel() { + if (isLogFromEnv()) { + return getEnvironmentLoggingLevel(); + } + if (logger.isDebugEnabled()) { + return LogLevel.VERBOSE; + } + if (logger.isInfoEnabled()) { + return LogLevel.INFORMATIONAL; + } + if (logger.isWarnEnabled()) { + return LogLevel.WARNING; + } + if (logger.isErrorEnabled()) { + return LogLevel.ERROR; } + return LogLevel.NOT_SET; } /* diff --git a/sdk/core/azure-core/src/main/java/com/azure/core/util/logging/LogLevel.java b/sdk/core/azure-core/src/main/java/com/azure/core/util/logging/LogLevel.java index 83b603d17b1e..7cd22e43900e 100644 --- a/sdk/core/azure-core/src/main/java/com/azure/core/util/logging/LogLevel.java +++ b/sdk/core/azure-core/src/main/java/com/azure/core/util/logging/LogLevel.java @@ -7,7 +7,7 @@ import java.util.Locale; /** - * Enum which represent logging levels used in Azure SDKs. + * Enum which represent logging levels used in Azure SDKs. */ public enum LogLevel { /** @@ -65,7 +65,7 @@ public int getLogLevel() { * Converts the passed log level string to the corresponding {@link LogLevel}. * * @param logLevelVal The log level value which needs to convert - * @return The LogLevel Enum if pass in the valid string. + * @return The LogLevel Enum if pass in the valid string. * The valid strings for {@link LogLevel} are: *