# log4j stderr/stdout



## takidoso (4. November 2009)

Hallo und halli,
ich habe das Problem, dass ich eine meiner Anwendungen von meinem eigenem Logger auf log4j umstellen will. Die Anwendung verwendet für Systemaufrufe einen sogenannten "Gobbler", der stdout und stderr ausliest, damit bei Ausgabe der Systemaufrufe auf diese Ströhme die Anwendung nicht hängen bleibt.

Nun ist es so, dass ich zumindest für stderr die Ausgaben *nicht * wegkippen will sondern in irgendeinerweise mitloggen möchte. Mein eigener Logger gibt dafür seinen verwendetn Ausgabestohm mit einer get-Routine aus. Für log4j scheint das offenbar nicht zuzutreffen und auch gegen seine Philosophie zu stehen.
auf einer Seite fand ich folgenden Tip zu einem offenbar gleichen Problem.
Zitat

```
Hi,

>We are using a third-party tool where its debugger
>only has the method 'getDebugStream(PrintStream s)'
>to config its debug io stream.

OK.

>We want to use log4j, which means we need to pass
>the streams associated with an Appender (file or
>socket appender). Can this be done and how to
>get the stream of an Appender?

I'm not sure how you would this. There are several reasons against
this. One reason, for example, is that log4j is thread safe, and if it
exposes its streams for manipulation by other components, they might
lock the streams, hence potentially locking log4j.

Another reason is that log4j conceptually doesn't want you to concern
yourself with streams per-se, only loggers, appenders, and the like.

Perhaps a solution to your problem would be: set your 3rd party tool
print stream to System.out or System.err, then configure a log4j console
appender to grab messages headed to System.out and/or System.err. This
extra level of redirection, while slowing down logging, will keep your
3rd party tool and log4j both happy and decoupled.
```

Hmmm irgendwiei interessant, aber wie wird das eigetnlich umgesetzt?
In anderen Worten wie kann man mit log4j z.b. nachrichten aus System.err abgreifen?

Für Hinweise fürchterlich dankbar
Takidoso


----------



## takidoso (19. November 2009)

Ich bin mir zwar nicht sicher ob ungefär dies als Lösungsansatz gedacht war, aber ich habe nun folgendes getan:
ich habe einen Log4jOutputStream gebastelt, so dass ich die Möglichkeit habe auf so etwas umzuleiten.
sieht so aus:

```
import java.io.IOException;
import java.io.OutputStream;

import org.apache.log4j.Level;
import org.apache.log4j.Logger;


public class Log4jOutputStream extends OutputStream
{
	private      Logger       m_logger;
	private      Level        m_lvl;

	public Log4jOutputStream(Logger logger, Level lvl)
	{
		m_lvl    = lvl;
		m_logger = logger;
	}

	public void write(int b) throws IOException
	{
		m_logger.log(m_lvl, new String(new byte[b]));	
	}
	

	public void write(byte b[], int off, int len) throws IOException
	{
		if (b == null)
		{
			throw new NullPointerException();
		}
		else if (( off < 0 ) || ( off > b.length ) || ( len < 0 ) || ( ( off + len ) > b.length ) || ( ( off + len ) < 0 ))
		{
			throw new IndexOutOfBoundsException();
		}
		else if (len > 0)
		{
			m_logger.log(m_lvl, new String(b,off,len));
		}
	}
	
	
}
```
Der oben erwähnte _Gobbler_ sieht so aus

```
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;

import de.cmk.util.ExceptionHandlerLike;
import de.cmk.util.MExceptionHandler;

/**
 * Original auf http://www.javaworld.com/javaworld/jw-12-2000/jw-1229-traps.html?page=4 gefunden
 * @author z300057
 *
 */
public class StreamGobbler extends Thread
{
	private ExceptionHandlerLike m_exceptionHandler = null;
	private InputStream          m_is;
	private OutputStream         m_os;
	private String               m_type;
	
	
	public StreamGobbler (InputStream is, String tpye)
	{
		this (is, tpye, System.out, null);
	}
	
	public StreamGobbler (InputStream is, String tpye, OutputStream redirectionOutputStream)
	{
		this (is, tpye, redirectionOutputStream, null);
	}
	
	public StreamGobbler (InputStream is, String tpye, ExceptionHandlerLike eHandler)
	{
		this (is, tpye, System.out, eHandler);
	}
	
	public StreamGobbler (InputStream is, String type, OutputStream redirectionOutputStream, ExceptionHandlerLike eHandler)
	{
		m_is               = is;
		m_type             = type == null ? "" : type+": ";
		m_os               = redirectionOutputStream;
		m_exceptionHandler = eHandler;
		
		if (is == null)
		{
			throw new IllegalArgumentException("InputStream must not be null");
		}
	}
	
	public void setExceptionHandler(ExceptionHandlerLike eHandler)
	{
		m_exceptionHandler = eHandler;
	}
	public ExceptionHandlerLike getExceptionHandler()
	{
		return m_exceptionHandler;
	}
	
	public void run()
	{
		PrintWriter pWriter = null;;
		try
		{
			if (m_os!=null)
			{
				pWriter = new PrintWriter(m_os);
			}

			
			BufferedReader bReader = new BufferedReader(new InputStreamReader(m_is));
			
			
			String line;
			while ((line=bReader.readLine())!=null)
			{
				if (pWriter != null)
				{
					pWriter.println(m_type+line);
				}
			}
			
		}
		catch (IOException ioEx)
		{
			if (m_exceptionHandler==null)
			{
				MExceptionHandler.handleException(ioEx);
			}
			else
			{
				m_exceptionHandler.handleException(ioEx);
			}
		}
		finally
		{
			System.out.println("StreamGobbler "+m_type+" finalized");
			pWriter.flush();
			if (m_os != System.out && m_os != System.err)
			{
				pWriter.close();
			}
		}
	}
}
```
Die Geschichte mit dem ExceptionHandler ist quasi meine proprietäre Art Exception-Verhalten von ausßen anpassbar zu machen.

Einsetzten tu ich in dem Fall den Gobbler für Systemaufrufe, die STD-OUTPUT bzw. ERROR mit Daten beglücken, und damit dabei die VM nicht ins endloses Verharren gerät sollte man dies Ausgabeströhme vorsichtshabler bei Systemaufrufen "fressen" (gobbeln)
Beispiel

```
String [] toks = applCall.split(" ");
            
            ProcessBuilder pb = new ProcessBuilder(toks);
            Process p = pb.start();
            
            StreamGobbler errorGobbler = new StreamGobbler(p.getErrorStream(),m_config.getStdErrBypassTag(originalFileName), m_config.getStdErrBypass(originalFileName), myExtHandler);
            StreamGobbler stdGobbler   = new StreamGobbler(p.getInputStream(),m_config.getStdOutBypassTag(originalFileName), m_config.getStdOutBypass(originalFileName), myExtHandler);
            errorGobbler.start();
            stdGobbler.start();
            // TODO Returncodes in der Konfiguration angebbar machen bei denen gestoppt werden soll bzw nicht gestoppt werden soll
            if (p.waitFor()!=0)
            {
              ...
            }
```
Hier sei angemerkt, dass m_confi eine wie auch immer geartete Konfiguration ist, die eine Art Eye-Catcher (tag) bzw einen wie auch immer gearteten Ausgabestrohm definiert und in diesem _StreamGobbler_ zur Verfügung stellt. Und das sowohl für STD-OUTPUT als auch STD-ERROR.

Soweit meine Tests da angesetzt wawren fuktioniert es offenbar sogar.

Falls es da doch mit Bordmitteln geht wie oben angedeutet, und jemand da was weiterführend weiß, bin ich noch immer neugierig auf solche Lösungen!


----------

