Switch to slf4j simple logger (fixes #835) (#868)

This commit is contained in:
Guillaume Nodet
2023-07-10 15:16:32 +02:00
committed by GitHub
parent daf68fd925
commit f8adf1b770
36 changed files with 1144 additions and 472 deletions

View File

@@ -43,12 +43,12 @@
<artifactId>mvnd-common</artifactId>
</dependency>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-embedder</artifactId>
<groupId>org.apache.maven.daemon</groupId>
<artifactId>mvnd-logging</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<groupId>org.apache.maven</groupId>
<artifactId>maven-embedder</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>

View File

@@ -24,12 +24,6 @@ import org.slf4j.LoggerFactory;
public class DefaultClient {
public static void main(String[] argv) throws Exception {
final String logbackConfFallback = System.getProperty("logback.configurationFile.fallback");
if (null != logbackConfFallback && !"".equals(logbackConfFallback)) {
System.setProperty("logback.configurationFile", logbackConfFallback);
System.clearProperty("logback.configurationFile.fallback");
}
final Logger LOGGER = LoggerFactory.getLogger(DefaultClient.class);
LOGGER.warn("Found old JDK, fallback to the embedded maven!");
LOGGER.warn("Use JDK 11+ to run maven-mvnd client!");

View File

@@ -60,6 +60,8 @@ import org.mvndaemon.mvnd.common.logging.TerminalOutput;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.bridge.SLF4JBridgeHandler;
import org.slf4j.impl.MvndLoggerFactory;
import org.slf4j.impl.StaticLoggerBinder;
import static org.mvndaemon.mvnd.client.DaemonParameters.LOG_EXTENSION;
@@ -70,8 +72,6 @@ public class DefaultClient implements Client {
private final DaemonParameters parameters;
public static void main(String[] argv) throws Exception {
System.clearProperty("logback.configurationFile.fallback");
final List<String> args = new ArrayList<>(Arrays.asList(argv));
// Log file
@@ -115,6 +115,10 @@ public class DefaultClient implements Client {
// System properties
setSystemPropertiesFromCommandLine(args);
if (StaticLoggerBinder.getSingleton().getLoggerFactory() instanceof MvndLoggerFactory) {
((MvndLoggerFactory) StaticLoggerBinder.getSingleton().getLoggerFactory()).reconfigure();
}
DaemonParameters parameters = new DaemonParameters();
if (parameters.serial()) {
System.setProperty(Environment.MVND_THREADS.getProperty(), Integer.toString(1));
@@ -191,9 +195,13 @@ public class DefaultClient implements Client {
/* This needs to be done very early, otherwise various DaemonParameters do not work properly */
final int eqPos = val.indexOf('=');
if (eqPos >= 0) {
System.setProperty(val.substring(0, eqPos), val.substring(eqPos + 1));
String k = val.substring(0, eqPos);
String v = val.substring(eqPos + 1);
System.setProperty(k, v);
LOGGER.trace("Setting system property {} to {}", k, v);
} else {
System.setProperty(val, "");
LOGGER.trace("Setting system property {}", val);
}
}
}

View File

@@ -57,6 +57,7 @@ import org.mvndaemon.mvnd.common.SocketFamily;
import org.mvndaemon.mvnd.common.logging.ClientOutput;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.impl.SimpleLogger;
import static java.lang.Thread.sleep;
import static org.mvndaemon.mvnd.common.DaemonState.Canceled;
@@ -433,10 +434,11 @@ public class DaemonConnector {
args.add("-Dmaven.conf=" + mvndHome.resolve("mvn").resolve("conf"));
args.add("-Dclassworlds.conf=" + mvndHome.resolve("bin").resolve("mvnd-daemon.conf"));
args.add("-D" + SimpleLogger.LOG_FILE_KEY + "="
+ parameters.daemonStorage().resolve("daemon-" + daemonId + ".log"));
Environment.MVND_JAVA_HOME.addSystemProperty(
args, parameters.javaHome().toString());
Environment.LOGBACK_CONFIGURATION_FILE.addSystemProperty(
args, parameters.logbackConfigurationPath().toString());
Environment.MVND_ID.addSystemProperty(args, daemonId);
Environment.MVND_DAEMON_STORAGE.addSystemProperty(
args, parameters.daemonStorage().toString());

View File

@@ -184,11 +184,21 @@ public class DaemonParameters {
}
public Path userDir() {
return value(Environment.USER_DIR).orSystemProperty().orFail().asPath().toAbsolutePath();
return value(Environment.USER_DIR)
.orSystemProperty()
.orFail()
.cache(provider)
.asPath()
.toAbsolutePath();
}
public Path userHome() {
return value(Environment.USER_HOME).orSystemProperty().orFail().asPath().toAbsolutePath();
return value(Environment.USER_HOME)
.orSystemProperty()
.orFail()
.cache(provider)
.asPath()
.toAbsolutePath();
}
public Path suppliedPropertiesPath() {
@@ -256,15 +266,6 @@ public class DaemonParameters {
.normalize();
}
public Path logbackConfigurationPath() {
return property(Environment.MVND_LOGBACK)
.orDefault(() -> mvndHome()
.resolve("mvn/conf/logging/logback-daemon.xml")
.toString())
.orFail()
.asPath();
}
public String minHeapSize() {
return property(Environment.MVND_MIN_HEAP_SIZE).asString();
}

View File

@@ -62,17 +62,6 @@ public enum Environment {
/** Use one thread, no log buffering and the default project builder to behave like a standard maven */
SERIAL("mvnd.serial", null, Boolean.FALSE, OptionType.VOID, Flags.OPTIONAL, "mvnd:-1", "mvnd:--serial"),
//
// Log properties
//
/**
* The location of the Logback configuration file the daemon should use to configure its logging.
*/
MVND_LOGBACK("mvnd.logback", null, null, OptionType.PATH, Flags.NONE),
/** The system property expected by logback to set the configuration file */
LOGBACK_CONFIGURATION_FILE("logback.configurationFile", null, null, OptionType.PATH, Flags.INTERNAL),
//
// System properties
//

View File

@@ -57,6 +57,8 @@ import org.apache.maven.cli.configuration.SettingsXmlConfigurationProcessor;
import org.apache.maven.cli.event.ExecutionEventLogger;
import org.apache.maven.cli.internal.BootstrapCoreExtensionManager;
import org.apache.maven.cli.internal.extension.model.CoreExtension;
import org.apache.maven.cli.logging.Slf4jConfiguration;
import org.apache.maven.cli.logging.Slf4jConfigurationFactory;
import org.apache.maven.cli.transfer.QuietMavenTransferListener;
import org.apache.maven.cli.transfer.Slf4jMavenTransferListener;
import org.apache.maven.eventspy.internal.EventSpyDispatcher;
@@ -113,6 +115,8 @@ import org.mvndaemon.mvnd.transfer.DaemonMavenTransferListener;
import org.slf4j.ILoggerFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.impl.MvndSimpleLogger;
import org.slf4j.spi.LocationAwareLogger;
import org.sonatype.plexus.components.sec.dispatcher.DefaultSecDispatcher;
import org.sonatype.plexus.components.sec.dispatcher.SecDispatcher;
@@ -365,15 +369,17 @@ public class DaemonMavenCli implements DaemonCli {
cliRequest.quiet = !cliRequest.debug && cliRequest.commandLine.hasOption(CLIManager.QUIET);
cliRequest.showErrors = cliRequest.debug || cliRequest.commandLine.hasOption(CLIManager.ERRORS);
ch.qos.logback.classic.Level level;
Slf4jConfiguration slf4jConfiguration = Slf4jConfigurationFactory.getConfiguration(slf4jLoggerFactory);
if (cliRequest.debug) {
level = ch.qos.logback.classic.Level.DEBUG;
cliRequest.request.setLoggingLevel(MavenExecutionRequest.LOGGING_LEVEL_DEBUG);
slf4jConfiguration.setRootLoggerLevel(Slf4jConfiguration.Level.DEBUG);
} else if (cliRequest.quiet) {
level = ch.qos.logback.classic.Level.WARN;
} else {
level = ch.qos.logback.classic.Level.INFO;
cliRequest.request.setLoggingLevel(MavenExecutionRequest.LOGGING_LEVEL_ERROR);
slf4jConfiguration.setRootLoggerLevel(Slf4jConfiguration.Level.ERROR);
}
((ch.qos.logback.classic.Logger) slf4jLoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME)).setLevel(level);
// else fall back to default log level specified in conf
// see https://issues.apache.org/jira/browse/MNG-2570
// LOG COLOR
String styleColor = cliRequest.getUserProperties().getProperty(STYLE_COLOR_PROPERTY, "auto");
@@ -389,11 +395,6 @@ public class DaemonMavenCli implements DaemonCli {
MessageUtils.setColorEnabled(false);
}
// Workaround for https://github.com/apache/maven-mvnd/issues/39
final ch.qos.logback.classic.Logger mvndLogger =
(ch.qos.logback.classic.Logger) slf4jLoggerFactory.getLogger("org.mvndaemon.mvnd");
mvndLogger.setLevel(ch.qos.logback.classic.Level.toLevel(System.getProperty("mvnd.log.level"), null));
// LOG STREAMS
if (cliRequest.commandLine.hasOption(CLIManager.LOG_FILE)) {
File logFile = new File(cliRequest.commandLine.getOptionValue(CLIManager.LOG_FILE));
@@ -413,15 +414,15 @@ public class DaemonMavenCli implements DaemonCli {
.asOptional()
.map(Boolean::parseBoolean)
.orElse(Boolean.FALSE)) {
ch.qos.logback.classic.Logger stdout =
(ch.qos.logback.classic.Logger) slf4jLoggerFactory.getLogger("stdout");
ch.qos.logback.classic.Logger stderr =
(ch.qos.logback.classic.Logger) slf4jLoggerFactory.getLogger("stderr");
stdout.setLevel(ch.qos.logback.classic.Level.INFO);
stderr.setLevel(ch.qos.logback.classic.Level.INFO);
MvndSimpleLogger stdout = (MvndSimpleLogger) slf4jLoggerFactory.getLogger("stdout");
MvndSimpleLogger stderr = (MvndSimpleLogger) slf4jLoggerFactory.getLogger("stderr");
stdout.setLogLevel(LocationAwareLogger.INFO_INT);
stderr.setLogLevel(LocationAwareLogger.INFO_INT);
System.setOut(new LoggingOutputStream(s -> stdout.info("[stdout] " + s)).printStream());
System.setErr(new LoggingOutputStream(s -> stderr.warn("[stderr] " + s)).printStream());
}
slf4jConfiguration.activate();
}
private void version(CliRequest cliRequest) throws ExitException {

View File

@@ -54,6 +54,8 @@ import org.apache.maven.cli.internal.BootstrapCoreExtensionManager;
import org.apache.maven.cli.internal.extension.model.CoreExtension;
import org.apache.maven.cli.jansi.JansiMessageBuilderFactory;
import org.apache.maven.cli.jansi.MessageUtils;
import org.apache.maven.cli.logging.Slf4jConfiguration;
import org.apache.maven.cli.logging.Slf4jConfigurationFactory;
import org.apache.maven.cli.transfer.QuietMavenTransferListener;
import org.apache.maven.cli.transfer.Slf4jMavenTransferListener;
import org.apache.maven.eventspy.internal.EventSpyDispatcher;
@@ -103,6 +105,8 @@ import org.mvndaemon.mvnd.transfer.DaemonMavenTransferListener;
import org.slf4j.ILoggerFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.impl.MvndSimpleLogger;
import org.slf4j.spi.LocationAwareLogger;
import org.sonatype.plexus.components.sec.dispatcher.DefaultSecDispatcher;
import org.sonatype.plexus.components.sec.dispatcher.SecDispatcher;
@@ -411,15 +415,17 @@ public class DaemonMavenCli implements DaemonCli {
cliRequest.quiet = !cliRequest.verbose && commandLine.hasOption(CLIManager.QUIET);
cliRequest.showErrors = cliRequest.verbose || commandLine.hasOption(CLIManager.ERRORS);
ch.qos.logback.classic.Level level;
Slf4jConfiguration slf4jConfiguration = Slf4jConfigurationFactory.getConfiguration(slf4jLoggerFactory);
if (cliRequest.verbose) {
level = ch.qos.logback.classic.Level.DEBUG;
cliRequest.request.setLoggingLevel(MavenExecutionRequest.LOGGING_LEVEL_DEBUG);
slf4jConfiguration.setRootLoggerLevel(Slf4jConfiguration.Level.DEBUG);
} else if (cliRequest.quiet) {
level = ch.qos.logback.classic.Level.WARN;
} else {
level = ch.qos.logback.classic.Level.INFO;
cliRequest.request.setLoggingLevel(MavenExecutionRequest.LOGGING_LEVEL_ERROR);
slf4jConfiguration.setRootLoggerLevel(Slf4jConfiguration.Level.ERROR);
}
((ch.qos.logback.classic.Logger) slf4jLoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME)).setLevel(level);
// else fall back to default log level specified in conf
// see https://issues.apache.org/jira/browse/MNG-2570
// LOG COLOR
String styleColor = cliRequest.getUserProperties().getProperty(STYLE_COLOR_PROPERTY, "auto");
@@ -438,11 +444,6 @@ public class DaemonMavenCli implements DaemonCli {
}
}
// Workaround for https://github.com/apache/maven-mvnd/issues/39
final ch.qos.logback.classic.Logger mvndLogger =
(ch.qos.logback.classic.Logger) slf4jLoggerFactory.getLogger("org.mvndaemon.mvnd");
mvndLogger.setLevel(ch.qos.logback.classic.Level.toLevel(System.getProperty("mvnd.log.level"), null));
// LOG STREAMS
if (commandLine.hasOption(CLIManager.LOG_FILE)) {
File logFile = new File(commandLine.getOptionValue(CLIManager.LOG_FILE));
@@ -462,15 +463,15 @@ public class DaemonMavenCli implements DaemonCli {
.asOptional()
.map(Boolean::parseBoolean)
.orElse(Boolean.FALSE)) {
ch.qos.logback.classic.Logger stdout =
(ch.qos.logback.classic.Logger) slf4jLoggerFactory.getLogger("stdout");
ch.qos.logback.classic.Logger stderr =
(ch.qos.logback.classic.Logger) slf4jLoggerFactory.getLogger("stderr");
stdout.setLevel(ch.qos.logback.classic.Level.INFO);
stderr.setLevel(ch.qos.logback.classic.Level.INFO);
MvndSimpleLogger stdout = (MvndSimpleLogger) slf4jLoggerFactory.getLogger("stdout");
MvndSimpleLogger stderr = (MvndSimpleLogger) slf4jLoggerFactory.getLogger("stderr");
stdout.setLogLevel(LocationAwareLogger.INFO_INT);
stderr.setLogLevel(LocationAwareLogger.INFO_INT);
System.setOut(new LoggingOutputStream(s -> stdout.info("[stdout] " + s)).printStream());
System.setErr(new LoggingOutputStream(s -> stderr.warn("[stderr] " + s)).printStream());
}
slf4jConfiguration.activate();
}
private void version(CliRequest cliRequest) throws ExitException {

View File

@@ -64,10 +64,6 @@
</dependency>
<!-- Logging -->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>log4j-over-slf4j</artifactId>

View File

@@ -1,19 +0,0 @@
#
# Copyright 2019 the original author or authors.
#
# Licensed 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.
#
# key = Slf4j effective logger factory implementation
# value = corresponding o.a.m.cli.logging.Slf4jConfiguration class
ch.qos.logback.classic.LoggerContext org.mvndaemon.mvnd.logging.internal.MvndSlf4jConfiguration

View File

@@ -20,7 +20,7 @@
<artifactSet to="/mvn">
<artifact id="org.apache.maven:apache-maven:tar.gz:bin:${maven3.version}">
<unpack useRoot="false"
excludes="conf/logging/*,lib/maven-slf4j-provider*" />
excludes="lib/maven-slf4j-*" />
</artifact>
</artifactSet>
@@ -28,12 +28,6 @@
<artifact id="org.apache.maven.daemon:mvnd-logging:${project.version}">
<exclusion id="*:*"/>
</artifact>
<artifact id="ch.qos.logback:logback-classic">
<exclusion id="*:*"/>
</artifact>
<artifact id="ch.qos.logback:logback-core">
<exclusion id="*:*"/>
</artifact>
<artifact id="org.slf4j:jul-to-slf4j">
<exclusion id="*:*"/>
</artifact>

View File

@@ -20,7 +20,7 @@
<artifactSet to="/mvn">
<artifact id="org.apache.maven:apache-maven:tar.gz:bin:${maven4.version}">
<unpack useRoot="false"
excludes="conf/logging/*,lib/maven-slf4j-provider*,lib/plexus-utils-3.*" />
excludes="lib/maven-slf4j-*,lib/plexus-utils-3.*" />
</artifact>
</artifactSet>
@@ -28,12 +28,6 @@
<artifact id="org.apache.maven.daemon:mvnd-logging:${project.version}">
<exclusion id="*:*"/>
</artifact>
<artifact id="ch.qos.logback:logback-classic">
<exclusion id="*:*"/>
</artifact>
<artifact id="ch.qos.logback:logback-core">
<exclusion id="*:*"/>
</artifact>
<artifact id="org.slf4j:jul-to-slf4j">
<exclusion id="*:*"/>
</artifact>

View File

@@ -218,7 +218,7 @@ _mvnd()
local mvnd_opts="-1"
local mvnd_long_opts="--color|--completion|--purge|--raw-streams|--serial|--status|--stop"
local mvnd_properties="-Djava.home|-Djdk.java.options|-Dmaven.multiModuleProjectDirectory|-Dmaven.repo.local|-Dmaven.settings|-Dmvnd.buildTime|-Dmvnd.builder|-Dmvnd.cancelConnectTimeout|-Dmvnd.connectTimeout|-Dmvnd.daemonStorage|-Dmvnd.debug|-Dmvnd.debug.address|-Dmvnd.duplicateDaemonGracePeriod|-Dmvnd.enableAssertions|-Dmvnd.expirationCheckDelay|-Dmvnd.home|-Dmvnd.idleTimeout|-Dmvnd.jvmArgs|-Dmvnd.keepAlive|-Dmvnd.logPurgePeriod|-Dmvnd.logback|-Dmvnd.maxHeapSize|-Dmvnd.maxLostKeepAlive|-Dmvnd.minHeapSize|-Dmvnd.minThreads|-Dmvnd.noBuffering|-Dmvnd.noDaemon|-Dmvnd.noModelCache|-Dmvnd.pluginRealmEvictPattern|-Dmvnd.propertiesPath|-Dmvnd.rawStreams|-Dmvnd.registry|-Dmvnd.rollingWindowSize|-Dmvnd.serial|-Dmvnd.socketConnectTimeout|-Dmvnd.socketFamily|-Dmvnd.threadStackSize|-Dmvnd.threads|-Dstyle.color|-Duser.dir|-Duser.home"
local mvnd_properties="-Djava.home|-Djdk.java.options|-Dmaven.multiModuleProjectDirectory|-Dmaven.repo.local|-Dmaven.settings|-Dmvnd.buildTime|-Dmvnd.builder|-Dmvnd.cancelConnectTimeout|-Dmvnd.connectTimeout|-Dmvnd.daemonStorage|-Dmvnd.debug|-Dmvnd.debug.address|-Dmvnd.duplicateDaemonGracePeriod|-Dmvnd.enableAssertions|-Dmvnd.expirationCheckDelay|-Dmvnd.home|-Dmvnd.idleTimeout|-Dmvnd.jvmArgs|-Dmvnd.keepAlive|-Dmvnd.logPurgePeriod|-Dmvnd.maxHeapSize|-Dmvnd.maxLostKeepAlive|-Dmvnd.minHeapSize|-Dmvnd.minThreads|-Dmvnd.noBuffering|-Dmvnd.noDaemon|-Dmvnd.noModelCache|-Dmvnd.pluginRealmEvictPattern|-Dmvnd.propertiesPath|-Dmvnd.rawStreams|-Dmvnd.registry|-Dmvnd.rollingWindowSize|-Dmvnd.serial|-Dmvnd.socketConnectTimeout|-Dmvnd.socketFamily|-Dmvnd.threadStackSize|-Dmvnd.threads|-Dstyle.color|-Duser.dir|-Duser.home"
local opts="-am|-amd|-B|-C|-c|-cpu|-D|-e|-emp|-ep|-f|-fae|-ff|-fn|-gs|-h|-l|-N|-npr|-npu|-nsu|-o|-P|-pl|-q|-rf|-s|-T|-t|-U|-up|-V|-v|-X|${mvnd_opts}"
local long_opts="--also-make|--also-make-dependents|--batch-mode|--strict-checksums|--lax-checksums|--check-plugin-updates|--define|--errors|--encrypt-master-password|--encrypt-password|--file|--fail-at-end|--fail-fast|--fail-never|--global-settings|--help|--log-file|--non-recursive|--no-plugin-registry|--no-plugin-updates|--no-snapshot-updates|--offline|--activate-profiles|--projects|--quiet|--resume-from|--settings|--threads|--toolchains|--update-snapshots|--update-plugins|--show-version|--version|--debug|${mvnd_long_opts}"

View File

@@ -20,8 +20,6 @@ set maven.home default ${mvnd.home}/mvn
set maven.conf default ${maven.home}/conf
set java.util.logging.config.file default ${maven.conf}/logging/java.util.logging.properties
set logback.configurationFile default ${maven.conf}/logging/logback-client.xml
set logback.configurationFile.fallback default ${maven.conf}/logging/logback.xml
[plexus.core]
load ${maven.conf}/logging

View File

@@ -20,8 +20,6 @@ set maven.home default ${mvnd.home}/mvn
set maven.conf default ${maven.home}/conf
set java.util.logging.config.file default ${maven.conf}/logging/java.util.logging.properties
set logback.configurationFile default ${maven.conf}/logging/logback-daemon.xml
set logback.configurationFile.fallback default ${maven.conf}/logging/logback.xml
[plexus.core]
load ${maven.conf}/logging

View File

@@ -1,34 +0,0 @@
<!--
Copyright 2019 the original author or authors.
Licensed 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.
-->
<!--
| mvnd client log configuration
-->
<configuration>
<contextListener class="ch.qos.logback.classic.jul.LevelChangePropagator"/>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%-5relative %-5level %logger{35} - %msg%n</pattern>
</encoder>
</appender>
<root level="${consoleLevel:-info}">
<appender-ref ref="STDOUT" />
</root>
</configuration>

View File

@@ -1,49 +0,0 @@
<!--
Copyright 2019 the original author or authors.
Licensed 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.
-->
<!--
| Local developer build logging configuration.
| * console log shows overall info+ build messages and project errors
| * overall build.log file includes all build log messages
| * project-specific build.log files include corresponding project build log messages
-->
<configuration>
<contextListener class="ch.qos.logback.classic.jul.LevelChangePropagator" />
<appender name="DAEMON" class="ch.qos.logback.core.FileAppender">
<file>${mvnd.daemonStorage}/daemon-${mvnd.id}.log</file>
<encoder>
<pattern>%d{HH:mm:ss.SSS} %.-1level %msg%n</pattern>
</encoder>
</appender>
<logger name="org.mvndaemon.mvnd.daemon" level="DEBUG" additivity="false">
<appender-ref ref="DAEMON" />
</logger>
<logger name="org.mvndaemon.mvnd.interactivity" level="DEBUG" additivity="false">
<appender-ref ref="DAEMON" />
</logger>
<logger name="Sisu" level="INFO" />
<!-- suppress annoying @threadSafe and checksum failure warning messages -->
<logger name="org.apache.maven.lifecycle.internal.builder.BuilderCommon" level="ERROR" />
<logger name="org.eclipse.aether.internal.impl.WarnChecksumPolicy" level="ERROR" />
</configuration>

View File

@@ -1,42 +0,0 @@
<!--
Copyright 2020 the original author or authors.
Licensed 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.
-->
<!--
| Local developer build logging configuration.
| * console log shows overall info+ build messages and project errors
| * overall build.log file includes all build log messages
| * project-specific build.log files include corresponding project build log messages
-->
<configuration>
<contextListener class="ch.qos.logback.classic.jul.LevelChangePropagator" />
<!--
| write project-specific build log messages to ${project.build.directory}/build.log files
-->
<appender name="CONSOLE" class="org.mvndaemon.mvnd.logging.internal.SimpleAppender" />
<logger name="Sisu" level="INFO" />
<!-- suppress annoying @threadSafe and checksum failure warning messages -->
<logger name="org.apache.maven.lifecycle.internal.builder.BuilderCommon" level="ERROR" />
<logger name="org.eclipse.aether.internal.impl.WarnChecksumPolicy" level="ERROR" />
<root level="${consoleLevel:-info}">
<appender-ref ref="CONSOLE" />
</root>
</configuration>

View File

@@ -20,10 +20,9 @@ package org.mvndaemon.mvnd.it;
import javax.inject.Inject;
import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.Logger;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.read.ListAppender;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
@@ -32,6 +31,8 @@ import org.mvndaemon.mvnd.assertj.TestClientOutput;
import org.mvndaemon.mvnd.client.Client;
import org.mvndaemon.mvnd.junit.MvndNativeTest;
import org.slf4j.LoggerFactory;
import org.slf4j.impl.MvndSimpleLogger;
import org.slf4j.spi.LocationAwareLogger;
import static org.junit.jupiter.api.Assertions.assertTrue;
@@ -42,33 +43,31 @@ public class MaxHeapNativeIT {
@Inject
Client client;
static ListAppender<ILoggingEvent> appender = new ListAppender<>();
static List<String> messages = new CopyOnWriteArrayList<>();
@BeforeAll
static void setup() {
Logger logger = (Logger) LoggerFactory.getLogger("org.mvndaemon.mvnd.client.DaemonConnector");
logger.setLevel(Level.DEBUG);
logger.addAppender(appender);
appender.start();
MvndSimpleLogger logger =
(MvndSimpleLogger) LoggerFactory.getLogger("org.mvndaemon.mvnd.client.DaemonConnector");
logger.setLogLevel(LocationAwareLogger.DEBUG_INT);
MvndSimpleLogger.setLogSink(messages::add);
}
@AfterAll
static void tearDown() {
Logger logger = (Logger) LoggerFactory.getLogger("org.mvndaemon.mvnd.client.DaemonConnector");
logger.detachAppender(appender);
MvndSimpleLogger.setLogSink(null);
}
static String getDaemonArgs() {
return appender.list.stream()
.filter(e -> e.getMessage().contains("Starting daemon process"))
.map(e -> e.getArgumentArray()[2].toString())
return messages.stream()
.filter(e -> e.contains("Starting daemon process"))
.findAny()
.orElseThrow();
}
@BeforeEach
void unitSetup() {
appender.list.clear();
messages.clear();
}
}

View File

@@ -74,7 +74,13 @@ public class MultiModuleTest {
Stream.of(installedJars).forEach(jar -> Assertions.assertThat(jar).doesNotExist());
final TestClientOutput output = new TestClientOutput();
client.execute(output, "clean", "install", "-e").assertSuccess();
client.execute(
output,
"-Dorg.slf4j.simpleLogger.log.io.takari.maven.builder.smart=DEBUG",
"clean",
"install",
"-e")
.assertSuccess();
{
final List<String> filteredMessages = output.getMessages().stream()

View File

@@ -238,8 +238,6 @@ public class MvndTestExtension implements BeforeAllCallback, BeforeEachCallback,
LOG.info("Building with mrm-maven-plugin");
settingsPath = createSettings(testDir.resolve("settings.xml"), mrmRepoUrl);
}
final Path logback =
Paths.get("src/test/resources/logback/logback.xml").toAbsolutePath();
final Path home = deleteDir(testDir.resolve("home"));
final TestParameters parameters = new TestParameters(
testDir,
@@ -251,7 +249,6 @@ public class MvndTestExtension implements BeforeAllCallback, BeforeEachCallback,
Paths.get(System.getProperty("java.home")).toAbsolutePath().normalize(),
localMavenRepository,
settingsPath,
logback,
TimeUtils.toDuration(Environment.MVND_IDLE_TIMEOUT.getDefault()),
keepAlive != null && !keepAlive.isEmpty()
? TimeUtils.toDuration(keepAlive)

View File

@@ -40,7 +40,6 @@ public class TestParameters extends DaemonParameters {
Path javaHome,
Path localMavenRepository,
Path settings,
Path logbackConfigurationPath,
Duration idleTimeout,
Duration keepAlive,
int maxLostKeepAlive,
@@ -55,7 +54,6 @@ public class TestParameters extends DaemonParameters {
.put(Environment.JAVA_HOME, javaHome)
.put(Environment.MAVEN_REPO_LOCAL, localMavenRepository)
.put(Environment.MAVEN_SETTINGS, settings)
.put(Environment.MVND_LOGBACK, logbackConfigurationPath)
.put(Environment.MVND_IDLE_TIMEOUT, TimeUtils.printDuration(idleTimeout))
.put(Environment.MVND_KEEP_ALIVE, TimeUtils.printDuration(keepAlive))
.put(Environment.MVND_MAX_LOST_KEEP_ALIVE, maxLostKeepAlive)
@@ -83,7 +81,6 @@ public class TestParameters extends DaemonParameters {
value(Environment.JAVA_HOME).asPath(),
value(Environment.MAVEN_REPO_LOCAL).asPath(),
value(Environment.MAVEN_SETTINGS).asPath(),
value(Environment.MVND_LOGBACK).asPath(),
value(Environment.MVND_IDLE_TIMEOUT).asDuration(),
value(Environment.MVND_KEEP_ALIVE).asDuration(),
value(Environment.MVND_MAX_LOST_KEEP_ALIVE).asInt(),

View File

@@ -1,47 +0,0 @@
<!--
Copyright 2019 the original author or authors.
Licensed 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.
-->
<!--
| Local developer build logging configuration.
| * console log shows overall info+ build messages and project errors
| * overall build.log file includes all build log messages
| * project-specific build.log files include corresponding project build log messages
-->
<configuration>
<contextListener class="ch.qos.logback.classic.jul.LevelChangePropagator" />
<appender name="DAEMON" class="ch.qos.logback.core.FileAppender">
<file>${mvnd.daemonStorage}/daemon-${mvnd.id}.log</file>
<encoder>
<pattern>%d{HH:mm:ss.SSS} %.-1level %msg%n</pattern>
</encoder>
</appender>
<logger name="org.mvndaemon.mvnd.daemon" level="DEBUG" additivity="false">
<appender-ref ref="DAEMON" />
</logger>
<logger name="io.takari.maven.builder.smart.SmartBuilder" level="DEBUG"/>
<logger name="Sisu" level="INFO" />
<!-- suppress annoying @threadSafe and checksum failure warning messages -->
<logger name="org.apache.maven.lifecycle.internal.builder.BuilderCommon" level="ERROR" />
<logger name="org.eclipse.aether.internal.impl.WarnChecksumPolicy" level="ERROR" />
</configuration>

View File

@@ -41,10 +41,6 @@
</dependency>
<!-- Logging -->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>log4j-over-slf4j</artifactId>
@@ -59,4 +55,59 @@
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>3.6.0</version>
<executions>
<execution>
<id>extract</id>
<goals>
<goal>unpack</goal>
</goals>
<configuration>
<artifactItems>
<artifactItem>
<groupId>org.apache.maven</groupId>
<artifactId>maven-slf4j-wrapper</artifactId>
<version>${maven4.version}</version>
<classifier>sources</classifier>
</artifactItem>
<artifactItem>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>${slf4j.version}</version>
<classifier>sources</classifier>
</artifactItem>
</artifactItems>
<includes>org/apache/maven/logwrapper/*.java,org/slf4j/impl/*.java</includes>
<excludes>**/StaticLoggerBinder.java,**/StaticMDCBinder.java</excludes>
<outputDirectory>${project.build.directory}/generated-sources/unpack</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<version>3.4.0</version>
<executions>
<execution>
<id>add-unpacked-source-dir</id>
<goals>
<goal>add-source</goal>
</goals>
<configuration>
<sources>
<source>${project.build.directory}/generated-sources/unpack</source>
</sources>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

View File

@@ -1,69 +0,0 @@
/*
* 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.
*/
package org.mvndaemon.mvnd.logging.internal;
import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.classic.spi.IThrowableProxy;
import ch.qos.logback.classic.spi.ThrowableProxyUtil;
import ch.qos.logback.core.AppenderBase;
import ch.qos.logback.core.CoreConstants;
import static org.apache.maven.shared.utils.logging.MessageUtils.level;
/**
* This appender acts like the slf4j simple logger.
* It's used
*/
public class SimpleAppender extends AppenderBase<ILoggingEvent> {
@Override
protected void append(ILoggingEvent eventObject) {
StringBuilder buf = new StringBuilder();
buf.append('[');
buf.append(renderLevel(eventObject.getLevel()));
buf.append(']');
buf.append(' ');
buf.append(eventObject.getFormattedMessage());
buf.append(CoreConstants.LINE_SEPARATOR);
IThrowableProxy tp = eventObject.getThrowableProxy();
if (tp != null) {
buf.append(CoreConstants.LINE_SEPARATOR);
buf.append(ThrowableProxyUtil.asString(tp));
}
System.out.print(buf.toString());
}
private String renderLevel(Level level) {
switch (level.toInt()) {
case Level.TRACE_INT:
return level().debug("TRACE");
case Level.DEBUG_INT:
return level().debug("DEBUG");
case Level.INFO_INT:
return level().info("INFO");
case Level.WARN_INT:
return level().warning("WARNING");
case Level.ERROR_INT:
return level().error("ERROR");
default:
throw new IllegalStateException("Level " + level + " is unknown.");
}
}
}

View File

@@ -18,24 +18,13 @@
*/
package org.mvndaemon.mvnd.logging.smart;
import java.util.Map;
import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.Logger;
import ch.qos.logback.classic.PatternLayout;
import ch.qos.logback.classic.pattern.ClassicConverter;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.AppenderBase;
import ch.qos.logback.core.Context;
import org.apache.maven.shared.utils.logging.LoggerLevelRenderer;
import org.apache.maven.shared.utils.logging.MessageUtils;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;
import org.slf4j.impl.MvndSimpleLogger;
/**
* Forwards log messages to the client.
*/
public class ProjectBuildLogAppender extends AppenderBase<ILoggingEvent> implements AutoCloseable {
public class ProjectBuildLogAppender implements AutoCloseable {
private static final String KEY_PROJECT_ID = "maven.project.id";
private static final ThreadLocal<String> PROJECT_ID = new InheritableThreadLocal<>();
@@ -80,71 +69,20 @@ public class ProjectBuildLogAppender extends AppenderBase<ILoggingEvent> impleme
}
}
private static final String pattern = "[%level] %msg%n";
private final PatternLayout layout;
private final BuildEventListener buildEventListener;
public ProjectBuildLogAppender(BuildEventListener buildEventListener) {
this.buildEventListener = buildEventListener;
this.name = ProjectBuildLogAppender.class.getName();
this.context = (Context) LoggerFactory.getILoggerFactory();
MvndSimpleLogger.setLogSink(this::accept);
}
final PatternLayout l = new PatternLayout();
l.setContext(context);
l.setPattern(pattern);
final Map<String, String> instanceConverterMap = l.getInstanceConverterMap();
final String levelConverterClassName = LevelConverter.class.getName();
instanceConverterMap.put("level", levelConverterClassName);
instanceConverterMap.put("le", levelConverterClassName);
instanceConverterMap.put("p", levelConverterClassName);
this.layout = l;
final Logger root = (Logger) LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME);
root.addAppender(this);
start();
protected void accept(String message) {
String projectId = MDC.get(KEY_PROJECT_ID);
buildEventListener.projectLogMessage(projectId, message);
}
@Override
public void start() {
layout.start();
super.start();
}
@Override
protected void append(ILoggingEvent event) {
String projectId = event.getMDCPropertyMap().get(KEY_PROJECT_ID);
buildEventListener.projectLogMessage(projectId, layout.doLayout(event));
}
public static class LevelConverter extends ClassicConverter {
@Override
public String convert(ILoggingEvent event) {
LoggerLevelRenderer llr = MessageUtils.level();
Level level = event.getLevel();
switch (level.toInt()) {
case Level.ERROR_INT:
return llr.error(level.toString());
case Level.WARN_INT:
return llr.warning(level.toString());
case Level.INFO_INT:
return llr.info(level.toString());
default:
return llr.debug(level.toString());
}
}
}
@Override
public void close() {
stop();
final Logger root = (Logger) LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME);
root.detachAppender(this);
}
@Override
public void stop() {
layout.stop();
super.stop();
public void close() throws Exception {
MvndSimpleLogger.setLogSink(null);
}
}

View File

@@ -0,0 +1,299 @@
/*
* 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.
*/
package org.slf4j.impl;
import org.slf4j.event.LoggingEvent;
import org.slf4j.helpers.FormattingTuple;
import org.slf4j.helpers.MarkerIgnoringBase;
import org.slf4j.helpers.MessageFormatter;
import org.slf4j.spi.LocationAwareLogger;
public abstract class MvndBaseLogger extends MarkerIgnoringBase {
protected static final int LOG_LEVEL_TRACE = LocationAwareLogger.TRACE_INT;
protected static final int LOG_LEVEL_DEBUG = LocationAwareLogger.DEBUG_INT;
protected static final int LOG_LEVEL_INFO = LocationAwareLogger.INFO_INT;
protected static final int LOG_LEVEL_WARN = LocationAwareLogger.WARN_INT;
protected static final int LOG_LEVEL_ERROR = LocationAwareLogger.ERROR_INT;
/** The current log level */
protected int currentLogLevel = LOG_LEVEL_INFO;
public MvndBaseLogger(String name) {
this.name = name;
}
protected void formatAndLog(int level, String format, Object arg1, Object arg2) {
if (!isLevelEnabled(level)) {
return;
}
FormattingTuple tp = MessageFormatter.format(format, arg1, arg2);
log(level, tp.getMessage(), tp.getThrowable());
}
protected void formatAndLog(int level, String format, Object... arguments) {
if (!isLevelEnabled(level)) {
return;
}
FormattingTuple tp = MessageFormatter.arrayFormat(format, arguments);
log(level, tp.getMessage(), tp.getThrowable());
}
protected void log(int level, String message, Throwable t) {
if (!isLevelEnabled(level)) {
return;
}
doLog(level, message, t);
}
protected abstract void doLog(int level, String message, Throwable t);
/**
* Is the given log level currently enabled?
*
* @param logLevel
* is this level enabled?
*/
protected boolean isLevelEnabled(int logLevel) {
// log level are numerically ordered so can use simple numeric
// comparison
return (logLevel >= currentLogLevel);
}
/** Are {@code trace} messages currently enabled? */
public boolean isTraceEnabled() {
return isLevelEnabled(LOG_LEVEL_TRACE);
}
/**
* A simple implementation which logs messages of level TRACE according to
* the format outlined above.
*/
public void trace(String msg) {
log(LOG_LEVEL_TRACE, msg, null);
}
/**
* Perform single parameter substitution before logging the message of level
* TRACE according to the format outlined above.
*/
public void trace(String format, Object param1) {
formatAndLog(LOG_LEVEL_TRACE, format, param1, null);
}
/**
* Perform double parameter substitution before logging the message of level
* TRACE according to the format outlined above.
*/
public void trace(String format, Object param1, Object param2) {
formatAndLog(LOG_LEVEL_TRACE, format, param1, param2);
}
/**
* Perform double parameter substitution before logging the message of level
* TRACE according to the format outlined above.
*/
public void trace(String format, Object... argArray) {
formatAndLog(LOG_LEVEL_TRACE, format, argArray);
}
/** Log a message of level TRACE, including an exception. */
public void trace(String msg, Throwable t) {
log(LOG_LEVEL_TRACE, msg, t);
}
/** Are {@code debug} messages currently enabled? */
public boolean isDebugEnabled() {
return isLevelEnabled(LOG_LEVEL_DEBUG);
}
/**
* A simple implementation which logs messages of level DEBUG according to
* the format outlined above.
*/
public void debug(String msg) {
log(LOG_LEVEL_DEBUG, msg, null);
}
/**
* Perform single parameter substitution before logging the message of level
* DEBUG according to the format outlined above.
*/
public void debug(String format, Object param1) {
formatAndLog(LOG_LEVEL_DEBUG, format, param1, null);
}
/**
* Perform double parameter substitution before logging the message of level
* DEBUG according to the format outlined above.
*/
public void debug(String format, Object param1, Object param2) {
formatAndLog(LOG_LEVEL_DEBUG, format, param1, param2);
}
/**
* Perform double parameter substitution before logging the message of level
* DEBUG according to the format outlined above.
*/
public void debug(String format, Object... argArray) {
formatAndLog(LOG_LEVEL_DEBUG, format, argArray);
}
/** Log a message of level DEBUG, including an exception. */
public void debug(String msg, Throwable t) {
log(LOG_LEVEL_DEBUG, msg, t);
}
/** Are {@code info} messages currently enabled? */
public boolean isInfoEnabled() {
return isLevelEnabled(LOG_LEVEL_INFO);
}
/**
* A simple implementation which logs messages of level INFO according to
* the format outlined above.
*/
public void info(String msg) {
log(LOG_LEVEL_INFO, msg, null);
}
/**
* Perform single parameter substitution before logging the message of level
* INFO according to the format outlined above.
*/
public void info(String format, Object arg) {
formatAndLog(LOG_LEVEL_INFO, format, arg, null);
}
/**
* Perform double parameter substitution before logging the message of level
* INFO according to the format outlined above.
*/
public void info(String format, Object arg1, Object arg2) {
formatAndLog(LOG_LEVEL_INFO, format, arg1, arg2);
}
/**
* Perform double parameter substitution before logging the message of level
* INFO according to the format outlined above.
*/
public void info(String format, Object... argArray) {
formatAndLog(LOG_LEVEL_INFO, format, argArray);
}
/** Log a message of level INFO, including an exception. */
public void info(String msg, Throwable t) {
log(LOG_LEVEL_INFO, msg, t);
}
/** Are {@code warn} messages currently enabled? */
public boolean isWarnEnabled() {
return isLevelEnabled(LOG_LEVEL_WARN);
}
/**
* A simple implementation which always logs messages of level WARN
* according to the format outlined above.
*/
public void warn(String msg) {
log(LOG_LEVEL_WARN, msg, null);
}
/**
* Perform single parameter substitution before logging the message of level
* WARN according to the format outlined above.
*/
public void warn(String format, Object arg) {
formatAndLog(LOG_LEVEL_WARN, format, arg, null);
}
/**
* Perform double parameter substitution before logging the message of level
* WARN according to the format outlined above.
*/
public void warn(String format, Object arg1, Object arg2) {
formatAndLog(LOG_LEVEL_WARN, format, arg1, arg2);
}
/**
* Perform double parameter substitution before logging the message of level
* WARN according to the format outlined above.
*/
public void warn(String format, Object... argArray) {
formatAndLog(LOG_LEVEL_WARN, format, argArray);
}
/** Log a message of level WARN, including an exception. */
public void warn(String msg, Throwable t) {
log(LOG_LEVEL_WARN, msg, t);
}
/** Are {@code error} messages currently enabled? */
public boolean isErrorEnabled() {
return isLevelEnabled(LOG_LEVEL_ERROR);
}
/**
* A simple implementation which always logs messages of level ERROR
* according to the format outlined above.
*/
public void error(String msg) {
log(LOG_LEVEL_ERROR, msg, null);
}
/**
* Perform single parameter substitution before logging the message of level
* ERROR according to the format outlined above.
*/
public void error(String format, Object arg) {
formatAndLog(LOG_LEVEL_ERROR, format, arg, null);
}
/**
* Perform double parameter substitution before logging the message of level
* ERROR according to the format outlined above.
*/
public void error(String format, Object arg1, Object arg2) {
formatAndLog(LOG_LEVEL_ERROR, format, arg1, arg2);
}
/**
* Perform double parameter substitution before logging the message of level
* ERROR according to the format outlined above.
*/
public void error(String format, Object... argArray) {
formatAndLog(LOG_LEVEL_ERROR, format, argArray);
}
/** Log a message of level ERROR, including an exception. */
public void error(String msg, Throwable t) {
log(LOG_LEVEL_ERROR, msg, t);
}
public void log(LoggingEvent event) {
int levelInt = event.getLevel().toInt();
if (!isLevelEnabled(levelInt)) {
return;
}
FormattingTuple tp =
MessageFormatter.arrayFormat(event.getMessage(), event.getArgumentArray(), event.getThrowable());
log(levelInt, tp.getMessage(), event.getThrowable());
}
}

View File

@@ -16,32 +16,36 @@
* specific language governing permissions and limitations
* under the License.
*/
package org.mvndaemon.mvnd.logging.internal;
package org.slf4j.impl;
import org.apache.maven.cli.logging.Slf4jConfiguration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.ILoggerFactory;
public class MvndSlf4jConfiguration implements Slf4jConfiguration {
public class MvndConfiguration implements Slf4jConfiguration {
@Override
public void setRootLoggerLevel(Level level) {
ch.qos.logback.classic.Level value;
String value;
switch (level) {
case DEBUG:
value = ch.qos.logback.classic.Level.DEBUG;
value = "debug";
break;
case INFO:
value = ch.qos.logback.classic.Level.INFO;
value = "info";
break;
default:
value = ch.qos.logback.classic.Level.ERROR;
value = "error";
break;
}
((ch.qos.logback.classic.Logger) LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME)).setLevel(value);
System.setProperty("org.slf4j.simpleLogger.defaultLogLevel", value);
}
@Override
public void activate() {}
public void activate() {
ILoggerFactory lf = StaticLoggerBinder.getSingleton().getLoggerFactory();
if (lf instanceof MvndLoggerFactory) {
((MvndLoggerFactory) lf).reconfigure();
}
}
}

View File

@@ -0,0 +1,71 @@
/*
* 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.
*/
package org.slf4j.impl;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
public class MvndDaemonLogger extends MvndBaseLogger {
final DateTimeFormatter dateTimeFormatter =
new DateTimeFormatterBuilder().appendPattern("HH:mm:ss.SSS").toFormatter();
PrintStream printStream;
public MvndDaemonLogger(String name) {
super(name);
}
@Override
protected void doLog(int level, String message, Throwable t) {
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
pw.append(dateTimeFormatter.format(LocalTime.now()));
pw.append(" ");
switch (level) {
case LOG_LEVEL_ERROR:
pw.append("E");
break;
case LOG_LEVEL_WARN:
pw.append("W");
break;
case LOG_LEVEL_INFO:
pw.append("I");
break;
case LOG_LEVEL_DEBUG:
pw.append("D");
break;
case LOG_LEVEL_TRACE:
pw.append("T");
break;
}
pw.append(" ");
pw.append(message);
if (t != null) {
t.printStackTrace(pw);
}
PrintStream printStream = MvndSimpleLogger.CONFIG_PARAMS.outputChoice.getTargetPrintStream();
printStream.println(sw);
printStream.flush();
}
}

View File

@@ -0,0 +1,129 @@
/*
* 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.
*/
package org.slf4j.impl;
import org.apache.maven.logwrapper.LogLevelRecorder;
import org.slf4j.event.Level;
/**
* A proxy which enhances the MavenSimpleLogger with functionality to track whether a logging threshold is hit.
* Currently only support WARN and ERROR states, since it's been used for the --fail-on-severity flag.
*/
public class MvndFailOnSeverityLogger extends MvndSimpleLogger {
private final LogLevelRecorder logLevelRecorder;
MvndFailOnSeverityLogger(String name, LogLevelRecorder logLevelRecorder) {
super(name);
this.logLevelRecorder = logLevelRecorder;
}
/**
* A simple implementation which always logs messages of level WARN
* according to the format outlined above.
*/
@Override
public void warn(String msg) {
super.warn(msg);
logLevelRecorder.record(Level.WARN);
}
/**
* Perform single parameter substitution before logging the message of level
* WARN according to the format outlined above.
*/
@Override
public void warn(String format, Object arg) {
super.warn(format, arg);
logLevelRecorder.record(Level.WARN);
}
/**
* Perform double parameter substitution before logging the message of level
* WARN according to the format outlined above.
*/
@Override
public void warn(String format, Object arg1, Object arg2) {
super.warn(format, arg1, arg2);
logLevelRecorder.record(Level.WARN);
}
/**
* Perform double parameter substitution before logging the message of level
* WARN according to the format outlined above.
*/
@Override
public void warn(String format, Object... argArray) {
super.warn(format, argArray);
logLevelRecorder.record(Level.WARN);
}
/** Log a message of level WARN, including an exception. */
@Override
public void warn(String msg, Throwable t) {
super.warn(msg, t);
logLevelRecorder.record(Level.WARN);
}
/**
* A simple implementation which always logs messages of level ERROR
* according to the format outlined above.
*/
@Override
public void error(String msg) {
super.error(msg);
logLevelRecorder.record(Level.ERROR);
}
/**
* Perform single parameter substitution before logging the message of level
* ERROR according to the format outlined above.
*/
@Override
public void error(String format, Object arg) {
super.error(format, arg);
logLevelRecorder.record(Level.ERROR);
}
/**
* Perform double parameter substitution before logging the message of level
* ERROR according to the format outlined above.
*/
@Override
public void error(String format, Object arg1, Object arg2) {
super.error(format, arg1, arg2);
logLevelRecorder.record(Level.ERROR);
}
/**
* Perform double parameter substitution before logging the message of level
* ERROR according to the format outlined above.
*/
@Override
public void error(String format, Object... argArray) {
super.error(format, argArray);
logLevelRecorder.record(Level.ERROR);
}
/** Log a message of level ERROR, including an exception. */
@Override
public void error(String msg, Throwable t) {
super.error(msg, t);
logLevelRecorder.record(Level.ERROR);
}
}

View File

@@ -0,0 +1,81 @@
/*
* 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.
*/
package org.slf4j.impl;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import org.apache.maven.logwrapper.LogLevelRecorder;
import org.apache.maven.logwrapper.MavenSlf4jWrapperFactory;
import org.slf4j.Logger;
/**
* LogFactory for Maven which can create a simple logger or one which, if set, fails the build on a severity threshold.
*/
public class MvndLoggerFactory implements MavenSlf4jWrapperFactory {
private LogLevelRecorder logLevelRecorder = null;
private final ConcurrentMap<String, Logger> loggerMap = new ConcurrentHashMap<>();
public MvndLoggerFactory() {
MvndSimpleLogger.lazyInit();
}
@Override
public void setLogLevelRecorder(LogLevelRecorder logLevelRecorder) {
if (this.logLevelRecorder != null) {
throw new IllegalStateException("LogLevelRecorder has already been set.");
}
this.logLevelRecorder = logLevelRecorder;
}
@Override
public Optional<LogLevelRecorder> getLogLevelRecorder() {
return Optional.ofNullable(logLevelRecorder);
}
/**
* Return an appropriate {@link Logger} instance by name.
*/
@Override
public Logger getLogger(String name) {
return loggerMap.computeIfAbsent(name, this::getNewLoggingInstance);
}
private Logger getNewLoggingInstance(String name) {
if (name.startsWith("org.mvndaemon.mvnd.daemon")) {
return new MvndDaemonLogger(name);
} else if (logLevelRecorder == null) {
return new MvndSimpleLogger(name);
} else {
return new MvndFailOnSeverityLogger(name, logLevelRecorder);
}
}
public void reconfigure() {
SimpleLoggerConfiguration config = MvndSimpleLogger.CONFIG_PARAMS;
config.init();
loggerMap.values().forEach(l -> {
if (l instanceof MvndSimpleLogger) {
((MvndSimpleLogger) l).configure(config.defaultLogLevel);
}
});
}
}

View File

@@ -0,0 +1,236 @@
/*
* 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.
*/
package org.slf4j.impl;
import java.util.Date;
import java.util.function.Consumer;
import org.apache.maven.shared.utils.logging.MessageBuilder;
import org.apache.maven.shared.utils.logging.MessageUtils;
import static org.apache.maven.shared.utils.logging.MessageUtils.level;
/**
* Logger for Maven, that support colorization of levels and stacktraces. This class implements 2 methods introduced in
* slf4j-simple provider local copy.
*
* @since 3.5.0
*/
public class MvndSimpleLogger extends MvndBaseLogger {
static final String TID_PREFIX = "tid=";
static long START_TIME = System.currentTimeMillis();
static boolean INITIALIZED = false;
static final SimpleLoggerConfiguration CONFIG_PARAMS = new SimpleLoggerConfiguration();
static void lazyInit() {
if (INITIALIZED) {
return;
}
INITIALIZED = true;
init();
}
// external software might be invoking this method directly. Do not rename
// or change its semantics.
static void init() {
CONFIG_PARAMS.init();
}
static Consumer<String> LOG_SINK;
public static void setLogSink(Consumer<String> logSink) {
LOG_SINK = logSink;
}
/** The short name of this simple log instance */
private transient String shortLogName = null;
MvndSimpleLogger(String name) {
super(name);
configure(CONFIG_PARAMS.defaultLogLevel);
}
String recursivelyComputeLevelString() {
String tempName = name;
String levelString = null;
int indexOfLastDot = tempName.length();
while ((levelString == null) && (indexOfLastDot > -1)) {
tempName = tempName.substring(0, indexOfLastDot);
levelString = CONFIG_PARAMS.getStringProperty(SimpleLogger.LOG_KEY_PREFIX + tempName, null);
indexOfLastDot = tempName.lastIndexOf(".");
}
return levelString;
}
@Override
protected void doLog(int level, String message, Throwable t) {
StringBuilder buf = new StringBuilder(32);
// Append date-time if so configured
if (CONFIG_PARAMS.showDateTime) {
if (CONFIG_PARAMS.dateFormatter != null) {
buf.append(getFormattedDate());
buf.append(' ');
} else {
buf.append(System.currentTimeMillis() - START_TIME);
buf.append(' ');
}
}
// Append current thread name if so configured
if (CONFIG_PARAMS.showThreadName) {
buf.append('[');
buf.append(Thread.currentThread().getName());
buf.append("] ");
}
if (CONFIG_PARAMS.showThreadId) {
buf.append(TID_PREFIX);
buf.append(Thread.currentThread().getId());
buf.append(' ');
}
if (CONFIG_PARAMS.levelInBrackets) buf.append('[');
// Append a readable representation of the log level
String levelStr = renderLevel(level);
buf.append(levelStr);
if (CONFIG_PARAMS.levelInBrackets) buf.append(']');
buf.append(' ');
// Append the name of the log instance if so configured
if (CONFIG_PARAMS.showShortLogName) {
if (shortLogName == null) shortLogName = computeShortName();
buf.append(String.valueOf(shortLogName)).append(" - ");
} else if (CONFIG_PARAMS.showLogName) {
buf.append(String.valueOf(name)).append(" - ");
}
// Append the message
buf.append(message);
writeThrowable(t, buf);
Consumer<String> sink = LOG_SINK;
if (sink != null) {
sink.accept(buf.toString());
} else {
CONFIG_PARAMS.outputChoice.getTargetPrintStream().println(buf.toString());
}
}
protected String getFormattedDate() {
Date now = new Date();
return CONFIG_PARAMS.dateFormatter.format(now);
}
private String computeShortName() {
return name.substring(name.lastIndexOf(".") + 1);
}
protected String renderLevel(int level) {
switch (level) {
case LOG_LEVEL_TRACE:
return level().debug("TRACE").toString();
case LOG_LEVEL_DEBUG:
return level().debug("DEBUG").toString();
case LOG_LEVEL_INFO:
return level().info("INFO").toString();
case LOG_LEVEL_WARN:
return level().warning("WARNING").toString();
case LOG_LEVEL_ERROR:
default:
return level().error("ERROR").toString();
}
}
protected void writeThrowable(Throwable t, StringBuilder sb) {
if (t == null) {
return;
}
MessageBuilder builder = MessageUtils.buffer(sb);
builder.failure(t.getClass().getName());
if (t.getMessage() != null) {
builder.a(": ");
builder.failure(t.getMessage());
}
builder.newline();
printStackTrace(t, builder, "");
}
private void printStackTrace(Throwable t, MessageBuilder builder, String prefix) {
for (StackTraceElement e : t.getStackTrace()) {
builder.a(prefix);
builder.a(" ");
builder.strong("at");
builder.a(" " + e.getClassName() + "." + e.getMethodName());
builder.a(" (").strong(getLocation(e)).a(")");
builder.newline();
}
for (Throwable se : t.getSuppressed()) {
writeThrowable(se, builder, "Suppressed", prefix + " ");
}
Throwable cause = t.getCause();
if (cause != null) {
writeThrowable(cause, builder, "Caused by", prefix);
}
}
private void writeThrowable(Throwable t, MessageBuilder builder, String caption, String prefix) {
builder.a(prefix).strong(caption).a(": ").a(t.getClass().getName());
if (t.getMessage() != null) {
builder.a(": ");
builder.failure(t.getMessage());
}
builder.newline();
printStackTrace(t, builder, prefix);
}
protected String getLocation(final StackTraceElement e) {
assert e != null;
if (e.isNativeMethod()) {
return "Native Method";
} else if (e.getFileName() == null) {
return "Unknown Source";
} else if (e.getLineNumber() >= 0) {
return String.format("%s:%s", e.getFileName(), e.getLineNumber());
} else {
return e.getFileName();
}
}
public void configure(int defaultLogLevel) {
String levelString = recursivelyComputeLevelString();
if (levelString != null) {
this.currentLogLevel = SimpleLoggerConfiguration.stringToLevel(levelString);
} else {
this.currentLogLevel = defaultLogLevel;
}
}
public void setLogLevel(int logLevel) {
this.currentLogLevel = logLevel;
}
}

View File

@@ -0,0 +1,82 @@
/*
* 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.
*/
package org.slf4j.impl;
import org.slf4j.ILoggerFactory;
import org.slf4j.spi.LoggerFactoryBinder;
/**
* SLF4J LoggerFactoryBinder implementation using MavenSimpleLogger.
* This class is part of the required classes used to specify an
* SLF4J logger provider implementation.
*
* @since 3.5.1
*/
public final class StaticLoggerBinder implements LoggerFactoryBinder {
/**
* Declare the version of the SLF4J API this implementation is compiled
* against. The value of this field is usually modified with each release.
*/
// to avoid constant folding by the compiler, this field must *not* be final
@SuppressWarnings({"checkstyle:staticvariablename", "checkstyle:visibilitymodifier"})
public static String REQUESTED_API_VERSION = "1.7.25"; // !final
private static final String LOGGER_FACTORY_CLASS_STR = MvndLoggerFactory.class.getName();
/**
* The unique instance of this class.
*/
private static final StaticLoggerBinder SINGLETON = new StaticLoggerBinder();
/**
* The ILoggerFactory instance returned by the {@link #getLoggerFactory}
* method should always be the same object
*/
private final ILoggerFactory loggerFactory;
/**
* Private constructor to prevent instantiation
*/
private StaticLoggerBinder() {
loggerFactory = new MvndLoggerFactory();
}
/**
* Returns the singleton of this class.
*/
public static StaticLoggerBinder getSingleton() {
return SINGLETON;
}
/**
* Returns the factory.
*/
@Override
public ILoggerFactory getLoggerFactory() {
return loggerFactory;
}
/**
* Returns the class name.
*/
@Override
public String getLoggerFactoryClassStr() {
return LOGGER_FACTORY_CLASS_STR;
}
}

View File

@@ -0,0 +1,57 @@
/*
* 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.
*/
package org.slf4j.impl;
import org.slf4j.helpers.BasicMDCAdapter;
import org.slf4j.spi.MDCAdapter;
/**
* This implementation is bound to {@link BasicMDCAdapter}.
*/
public class StaticMDCBinder {
/**
* The unique instance of this class.
*/
public static final StaticMDCBinder SINGLETON = new StaticMDCBinder();
private StaticMDCBinder() {}
/**
* Return the singleton of this class.
*
* @return the StaticMDCBinder singleton
* @since 1.7.14
*/
public static final StaticMDCBinder getSingleton() {
return SINGLETON;
}
/**
* Currently this method always returns an instance of
* {@link StaticMDCBinder}.
*/
public MDCAdapter getMDCA() {
return new BasicMDCAdapter();
}
public String getMDCAdapterClassStr() {
return BasicMDCAdapter.class.getName();
}
}

View File

@@ -0,0 +1,20 @@
# 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.
# key = Slf4j effective logger factory implementation
# value = corresponding o.a.m.cli.logging.Slf4jConfiguration class
org.slf4j.impl.MvndLoggerFactory org.slf4j.impl.MvndConfiguration

11
pom.xml
View File

@@ -87,7 +87,6 @@
<jansi.version>2.4.0</jansi.version>
<jline.version>3.23.0</jline.version>
<junit.jupiter.version>5.9.2</junit.jupiter.version>
<logback.version>1.2.11</logback.version>
<maven.version>4.0.0-alpha-7</maven.version>
<maven3.version>3.9.3</maven3.version>
<maven4.version>${maven.version}</maven4.version>
@@ -122,16 +121,6 @@
<dependencyManagement>
<dependencies>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>${logback.version}</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>${logback.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>