-
Notifications
You must be signed in to change notification settings - Fork 2k
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
Implements a slf4j logger impl as default logger in azure core #7298
Conversation
sdk/core/azure-core/src/main/java/com/azure/core/implementation/logging/DefaultLogger.java
Outdated
Show resolved
Hide resolved
sdk/core/azure-core/src/main/java/com/azure/core/implementation/logging/DefaultLogger.java
Outdated
Show resolved
Hide resolved
sdk/core/azure-core/src/main/java/com/azure/core/implementation/logging/DefaultLoggerBase.java
Outdated
Show resolved
Hide resolved
sdk/core/azure-core/src/main/java/com/azure/core/implementation/logging/DefaultLoggerBase.java
Outdated
Show resolved
Hide resolved
sdk/core/azure-core/src/main/java/com/azure/core/implementation/logging/DefaultLoggerBase.java
Outdated
Show resolved
Hide resolved
sdk/core/azure-core/src/main/java/com/azure/core/implementation/logging/DefaultLogger.java
Show resolved
Hide resolved
sdk/core/azure-core/src/main/java/com/azure/core/implementation/logging/DefaultLoggerBase.java
Outdated
Show resolved
Hide resolved
void write(StringBuilder buf, Throwable t) { | ||
PrintStream targetStream = System.out; | ||
|
||
targetStream.println(buf.toString()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should make the entire print statement a single operation to prevent race conditions interleaving messages
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Make the print process atomic so the log message will not intervene by other message, or print throwable to other places.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The individual print statement shouldn't interleave but right now we print the message and stack trace in two separate calls which could result in the following scenario.
Two exceptions are being logged, problemA and problemB, logging could have the following outcome
- problemA message
- problemB message
- problemA stack trace
- problemB stack trace
Instead we should build the message + stack trace and log them in one print call.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
void write(StringBuilder buf, Throwable t) {
if (t != null) {
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
t.printStackTrace(pw);
String sStackTrace = sw.toString();
buf.append(sStackTrace);
}
System.out.println(buf.toString());
}
sdk/core/azure-core/src/main/java/com/azure/core/implementation/logging/DefaultLogger.java
Outdated
Show resolved
Hide resolved
sdk/core/azure-core/src/main/java/com/azure/core/util/logging/ClientLogger.java
Outdated
Show resolved
Hide resolved
eng/code-quality-reports/src/main/resources/checkstyle/checkstyle-suppressions.xml
Outdated
Show resolved
Hide resolved
/** | ||
* Log a message at the TRACE level. It is currently not supported. | ||
* | ||
* @param msg the message string to be logged | ||
* @throws UnsupportedOperationException It is currently not supported. | ||
*/ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's remove these Javadocs and just use
/**
* {@inheritDoc}
*/
import org.slf4j.Logger; | ||
import org.slf4j.Marker; | ||
|
||
abstract class DefaultLoggerBase implements Logger { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
javadoc
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed.
StringWriter sw = new StringWriter(); | ||
PrintWriter pw = new PrintWriter(sw); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Both StringWriter
and PrintWriter
should be closed after use
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
StringWriter does not need to close as it is a no op.
https://stackoverflow.com/questions/14542535/will-not-closing-a-stringwriter-cause-a-leak
Closed the PrintStream
* (non-parameterized) log messages. | ||
* | ||
* @param level | ||
* One of the LOG_LEVEL_XXX constants defining the log level |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: fix formatting.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
*/ | ||
@Override | ||
public boolean isDebugEnabled() { | ||
throw new UnsupportedOperationException(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be supported since we have an implementation for debug(String format, Object.. argArray)
on line 61.
*/ | ||
@Override | ||
public void debug(final String msg) { | ||
throw new UnsupportedOperationException(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be supported too as we have support for debug overload with formatted strings.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I enabled the ones used by ClientLogger.
*/ | ||
@Override | ||
public String getName() { | ||
throw new UnsupportedOperationException(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be supported. We should return the name of this logger instance.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Talked offline. Will create an issue and put Up-for-grabs label.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
github.com//issues/7341
*/ | ||
@Override | ||
public boolean isInfoEnabled() { | ||
throw new UnsupportedOperationException(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All is*Enabled()
methods should be supported.
*/ | ||
@Override | ||
public void info(final String msg) { | ||
throw new UnsupportedOperationException(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These should be implemented too.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as above
PrintWriter pw = new PrintWriter(sw); | ||
t.printStackTrace(pw); | ||
buf.append(sw.toString()); | ||
pw.close(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use try-with-resources
to ensure the resource is always closed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since StringWriter has no-op close(), I only move pw to try with resource. Thanks for pointing this out!
* @return The log level. | ||
*/ | ||
private LogLevel getConfiguredLogLevel() { | ||
if (isFromEnv) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we have the default logger implement the isDebugEnabled
and other similar APIs there would be no need for isFromEnv
nor would there need to be any different handling here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The only reason the environment logging level was passed around was to handle the fact that there was a two tiered structure of SLF4J logging level and environment logging level, not that this is being merged a lot of the logic in this class and within HttpLoggingPolicy
could be cleaned up.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
sdk/core/azure-core/src/main/java/com/azure/core/implementation/logging/DefaultLogger.java
Outdated
Show resolved
Hide resolved
String logLevelStr = Configuration.getGlobalConfiguration().get(AZURE_LOG_LEVEL); | ||
LogLevel currentLogLevel = LogLevel.fromString(logLevelStr); | ||
return LogLevel.VERBOSE.getLogLevel() >= currentLogLevel.getLogLevel(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This code is common for all is*Enabled()
methods. You can extract this out to a method to reduce duplication.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
|
||
/** | ||
* {@inheritDoc} | ||
* @param format The formattable message to log. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Combination of inheritdoc and @param docs don't work correctly. Just use @inheritDoc
and skip @param
docs.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
@@ -36,6 +35,7 @@ | |||
*/ | |||
public class ClientLogger { | |||
private final Logger logger; | |||
private final boolean isFromEnv; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think you need this anymore.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
sdk/core/azure-core/src/main/java/com/azure/core/util/logging/ClientLogger.java
Show resolved
Hide resolved
sdk/core/azure-core/src/main/java/com/azure/core/util/logging/ClientLogger.java
Outdated
Show resolved
Hide resolved
@@ -36,6 +35,7 @@ | |||
*/ | |||
public class ClientLogger { | |||
private final Logger logger; | |||
private final boolean isFromEnv; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this being used by anything other than the instantiation in the constructor? If not let's remove it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
String logLevelStr = Configuration.getGlobalConfiguration().get(AZURE_LOG_LEVEL); | ||
LogLevel currentLogLevel = LogLevel.fromString(logLevelStr); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this logic be abstracted into LoggingUtils
or as a private static method on this class?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Have a private helper method in class. Env log level is only needed for default logger, so it is ok to leave it here for current use.
String dateTime = getFormattedDate(); | ||
String threadName = Thread.currentThread().getName(); | ||
String levelName = level.name(); | ||
StringBuilder buf = new StringBuilder(32); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Any reason to instantiate the StringBuilder
with an internal capacity of 32? Instead could it be instantiated with a capacity large enough to hold the initial string being written to it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is inherited from simple logger.
The message we know definitely will be printed out is:
2020-01-09 12:35 [main] [Informational]
This is 39 character long. I can put 64 instead of 32 characters to minimize capacity increase.
sdk/core/azure-core/src/main/java/com/azure/core/implementation/logging/DefaultLogger.java
Outdated
Show resolved
Hide resolved
sdk/core/azure-core/src/main/java/com/azure/core/implementation/logging/DefaultLogger.java
Outdated
Show resolved
Hide resolved
sdk/core/azure-core/src/main/java/com/azure/core/implementation/logging/DefaultLogger.java
Outdated
Show resolved
Hide resolved
<suppress checks="com.azure.tools.checkstyle.checks.GoodLoggingCheck" files="ClientLogger.java"/> | ||
<suppress checks="com.azure.tools.checkstyle.checks.GoodLoggingCheck" files="DefaultLogger.java"/> | ||
<suppress checks="com.azure.tools.checkstyle.checks.GoodLoggingCheck" files="DefaultLoggerBase.java"/> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This line can now be removed as DefaultLoggerBase
does not exist.
sdk/core/azure-core/src/main/java/com/azure/core/implementation/logging/DefaultLogger.java
Outdated
Show resolved
Hide resolved
/check-enforcer reset |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Even if the functionality in DefaultLogger is unused, it is trivial to implement and should be done now rather than when we get bug reports from customers.
* {@inheritDoc} | ||
*/ | ||
@Override | ||
public void trace(final String msg, final Throwable t) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why overload all of these methods to throw an exception when the base class has an actual useful implementation? Look at https://github.com/qos-ch/slf4j/blob/master/slf4j-api/src/main/java/org/slf4j/helpers/MarkerIgnoringBase.java
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
/check-enforcer reset |
/check-enforcer evaluate |
* Construct DefaultLogger for the given class name. | ||
* | ||
* @param className Class name creating the logger. | ||
* @throws RuntimeException it is an error. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will this throw an exception now that you have a catch
block?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not logger throw an exception. Good catch. Will update the JavaDoc
@@ -153,6 +153,7 @@ | |||
|
|||
<!-- Any code in any package, it should never be a 'throw' keyword in the client library codebase except for in the client logger --> | |||
<suppress checks="com.azure.tools.checkstyle.checks.ThrowFromClientLoggerCheck" files=".*[/\\]com[/\\]azure[/\\]core[/\\]util[/\\]logging[/\\]*"/> | |||
<suppress checks="com.azure.tools.checkstyle.checks.ThrowFromClientLoggerCheck" files=".*[/\\]com[/\\]azure[/\\]core[/\\]implementation[/\\]logging[/\\]*"/> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Now that all methods are implemented in DefaultLogger
this exception is no longer required.
@@ -144,7 +133,7 @@ public void onlyLogExceptionMessage() { | |||
*/ | |||
@Test | |||
public void logExceptionStackTrace() { | |||
String logMessage = "This is an exception"; | |||
String logMessage = "This is an exception fdsafdafdomcklamfd fdsafdafmlkdfmalsf fdsafdcacdalmd"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this an error message?
No description provided.