/*
* SyslogHandler.java
*
* This work 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 work 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
*
* Copyright (c) 2005 Per Cederberg. All rights reserved.
*/
package org.liquidsite.util.log;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.LogRecord;
/**
* A UNIX syslog handler. This implementation is based on RFC 3164.
*
* @author Per Cederberg, <per at percederberg dot net>
* @version 1.0
*/
public class SyslogHandler extends Handler {
/**
* The emergency log severity. Used when the system is unusable.
*/
protected static final int EMERGENCY_SEVERITY = 0;
/**
* The alert log severity. Used when action must be taken
* immediately.
*/
protected static final int ALERT_SEVERITY = 1;
/**
* The critical log severity. Used for critical conditions.
*/
protected static final int CRITICAL_SEVERITY = 2;
/**
* The error log severity. Used for error conditions.
*/
protected static final int ERROR_SEVERITY = 3;
/**
* The warning log severity. Used for warning conditions.
*/
protected static final int WARNING_SEVERITY = 4;
/**
* The notice log severity. Used for normal but significant
* conditions.
*/
protected static final int NOTICE_SEVERITY = 5;
/**
* The informational log severity. Used for informational
* messages.
*/
protected static final int INFO_SEVERITY = 6;
/**
* The debug log severity. Used for debug-level messages.
*/
protected static final int DEBUG_SEVERITY = 7;
/**
* The date format to use.
*/
private static final SimpleDateFormat DATE_FORMAT =
new SimpleDateFormat("MMM dd HH:MM:ss");
/**
* The maximum log message size.
*/
private static int MAX_SIZE = 1024;
/**
* The datagram socket used for sending log messages.
*/
private DatagramSocket socket = null;
/**
* The IP address of the syslog server.
*/
private InetAddress address = null;
/**
* The port number of the syslog server.
*/
private int port = 514;
/**
* The facility number.
*/
private int facility = 16;
/**
* The host name.
*/
private String hostname = "localhost";
/**
* The tag name.
*/
private String tag = "java";
/**
* Creates a new syslog handler.
*
* @throws SocketException if an UDP socket couldn't be opened
* @throws UnknownHostException if the localhost IP address
* couldn't be determined
*/
public SyslogHandler() throws SocketException, UnknownHostException {
socket = new DatagramSocket();
address = InetAddress.getLocalHost();
}
/**
* Returns the IP address of the syslog server. The default is
* to use localhost.
*
* @return the IP address of the syslog server
*/
public InetAddress getAddress() {
return this.address;
}
/**
* Sets the IP address of the syslog server.
*
* @param address the IP address of the syslog server
*/
public void setAddress(InetAddress address) {
this.address = address;
}
/**
* Returns the port number of the syslog server. The default is
* to use port 514.
*
* @return the port number of the syslog server
*/
public int getPort() {
return this.port;
}
/**
* Sets the port number of the syslog server.
*
* @param port the port number of the syslog server
*/
public void setPort(int port) {
this.port = port;
}
/**
* Returns the log facility to use.
*
* @return the log facility to use
*/
public int getFacility() {
return facility;
}
/**
* Sets the log facility to use.
*
* @param facility the new log facility
*/
public void setFacility(int facility) {
this.facility = facility;
}
/**
* Returns the hostname to use.
*
* @return the hostname to use
*/
public String getHostname() {
return hostname;
}
/**
* Sets the hostname to use.
*
* @param hostname the new hostname
*/
public void setHostname(String hostname) {
this.hostname = hostname;
}
/**
* Returns the log tag to use.
*
* @return the log tag to use
*/
public String getTag() {
return tag;
}
/**
* Sets the log tag to use.
*
* @param tag the new log tag
*/
public void setTag(String tag) {
this.tag = tag;
}
/**
* Publishes a log record.
*
* @param record the log record to publish
*/
public void publish(LogRecord record) {
StringBuffer buffer = new StringBuffer(256);
DatagramPacket packet;
byte[] payload;
int size;
// Write the PRI part
buffer.append("<");
buffer.append(facility << 3 + getSeverity(record));
buffer.append(">");
// Write the HEADER part
buffer.append(DATE_FORMAT.format(new Date(record.getMillis())));
buffer.append(" ");
buffer.append(hostname);
buffer.append(" ");
// Write the MSG part
buffer.append(tag);
buffer.append(": ");
buffer.append("[");
buffer.append(record.getSourceClassName());
buffer.append(" ");
buffer.append(record.getSourceMethodName());
buffer.append("] ");
buffer.append(record.getMessage());
// Send datagram packet
try {
payload = buffer.toString().getBytes();
size = (payload.length > MAX_SIZE) ? MAX_SIZE : payload.length;
packet = new DatagramPacket(payload, size, address, port);
socket.send(packet);
} catch (IOException e) {
System.err.println("failed to write to syslog: " +
e.getMessage());
}
}
/**
* Closes the log handler and frees any resources.
*/
public void close() {
socket.close();
}
/**
* Flushes any buffered output.
*/
public void flush() {
// Do nothing
}
/**
* Returns the syslog severity constant corresponding to a log
* record.
*
* @param record the log record
*
* @return the syslog severity constant value
*/
private int getSeverity(LogRecord record) {
int level = record.getLevel().intValue();
if (level == Level.SEVERE.intValue()) {
return ERROR_SEVERITY;
} else if (level == Level.WARNING.intValue()) {
return WARNING_SEVERITY;
} else if (level == Level.INFO.intValue()) {
return INFO_SEVERITY;
} else {
return DEBUG_SEVERITY;
}
}
}