/*
* 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 syslog(3C)
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 {
/**
* syslog(3C)
ident string, prepended to every
* message.
*/
private String ident;
/**
* syslog
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
* thrown
field is set. They will be formatted in
* a single line by SuccinctStackTraceFormatter
,
* which does not include the Throwable's description, since
* it's presumably described by the log message). Default
* true
.
*/
private static boolean useStackTraces = true;
/**
* Default logging option value. Sets no options. (Corresponds
* to the logopt
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 syslog(3C)
.
*/
private static native void syslog(int severity, String message);
/**
* Calls openlog(3C)
.
*/
private static native void openlog(String ident, int logopt,
int facility);
/**
* Calls closelog(3C)
.
*/
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 syslog(3C)
ident string, which is
* prepended to every message.
*/
public String getIdent()
{
return (ident);
}
/**
* Returns the syslog
facility to be logged to.
*/
public Facility getFacility()
{
return (facility);
}
}