Re: JEP 264: Platform Logging API and Service
Hi, I have pushed an implementation of the prototype in the sandbox. The branch name is JDK-8046565-branch Instructions for cloning a sandbox branch can be found here: http://cr.openjdk.java.net/~chegar/docs/sandbox.html best regards, -- daniel On 05/10/15 12:54, Daniel Fuchs wrote: New JEP Candidate: http://openjdk.java.net/jeps/264 Hi I have uploaded an initial prototype specdiff: http://cr.openjdk.java.net/~dfuchs/8046565/proto.01/specdiff-api/overview-summary.html LoggerFinder methods that take a Class caller argument will take a java.lang.reflect.Module callerModule instead when that is available in jdk9/dev. comments welcome, best regards, -- daniel
Re: JEP 264: Platform Logging API and Service
On 10/05/2015 09:59 PM, Daniel Fuchs wrote: Thanks Roger! I have updated the specdiff online. http://cr.openjdk.java.net/~dfuchs/8046565/proto.01/specdiff-api/overview-summary.html The only comment I haven't taken into account yet is this: > - the LoggerFinder constructor says "Only one instance will be created". > That applies to the normal static logger initialization > (getLoggerFinder). > But there might be other cases where the application or service > might create a LoggerFinder > for its own purposes, and the phrase is not accurate in that case. I was wondering whether I should try enforcing this actually, by throwing a ServiceConfigurationError or whatever if the LoggerFinder service is already loaded when the constructor is invoked. We had trouble in the past with LogManager - because the spec said there should be only one instance, but the implementation did not enforce it. It may be a bit different with LoggerFinder - as this is an abstract class devoid of instance state (the only method with a body is getLocalizedLogger and that's stateless) - so there may not be as much harm as with LogManager. There is probably no good way of implementing such enforcement though - so it would be a best effort :-( Hi Daniel, Scala has singleton objects. Java hasn't. Your statement intrigued me to think whether it would be possible to enforce a one-instance-per-concrete-class rule in Java using just API. Here's a prototype that I think does that. Can you think of a corner case that fools it? /** * An abstract base class for subclasses that can only have one instance * per concrete subclass. Subclasses must define a public no-args constructor * which must never be called directly from code (it throws * UnsupportedOperationException), but via the factory method: * {@link #getInstance(Class)}. */ public abstract class ClassObject { /** * Lazily constructs and returns a singleton instance per given concrete * {@code ClassObject} subclass or throws exception. * Subclasses must define a public no-argument constructor. Multiple * invocations of this method with same {@code clazz} parameter either return * the same instance or throw the same exception. The result of this method * is therefore stable for given parameter. * * @param clazz the Class representing concrete {@code ClassObject} subclass * @paramthe type of the {@code ClassObject} subclass * @return a singleton instance for given {@code clazz} * @throws InstantiationException see {@link Constructor#newInstance} * @throws IllegalAccessException see {@link Constructor#newInstance} * @throws InvocationTargetException see {@link Constructor#newInstance} */ public static T getInstance(Class clazz) throws InstantiationException, IllegalAccessException, InvocationTargetException { return clazz.cast(factoryCV.get(clazz).get()); } /** * ClassObject constructor allows construction of a single instance of * {@code ClassObject} subclass per concrete subclass. */ public ClassObject() { Factory factory = factoryCV.get(getClass()); synchronized (factory) { if (!factory.inConstruction) { throw new UnsupportedOperationException( "Direct construction of ClassObject instances is not supported." + " Please use ClassObject.getInstance(Class) instead."); } if (factory.constructed != null) { throw new IllegalStateException( "Attempt to instantiate a second " + getClass().getName() + " instance."); } factory.constructed = this; } } /** * A ClassValue cache of Factory instances per class */ private static final ClassValue factoryCV = new ClassValue() { @Override protected Factory computeValue(Class clazz) { return new Factory(clazz.asSubclass(ClassObject.class)); } }; /** * A Factory responsible for constructing and caching a singleton instance * of specified class. */ private static final class Factory { // the class of instance to construct private final Class clazz; // published instance or Throwable private volatile Object instance; // temporarily set to true while constructing and checked in ClassObject constructor boolean inConstruction; // the just being constructed instance or Throwable, set in ClassObject constructor Object constructed; Factory(Class clazz) { this.clazz = clazz; } ClassObject get() throws InstantiationException, IllegalAccessException, InvocationTargetException { Object obj = instance; if (obj == null) { synchronized (this) {
Re: JEP 264: Platform Logging API and Service
Hi, This case does not require a restriction. This is not really a case of a singleton object. I think the statement is a statement of fact. The behavior should be attributed to the LoggerFinder.getLoggerFinder method and not to the constructor of LoggerFinder. Roger On 10/6/2015 9:32 AM, Peter Levart wrote: On 10/05/2015 09:59 PM, Daniel Fuchs wrote: Thanks Roger! I have updated the specdiff online. http://cr.openjdk.java.net/~dfuchs/8046565/proto.01/specdiff-api/overview-summary.html The only comment I haven't taken into account yet is this: > - the LoggerFinder constructor says "Only one instance will be created". > That applies to the normal static logger initialization > (getLoggerFinder). > But there might be other cases where the application or service > might create a LoggerFinder > for its own purposes, and the phrase is not accurate in that case. I was wondering whether I should try enforcing this actually, by throwing a ServiceConfigurationError or whatever if the LoggerFinder service is already loaded when the constructor is invoked. We had trouble in the past with LogManager - because the spec said there should be only one instance, but the implementation did not enforce it. It may be a bit different with LoggerFinder - as this is an abstract class devoid of instance state (the only method with a body is getLocalizedLogger and that's stateless) - so there may not be as much harm as with LogManager. There is probably no good way of implementing such enforcement though - so it would be a best effort :-( Hi Daniel, Scala has singleton objects. Java hasn't. Your statement intrigued me to think whether it would be possible to enforce a one-instance-per-concrete-class rule in Java using just API. Here's a prototype that I think does that. Can you think of a corner case that fools it? /** * An abstract base class for subclasses that can only have one instance * per concrete subclass. Subclasses must define a public no-args constructor * which must never be called directly from code (it throws * UnsupportedOperationException), but via the factory method: * {@link #getInstance(Class)}. */ public abstract class ClassObject { /** * Lazily constructs and returns a singleton instance per given concrete * {@code ClassObject} subclass or throws exception. * Subclasses must define a public no-argument constructor. Multiple * invocations of this method with same {@code clazz} parameter either return * the same instance or throw the same exception. The result of this method * is therefore stable for given parameter. * * @param clazz the Class representing concrete {@code ClassObject} subclass * @paramthe type of the {@code ClassObject} subclass * @return a singleton instance for given {@code clazz} * @throws InstantiationException see {@link Constructor#newInstance} * @throws IllegalAccessException see {@link Constructor#newInstance} * @throws InvocationTargetException see {@link Constructor#newInstance} */ public static T getInstance(Class clazz) throws InstantiationException, IllegalAccessException, InvocationTargetException { return clazz.cast(factoryCV.get(clazz).get()); } /** * ClassObject constructor allows construction of a single instance of * {@code ClassObject} subclass per concrete subclass. */ public ClassObject() { Factory factory = factoryCV.get(getClass()); synchronized (factory) { if (!factory.inConstruction) { throw new UnsupportedOperationException( "Direct construction of ClassObject instances is not supported." + " Please use ClassObject.getInstance(Class) instead."); } if (factory.constructed != null) { throw new IllegalStateException( "Attempt to instantiate a second " + getClass().getName() + " instance."); } factory.constructed = this; } } /** * A ClassValue cache of Factory instances per class */ private static final ClassValue factoryCV = new ClassValue() { @Override protected Factory computeValue(Class clazz) { return new Factory(clazz.asSubclass(ClassObject.class)); } }; /** * A Factory responsible for constructing and caching a singleton instance * of specified class. */ private static final class Factory { // the class of instance to construct private final Class clazz; // published instance or Throwable private volatile Object instance; // temporarily set to true while constructing and checked in ClassObject constructor boolean inConstruction; // the just being constructed instance or Throwable, set in ClassObject constructor Object
Re: JEP 264: Platform Logging API and Service
New JEP Candidate: http://openjdk.java.net/jeps/264 Hi I have uploaded an initial prototype specdiff: http://cr.openjdk.java.net/~dfuchs/8046565/proto.01/specdiff-api/overview-summary.html LoggerFinder methods that take a Class caller argument will take a java.lang.reflect.Module callerModule instead when that is available in jdk9/dev. comments welcome, best regards, -- daniel
Re: JEP 264: Platform Logging API and Service
Hi Daniel, This looks good, a few comments... j.l.System: - the behaviors described by the @implNote in getLogger(name) and @implSpec in getLogger(name, resourceBundle) seem like they should be consistent for the two methods. System.Logger: - log(level, throwable, Supplier) - to be more consistent, the Suppler argument should be before the Throwable argument. Then in all cases the msg/string is before the Throwable. System.Logger.Level - TRACE might be used for more than just method entry and exit, perhaps the description can be more general: "usually used for diagnostic information." LoggerFinder: - should the CONTROL_PERMISSION field be renamed to "LOGGERFINDER_PERMISSION"? - the LoggerFinder constructor says "Only one instance will be created". That applies to the normal static logger initialization (getLoggerFinder). But there might be other cases where the application or service might create a LoggerFinder for its own purposes, and the phrase is not accurate in that case. Editorial: - The @since tags can be set to "9". - "JVM" -> "Java runtime"; JVM would specifically refer to the virtual machine implementation. (j.u.System.LoggerFinder) - "used by the JDK" can be omitted. (j.u.System.LoggerFinder) When used in the context of the JDK documentation itself it seems out of place and is unnecessary. - the word 'actually' can/should be omitted from descriptions. (j.l.System) Thanks, Roger On 10/5/2015 6:54 AM, Daniel Fuchs wrote: New JEP Candidate: http://openjdk.java.net/jeps/264 Hi I have uploaded an initial prototype specdiff: http://cr.openjdk.java.net/~dfuchs/8046565/proto.01/specdiff-api/overview-summary.html LoggerFinder methods that take a Class caller argument will take a java.lang.reflect.Module callerModule instead when that is available in jdk9/dev. comments welcome, best regards, -- daniel
Re: JEP 264: Platform Logging API and Service
You are correct that the discussion on the serviceLoader may be off-topic wrt JEP 264. I believe I mentioned that currently Log4j only supports binding with a single implementation as well. But we don’t take the first, we take the one with the highest priority. Ralph > On Sep 30, 2015, at 9:50 AM, Daniel Fuchswrote: > > Hi Ralph, > > On 30/09/15 18:30, Ralph Goers wrote: >> What would be preferable is to have the serviceLoader accept “criteria” >> (which are callbacks) that can evaluate each of the located services based >> on any additional properties that are included in the properties file and >> either eliminate them or return a “ranking". The serviceLoader would then >> end up with a set of eligible services in their preferred order. > > I understand you may have another use case in mind, but in > what concerns jep264's LoggerFinder though - I don't think > that would be useful. The JDK can only use one LoggerFinder > service implementation, and if more than one is found, it most > probably indicates a configuration error - where several > implementations have been put by mistake on the classpath. > > Just taking the first and silently continue could end up in > strange misbehavior, where the application's developer would > not see the expected debug traces - because she configured > one framework but it's the other that happens to be used. > > I believe it's a better idea to fail fast in this case. > > best regards, > > -- daniel > >
Re: JEP 264: Platform Logging API and Service
On 09/29/2015 11:17 PM, Ralph Goers wrote: FWIW, I considered using the ServiceLoader to bind the Log4j API to the implementation. However, Log4j also includes the API version and only looks for bindings that implement that version. We also include a “priority” - the binding with the highest priority wins - at the moment. At some future time we might consider supporting multiple bindings. It would have been nice if ServlceLoader could be extended by the user to do these sort of checks instead of not being able to use it at all. Ralph Hi Ralph, ServiceLoader can be used to load all services that implement a particular type (it's an Iterable). So you can decide which one(s) to use in your own logic. You just have to design the service type in a way where it's implementations expose some attributes that are relevant for selection and initialize the underlying service lazily, after selection is done. This would usually mean that the service interface/abstract class implements a factory for the real service and exposes some properties such as version, priority, etc... Would that work for Log4j? Regards, Peter On Sep 29, 2015, at 11:40 AM, Daniel Fuchswrote: On 20/09/15 15:46, Peter Levart wrote: On 09/18/2015 06:17 PM, mark.reinh...@oracle.com wrote: New JEP Candidate:http://openjdk.java.net/jeps/264 - Mark Hi, What is the purpose of exposing a factory for loggers in the generally exported package (java.lang) and making it standard Java API as opposed to keeping it internal API as it is now (sun.util.logging.PlatformLogger)? Is this going to become an official front-end for JDK-internal and applications use, available in the platform itself? Hi Peter, sun.util.logging.PlatformLogger is a module private API in java.base, yet it is used by other modules in the JDK - and this requires qualified exports to the modules that use it. Having a public API that JDK modules could use would simplify the module graph in this respect. In time, I'd hope to see sun.util.logging.PlatformLogger disappear in favor of the public API. Otherwise I think it's good to add support for interfacing other backends (besides JDK14 Logging and stderr) to platform logger. If one wants to interface some other backend to platform logger now, it's actually doable, but only via the intermediate JDK14 Logging API, like this: PlatformLogger -> j.u.l.Logger -> jul-to-slf4j -> slf4j-WHATEVER-BACKEND Adding support to skip JDK14 Logging would simplify configuration and make it more lightweight. Yes - the goal of the LoggerFinder service API is to make it possible for applications - or frameworks - to provide their own implementation. best regards, -- daniel Regards, Peter
Re: JEP 264: Platform Logging API and Service
On 30/09/2015 14:59, Ralph Goers wrote: If I understand you correctly, then no that isn’t what I would want. The version and priority are captured in the same properties file where the class name is specified. If the class implements the wrong version or isn’t chosen due to its priority then the class isn’t loaded. To do what you are describing would require that serviceLoader load each class and that methods be called on each class to get that information. While that makes life simpler for the serviceLoader it makes it more complicated for the services being loaded. It should be possible to create a service type that allows you to select the appropriate service provider implementation. The service type can also work as a factory so that once you select the service provider then you invoke some method on it to get the actual logging provider. -Alan.
Re: JEP 264: Platform Logging API and Service
Alan, Your suggestion is literally the same thing that Peter suggested which is what my reply below was to. So you can take that reply as the reply to your message as well. What would be preferable is to have the serviceLoader accept “criteria” (which are callbacks) that can evaluate each of the located services based on any additional properties that are included in the properties file and either eliminate them or return a “ranking". The serviceLoader would then end up with a set of eligible services in their preferred order. Ralph > On Sep 30, 2015, at 7:14 AM, Alan Batemanwrote: > > On 30/09/2015 14:59, Ralph Goers wrote: >> If I understand you correctly, then no that isn’t what I would want. The >> version and priority are captured in the same properties file where the >> class name is specified. If the class implements the wrong version or isn’t >> chosen due to its priority then the class isn’t loaded. To do what you are >> describing would require that serviceLoader load each class and that methods >> be called on each class to get that information. While that makes life >> simpler for the serviceLoader it makes it more complicated for the services >> being loaded. >> > It should be possible to create a service type that allows you to select the > appropriate service provider implementation. The service type can also work > as a factory so that once you select the service provider then you invoke > some method on it to get the actual logging provider. > > -Alan. >
Re: JEP 264: Platform Logging API and Service
Hi Ralph, On 30/09/15 18:30, Ralph Goers wrote: What would be preferable is to have the serviceLoader accept “criteria” (which are callbacks) that can evaluate each of the located services based on any additional properties that are included in the properties file and either eliminate them or return a “ranking". The serviceLoader would then end up with a set of eligible services in their preferred order. I understand you may have another use case in mind, but in what concerns jep264's LoggerFinder though - I don't think that would be useful. The JDK can only use one LoggerFinder service implementation, and if more than one is found, it most probably indicates a configuration error - where several implementations have been put by mistake on the classpath. Just taking the first and silently continue could end up in strange misbehavior, where the application's developer would not see the expected debug traces - because she configured one framework but it's the other that happens to be used. I believe it's a better idea to fail fast in this case. best regards, -- daniel
Re: JEP 264: Platform Logging API and Service
FWIW, I considered using the ServiceLoader to bind the Log4j API to the implementation. However, Log4j also includes the API version and only looks for bindings that implement that version. We also include a “priority” - the binding with the highest priority wins - at the moment. At some future time we might consider supporting multiple bindings. It would have been nice if ServlceLoader could be extended by the user to do these sort of checks instead of not being able to use it at all. Ralph > On Sep 29, 2015, at 11:40 AM, Daniel Fuchswrote: > > On 20/09/15 15:46, Peter Levart wrote: >> >> >> On 09/18/2015 06:17 PM, mark.reinh...@oracle.com wrote: >>> New JEP Candidate:http://openjdk.java.net/jeps/264 >>> >>> - Mark >> >> Hi, >> >> What is the purpose of exposing a factory for loggers in the generally >> exported package (java.lang) and making it standard Java API as opposed >> to keeping it internal API as it is now >> (sun.util.logging.PlatformLogger)? Is this going to become an official >> front-end for JDK-internal and applications use, available in the >> platform itself? > > Hi Peter, > > sun.util.logging.PlatformLogger is a module private API in > java.base, yet it is used by other modules in the JDK - and > this requires qualified exports to the modules that use it. > Having a public API that JDK modules could use would simplify > the module graph in this respect. > > In time, I'd hope to see sun.util.logging.PlatformLogger disappear > in favor of the public API. > >> Otherwise I think it's good to add support for interfacing other >> backends (besides JDK14 Logging and stderr) to platform logger. If one >> wants to interface some other backend to platform logger now, it's >> actually doable, but only via the intermediate JDK14 Logging API, like this: >> >> PlatformLogger -> j.u.l.Logger -> jul-to-slf4j -> slf4j-WHATEVER-BACKEND >> >> Adding support to skip JDK14 Logging would simplify configuration and >> make it more lightweight. > > Yes - the goal of the LoggerFinder service API is to make it possible > for applications - or frameworks - to provide their own implementation. > > best regards, > > -- daniel > >> >> Regards, Peter >> > >
Re: JEP 264: Platform Logging API and Service
On 20/09/15 15:46, Peter Levart wrote: On 09/18/2015 06:17 PM, mark.reinh...@oracle.com wrote: New JEP Candidate:http://openjdk.java.net/jeps/264 - Mark Hi, What is the purpose of exposing a factory for loggers in the generally exported package (java.lang) and making it standard Java API as opposed to keeping it internal API as it is now (sun.util.logging.PlatformLogger)? Is this going to become an official front-end for JDK-internal and applications use, available in the platform itself? Hi Peter, sun.util.logging.PlatformLogger is a module private API in java.base, yet it is used by other modules in the JDK - and this requires qualified exports to the modules that use it. Having a public API that JDK modules could use would simplify the module graph in this respect. In time, I'd hope to see sun.util.logging.PlatformLogger disappear in favor of the public API. Otherwise I think it's good to add support for interfacing other backends (besides JDK14 Logging and stderr) to platform logger. If one wants to interface some other backend to platform logger now, it's actually doable, but only via the intermediate JDK14 Logging API, like this: PlatformLogger -> j.u.l.Logger -> jul-to-slf4j -> slf4j-WHATEVER-BACKEND Adding support to skip JDK14 Logging would simplify configuration and make it more lightweight. Yes - the goal of the LoggerFinder service API is to make it possible for applications - or frameworks - to provide their own implementation. best regards, -- daniel Regards, Peter
Re: JEP 264: Platform Logging API and Service
Hi Ralph, On 20/09/15 07:54, Ralph Goers wrote: I do have some questions on this. Would anyone realistically be able to use SLF4J/Logback or Log4j 2 as the implementation? The logging implementation needs to be able to configure itself before logging can realistically be performed. If logging initialization happens too soon the application’s configuration may not be able to be located. Bootstraping issues is one of the points that the implementation of this JEP will need to address. We have already some experience in that with java.util.logging and the s.u.l.PlatformLogger, but it's possible that the provider of the concrete LoggerFinder service implementation will need to play a role as well - depending on the requirements of the underlying implementation it provides. The logger returned by System.getLogger may not be directly a logger obtained from the LoggerFinder service, but a wrapper that will deal with possible bootstrap issue - for instance by delaying the creation of the actual logger until such time where it is actually used. Also, to do this would SLF4J/Logback or Log4j 2 have to be added to the boot classpath for them to be used for this? I believe that the appropriate thing to do is to load the implementation of the service with the ServiceLoader from the System ClassLoader. I also believe that a ServiceConfigurationError should be thrown if more than one implementation of the service is found. best regards, -- daniel Ralph On Sep 18, 2015, at 9:17 AM, mark.reinh...@oracle.com wrote: New JEP Candidate: http://openjdk.java.net/jeps/264 - Mark
Re: JEP 264: Platform Logging API and Service
On 09/18/2015 06:17 PM, mark.reinh...@oracle.com wrote: New JEP Candidate: http://openjdk.java.net/jeps/264 - Mark Hi, What is the purpose of exposing a factory for loggers in the generally exported package (java.lang) and making it standard Java API as opposed to keeping it internal API as it is now (sun.util.logging.PlatformLogger)? Is this going to become an official front-end for JDK-internal and applications use, available in the platform itself? Otherwise I think it's good to add support for interfacing other backends (besides JDK14 Logging and stderr) to platform logger. If one wants to interface some other backend to platform logger now, it's actually doable, but only via the intermediate JDK14 Logging API, like this: PlatformLogger -> j.u.l.Logger -> jul-to-slf4j -> slf4j-WHATEVER-BACKEND Adding support to skip JDK14 Logging would simplify configuration and make it more lightweight. Regards, Peter
Re: JEP 264: Platform Logging API and Service
I do have some questions on this. Would anyone realistically be able to use SLF4J/Logback or Log4j 2 as the implementation? The logging implementation needs to be able to configure itself before logging can realistically be performed. If logging initialization happens too soon the application’s configuration may not be able to be located. Also, to do this would SLF4J/Logback or Log4j 2 have to be added to the boot classpath for them to be used for this? Ralph > On Sep 18, 2015, at 9:17 AM, mark.reinh...@oracle.com wrote: > > New JEP Candidate: http://openjdk.java.net/jeps/264 > > - Mark >
Re: JEP 264: Platform Logging API and Service
On 09/18/2015 11:17 AM, mark.reinh...@oracle.com wrote: New JEP Candidate: http://openjdk.java.net/jeps/264 +1 good idea! -- - DML