/*
* Copyright (C) 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.logging.impl;
import java.io.OutputStream;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.List;
import org.gudy.azureus2.core3.config.ParameterListener;
import org.gudy.azureus2.core3.config.impl.ConfigurationManager;
import org.gudy.azureus2.core3.internat.MessageText;
import org.gudy.azureus2.core3.logging.ILogAlertListener;
import org.gudy.azureus2.core3.logging.ILogEventListener;
import org.gudy.azureus2.core3.logging.LogAlert;
import org.gudy.azureus2.core3.logging.LogEvent;
import org.gudy.azureus2.core3.logging.LogIDs;
import org.gudy.azureus2.core3.logging.Logger;
import org.gudy.azureus2.core3.util.AEDiagnostics;
import org.gudy.azureus2.core3.util.AEDiagnosticsLogger;
import org.gudy.azureus2.core3.util.Debug;
/**
* Logging tool
*
* @author TuxPaper
* @since 2.3.0.7
*/
public class LoggerImpl {
private final int MAXHISTORY = 256;
private boolean bLogToStdOut = System.getProperty("azureus.log.stdout") != null;
private boolean bEventLoggingEnabled = false;
private PrintStream psOldOut = null;
private PrintStream psOldErr = null;
private PrintStream psOut;
private PrintStream psErr;
private List logListeners = new ArrayList();
private AEDiagnosticsLogger alertLogger;
private List alertListeners = new ArrayList();
private List alertHistory = new ArrayList();
private boolean logToStdErrAllowed = true;
/**
* Initializes the Logger and sets up a file logger.
*/
public LoggerImpl() {
doRedirects();
}
/**
* Must be seperate from constructor, because the code may call a Logger.*
* method, which requires a loggerImpl to be not null.
*
*/
public void init() {
// temporarily set to true, to log any errors between now and setting
// bEnabled properly.
bEventLoggingEnabled = true;
// Shorten from COConfigurationManager To make code more readable
final ConfigurationManager config = ConfigurationManager.getInstance();
boolean overrideLog = System.getProperty("azureus.overridelog") != null;
if (overrideLog) {
bEventLoggingEnabled = true;
} else {
bEventLoggingEnabled = config.getBooleanParameter("Logger.Enabled");
config.addParameterListener("Logger.Enabled", new ParameterListener() {
public void parameterChanged(String parameterName) {
bEventLoggingEnabled = config.getBooleanParameter("Logger.Enabled");
}
});
}
}
/**
* Set up stdout/stderr redirects
*/
public void doRedirects() {
try {
if (System.out != psOut) {
if (psOldOut == null)
psOldOut = System.out;
psOut = new PrintStream(new RedirectorStream(psOldOut, LogIDs.STDOUT,
LogEvent.LT_INFORMATION));
System.setOut(psOut);
}
if (System.err != psErr) {
if (psOldErr == null)
psOldErr = System.err;
psErr = new PrintStream(new RedirectorStream(psOldErr, LogIDs.STDERR,
LogEvent.LT_ERROR));
System.setErr(psErr);
}
} catch (Throwable e) {
Debug.printStackTrace(e);
}
}
public boolean isEnabled() {
return bEventLoggingEnabled;
}
/**
* Redirects any incoming text to the logger
*/
private class RedirectorStream extends OutputStream {
protected PrintStream ps;
protected StringBuffer buffer = new StringBuffer(1024);
protected LogIDs logID;
protected int logType;
protected RedirectorStream(PrintStream _ps, LogIDs _logID, int _logType) {
ps = _ps;
logType = _logType;
logID = _logID;
}
public void write(int data) {
char c = (char) data;
if (c == '\n') {
if (!bLogToStdOut) {
ps.println(buffer);
}
log(new LogEvent(logID, logType, buffer.toString()));
buffer.setLength(0);
} else if (c != '\r') {
buffer.append(c);
}
}
public void write(byte b[], int off, int len) {
for (int i = off; i < off + len; i++) {
int d = b[i];
if (d < 0)
d += 256;
write(d);
}
}
}
// Log Event Functions
// ===================
/**
* Log an event
*
* @param event
* event to log
*/
public void log(LogEvent event) {
/**
* This highlights bits of code which log, but don't bother
* to check whether logging is enabled or not.
*/
//if (!bEventLoggingEnabled) {
// new Exception("No logging check done!").printStackTrace(psOldErr);
//}
if (bLogToStdOut && psOldOut != null)
psOldOut.println(event.text);
if (event.entryType == LogEvent.LT_ERROR) {
if ( AEDiagnostics.isStartupComplete()){
// more recursive horrors here if we try and log too early
Debug.outDiagLoggerOnly("[" + event.logID + "] " + event.text);
}
if (logToStdErrAllowed && psOldErr != null && event.logID != LogIDs.STDERR) {
psOldErr.println("[" + event.logID + "] " + event.text);
}
}
if (bEventLoggingEnabled)
for (int i = 0; i < logListeners.size(); i++) {
try {
Object listener = logListeners.get(i);
if (listener instanceof ILogEventListener)
((ILogEventListener) listener).log(event);
} catch (Throwable e) {
if (logToStdErrAllowed && psOldErr != null) {
psOldErr.println("Error while logging: " + e.getMessage());
e.printStackTrace(psOldErr);
}
}
}
// Write error to stderr, which will eventually get back here
if (event.err != null && event.entryType == LogEvent.LT_ERROR){
Debug.printStackTrace(event.err);
}
}
public void logTextResource(LogEvent event) {
event.text = MessageText.getString(event.text);
log(event);
}
public void logTextResource(LogEvent event, String params[]) {
event.text = MessageText.getString(event.text, params);
log(event);
}
public void addListener(ILogEventListener aListener) {
logListeners.add(aListener);
}
public void removeListener(ILogEventListener aListener) {
logListeners.remove(aListener);
}
// Log Alert Functions
// ===================
public void log(LogAlert alert) {
String logText = "Alert:" + alert.entryType + ":" + alert.text;
// Log all Alerts as Events
LogEvent alertEvent = new LogEvent(LogIDs.ALERT, alert.entryType,
logText);
alertEvent.err = alert.err;
Logger.log(alertEvent);
synchronized (this) {
if (alertLogger == null) {
alertLogger = AEDiagnostics.getLogger("alerts");
}
}
Throwable error = alert.getError();
if ( error != null ){
logText += " (" + Debug.getNestedExceptionMessage( error ) + ")";
}
alertLogger.log(logText);
alertHistory.add(alert);
if (alertHistory.size() > MAXHISTORY)
alertHistory.remove(0);
for (int i = 0; i < alertListeners.size(); i++) {
try {
Object listener = alertListeners.get(i);
if (listener instanceof ILogAlertListener)
((ILogAlertListener) listener).alertRaised(alert);
} catch (Throwable f) {
if (psOldErr != null) {
psOldErr.println("Error while alerting: " + f.getMessage());
f.printStackTrace(psOldErr);
}
}
}
}
public void logTextResource(LogAlert alert) {
alert.text = MessageText.getString(alert.text);
log(alert);
}
public void logTextResource(LogAlert alert, String params[]) {
alert.text = MessageText.getString(alert.text, params);
log(alert);
}
public void addListener(ILogAlertListener l) {
alertListeners.add(l);
for (int i = 0; i < alertHistory.size(); i++) {
LogAlert alert = (LogAlert) alertHistory.get(i);
l.alertRaised(alert);
}
}
public void removeListener(ILogAlertListener l) {
alertListeners.remove(l);
}
public PrintStream getOldStdErr() {
return psOldErr;
}
public void allowLoggingToStdErr(boolean allowed) {
this.logToStdErrAllowed = allowed;
}
}