/* * Copyright 2014 Higher Frequency Trading * * http://www.higherfrequencytrading.com * * 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 net.openhft.chronicle.logger; import net.openhft.chronicle.Chronicle; import net.openhft.chronicle.ExcerptAppender; import net.openhft.chronicle.VanillaChronicle; import net.openhft.lang.model.constraints.NotNull; import java.io.Closeable; import java.io.IOException; import java.io.PrintStream; public class ChronicleLogWriters { public interface ExcerptAppenderProvider { ExcerptAppender get(); } // ************************************************************************* // // ************************************************************************* public static class IndexedExcerptAppenderProvider implements ExcerptAppenderProvider { private ExcerptAppender appender; public IndexedExcerptAppenderProvider(@NotNull final Chronicle chronicle) { try { this.appender = chronicle.createAppender(); } catch (IOException e) { this.appender = null; e.printStackTrace(); } } @Override public ExcerptAppender get() { return this.appender; } } public static class VanillaExcerptAppenderProvider implements ExcerptAppenderProvider { private final Chronicle chronicle; public VanillaExcerptAppenderProvider(@NotNull final Chronicle chronicle) { this.chronicle = chronicle; } @Override public ExcerptAppender get() { try { return this.chronicle.createAppender(); } catch (IOException e) { e.printStackTrace(); } return null; } } // ************************************************************************* // // ************************************************************************* public abstract static class AbstractChronicleLogWriter implements ChronicleLogWriter { private final ExcerptAppenderProvider appenderProvider; private final Chronicle chronicle; public AbstractChronicleLogWriter(@NotNull Chronicle chronicle) throws IOException { this.chronicle = chronicle; this.appenderProvider = (chronicle instanceof VanillaChronicle) ? new VanillaExcerptAppenderProvider(chronicle) : new IndexedExcerptAppenderProvider(chronicle); } @Override public Chronicle getChronicle() { return this.chronicle; } @Override public void close() throws IOException { if (this.chronicle != null) { this.chronicle.close(); } } protected ExcerptAppender getAppender() { return this.appenderProvider.get(); } } // ************************************************************************* // // ************************************************************************* public static final class BinaryWriter extends AbstractChronicleLogWriter { public BinaryWriter(@NotNull Chronicle chronicle) throws IOException { super(chronicle); } private void logCommon( final ExcerptAppender appender, final ChronicleLogLevel level, final long timestamp, final String threadName, final String loggerName, final String message) { appender.writeByte(ChronicleLog.VERSION); appender.writeLong(timestamp); level.writeTo(appender); appender.writeUTFΔ(threadName); appender.writeUTFΔ(loggerName); appender.writeUTFΔ(message); } @Override public void write( final ChronicleLogLevel level, final long timestamp, final String threadName, final String loggerName, final String message) { final ExcerptAppender appender = getAppender(); if (appender != null) { appender.startExcerpt(); logCommon(appender, level, timestamp, threadName, loggerName, message); appender.finish(); } } @Override public void write( final ChronicleLogLevel level, final long timestamp, final String threadName, final String loggerName, final String message, final Throwable throwable) { final ExcerptAppender appender = getAppender(); if (appender != null) { appender.startExcerpt(); logCommon(appender, level, timestamp, threadName, loggerName, message); appender.writeStopBit(0); if(throwable != null) { appender.writeBoolean(true); appender.writeObject(throwable); } else { appender.writeBoolean(false); } appender.finish(); } } @Override public void write( final ChronicleLogLevel level, final long timestamp, final String threadName, final String loggerName, final String message, final Throwable throwable, final Object arg1) { final ExcerptAppender appender = getAppender(); if (appender != null) { appender.startExcerpt(); logCommon(appender, level, timestamp, threadName, loggerName, message); appender.writeStopBit(1); appender.writeObject(arg1); if(throwable != null) { appender.writeBoolean(true); appender.writeObject(throwable); } else { appender.writeBoolean(false); } appender.finish(); } } @Override public void write( final ChronicleLogLevel level, final long timestamp, final String threadName, final String loggerName, final String message, final Throwable throwable, final Object arg1, final Object arg2) { final ExcerptAppender appender = getAppender(); if (appender != null) { appender.startExcerpt(); logCommon(appender, level, timestamp, threadName, loggerName, message); appender.writeStopBit(2); appender.writeObject(arg1); appender.writeObject(arg2); if(throwable != null) { appender.writeBoolean(true); appender.writeObject(throwable); } else { appender.writeBoolean(false); } appender.finish(); } } @Override public void write( final ChronicleLogLevel level, final long timestamp, final String threadName, final String loggerName, final String message, final Throwable throwable, final Object[] args) { final ExcerptAppender appender = getAppender(); if (appender != null) { appender.startExcerpt(); logCommon(appender, level, timestamp, threadName, loggerName, message); if(args != null) { appender.writeStopBit(args.length); for(int i=0;i <args.length; i++) { appender.writeObject(args[i]); } } else { appender.writeStopBit(0); } if(throwable != null) { appender.writeBoolean(true); appender.writeObject(throwable); } else { appender.writeBoolean(false); } appender.finish(); } } } // ************************************************************************* // // ************************************************************************* public static class TextWriter extends AbstractChronicleLogWriter { private final TimeStampFormatter timeStampFormatter; private final int stackTraceDepth; public TextWriter( @NotNull Chronicle chronicle, String dateFormat, Integer stackTraceDepth) throws IOException { super(chronicle); this.stackTraceDepth = stackTraceDepth != null ? stackTraceDepth : -1; this.timeStampFormatter = TimeStampFormatter.fromDateFormat(dateFormat); } @Override public void write( final ChronicleLogLevel level, long timestamp, final String threadName, final String loggerName, final String message) { write(level, timestamp, threadName, loggerName, message, null); } @Override public void write( final ChronicleLogLevel level, long timestamp, final String threadName, final String loggerName, final String message, final Throwable throwable) { final ExcerptAppender appender = getAppender(); if (appender != null) { appender.startExcerpt(); timeStampFormatter.format(timestamp, appender); appender.append('|'); level.printTo(appender); appender.append('|'); appender.append(threadName); appender.append('|'); appender.append(loggerName); appender.append('|'); appender.append(message); if (throwable != null) { appender.append(" - "); ChronicleLogHelper.appendStackTraceAsString( appender, throwable, ChronicleLog.COMMA, this.stackTraceDepth); } appender.append('\n'); appender.finish(); } } @Override public void write( ChronicleLogLevel level, long timestamp, String threadName, String loggerName, String message, Throwable throwable, Object arg1) { throw new UnsupportedOperationException(); } @Override public void write( ChronicleLogLevel level, long timestamp, String threadName, String loggerName, String message, Throwable throwable, Object arg1, Object arg2) { throw new UnsupportedOperationException(); } @Override public void write( ChronicleLogLevel level, long timestamp, String threadName, String loggerName, String message, Throwable throwable, Object[] args) { } } // ************************************************************************* // // ************************************************************************* public static class SimpleWriter implements ChronicleLogWriter { private final TimeStampFormatter timeStampFormatter; private final PrintStream stream; public SimpleWriter( @NotNull PrintStream stream) throws IOException { this.timeStampFormatter = TimeStampFormatter.fromDateFormat(ChronicleLog.DEFAULT_DATE_FORMAT); this.stream = stream; } @Override public Chronicle getChronicle() { return null; } @Override public void close() throws IOException { } @Override public void write( final ChronicleLogLevel level, long timestamp, final String threadName, final String loggerName, final String message, final Throwable throwable) { if (throwable == null) { stream.printf("%s|%s|%s|%s|%s%n", timeStampFormatter.format(timestamp), level.toString(), threadName, loggerName, message); } else { stream.printf("%s|%s|%s|%s|%s|%s%n", timeStampFormatter.format(timestamp), level.toString(), threadName, loggerName, message, throwable.toString()); } } @Override public void write( final ChronicleLogLevel level, final long timestamp, final String threadName, final String loggerName, final String message) { write(level, timestamp, threadName, loggerName, message, null); } @Override public void write( final ChronicleLogLevel level, final long timestamp, final String threadName, final String loggerName, final String message, final Throwable throwable, final Object arg1) { write(level, timestamp, threadName, loggerName, message, throwable); } @Override public void write( final ChronicleLogLevel level, final long timestamp, final String threadName, final String loggerName, final String message, final Throwable throwable, final Object arg1, final Object arg2) { write(level, timestamp, threadName, loggerName, message, throwable); } @Override public void write( final ChronicleLogLevel level, final long timestamp, final String threadName, final String loggerName, final String message, final Throwable throwable, final Object[] args) { write(level, timestamp, threadName, loggerName, message, throwable); } } // ************************************************************************* // // ************************************************************************* public static final class SynchronizedWriter implements ChronicleLogWriter, Closeable { private final ChronicleLogWriter writer; private final Object sync; public SynchronizedWriter(final ChronicleLogWriter writer) { this.writer = writer; this.sync = new Object(); } public ChronicleLogWriter writer() { return writer; } @Override public Chronicle getChronicle() { return this.writer.getChronicle(); } @Override public void close() throws IOException { synchronized(this.sync) { this.writer.close(); } } @Override public void write( ChronicleLogLevel level, long timestamp, String threadName, String loggerName, String message) { synchronized (this.sync) { this.writer.write(level, timestamp, threadName, loggerName, message); } } @Override public void write( ChronicleLogLevel level, long timestamp, String threadName, String loggerName, String message, Throwable throwable) { synchronized (this.sync) { this.writer.write(level, timestamp, threadName, loggerName, message, throwable); } } @Override public void write( ChronicleLogLevel level, long timestamp, String threadName, String loggerName, String message, Throwable throwable, Object arg1) { synchronized (this.sync) { this.writer.write(level, timestamp, threadName, loggerName, message, throwable, arg1); } } @Override public void write( ChronicleLogLevel level, long timestamp, String threadName, String loggerName, String message, Throwable throwable, Object arg1, Object arg2) { synchronized (this.sync) { this.writer.write(level, timestamp, threadName, loggerName, message, throwable, arg1, arg2); } } @Override public void write( ChronicleLogLevel level, long timestamp, String threadName, String loggerName, String message, Throwable throwable, Object[] args) { synchronized (this.sync) { this.writer.write(level, timestamp, threadName, loggerName, message, throwable, args); } } } // ************************************************************************* // // ************************************************************************* public static ChronicleLogWriter binary( @NotNull Chronicle chronicle) throws IOException { return chronicle instanceof VanillaChronicle ? new BinaryWriter(chronicle) : new SynchronizedWriter(new BinaryWriter(chronicle)); } public static ChronicleLogWriter binary( @NotNull ChronicleLogAppenderConfig cfg, String path) throws IOException { return binary(cfg.build(path)); } // ************************************************************************* // // ************************************************************************* public static ChronicleLogWriter text( @NotNull Chronicle chronicle, String dateFormat, Integer stackTraceDepth) throws IOException { return chronicle instanceof VanillaChronicle ? new TextWriter(chronicle, dateFormat, stackTraceDepth) : new SynchronizedWriter(new TextWriter(chronicle, dateFormat, stackTraceDepth)); } public static ChronicleLogWriter text( @NotNull ChronicleLogAppenderConfig cfg, String path, String dateFormat, Integer stackTraceDepth) throws IOException { return text(cfg.build(path), dateFormat, stackTraceDepth); } }