Hi,

This attachments fix the most obvious flaw in my submission: The class
names ended in Logger instead of Appender.

Thanks for your patience,
Markus


-- 
markus schaber | dipl. informatiker
logi-track ag | rennweg 14-16 | ch 8001 z�rich
phone +41-43-888 62 52 | fax +41-43-888 62 53
mailto:[EMAIL PROTECTED] | www.logi-track.com
/*
 * Logger Command Appender Class
 * 
 * $Id: MultipipeLogger.java,v 1.1 2004/04/08 10:52:05 schabi Exp $
 * 
 * (C) 2004 Markus Schaber, logi-track ag, Z�rich, Switzerland.
 * 
 * Submitted for inclusion into the apache.org log4j project, Copyright (C) The
 * Apache Software Foundation. All rights reserved.
 * 
 * This software is published under the terms of the Apache Software License
 * version 1.1, a copy of which has been included with this distribution in the
 * LICENSE.txt file.
 */
package com.logitrack.sql.posinsertdaemon.log;

import java.io.IOException;

import org.apache.log4j.Appender;
import org.apache.log4j.AppenderSkeleton;
import org.apache.log4j.Layout;
import org.apache.log4j.Logger;
import org.apache.log4j.WriterAppender;
import org.apache.log4j.helpers.LogLog;
import org.apache.log4j.spi.LoggingEvent;

/**
 * MultipipeLogger - allows to log via syslog "logger" command or other
 * processes that log stdin.
 * 
 * CAVEATS: Currently, when a pipe breaks, some log events will be lost until
 * successful restart of the pipe process, including the event that triggered
 * the successful recreation, and as it uses WriterAppenders internally, it
 * blocks when the pipe is full.
 * 
 * @author Markus Schaber, logi-track ag, Z�rich, Switzerland.
 *  
 */
public class MultipipeAppender extends AppenderSkeleton {

    protected String pipeCommand;
    protected String facility;
    protected final WriterAppender[] writers = new WriterAppender[8];
    protected final Process[] processes = new Process[8];
    protected final BrokenPipeHandler[] recreatePipes = new BrokenPipeHandler[8];

    boolean badcallmessage = true;
    private static final String[] levels = new String[] { "crit", "crit", "crit", "error", "warning", "warning",
            "info", "debug"};

    /**
     * simple constructor.
     * 
     * You have to set layout, pipecommand and facility and then call
     * activateOptions() before you can use it.
     */
    public MultipipeAppender() {
        super();
        for (int i = 0; i < recreatePipes.length; i++) {
            recreatePipes[i] = new BrokenPipeHandler(i);
        }
    }

    /**
     * This constructor produces an ready-to-use MultipipeLogger.
     * 
     * @param layout
     * @param pipecommand
     * @param facility
     */
    public MultipipeAppender(Layout layout, String pipecommand, String facility) {
        this();
        super.setLayout(layout);
        this.pipeCommand = pipecommand;
        this.facility = facility;
        this.activateOptions();
    }

    protected void append(LoggingEvent event) {
        int pri = event.getLevel().getSyslogEquivalent();
        if (pri < 0) {
            pri = 0;
        } else if (pri >= writers.length) {
            pri = writers.length - 1;
        }
        if (writers[pri] == null) { //We try to reinstantiate logger
            activateWriter(pri);
        }
        if (writers[pri] != null) { //maybe reinstantiation was not successfull
            writers[pri].doAppend(event);
        }
    }

    /**
     * Close this appenders - tries to stop all processes
     */
    public synchronized void close() {
        if (closed) {
            return;
        }

        for (int i = 0; i < writers.length; i++) {
            close(i);
        }

        closed = true;
    }

    /**
     * Derived appenders should override this method if option structure
     * requires it.
     */
    public synchronized void activateOptions() {
        close();
        for (int i = 0; i < writers.length; i++) {
            activateWriter(i);
        }
        closed = false;
    }

    protected void close(int i) {
        Process process = processes[i];
        if (writers[i] != null) {
            writers[i].close();
            writers[i] = null;
        }
        if (process != null) {
            try {
                process.getOutputStream().close();
            } catch (IOException E) {
                LogLog.warn("Error closing Stream for " + levels[i], E);
            }
            try {
                process.waitFor();
            } catch (InterruptedException E) {
                LogLog.warn("Error closing Process for " + levels[i], E);
            }
            processes[i] = null;
        }
    }

    protected void activateWriter(int i) {
        try {
            if ((i > 0) && (levels[i - 1].equals(levels[i])) && (writers[i - 1] != null)) {
                writers[i] = writers[i - 1];
                processes[i] = processes[i - 1];
            } else {
                Process p = Runtime.getRuntime().exec(createCommandString(i));
                processes[i] = p;
                writers[i] = new WriterAppender(layout, p.getOutputStream());
                writers[i].setErrorHandler(recreatePipes[i]);
            }
        } catch (IOException E) {
            LogLog.error("Cannot open pipe for " + levels[i], E);
        }
    }

    /**
     * @param i
     * @return
     */
    private String createCommandString(int i) {
        return pipeCommand + " " + facility + "." + levels[i];
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.apache.log4j.Appender#requiresLayout()
     */
    public boolean requiresLayout() {
        return true;
    }

    /**
     * Bean Getter for pipeCommand
     * 
     * @return The content of pipeCommand.
     */
    public String getPipeCommand() {
        return pipeCommand;
    }

    /**
     * Bean Setter for pipeCommand
     * 
     * @param pipeCommand The new value for pipeCommand.
     */
    public void setPipeCommand(String pipeCommand) {
        this.pipeCommand = pipeCommand;

    }

    /**
     * Bean Getter for facility
     * 
     * @return The content of facility.
     */
    public String getFacility() {
        return facility;
    }

    /**
     * Bean Setter for facility
     * 
     * @param facility The new value for facility.
     */
    public void setFacility(String facility) {
        this.facility = facility;
    }

    /**
     * BrokenPipeHandler is triggered when the internally used WriterAppenders
     * fail, and it tries to recreate the broken pipes again.
     */

    protected class BrokenPipeHandler implements org.apache.log4j.spi.ErrorHandler {

        private int index;

        /**
         * default constructor
         * 
         * @param i The index of our Writer
         */
        protected BrokenPipeHandler(int i) {
            this.index = i;
        }

        public void setLogger(Logger logger) {
        // ignored
        }

        public void error(String message) {
            LogLog.warn("Error '" + message + " occured. Trying to recreate MultipipeLogger pipe " + index);
            recover();
        }

        public void error(String message, Exception e, int errorCode) {
            LogLog.warn("Error '" + message + "' occured with Errorcode " + errorCode
                    + ".\nTrying to recreate MultipipeLogger pipe " + index, e);
            recover();
        }

        public void error(String message, Exception e, int errorCode, LoggingEvent event) {
            LogLog.warn("Logging Event " + e + " caused a logging error:");
            error(message, e, errorCode);
        }

        private void recover() {
            try {
                close(index);
                activateWriter(index);
            } catch (Exception E) {
                LogLog.debug("Error while trying to recover from Broken Pipe Error", E);
            }
        }

        public void setAppender(Appender appender) {
        // ignored
        }

        public void setBackupAppender(Appender appender) {
        // ignored
        }

        public void activateOptions() {
        //ignored
        }
    }
}
/*
 * MultipipeLoggerTester.java Created on 08.04.2004 11:53:03 by schabi
 * 
 * $Id: MultipipeLoggerTester.java,v 1.1 2004/04/08 10:52:05 schabi Exp $
 * 
 * (C) 2004 Markus Schaber, logi-track ag, Z�rich, Switzerland.
 * 
 * Submitted for inclusion into the apache.org log4j project, Copyright (C) The
 * Apache Software Foundation. All rights reserved.
 * 
 * This software is published under the terms of the Apache Software License
 * version 1.1, a copy of which has been included with this distribution in the
 * LICENSE.txt file.
 */

package com.logitrack.sql.posinsertdaemon.log;

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

/**
 * Test class for the multipipe Logger.
 * 
 * It is not easy to create a sensible unit test for this as there is no easy,
 * platform-independent way to read the written syslogs back :-/
 * 
 * @author Markus Schaber, logi-track ag, Z�rich, Switzerland.
 *  
 */
public class MultipipeAppenderTester {

    /**
     * Shell commant to test MultipipeLogger
     * 
     * @param args
     */
    public static void main(String[] args) {

        System.out.println("Initializing Loging System");

        MultipipeAppender app = new MultipipeAppender(new org.apache.log4j.PatternLayout(
                org.apache.log4j.PatternLayout.TTCC_CONVERSION_PATTERN), "/usr/bin/logger -p", "user");
        app.setThreshold(Level.ALL);
        BasicConfigurator.configure(app);
        Logger log = Logger.getLogger(MultipipeAppenderTester.class);

        System.out.println("Simple logging tests");
        log.debug("Debug log test");
        log.info("Info log test");
        log.warn("Warn log test");
        log.error("Error log test");
        log.fatal("Fatal log test");

        System.out.println("Failed backend recovety test");
        log.debug("Going to destroy logging backend 7");
        app.processes[7].destroy();
        log.debug("First message after destruction - will get lost");
        log.debug("Second message after destruction - should reach syslog");
        
        System.out.println("Finished - now visit your syslog files to see the results.");
    }

}

---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to