Java tutorial
/* * Copyright (c) 2011-2014 Pivotal Software, Inc. * * 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. */ package reactor.logback; import ch.qos.logback.classic.BasicConfigurator; import ch.qos.logback.classic.Level; import ch.qos.logback.classic.Logger; import ch.qos.logback.classic.LoggerContext; import ch.qos.logback.classic.joran.JoranConfigurator; import ch.qos.logback.classic.spi.LoggingEvent; import ch.qos.logback.classic.spi.ThrowableProxy; import ch.qos.logback.core.Appender; import ch.qos.logback.core.joran.spi.JoranException; import ch.qos.logback.core.util.StatusPrinter; import net.openhft.chronicle.Chronicle; import net.openhft.chronicle.ChronicleQueueBuilder; import net.openhft.chronicle.ExcerptTailer; import net.openhft.chronicle.tools.ChronicleTools; import org.apache.commons.cli.*; import org.slf4j.LoggerFactory; import java.io.IOException; import java.util.Queue; import java.util.concurrent.LinkedBlockingQueue; import java.util.regex.Pattern; /** * @author Jon Brisbin */ public class DurableLogUtility { private static Options OPTS = new Options(); private DurableLogUtility() { } static { Option path = new Option("p", "path", true, "Base path to a durable log file to interpret"); path.setRequired(true); Option config = new Option("c", "config", true, "Logback configuration XML file to parse"); Option output = new Option("o", "output", true, "Appender to use to output results"); Option regex = new Option("search", true, "Search for the given regex and print to standard out"); Option level = new Option("level", true, "Log level to filter"); Option head = new Option("head", true, "Number of lines to display from the head of the file"); Option tail = new Option("tail", true, "Number of lines to display from the tail of the file"); OptionGroup findOpts = new OptionGroup().addOption(regex).addOption(head).addOption(tail); OPTS.addOption(path).addOption(config).addOption(output).addOption(level).addOptionGroup(findOpts); } @SuppressWarnings("unchecked") public static void main(String... args) throws ParseException, JoranException, IOException { Parser parser = new BasicParser(); CommandLine cl = null; try { cl = parser.parse(OPTS, args); } catch (ParseException e) { HelpFormatter help = new HelpFormatter(); help.printHelp("dlog", OPTS, true); System.exit(-1); } LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory(); loggerContext.reset(); if (cl.hasOption("config")) { // Read Logback configuration JoranConfigurator configurator = new JoranConfigurator(); configurator.setContext(loggerContext); configurator.doConfigure(cl.getOptionValue("file", "logback.xml")); StatusPrinter.printInCaseOfErrorsOrWarnings(loggerContext); } else { BasicConfigurator.configure(loggerContext); } Appender appender = null; if (cl.hasOption("output")) { String outputAppender = cl.getOptionValue("output", "console"); appender = loggerContext.getLogger(Logger.ROOT_LOGGER_NAME).getAppender(outputAppender); } ChronicleTools.warmup(); Chronicle chronicle = ChronicleQueueBuilder.indexed(cl.getOptionValue("path")).build(); ExcerptTailer ex = chronicle.createTailer(); Level level = Level.valueOf(cl.getOptionValue("level", "TRACE")); if (cl.hasOption("head")) { int lines = Integer.parseInt(cl.getOptionValue("head", "10")); for (int i = 0; i < lines; i++) { LoggingEvent evt = readLoggingEvent(ex, loggerContext); if (evt.getLevel().isGreaterOrEqual(level)) { writeEvent(evt, appender); } } } else if (cl.hasOption("tail")) { int lines = Integer.parseInt(cl.getOptionValue("tail", "10")); Queue<LoggingEvent> tail = new LinkedBlockingQueue<LoggingEvent>(lines); while (ex.nextIndex()) { LoggingEvent evt = readLoggingEvent(ex, loggerContext); if (!tail.offer(evt)) { tail.poll(); tail.add(evt); } } LoggingEvent evt; while (null != (evt = tail.poll())) { if (evt.getLevel().isGreaterOrEqual(level)) { writeEvent(evt, appender); } } } else if (cl.hasOption("search")) { String regex = cl.getOptionValue("search"); Pattern regexPatt = Pattern.compile(regex); while (ex.nextIndex()) { LoggingEvent evt = readLoggingEvent(ex, loggerContext); if (null != evt && evt.getLevel().isGreaterOrEqual(level)) { if (regexPatt.matcher(evt.getFormattedMessage()).matches()) { writeEvent(evt, appender); } } } } loggerContext.stop(); chronicle.close(); } @SuppressWarnings("unchecked") private static void writeEvent(LoggingEvent evt, Appender appender) { if (null == evt) { return; } if (null != appender) { appender.doAppend(evt); } else { System.out.println(evt.getFormattedMessage()); } } @SuppressWarnings("unchecked") private static LoggingEvent readLoggingEvent(ExcerptTailer ex, LoggerContext ctx) { LoggingEventRecord rec = LoggingEventRecord.read(ex); Logger logger = ctx.getLogger(rec.getLoggerName()); LoggingEvent evt = new LoggingEvent(logger.getClass().getName(), logger, Level.toLevel(rec.getLevel()), rec.getMessage(), rec.getCause(), rec.getArgs()); evt.setTimeStamp(rec.getTimestamp()); evt.setThreadName(rec.getThreadName()); evt.setMDCPropertyMap(rec.getMdcProps()); if (null != rec.getCause()) { evt.setThrowableProxy(new ThrowableProxy(rec.getCause())); } evt.setCallerData(rec.getCallerData()); return evt; } }