Skip to content

Commit

Permalink
Merge pull request #74 from alechenninger/verbose
Browse files Browse the repository at this point in the history
Fixes #73: Add verbose flag
  • Loading branch information
alechenninger authored Jan 15, 2017
2 parents 5c068a4 + 393ef9e commit 87e0c10
Show file tree
Hide file tree
Showing 9 changed files with 244 additions and 58 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,12 @@
import io.github.alechenninger.monarch.yaml.YamlConfiguration;
import net.sourceforge.argparse4j.ArgumentParsers;
import net.sourceforge.argparse4j.impl.Arguments;
import net.sourceforge.argparse4j.impl.action.StoreTrueArgumentAction;
import net.sourceforge.argparse4j.inf.Argument;
import net.sourceforge.argparse4j.inf.ArgumentAction;
import net.sourceforge.argparse4j.inf.ArgumentParser;
import net.sourceforge.argparse4j.inf.ArgumentParserException;
import net.sourceforge.argparse4j.inf.MutuallyExclusiveGroup;
import net.sourceforge.argparse4j.inf.Namespace;
import net.sourceforge.argparse4j.inf.Subparser;
import net.sourceforge.argparse4j.inf.Subparsers;
Expand All @@ -42,6 +44,7 @@
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.logging.Level;
import java.util.stream.Collectors;

public class ArgParseMonarchArgParser implements MonarchArgParser {
Expand Down Expand Up @@ -69,11 +72,27 @@ public CommandInput parse(String[] args) throws MonarchArgParserException {
.action(new AbortParsingAction(Arguments.storeTrue()))
.help("Show this message and exit.");

parser.addArgument("--version")
parser.addArgument("-v", "--version")
.dest("show_version")
.action(new AbortParsingAction(Arguments.storeTrue()))
.help("Show the running version of monarch and exit.");

MutuallyExclusiveGroup logGroup = parser.addMutuallyExclusiveGroup("logging flags")
.description("Control log levels. Without either flag, some logs are written. " +
"Errors and warnings are output to stderr.");

logGroup.addArgument("--verbose")
.action(new StoreTrueArgumentAction())
.setDefault(false)
.dest("verbose")
.help("Log everything. Useful to understand what your changeset is doing.");

logGroup.addArgument("--quiet")
.action(new StoreTrueArgumentAction())
.setDefault(false)
.dest("quiet")
.help("Log nothing.");

Subparsers subparsers = parser.addSubparsers().dest(SUBPARSER_DEST)
.title("commands")
.description("If none chosen, defaults to '" + applySpec.name() + "'")
Expand Down Expand Up @@ -130,6 +149,19 @@ public boolean isVersionRequested() {
public String getVersionMessage() {
return parser.formatVersion() + '\n';
}

@Override
public Optional<Level> getLogLevel() {
if (parsed.getBoolean("verbose")) {
return Optional.of(Level.ALL);
}

if (parsed.getBoolean("quiet")) {
return Optional.of(Level.OFF);
}

return Optional.of(Level.INFO);
}
};
} catch (ArgumentParserException e) {
try {
Expand Down
6 changes: 6 additions & 0 deletions bin/src/io/github/alechenninger/monarch/CommandInput.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
import io.github.alechenninger.monarch.set.UpdateSetInput;

import java.util.List;
import java.util.Optional;
import java.util.logging.Level;

public interface CommandInput {
List<ApplyChangesInput> getApplyCommands();
Expand All @@ -35,4 +37,8 @@ public interface CommandInput {
boolean isVersionRequested();

String getVersionMessage();

default Optional<Level> getLogLevel() {
return Optional.empty();
}
}
69 changes: 13 additions & 56 deletions bin/src/io/github/alechenninger/monarch/Main.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

import io.github.alechenninger.monarch.apply.ApplyChangesInput;
import io.github.alechenninger.monarch.apply.ApplyChangesOptions;
import io.github.alechenninger.monarch.logging.Logging;
import io.github.alechenninger.monarch.set.UpdateSetInput;
import io.github.alechenninger.monarch.set.UpdateSetOptions;
import io.github.alechenninger.monarch.yaml.YamlConfiguration;
Expand All @@ -31,9 +32,6 @@
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.nio.file.FileSystem;
import java.nio.file.FileSystems;
import java.nio.file.Files;
Expand All @@ -47,12 +45,7 @@
import java.util.Optional;
import java.util.Set;
import java.util.function.Supplier;
import java.util.logging.Formatter;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.LogRecord;
import java.util.logging.Logger;
import java.util.logging.StreamHandler;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;

Expand All @@ -62,21 +55,22 @@ public class Main {
private final Monarch monarch;
private final DataFormats dataFormats;
private final Yaml yaml;

private final MonarchArgParser parser;

private static final org.slf4j.Logger log = LoggerFactory.getLogger(Main.class);

// TODO: Don't use yaml directly for update changeset?
public Main(Monarch monarch, Yaml yaml, String defaultConfigPath, FileSystem fileSystem,
DataFormats dataFormats, OutputStream stdout) {
DataFormats dataFormats, OutputStream stdout, OutputStream stderr) {
this.monarch = monarch;
this.yaml = yaml;
this.dataFormats = dataFormats;
this.defaultConfigPath = fileSystem.getPath(defaultConfigPath);
this.fileSystem = fileSystem;
this.parser = new ArgParseMonarchArgParser(new DefaultAppInfo());

configureLogging(stdout);
Logging.outputTo(stdout, stderr);
Logging.setLevel(Level.INFO);
}

public int run(String argsSpaceDelimited) {
Expand All @@ -89,12 +83,14 @@ public int run(String... args) {
try {
commandInput = parser.parse(args);
} catch (MonarchArgParserException e) {
log.error(e.getMessage(), e);
log.error("Error parsing arguments.", e);
log.info("");
log.info(e.getHelpMessage());
return 2;
}

commandInput.getLogLevel().ifPresent(Logging::setLevel);

if (commandInput.isHelpRequested()) {
log.info(commandInput.getHelpMessage());
}
Expand All @@ -121,7 +117,7 @@ public int run(String... args) {
updateSetInChange(source, outputPath, options.changes(), options.putInSet(),
options.removeFromSet(), options.hierarchy());
} catch (Exception e) {
log.error(e.getMessage(), e);
log.error("Error while updating 'set' in change.", e);
return 2;
}
}
Expand Down Expand Up @@ -157,7 +153,7 @@ public int run(String... args) {

applyChanges(outputDir, options.changes(), options.mergeKeys(), currentData, target);
} catch (Exception e) {
printError(e);
log.error("Error while applying changes.", e);
return 2;
}
}
Expand Down Expand Up @@ -200,7 +196,7 @@ private void applyChanges(Path outputDir, Iterable<Change> changes, Set<String>
continue;
}

log.info("Writing result source data for {} to {}", path, outPath);
log.debug("Writing result source data for {} to {}", path, outPath);

try {
ByteArrayOutputStream out = new ByteArrayOutputStream();
Expand Down Expand Up @@ -241,7 +237,7 @@ private void updateSetInChange(SourceSpec source, Path outputPath, Iterable<Chan
}

if (hierarchy.map(h -> !h.sourceFor(source).isPresent()).orElse(false)) {
log.info("Warning: source not found in provided hierarchy. source=" + source);
log.warn("Source not found in provided hierarchy. source={}", source);
}

// Sort by hierarchy depth if provided, else sort alphabetically
Expand Down Expand Up @@ -286,10 +282,6 @@ private static Supplier<? extends RuntimeException> missingOptionException(Strin
return () -> new MonarchException("Missing required option: " + option);
}

private void printError(Throwable e) {
log.error(e.getMessage(), e);
}

public static void main(String[] args) throws IOException, ArgumentParserException {
DumperOptions dumperOptions = new DumperOptions();
dumperOptions.setPrettyFlow(true);
Expand All @@ -309,44 +301,9 @@ public Optional<YamlConfiguration> yamlConfiguration() {
return Optional.of(YamlConfiguration.DEFAULT);
}
}),
System.out)
System.out, System.err)
.run(args);

System.exit(exitCode);
}

private static void configureLogging(OutputStream stdout) {
Logger rootLogger = Logger.getLogger("");

for (Handler handler : rootLogger.getHandlers()) {
rootLogger.removeHandler(handler);
}

// TODO: Output errors to stderr
StreamHandler handler = new StreamHandler(stdout, new Formatter() {
@Override
public String format(LogRecord record) {
String levelPrefix = record.getLevel().intValue() >= Level.WARNING.intValue()
? record.getLevel().getLocalizedName() + ": "
: "";
Throwable thrown = record.getThrown();
String stackTrace = "";
if (thrown != null) {
StringWriter writer = new StringWriter();
thrown.printStackTrace(new PrintWriter(writer));
stackTrace = writer.toString();
}
return levelPrefix + record.getMessage() + '\n' + stackTrace;
}
}) {
@Override
public synchronized void publish(LogRecord record) {
super.publish(record);
flush();
}
};
handler.setLevel(Level.ALL);
rootLogger.addHandler(handler);
rootLogger.setLevel(Level.ALL);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*
* monarch - A tool for managing hierarchical data.
* Copyright (C) 2017 Alec Henninger
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

package io.github.alechenninger.monarch.logging;

import java.io.OutputStream;
import java.util.logging.Formatter;
import java.util.logging.LogRecord;
import java.util.logging.StreamHandler;

public class ImmediateFlushStreamHandler extends StreamHandler {
public ImmediateFlushStreamHandler(OutputStream out, Formatter formatter) {
super(out, formatter);
}

@Override
public synchronized void publish(LogRecord record) {
super.publish(record);
flush();
}
}
45 changes: 45 additions & 0 deletions bin/src/io/github/alechenninger/monarch/logging/Logging.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*
* monarch - A tool for managing hierarchical data.
* Copyright (C) 2017 Alec Henninger
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

package io.github.alechenninger.monarch.logging;

import java.io.OutputStream;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.Logger;

public abstract class Logging {
private static Logger rootLogger = Logger.getLogger("");

/**
* Configures warnings and above to {@code stderr}, everything else to {@code stdout}. For either
* output stream, only log record at or above {@code logLevel} are written.
*/
public static void outputTo(OutputStream stdout, OutputStream stderr) {
for (Handler handler : rootLogger.getHandlers()) {
rootLogger.removeHandler(handler);
}

rootLogger.addHandler(new MonarchStdoutLogHandler(stdout));
rootLogger.addHandler(new MonarchStderrLogHandler(stderr));
}

public static void setLevel(Level logLevel) {
rootLogger.setLevel(logLevel);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
* monarch - A tool for managing hierarchical data.
* Copyright (C) 2017 Alec Henninger
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

package io.github.alechenninger.monarch.logging;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.logging.Formatter;
import java.util.logging.Level;
import java.util.logging.LogRecord;

public class MonarchLogFormatter extends Formatter {
@Override
public String format(LogRecord record) {
String levelPrefix = record.getLevel().intValue() >= Level.WARNING.intValue()
? record.getLevel().getLocalizedName() + ": "
: "";
Throwable thrown = record.getThrown();
String stackTrace = "";
if (thrown != null) {
StringWriter writer = new StringWriter();
thrown.printStackTrace(new PrintWriter(writer));
stackTrace = writer.toString();
}
return levelPrefix + record.getMessage() + '\n' + stackTrace;
}
}
Loading

0 comments on commit 87e0c10

Please sign in to comment.