/*
* Created on 22-Sep-2004
* Created by Paul Gardner
* Copyright (C) 2004, 2005, 2006 Aelitis, All Rights Reserved.
*
* 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 2
* 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* AELITIS, SAS au capital de 46,603.30 euros
* 8 Allee Lenotre, La Grille Royale, 78600 Le Mesnil le Roi, France.
*
*/
package org.gudy.azureus2.core3.util;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileWriter;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.LinkedList;
import java.util.TimeZone;
import org.gudy.azureus2.core3.logging.Logger;
/**
* @author parg
*
*/
public class
AEDiagnosticsLogger
{
private static final int MAX_PENDING = 8*1024;
private String name;
private int max_size;
private File debug_dir;
private boolean timestamp_enable = true;
private boolean force;
private boolean first_file = true;
private boolean first_write = true;
private PrintWriter current_writer;
private LinkedList<StringBuilder> pending;
private int pending_size;
private boolean direct_writes;
private boolean close_pws = false;
private static final String start_date;
private static final long timezone_offset;
static{
long now = System.currentTimeMillis();
start_date = new SimpleDateFormat().format( new Date(now));
timezone_offset = TimeZone.getDefault().getOffset(now);
}
protected
AEDiagnosticsLogger(
File _debug_dir,
String _name,
int _max_size,
boolean _direct_writes )
{
debug_dir = _debug_dir;
name = _name;
max_size = _max_size;
direct_writes = _direct_writes;
try{
File f1 = getLogFile();
first_file = false;
File f2 = getLogFile();
first_file = true;
// if we were writing to the second file, carry on from there
if ( f1.exists() && f2.exists()){
if ( f1.lastModified() < f2.lastModified()){
first_file = false;
}
}
}catch( Throwable ignore ){
}
}
public void
setForced(
boolean _force )
{
force = _force;
}
public boolean
isForced()
{
return( force );
}
protected String
getName()
{
return( name );
}
public void
setMaxFileSize(
int _max_size )
{
max_size = _max_size;
}
public void
enableTimeStamp(
boolean enable )
{
timestamp_enable = enable;
}
public void
log(
Throwable e )
{
try{
ByteArrayOutputStream baos = new ByteArrayOutputStream();
PrintWriter pw = new PrintWriter( new OutputStreamWriter( baos ));
e.printStackTrace( pw );
pw.close();
log( baos.toString());
}catch( Throwable ignore ){
}
}
public void
logAndOut(
String str )
{
logAndOut( str, false );
}
public void
logAndOut(
String str,
boolean stderr )
{
if ( stderr ){
System.err.println( str );
// Logger dumps the stderr, but if it's not setup, do it outselves
if (Logger.getOldStdErr() == null) {
log( str );
}
}else{
System.out.println( str );
log( str );
}
}
public void
logAndOut(
Throwable e )
{
e.printStackTrace();
log( e );
}
/*
public static String
getTimestamp()
{
Calendar now = GregorianCalendar.getInstance();
String timeStamp = "[" + format(now.get(Calendar.DAY_OF_MONTH))+format(now.get(Calendar.MONTH)+1) + " " +
format(now.get(Calendar.HOUR_OF_DAY))+ ":" + format(now.get(Calendar.MINUTE)) + ":" + format(now.get(Calendar.SECOND)) + "] ";
return( timeStamp );
}
*/
public static String
getTimestamp()
{
long time = SystemTime.getCurrentTime();
time += timezone_offset; // we'll live with this changing...
time /= 1000;
int secs = (int)time % 60;
int mins = (int)(time / 60) % 60;
int hours = (int)(time /3600) % 24;
char[] chars = new char[11];
chars[0] = '[';
format( hours, chars, 1 );
chars[3] = ':';
format( mins, chars, 4 );
chars[6] = ':';
format( secs, chars, 7 );
chars[9] = ']';
chars[10] = ' ';
return( new String( chars ));
}
private static final void
format(
int num,
char[] chars,
int pos )
{
if ( num < 10 ){
chars[pos] = '0';
chars[pos+1] =(char)( '0' + num );
}else{
chars[pos] = (char)('0' + (num/10));
chars[pos+1] = (char)('0' + (num%10));
}
}
public void
log(
String _str )
{
if ( !AEDiagnostics.loggers_enabled ){
if ( !force ){
return;
}
}
StringBuilder str = new StringBuilder( _str.length() + 20 );
final String timeStamp;
if ( timestamp_enable ){
timeStamp = getTimestamp();
}else{
timeStamp = null;
}
synchronized( this ){
if ( first_write ){
first_write = false;
Calendar now = GregorianCalendar.getInstance();
str.append( "\r\n[" );
str.append( start_date );
str.append( "] Log File Opened for " );
str.append( Constants.APP_NAME );
str.append( " " );
str.append( Constants.AZUREUS_VERSION );
str.append( "\r\n" );
}
if ( timeStamp != null ){
str.append( timeStamp );
}
str.append( _str );
if ( !direct_writes ){
if ( pending == null ){
pending = new LinkedList<StringBuilder>();
}
pending.add( str );
pending_size += str.length();
if ( pending_size > MAX_PENDING ){
writePending();
}
return;
}
write( str );
}
}
private void
write(
StringBuilder str )
{
try{
File log_file = getLogFile();
/**
* log_file.length will return 0 if the file doesn't exist, so we don't need
* to explicitly check for its existence.
*/
if ( log_file.length() >= max_size ){
if ( current_writer != null ){
current_writer.close();
current_writer = null;
}
first_file = !first_file;
log_file = getLogFile();
// If the file doesn't exist, this will just return false.
log_file.delete();
}
if ( current_writer == null ){
current_writer = new PrintWriter(new FileWriter( log_file, true ));
}
current_writer.println( str );
current_writer.flush();
}catch( Throwable e ){
}finally{
if ( current_writer != null && close_pws ){
current_writer.close();
current_writer = null;
}
}
}
protected void
writePending()
{
synchronized( this ){
if ( pending == null ){
return;
}
// System.out.println( getName() + ": flushing " + pending_size );
try{
File log_file = getLogFile();
/**
* log_file.length will return 0 if the file doesn't exist, so we don't need
* to explicitly check for its existence.
*/
if ( log_file.length() >= max_size ){
if ( current_writer != null ){
current_writer.close();
current_writer = null;
}
first_file = !first_file;
log_file = getLogFile();
// If the file doesn't exist, this will just return false.
log_file.delete();
}
if ( current_writer == null ){
current_writer = new PrintWriter(new FileWriter( log_file, true ));
}
for ( StringBuilder str: pending ){
current_writer.println( str );
}
current_writer.flush();
}catch( Throwable e ){
}finally{
direct_writes = true;
pending = null;
if ( current_writer != null && close_pws ){
current_writer.close();
current_writer = null;
}
}
}
}
private File
getLogFile()
{
return( new File( debug_dir, getName() + "_" + (first_file?"1":"2") + ".log" ));
}
private static String
format(
int n )
{
if (n < 10){
return( "0" + n );
}
return( String.valueOf(n));
}
}