root/usr/src/cmd/pools/poold/com/sun/solaris/service/logging/SyslogHandler.java
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */
/*
 * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

/* ident        "%Z%%M% %I%     %E% SMI" */

package com.sun.solaris.service.logging;

import java.text.*;
import java.util.*;
import java.util.logging.Formatter;
import java.util.logging.Handler;
import java.util.logging.LogRecord;

import com.sun.solaris.service.exception.SuccinctStackTraceFormatter;

/**
 * This handler outputs LogRecords with <code>syslog(3C)</code> to the
 * given facility with a severity translated by Level with a fixed
 * table.  Formatters are not used.
 *
 * Multiple SyslogHandlers may not be in concurrent use in one virtual
 * machine.
 */
public final class SyslogHandler extends Handler {
        /**
         * <code>syslog(3C)</code> ident string, prepended to every
         * message.
         */
        private String ident;

        /**
         * <code>syslog</code> facility to be logged to.
         */
        private Facility facility;

        /**
         * Records the instance of this singleton.
         */
        private static SyslogHandler instance = null;

        /**
         * Flag whether stack traces should be output when a record's
         * <code>thrown</code> field is set.  They will be formatted in
         * a single line by <code>SuccinctStackTraceFormatter</code>,
         * which does not include the Throwable's description, since
         * it's presumably described by the log message).  Default
         * <code>true</code>.
         */
        private static boolean useStackTraces = true;

        /**
         * Default logging option value.  Sets no options.  (Corresponds
         * to the <code>logopt</code> argument to openlog(3c).)
         */
        private static final int DEF_LOGOPT = 0;

        /**
         * Flag to set whether log records should indicate the record's
         * logger.  (default false)
         */
        private boolean useLoggerName = false;

        /**
         * Flag to set whether log records should indicate the last
         * component of the record's logger name, if useLoggerName isn't
         * set.  (default true)
         */
        private boolean useShortLoggerName = true;

        static {
                System.loadLibrary("jsyslog");
        }

        private SyslogHandler(String ident, Facility facility)
        {
                if (ident == null || facility == null)
                        throw new IllegalArgumentException();

                this.ident = ident;
                this.facility = facility;

                openlog(ident, DEF_LOGOPT, facility.getNative());
                instance = this;
        }

        /**
         * Return this virtual machine's instance of SyslogHandler,
         * creating one which logs with the given identity to the given
         * facility if necessary, unless an instance with a different
         * identity or facility is already open, in which case an
         * IllegalArgumentException is thrown.
         *
         * @throws IllegalArgumentException if the requested identity or
         * facility differs from a previously-created instance.
         */
        public static SyslogHandler getInstance(String ident,
           Facility facility)
        {
                if (instance != null) {
                        if (!instance.ident.equals(ident) ||
                            !instance.facility.equals(facility))
                                throw new IllegalArgumentException();
                        else
                                return (instance);
                } else
                        return (instance = new SyslogHandler(ident, facility));
        }

        public void finalize()
        {
                try {
                        close();
                } catch (Exception e) {
                        // superclass-defined exceptions do not apply
                }
        }

        public String toString()
        {
                return ("SyslogHandler(" + ident + ", " + facility.toString() +
                    ")");
        }

        /**
         * Calls <code>syslog(3C)</code>.
         */
        private static native void syslog(int severity, String message);

        /**
         * Calls <code>openlog(3C)</code>.
         */
        private static native void openlog(String ident, int logopt,
            int facility);

        /**
         * Calls <code>closelog(3C)</code>.
         */
        private static native void closelog();

        /**
         * Publishes the given record with its associated Severity (or
         * infers its severity with Severity.severityForLevel(), if
         * another type of Level is used), if the result is non-null.
         */
        public void publish(LogRecord record)
        {
                Severity severity;

                if (record.getLevel() instanceof Severity)
                        severity = (Severity)record.getLevel();
                else
                        severity = Severity.severityForLevel(record
                            .getLevel());

                if (getLevel().intValue() > severity.intValue())
                        return;

                /*
                 * If the severity is null, the message isn't meant to
                 * be sent to syslog.
                 */
                if (severity == null)
                        return;

                StringBuffer message = new StringBuffer();
                String loggerName = record.getLoggerName();
                if (useLoggerName) {
                        if (loggerName != null) {
                                message.append("(");
                                message.append(record.getLoggerName());
                                message.append(") ");
                        }
                } else if (useShortLoggerName) {
                        if (loggerName != null) {
                                message.append("(");
                                int lastDot = loggerName.lastIndexOf('.');
                                if (lastDot >= 0)
                                        loggerName = loggerName.substring(
                                            lastDot + 1);
                                message.append(loggerName);
                                message.append(") ");
                        }
                }

                message.append(record.getMessage());

                /*
                 * If the Severity is null, it's not meant to be logged
                 * via syslog.
                 */
                if (record.getThrown() != null && useStackTraces == true) {
                        /*
                         * Format the stack trace as one line and tack
                         * it onto the message.
                         */
                        message.append(" ");
                        message.append(SuccinctStackTraceFormatter
                            .formatWithDescription(record.getThrown(),
                            "with tracing information: ").toString());
                }
                syslog(severity.getNative(), message.toString());
        }

        public void flush()
        {
        }

        public void close() throws SecurityException
        {
                if (instance != null) {
                        closelog();
                        instance = null;
                }
        }

        /**
         * Formatters may not be used with SyslogHandler.
         *
         * @throws IllegalArgumentException if the use of one is
         * attempted.
         */
        public void setFormatter(Formatter formatter)
        {
                throw new IllegalArgumentException();
        }

        /**
         * Returns the <code>syslog(3C)</code> ident string, which is
         * prepended to every message.
         */
        public String getIdent()
        {
                return (ident);
        }

        /**
         * Returns the <code>syslog</code> facility to be logged to.
         */
        public Facility getFacility()
        {
                return (facility);
        }

}