blob: 4475f6aba7d327870be86b38fcbd9cf9f3fc7ff9 [file] [log] [blame]
/*
* 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.apache.log4j.config;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.concurrent.atomic.AtomicInteger;
import org.apache.logging.log4j.core.config.ConfigurationException;
import org.apache.logging.log4j.core.config.builder.api.ConfigurationBuilder;
import org.apache.logging.log4j.core.config.builder.impl.BuiltConfiguration;
import org.apache.logging.log4j.core.tools.BasicCommandLineArguments;
import org.apache.logging.log4j.core.tools.picocli.CommandLine;
import org.apache.logging.log4j.core.tools.picocli.CommandLine.Command;
import org.apache.logging.log4j.core.tools.picocli.CommandLine.Option;
/**
* Tool for converting a Log4j 1.x properties configuration file to Log4j 2.x XML configuration file.
*
* <p>
* Run with "--help" on the command line.
* </p>
*
* <p>
* Example:
* </p>
*
* <pre>
* java org.apache.log4j.config.Log4j1ConfigurationConverter --recurse
* E:\vcs\git\apache\logging\logging-log4j2\log4j-1.2-api\src\test\resources\config-1.2\hadoop --in log4j.properties --verbose
* </pre>
*/
public final class Log4j1ConfigurationConverter {
@Command(name = "Log4j1ConfigurationConverter")
public static class CommandLineArguments extends BasicCommandLineArguments implements Runnable {
@Option(names = { "--failfast", "-f" }, description = "Fails on the first failure in recurse mode.")
private boolean failFast;
@Option(names = { "--in", "-i" }, description = "Specifies the input file.")
private Path pathIn;
@Option(names = { "--out", "-o" }, description = "Specifies the output file.")
private Path pathOut;
@Option(names = { "--recurse", "-r" }, description = "Recurses into this folder looking for the input file")
private Path recurseIntoPath;
@Option(names = { "--verbose", "-v" }, description = "Be verbose.")
private boolean verbose;
public Path getPathIn() {
return pathIn;
}
public Path getPathOut() {
return pathOut;
}
public Path getRecurseIntoPath() {
return recurseIntoPath;
}
public boolean isFailFast() {
return failFast;
}
public boolean isVerbose() {
return verbose;
}
public void setFailFast(final boolean failFast) {
this.failFast = failFast;
}
public void setPathIn(final Path pathIn) {
this.pathIn = pathIn;
}
public void setPathOut(final Path pathOut) {
this.pathOut = pathOut;
}
public void setRecurseIntoPath(final Path recurseIntoPath) {
this.recurseIntoPath = recurseIntoPath;
}
public void setVerbose(final boolean verbose) {
this.verbose = verbose;
}
@Override
public void run() {
if (isHelp()) {
CommandLine.usage(this, System.err);
return;
}
new Log4j1ConfigurationConverter(this).run();
}
@Override
public String toString() {
return "CommandLineArguments [recurseIntoPath=" + recurseIntoPath + ", verbose=" + verbose + ", pathIn="
+ pathIn + ", pathOut=" + pathOut + "]";
}
}
private static final String FILE_EXT_XML = ".xml";
public static void main(final String[] args) {
CommandLine.run(new CommandLineArguments(), System.err, args);
}
public static Log4j1ConfigurationConverter run(final CommandLineArguments cla) {
final Log4j1ConfigurationConverter log4j1ConfigurationConverter = new Log4j1ConfigurationConverter(cla);
log4j1ConfigurationConverter.run();
return log4j1ConfigurationConverter;
}
private final CommandLineArguments cla;
private Log4j1ConfigurationConverter(final CommandLineArguments cla) {
this.cla = cla;
}
protected void convert(final InputStream input, final OutputStream output) throws IOException {
final ConfigurationBuilder<BuiltConfiguration> builder = new Log4j1ConfigurationParser()
.buildConfigurationBuilder(input);
builder.writeXmlConfiguration(output);
}
InputStream getInputStream() throws IOException {
final Path pathIn = cla.getPathIn();
return pathIn == null ? System.in : new InputStreamWrapper(Files.newInputStream(pathIn), pathIn.toString());
}
OutputStream getOutputStream() throws IOException {
final Path pathOut = cla.getPathOut();
return pathOut == null ? System.out : Files.newOutputStream(pathOut);
}
private void run() {
if (cla.getRecurseIntoPath() != null) {
final AtomicInteger countOKs = new AtomicInteger();
final AtomicInteger countFails = new AtomicInteger();
try {
Files.walkFileTree(cla.getRecurseIntoPath(), new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult visitFile(final Path file, final BasicFileAttributes attrs)
throws IOException {
if (cla.getPathIn() == null || file.getFileName().equals(cla.getPathIn())) {
verbose("Reading %s", file);
String newFile = file.getFileName().toString();
final int lastIndex = newFile.lastIndexOf(".");
newFile = lastIndex < 0 ? newFile + FILE_EXT_XML
: newFile.substring(0, lastIndex) + FILE_EXT_XML;
final Path resolved = file.resolveSibling(newFile);
try (final InputStream input = new InputStreamWrapper(Files.newInputStream(file), file.toString());
final OutputStream output = Files.newOutputStream(resolved)) {
try {
convert(input, output);
countOKs.incrementAndGet();
} catch (ConfigurationException | IOException e) {
countFails.incrementAndGet();
if (cla.isFailFast()) {
throw e;
}
e.printStackTrace();
}
verbose("Wrote %s", resolved);
}
}
return FileVisitResult.CONTINUE;
}
});
} catch (final IOException e) {
throw new ConfigurationException(e);
} finally {
verbose("OK = %,d, Failures = %,d, Total = %,d", countOKs.get(), countFails.get(),
countOKs.get() + countFails.get());
}
} else {
verbose("Reading %s", cla.getPathIn());
try (final InputStream input = getInputStream(); final OutputStream output = getOutputStream()) {
convert(input, output);
} catch (final IOException e) {
throw new ConfigurationException(e);
}
verbose("Wrote %s", cla.getPathOut());
}
}
private void verbose(final String template, final Object... args) {
if (cla.isVerbose()) {
System.err.println(String.format(template, args));
}
}
}