/*! ****************************************************************************** * * Pentaho Data Integration * * Copyright (C) 2002-2017 by Pentaho : http://www.pentaho.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 org.pentaho.di.core.logging; import java.io.IOException; import java.io.OutputStream; import java.util.concurrent.atomic.AtomicBoolean; import org.apache.commons.vfs2.FileObject; import org.pentaho.di.core.exception.KettleException; import org.pentaho.di.core.vfs.KettleVFS; /** * This class takes care of polling the central log store for new log messages belonging to a certain log channel ID * (and children). The log lines will be written to a logging file. * * @author matt * */ public class LogChannelFileWriter { private String logChannelId; private FileObject logFile; private boolean appending; private int pollingInterval; private AtomicBoolean active; private KettleException exception; protected OutputStream logFileOutputStream; private LogChannelFileWriterBuffer buffer; /** * Create a new log channel file writer * * @param logChannelId * The log channel (+children) to write to the log file * @param logFile * The logging file to write to * @param appending * set to true if you want to append to an existing file * @param pollingInterval * The polling interval in milliseconds. * * @throws KettleException * in case the specified log file can't be created. */ public LogChannelFileWriter( String logChannelId, FileObject logFile, boolean appending, int pollingInterval ) throws KettleException { this.logChannelId = logChannelId; this.logFile = logFile; this.appending = appending; this.pollingInterval = pollingInterval; active = new AtomicBoolean( false ); try { logFileOutputStream = KettleVFS.getOutputStream( logFile, appending ); } catch ( IOException e ) { throw new KettleException( "There was an error while trying to open file '" + logFile + "' for writing", e ); } this.buffer = new LogChannelFileWriterBuffer( this.logChannelId ); LoggingRegistry.getInstance().registerLogChannelFileWriterBuffer( this.buffer ); } /** * Create a new log channel file writer * * @param logChannelId * The log channel (+children) to write to the log file * @param logFile * The logging file to write to * @param appending * set to true if you want to append to an existing file * * @throws KettleException * in case the specified log file can't be created. */ public LogChannelFileWriter( String logChannelId, FileObject logFile, boolean appending ) throws KettleException { this( logChannelId, logFile, appending, 1000 ); } /** * Start the logging thread which will write log data from the specified log channel to the log file. In case of an * error, the exception will be available with method getException(). */ public void startLogging() { exception = null; active.set( true ); Thread thread = new Thread( new Runnable() { public void run() { try { while ( active.get() && exception == null ) { flush(); Thread.sleep( pollingInterval ); } // When done, save the last bit as well... flush(); } catch ( Exception e ) { exception = new KettleException( "There was an error logging to file '" + logFile + "'", e ); } finally { try { if ( logFileOutputStream != null ) { logFileOutputStream.close(); logFileOutputStream = null; } } catch ( Exception e ) { exception = new KettleException( "There was an error closing log file file '" + logFile + "'", e ); } } } } ); thread.start(); } public synchronized void flush() { try { StringBuffer buffer = this.buffer.getBuffer(); logFileOutputStream.write( buffer.toString().getBytes() ); logFileOutputStream.flush(); } catch ( Exception e ) { exception = new KettleException( "There was an error logging to file '" + logFile + "'", e ); } } public void stopLogging() { flush(); active.set( false ); } public KettleException getException() { return exception; } /** * @return the logChannelId */ public String getLogChannelId() { return logChannelId; } /** * @param logChannelId * the logChannelId to set */ public void setLogChannelId( String logChannelId ) { this.logChannelId = logChannelId; } /** * @return the logFile */ public FileObject getLogFile() { return logFile; } /** * @param logFile * the logFile to set */ public void setLogFile( FileObject logFile ) { this.logFile = logFile; } /** * @return the appending */ public boolean isAppending() { return appending; } /** * @param appending * the appending to set */ public void setAppending( boolean appending ) { this.appending = appending; } /** * @return the pollingInterval */ public int getPollingInterval() { return pollingInterval; } /** * @param pollingInterval * the pollingInterval to set */ public void setPollingInterval( int pollingInterval ) { this.pollingInterval = pollingInterval; } }