Stable logging API - the basic use case#86612
Conversation
draft
|
Hi @pgomulka, I've created a changelog YAML for you. |
…asticsearch into logging_api_minimum_use_case
|
Pinging @elastic/es-core-infra (Team:Core/Infra) |
|
should we mark this as experimental? |
libs/logging/src/main/java/org/elasticsearch/logging/Level.java
Outdated
Show resolved
Hide resolved
Is there a standard way of doing that ? |
libs/logging/src/main/java/org/elasticsearch/logging/Level.java
Outdated
Show resolved
Hide resolved
libs/logging/src/main/java/org/elasticsearch/logging/Level.java
Outdated
Show resolved
Hide resolved
libs/logging/src/main/java/org/elasticsearch/logging/Level.java
Outdated
Show resolved
Hide resolved
libs/logging/src/main/java/org/elasticsearch/logging/Level.java
Outdated
Show resolved
Hide resolved
server/src/main/java/org/elasticsearch/common/logging/api/impl/LoggerImpl.java
Outdated
Show resolved
Hide resolved
| LogManagerFactory INSTANCE = loadProvider(); | ||
|
|
||
| static LogManagerFactory loadProvider() { | ||
| ServiceLoader<LogManagerFactory> sl = ServiceLoader.load(LogManagerFactory.class, ClassLoader.getSystemClassLoader()); |
There was a problem hiding this comment.
Instead of using service loader directly here, can we have a setter method (since this package is only exported to server) and have server set this early? We won't always necessarily have this on the system classloader. @ChrisHegarty wdyt?
There was a problem hiding this comment.
I was thinking that this class will change when we move the log4j off the system classloader. Something similar to what we have here https://github.com/ChrisHegarty/elasticsearch/blob/logging-module/libs/logging/src/main/java/org/elasticsearch/logging/spi/LogManagerFactory.java
There was a problem hiding this comment.
How about we look up the implementation using the service loader variant that accepts a module layer? Or is the question more related to the use of service loader at all?
There was a problem hiding this comment.
The latter. While eventually I think service loader will be used when we can move log4j off the system classloader, I was suggesting starting by loading this in server and setting statically here.
There was a problem hiding this comment.
What is the benefit of setting this statically from server? We would have to remember to set this with LogConfigurator, and once we move implementation off the system classloader to remove it.
I personally think this is an easier to read solution, but don't have strong opinion against setting as well.
There was a problem hiding this comment.
For stable plugin api, we are thinking about changing the way the system classloader is setup. Right now, everything from server is in the system classloader. For stable plugin api, we want to first load the stable api jars, then create a separate loader, parented by the stable api jars, that is everything from server. That separation would break this ServerLoader lookup, because the logging api impl would not be on the system classloader, and this code could not statically find the loader wtih the impl (since it will not yet have been created). Thus, setting this statically as an init of the logging api allows us to delay until server has actually been loaded.
libs/logging/src/main/java/org/elasticsearch/logging/spi/StandardLevels.java
Outdated
Show resolved
Hide resolved
|
@elasticmachine run elasticsearch-ci/example-plugins |
libs/logging/src/main/java/org/elasticsearch/logging/Level.java
Outdated
Show resolved
Hide resolved
| * @return The Logger. | ||
| */ | ||
| public static Logger getLogger(final String name) { | ||
| return LogManagerFactory.provider().getLogger(name); |
There was a problem hiding this comment.
I assume null in results in a NPE? If so, maybe a class-level comment, e.g.
Unless otherwise noted, passing a null argument to a method of any class will cause a NullPointerException
There was a problem hiding this comment.
actually this depends on log4j. and if a null is passed as a name or clazz parameter, it will take caler's class
StackLocatorUtil.getCallerClass(2)
There was a problem hiding this comment.
We should clarify this in the javadoc, no ? Or alternatively, just disallow null (throw NPE)
There was a problem hiding this comment.
Has this been address in the javadoc? I'm not seeing it
There was a problem hiding this comment.
I did not add the javadoc. This depends on how log4j does this and I did not want to mention this in the API's javadoc. I think is is rare that a name is null.
| import org.elasticsearch.logging.internal.spi.LogManagerFactory; | ||
|
|
||
| /** | ||
| * A class used for creating loggers. |
There was a problem hiding this comment.
Maybe expand this a little, e.g.
"A Manager of {@code Loggers}. This class consists of factory methods for creating and retrieving Loggers."
| * @param level the logging level | ||
| * @param messageSupplier A function, which when called, produces the desired log String message; | ||
| */ | ||
| void log(Level level, java.util.function.Supplier<String> messageSupplier, Throwable throwable); |
There was a problem hiding this comment.
Suggest, highlighting the LAZY aspect. e.g.
"Logs a lazily supplied String message associated with a given throwable. If the logger is currently enabled for the specified log message level, then a message is logged that is the result produced by the given supplier function."
Note: missing at param for throwable
There was a problem hiding this comment.
This looks good overall. I have a few more nits.
I also think it would be good to generate the javadocs and see what they look like. I think some formatting is missing in several methods.
Also, this will need to be followed up by adding the jar to the release configuration.
libs/logging/build.gradle
Outdated
| tasks.named("loggerUsageCheck").configure {enabled = false } | ||
|
|
||
| dependencies { | ||
| testImplementation "com.carrotsearch.randomizedtesting:randomizedtesting-runner:${versions.randomizedrunner}" |
There was a problem hiding this comment.
these should all be pulled in by the test:framework dep below right?
| * @return The Logger. | ||
| */ | ||
| public static Logger getLogger(final String name) { | ||
| return LogManagerFactory.provider().getLogger(name); |
There was a problem hiding this comment.
Has this been address in the javadoc? I'm not seeing it
| * Logs a message String with the given level. | ||
| * | ||
| * @param level the logging level | ||
| * @param message the message CharSequence to log. |
|
|
||
| /** | ||
| * Main interface for logging. Most operations are done through this interface. | ||
| * This is interface heavily influenced by org.apache.logging.log4j2.Logger. |
There was a problem hiding this comment.
reversed words: is interface -> interface is
| * that is the result produced by the given supplier function. | ||
| * @param messageSupplier A function, which when called, produces the desired log String message; | ||
| */ | ||
| void error(java.util.function.Supplier<String> messageSupplier); |
There was a problem hiding this comment.
Is the fully qualified name for Supplier needed?
| * @param message the message to log | ||
| * @param p0 parameter to the message. | ||
| */ | ||
| void trace(String message, Object p0); |
There was a problem hiding this comment.
I wonder if we should omit the single arg variants of these methods for all levels. The reason is it can be ambiguous with the general method taking an array of args. I'm not sure if there is a performance hit for that, but we are talking about logging so I can't imagine a single implicit array creation is going to make a huge difference.
There was a problem hiding this comment.
good point, I will remove them. Should we do the same for variants of this (p0, p1... p5 ) ?
There was a problem hiding this comment.
Yeah I think we should. We can always add them back.
| import org.elasticsearch.logging.Logger; | ||
|
|
||
| /** | ||
| * SPI for creating new loggers |
There was a problem hiding this comment.
not really SPI anymore, it's just a static holder for the factory
There was a problem hiding this comment.
but doesn't it still serve a purpose of SPI? the implementation has to provide the concrete getLogger methods that this class declares
There was a problem hiding this comment.
SPI normally has the connotation of being loaded by ServiceProvider, but this is not.
| public class LogManagerFactoryImpl extends LogManagerFactory { | ||
| @Override | ||
| public Logger getLogger(String name) { | ||
| // TODO PG logger impl instance caching |
There was a problem hiding this comment.
Can you create an issue for this?
There was a problem hiding this comment.
Thanks! Please add a link to the issue in the comment :)
| } | ||
|
|
||
| private org.apache.logging.log4j.util.Supplier<?> mapSupplier(Supplier<String> msgSupplier) { | ||
| return (org.apache.logging.log4j.util.Supplier<Object>) () -> msgSupplier.get(); |
There was a problem hiding this comment.
is the cast necessary given the return type?
Introducing a stable logging API under libs/logging.
This change covers the most common use cases for logging: fetching a logger with LogManager, emitting a log messages with Logger and Level.
It is influenced by log4j2-api, but do not include Marker and LogBuilder methods.
Also methods using org.apache.logging.log4j.util.Supplier are replaced with java.util.Supplier
The basic implementation is present in server and injected statically in LogConfigurator
relates #84478