
org.neo4j.kernel.impl.util.StringLogger Maven / Gradle / Ivy
/**
* Copyright (c) 2002-2013 "Neo Technology,"
* Network Engine for Objects in Lund AB [http://neotechnology.com]
*
* This file is part of Neo4j.
*
* Neo4j 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 .
*/
package org.neo4j.kernel.impl.util;
import static org.neo4j.helpers.collection.IteratorUtil.loop;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.Writer;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import org.neo4j.helpers.Format;
import org.neo4j.helpers.collection.Visitor;
import org.neo4j.kernel.impl.nioneo.store.FileSystemAbstraction;
import org.neo4j.kernel.logging.LogMarker;
public abstract class StringLogger
{
public static final String DEFAULT_NAME = "messages.log";
public static final String DEFAULT_ENCODING = "UTF-8";
public static final StringLogger SYSTEM = new ActualStringLogger( new PrintWriter( System.out, true ) )
{
@Override
public void close()
{
// don't close System.out
}
};
private static final int DEFAULT_THRESHOLD_FOR_ROTATION = 100 * 1024 * 1024;
private static final int NUMBER_OF_OLD_LOGS_TO_KEEP = 2;
public interface LineLogger
{
void logLine( String line );
}
public static StringLogger logger( File logfile )
{
try
{
return new ActualStringLogger( new PrintWriter(
new OutputStreamWriter( new FileOutputStream( logfile, true), DEFAULT_ENCODING ) ) );
}
catch ( IOException cause )
{
throw new RuntimeException( "Could not create log file: " + logfile, cause );
}
}
public static StringLogger loggerDirectory( FileSystemAbstraction fileSystem, File logDirectory )
{
return loggerDirectory( fileSystem, logDirectory, DEFAULT_THRESHOLD_FOR_ROTATION );
}
public static StringLogger loggerDirectory( FileSystemAbstraction fileSystem, File logDirectory, int rotationThreshold )
{
return new ActualStringLogger( fileSystem, new File( logDirectory, DEFAULT_NAME ).getPath(),
rotationThreshold );
}
public static StringLogger wrap( Writer writer )
{
return new ActualStringLogger(
writer instanceof PrintWriter ? (PrintWriter) writer : new PrintWriter( writer ) );
}
public static StringLogger wrap( final StringBuffer target )
{
return new ActualStringLogger( new PrintWriter( new Writer()
{
@Override
public void write( char[] cbuf, int off, int len ) throws IOException
{
target.append( cbuf, off, len );
}
@Override
public void write( int c ) throws IOException
{
target.appendCodePoint( c );
}
@Override
public void write( char[] cbuf ) throws IOException
{
target.append( cbuf );
}
@Override
public void write( String str ) throws IOException
{
target.append( str );
}
@Override
public void write( String str, int off, int len ) throws IOException
{
target.append( str, off, len );
}
@Override
public Writer append( char c ) throws IOException
{
target.append( c );
return this;
}
@Override
public Writer append( CharSequence csq ) throws IOException
{
target.append( csq );
return this;
}
@Override
public Writer append( CharSequence csq, int start, int end ) throws IOException
{
target.append( csq, start, end );
return this;
}
@Override
public void flush() throws IOException
{
// do nothing
}
@Override
public void close() throws IOException
{
// do nothing
}
} ) );
}
public static StringLogger tee( final StringLogger logger1, final StringLogger logger2 )
{
return new StringLogger() {
@Override
public void logLongMessage( String msg, Visitor source, boolean flush )
{
logger1.logLongMessage( msg, source, flush );
logger2.logLongMessage( msg, source, flush );
}
@Override
public void logMessage( String msg, boolean flush )
{
logger1.logMessage( msg, flush );
logger2.logMessage( msg, flush );
}
@Override
public void logMessage( String msg, LogMarker marker )
{
logger1.logMessage( msg, marker );
logger2.logMessage( msg, marker );
}
@Override
public void logMessage( String msg, Throwable cause, boolean flush )
{
logger1.logMessage( msg, cause, flush );
logger2.logMessage( msg, cause, flush );
}
@Override
public void addRotationListener( Runnable listener )
{
logger1.addRotationListener( listener );
logger2.addRotationListener( listener );
}
@Override
public void flush()
{
logger1.flush();
logger2.flush();
}
@Override
public void close()
{
logger1.close();
logger2.close();
}
@Override
protected void logLine( String line )
{
logger1.logLine( line );
logger2.logLine( line );
}
};
}
/**
* Create a StringLogger that only creates a file on the first attempt to write something to the log.
*/
public static StringLogger lazyLogger( final File logFile )
{
return new StringLogger() {
StringLogger logger = null;
@Override
public void logLongMessage( String msg, Visitor source, boolean flush )
{
createLogger();
logger.logLongMessage( msg, source, flush );
}
@Override
public void logMessage( String msg, boolean flush )
{
createLogger();
logger.logMessage( msg, flush );
}
@Override
public void logMessage( String msg, LogMarker marker )
{
createLogger();
logger.logMessage( msg, marker );
}
@Override
public void logMessage( String msg, Throwable cause, boolean flush )
{
createLogger();
logger.logMessage( msg, cause, flush );
}
@Override
public void addRotationListener( Runnable listener )
{
createLogger();
logger.addRotationListener( listener );
}
@Override
public void flush()
{
createLogger();
logger.flush();
}
@Override
public void close()
{
createLogger();
logger.close();
}
@Override
protected void logLine( String line )
{
createLogger();
logger.logLine( line );
}
private synchronized void createLogger()
{
if (logger == null){
logger = logger( logFile );
}
}
};
}
public void logMessage( String msg )
{
logMessage( msg, false );
}
public void logMessage( String msg, Throwable cause )
{
logMessage( msg, cause, false );
}
public void debug( String msg )
{
if ( isDebugEnabled() )
logMessage( msg );
}
public void debug( String msg, Throwable cause )
{
if ( isDebugEnabled() )
logMessage( msg, cause );
}
public boolean isDebugEnabled()
{
return false;
}
public void info( String msg )
{
logMessage( msg );
}
public void info( String msg, Throwable cause )
{
logMessage( msg, cause );
}
public void warn( String msg )
{
logMessage( msg );
}
public void warn( String msg, Throwable throwable )
{
logMessage( msg, throwable );
}
public void error( String msg )
{
logMessage( msg );
}
public void error( String msg, Throwable throwable )
{
logMessage( msg, throwable );
}
public void logLongMessage( String msg, Visitor source )
{
logLongMessage( msg, source, false );
}
public void logLongMessage( String msg, Iterable source )
{
logLongMessage( msg, source, false );
}
public void logLongMessage( String msg, Iterable source, boolean flush )
{
logLongMessage( msg, source.iterator(), flush );
}
public void logLongMessage( String msg, Iterator source )
{
logLongMessage( msg, source, false );
}
public void logLongMessage( String msg, final Iterator source, boolean flush )
{
logLongMessage( msg, new Visitor()
{
@Override
public boolean visit( LineLogger logger )
{
for ( String line : loop( source ) )
{
logger.logLine( line );
}
return true;
}
}, flush );
}
public abstract void logLongMessage( String msg, Visitor source, boolean flush );
public abstract void logMessage( String msg, boolean flush );
public abstract void logMessage( String msg, LogMarker marker );
public abstract void logMessage( String msg, Throwable cause, boolean flush );
public abstract void addRotationListener( Runnable listener );
public abstract void flush();
public abstract void close();
protected abstract void logLine( String line );
public static final StringLogger DEV_NULL = new StringLogger()
{
@Override
public void logMessage( String msg, boolean flush )
{
}
@Override
public void logMessage( String msg, LogMarker marker )
{
}
@Override
public void logMessage( String msg, Throwable cause, boolean flush )
{
}
@Override
public void logLongMessage( String msg, Visitor source, boolean flush )
{
}
@Override
protected void logLine( String line )
{
}
@Override
public void flush()
{
}
@Override
public void close()
{
}
@Override
public void addRotationListener( Runnable listener )
{
}
};
private static class ActualStringLogger extends StringLogger
{
private PrintWriter out;
private final Integer rotationThreshold;
private final File file;
private final List onRotation = new CopyOnWriteArrayList();
private final String encoding = "UTF-8";
private final FileSystemAbstraction fileSystem;
private ActualStringLogger( FileSystemAbstraction fileSystem, String filename, int rotationThreshold )
{
this.fileSystem = fileSystem;
this.rotationThreshold = rotationThreshold;
try
{
file = new File( filename );
if ( file.getParentFile() != null )
{
fileSystem.mkdirs( file.getParentFile() );
}
instantiateWriter();
}
catch ( IOException e )
{
throw new RuntimeException( e );
}
}
private ActualStringLogger( PrintWriter writer )
{
this.out = writer;
this.rotationThreshold = null;
this.file = null;
this.fileSystem = null;
}
@Override
public void addRotationListener( Runnable trigger )
{
onRotation.add( trigger );
}
private void instantiateWriter() throws IOException
{
out = new PrintWriter( new OutputStreamWriter( fileSystem.openAsOutputStream( file, true ), encoding ) );
for ( Runnable trigger : onRotation )
{
trigger.run();
}
}
@Override
public synchronized void logMessage( String msg, boolean flush )
{
out.println( time() + " INFO [org.neo4j]: " + msg );
if ( flush )
{
out.flush();
}
checkRotation();
}
@Override
public void logMessage( String msg, LogMarker marker )
{
logMessage( msg );
}
private String time()
{
return Format.date();
}
@Override
public synchronized void logMessage( String msg, Throwable cause, boolean flush )
{
out.println( time() + " ERROR [org.neo4j]: " + msg + " " + cause.getMessage());
cause.printStackTrace( out );
if ( flush )
{
out.flush();
}
checkRotation();
}
@Override
public synchronized void logLongMessage( String msg, Visitor source, boolean flush )
{
out.println( time() + " INFO [org.neo4j]: " + msg );
source.visit( new LineLoggerImpl( this ) );
if ( flush )
{
out.flush();
}
checkRotation();
}
@Override
protected void logLine( String line )
{
out.println( " " + line );
}
private volatile boolean doingRotation = false;
private void checkRotation()
{
if ( rotationThreshold != null && fileSystem.getFileSize( file ) > rotationThreshold.intValue() && !doingRotation )
{
doRotation();
}
}
private void doRotation()
{
doingRotation = true;
out.close();
moveAwayFile();
try
{
instantiateWriter();
}
catch ( IOException e )
{
throw new RuntimeException( e );
}
finally
{
doingRotation = false;
}
}
/**
* Will move:
* messages.log.1 -> messages.log.2
* messages.log -> messages.log.1
*
* Will delete (if exists):
* messages.log.2
*/
private void moveAwayFile()
{
File oldLogFile = new File( file.getParentFile(), file.getName() + "." + NUMBER_OF_OLD_LOGS_TO_KEEP );
if ( fileSystem.fileExists( oldLogFile ) )
{
fileSystem.deleteFile( oldLogFile );
}
for ( int i = NUMBER_OF_OLD_LOGS_TO_KEEP - 1; i >= 0; i-- )
{
oldLogFile = new File( file.getParentFile(), file.getName() + (i == 0 ? "" : ("." + i)) );
if ( fileSystem.fileExists( oldLogFile ) )
{
try
{
fileSystem.renameFile( oldLogFile, new File( file.getParentFile(), file.getName() + "." + (i + 1) ) );
}
catch ( IOException e )
{
throw new RuntimeException( e );
}
}
}
}
@Override
public void flush()
{
out.flush();
}
@Override
public void close()
{
out.close();
}
@Override
public String toString()
{
return "StringLogger[" + this.file + "]";
}
}
protected static final class LineLoggerImpl implements LineLogger
{
private final StringLogger target;
public LineLoggerImpl( StringLogger target )
{
this.target = target;
}
@Override
public void logLine( String line )
{
target.logLine( line );
}
}
protected static class SystemLogger extends ActualStringLogger
{
private final boolean debugEnabled;
private SystemLogger( boolean debugEnabled )
{
super( new PrintWriter( System.out ) );
this.debugEnabled = debugEnabled;
}
@Override
public boolean isDebugEnabled()
{
return debugEnabled;
}
@Override
public void close()
{
// don't close System.out
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy