-
Notifications
You must be signed in to change notification settings - Fork 2.9k
Mojo API update proposal #565
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
Changes from all commits
41ba264
7a77582
c7e11f5
affa287
64c91f4
1683b45
97043af
b496948
ac72869
ea7511c
c0f830c
26ca307
e29ce6f
60d49b5
8d38a7a
0135660
62acc00
3e2ccb0
4a291d4
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,206 @@ | ||
| package org.apache.maven.plugin.internal; | ||
|
|
||
| /* | ||
| * Licensed to the Apache Software Foundation (ASF) under one | ||
| * or more contributor license agreements. See the NOTICE file | ||
| * distributed with this work for additional information | ||
| * regarding copyright ownership. The ASF licenses this file | ||
| * to you under the Apache License, Version 2.0 (the | ||
| * "License"); you may not use this file except in compliance | ||
| * with the License. You may obtain a copy of the License at | ||
| * | ||
| * http://www.apache.org/licenses/LICENSE-2.0 | ||
| * | ||
| * Unless required by applicable law or agreed to in writing, | ||
| * software distributed under the License is distributed on an | ||
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | ||
| * KIND, either express or implied. See the License for the | ||
| * specific language governing permissions and limitations | ||
| * under the License. | ||
| */ | ||
|
|
||
| import org.apache.maven.plugin.logging.Log; | ||
| import org.slf4j.Logger; | ||
|
|
||
| import javax.inject.Provider; | ||
|
|
||
| import static java.util.Objects.requireNonNull; | ||
|
|
||
| /** | ||
| * Mojo {@link Log} implementation that lazily creates {@link Logger} instances. To achieve "lazyness" it uses | ||
| * {@link Provider} for logger, but guarantees that {@link Provider#get()} is invoked only once, and once got | ||
| * Logger instance is reused. | ||
| * | ||
| * @since TBD | ||
| */ | ||
| public class MojoLog | ||
| implements Log | ||
| { | ||
| private final Provider<Logger> loggerProvider; | ||
|
|
||
| public MojoLog( Provider<Logger> loggerProvider ) | ||
| { | ||
| this.loggerProvider = memoize( loggerProvider ); | ||
| } | ||
|
|
||
| private Logger getLogger() | ||
| { | ||
| return loggerProvider.get(); | ||
| } | ||
|
|
||
| private String toString( CharSequence content ) | ||
| { | ||
| if ( content == null ) | ||
| { | ||
| return ""; | ||
| } | ||
| else | ||
| { | ||
| return content.toString(); | ||
| } | ||
| } | ||
|
|
||
| @Override | ||
| public void debug( CharSequence content ) | ||
| { | ||
| if ( getLogger().isDebugEnabled() ) | ||
| { | ||
| getLogger().debug( toString( content ) ); | ||
| } | ||
| } | ||
|
|
||
| @Override | ||
| public void debug( CharSequence format, Object... arguments ) | ||
| { | ||
| if ( getLogger().isDebugEnabled() ) | ||
| { | ||
| getLogger().debug( toString( format ), arguments ); | ||
| } | ||
| } | ||
|
|
||
| @Override | ||
| public void debug( CharSequence content, Throwable error ) | ||
| { | ||
| if ( getLogger().isDebugEnabled() ) | ||
| { | ||
| getLogger().debug( toString( content ), error ); | ||
| } | ||
| } | ||
|
|
||
| @Override | ||
| public void debug( Throwable error ) | ||
| { | ||
| getLogger().debug( "", error ); | ||
| } | ||
|
|
||
| @Override | ||
| public void info( CharSequence content ) | ||
| { | ||
| getLogger().info( toString( content ) ); | ||
| } | ||
|
|
||
| @Override | ||
| public void info( CharSequence content, Throwable error ) | ||
| { | ||
| getLogger().info( toString( content ), error ); | ||
| } | ||
|
|
||
| @Override | ||
| public void info( Throwable error ) | ||
| { | ||
| getLogger().info( "", error ); | ||
| } | ||
|
|
||
| @Override | ||
| public void warn( CharSequence content ) | ||
| { | ||
| getLogger().warn( toString( content ) ); | ||
| } | ||
|
|
||
| @Override | ||
| public void warn( CharSequence content, Throwable error ) | ||
| { | ||
| getLogger().warn( toString( content ), error ); | ||
| } | ||
|
|
||
| @Override | ||
| public void warn( Throwable error ) | ||
| { | ||
| getLogger().warn( "", error ); | ||
| } | ||
|
|
||
| @Override | ||
| public void error( CharSequence content ) | ||
| { | ||
| getLogger().error( toString( content ) ); | ||
| } | ||
|
|
||
| @Override | ||
| public void error( CharSequence content, Throwable error ) | ||
| { | ||
| getLogger().error( toString( content ), error ); | ||
| } | ||
|
|
||
| @Override | ||
| public void error( Throwable error ) | ||
| { | ||
| getLogger().error( "", error ); | ||
| } | ||
|
|
||
| @Override | ||
| public boolean isDebugEnabled() | ||
| { | ||
| return getLogger().isDebugEnabled(); | ||
| } | ||
|
|
||
| @Override | ||
| public boolean isInfoEnabled() | ||
| { | ||
| return getLogger().isInfoEnabled(); | ||
| } | ||
|
|
||
| @Override | ||
| public boolean isWarnEnabled() | ||
| { | ||
| return getLogger().isWarnEnabled(); | ||
| } | ||
|
|
||
| @Override | ||
| public boolean isErrorEnabled() | ||
| { | ||
| return getLogger().isErrorEnabled(); | ||
| } | ||
|
|
||
| /** | ||
| * A helper bit to make users of this class easier: it wraps {@link Provider} into "memoizing" provider: the | ||
| * wrapped (delegate) provider will be invoked only once, and the returned value will be stored for subsequent | ||
| * invocations of {@link Provider#get()} on wrapper. | ||
| */ | ||
| private static <T> Provider<T> memoize( Provider<T> provider ) | ||
| { | ||
| requireNonNull( provider ); | ||
| return new Provider<T>() | ||
| { | ||
| Provider<T> delegate = this::memoize; | ||
|
|
||
| volatile boolean memoized = false; | ||
|
|
||
| @Override | ||
| public T get() | ||
| { | ||
| return delegate.get(); | ||
| } | ||
|
|
||
| private synchronized T memoize() | ||
| { | ||
| if ( !memoized ) | ||
| { | ||
| T value = provider.get(); | ||
| delegate = () -> value; | ||
| memoized = true; | ||
| } | ||
| return delegate.get(); | ||
| } | ||
| }; | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,46 @@ | ||
| package org.apache.maven.plugin.internal; | ||
|
|
||
| /* | ||
| * Licensed to the Apache Software Foundation (ASF) under one | ||
| * or more contributor license agreements. See the NOTICE file | ||
| * distributed with this work for additional information | ||
| * regarding copyright ownership. The ASF licenses this file | ||
| * to you under the Apache License, Version 2.0 (the | ||
| * "License"); you may not use this file except in compliance | ||
| * with the License. You may obtain a copy of the License at | ||
| * | ||
| * http://www.apache.org/licenses/LICENSE-2.0 | ||
| * | ||
| * Unless required by applicable law or agreed to in writing, | ||
| * software distributed under the License is distributed on an | ||
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | ||
| * KIND, either express or implied. See the License for the | ||
| * specific language governing permissions and limitations | ||
| * under the License. | ||
| */ | ||
|
|
||
| import javax.inject.Named; | ||
| import javax.inject.Singleton; | ||
|
|
||
| import org.apache.maven.plugin.logging.Log; | ||
| import org.slf4j.LoggerFactory; | ||
|
|
||
| /** | ||
| * Implementation of Mojo {@link Log} factory backed by Maven internal logging (slf4j). | ||
| * | ||
| * @since TBD | ||
| */ | ||
| @Singleton | ||
| @Named | ||
| public class MojoLogFactory | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. One of the issues we now have is that we can only specify a global loglevel. In case something with The changes that are proposed must be prepared to be able to log for 1 specific plugin or goal.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. IMO, for plugin you'd want to just set logging level of given logger (but how to map plugin name -> class name)? As this class just wraps Slfj4 LoggerFactory... To achieve that, IMHO you'd want:
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. i think it is a bit more complex. It is not just the mojo, but all other classes of the plugin, both inside the jar and the other used classes. What is the plugin calls maven-core code? I would expect that to be logged at the mojo-loglevel too. We need to dive into the possibilities with classworlds to achieve this.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It may be easier to set a MDC flag on the logger before executing a plugin. At least, this would allow to easily filter all log statements related to a given invocation.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Think a threadlocal solution does not work since a lot of mojo are multithreaded so, until we replace through the ClassRealm the
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @rfscholte so you want even core calls as DEBUG?
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Fwiw, in
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
No, you're right. But there's no reason to stay on SimpleLogger if there's a need to change. Anyway, in
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
This is why I'm saying a thread local solution can be a quick impl but not a final solution, several mojos are not properly logged. While just in the window of mvnd it is okish but if we speak about configuring loggers it will not be the same tolerance at all IMHO.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
What I would expect is a behavior similar to: at start of Mojo reset the loggers and change the root logger to debug, at end of the Mojo restore the loggers. Reason is that the issue might not be in the plugin code itself, but in one of its dependencies and if that uses logging it might be very very helpful. |
||
| { | ||
| public Log getLog( final Class<?> clazz ) | ||
| { | ||
| return new MojoLog( () -> LoggerFactory.getLogger( clazz ) ); | ||
| } | ||
|
|
||
| public Log getLog( final String name ) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this still used? And do we really want to support this? |
||
| { | ||
| return new MojoLog( () -> LoggerFactory.getLogger( name ) ); | ||
| } | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.