All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.cloudbees.syslog.SyslogMessage Maven / Gradle / Ivy

There is a newer version: 1.1.7
Show newest version
/*
 * Copyright 2010-2014, CloudBees Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.cloudbees.syslog;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.io.CharArrayWriter;
import java.io.IOException;
import java.io.StringWriter;
import java.io.Writer;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Date;
import java.util.HashSet;
import java.util.Locale;
import java.util.Set;
import java.util.TimeZone;
import java.util.concurrent.TimeUnit;

import com.cloudbees.syslog.util.CachingReference;
import com.cloudbees.syslog.util.ConcurrentDateFormat;

/**
 * Syslog message as defined in RFC 5424 - The Syslog Protocol.
 *
 * Also compatible with RFC-3164: The BSD syslog Protocol,
 *
 * @author Cyrille Le Clerc
 */
public class SyslogMessage {
    public final static char SP = ' ';
    public final static char NILVALUE = '-';

    private final static int DEFAULT_CONCURRENCY = 50;
    protected final static ConcurrentDateFormat rfc3339DateFormat;
    protected final static ConcurrentDateFormat rfc3164DateFormat;
    private static CachingReference localhostNameReference = new CachingReference(10, TimeUnit.SECONDS) {
        @Override
        protected String newObject() {
            try {
                return InetAddress.getLocalHost().getHostName();
            } catch (UnknownHostException e) {
                return String.valueOf(NILVALUE);
            }
        }
    };

    static {
        int concurrency;
        try {
            concurrency = Integer.parseInt(System.getProperty(SyslogMessage.class.getPackage().getName() + ".concurrency", String.valueOf(DEFAULT_CONCURRENCY)));
        } catch (Exception e) {
            concurrency = DEFAULT_CONCURRENCY;
        }

        rfc3339DateFormat = new ConcurrentDateFormat(
                "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'",
                Locale.US,
                TimeZone.getTimeZone("GMT"),
                concurrency);

        /**
         * According to RFC31614- 4.1.2 HEADER Part of a syslog Packet,
         * we should use local time and not GMT.
         * 
         *     The TIMESTAMP field is the local time and is in the format of "Mmm dd hh:mm:ss" (without the quote marks)
         * 
         */
        rfc3164DateFormat = new ConcurrentDateFormat(
                "MMM dd HH:mm:ss",
                Locale.US,
                TimeZone.getDefault(),
                concurrency);
    }

    private Facility facility;
    private Severity severity;
    private Date timestamp;
    private String hostname;
    private String appName;
    private String procId;
    private String msgId;
    private Set sdElements;
    /**
     * Use a {@link java.io.CharArrayWriter} instead of a {@link String}  or a {@code char[]} because middlewares like
     * Apache Tomcat use {@code CharArrayWriter} and it's convenient for pooling objects.
     */
    private CharArrayWriter msg;

    public Facility getFacility() {
        return facility;
    }

    public void setFacility(Facility facility) {
        this.facility = facility;
    }

    public SyslogMessage withFacility(Facility facility) {
        this.facility = facility;
        return this;
    }

    public Severity getSeverity() {
        return severity;
    }

    public void setSeverity(Severity severity) {
        this.severity = severity;
    }

    public SyslogMessage withSeverity(Severity severity) {
        this.severity = severity;
        return this;
    }

    public Date getTimestamp() {
        return timestamp;
    }

    public void setTimestamp(Date timestamp) {
        this.timestamp = timestamp;
    }

    public SyslogMessage withTimestamp(long timestamp) {
        this.timestamp = new Date(timestamp);
        return this;
    }

    public SyslogMessage withTimestamp(Date timestamp) {
        this.timestamp = timestamp;
        return this;
    }

    public String getHostname() {
        return hostname;
    }

    public void setHostname(String hostname) {
        this.hostname = hostname;
    }

    public SyslogMessage withHostname(String hostname) {
        this.hostname = hostname;
        return this;
    }

    public String getAppName() {
        return appName;
    }

    public void setAppName(String appName) {
        this.appName = appName;
    }

    public SyslogMessage withAppName(String appName) {
        this.appName = appName;
        return this;
    }

    public String getProcId() {
        return procId;
    }

    public void setProcId(String procId) {
        this.procId = procId;
    }

    public SyslogMessage withProcId(String procId) {
        this.procId = procId;
        return this;
    }

    public String getMsgId() {
        return msgId;
    }

    public void setMsgId(String msgId) {
        this.msgId = msgId;
    }

    public SyslogMessage withMsgId(String msgId) {
        this.msgId = msgId;
        return this;
    }

    public CharArrayWriter getMsg() {
        return msg;
    }

    public void setMsg(CharArrayWriter msg) {
        this.msg = msg;
    }

    public SyslogMessage withMsg(CharArrayWriter msg) {
        this.msg = msg;
        return this;
    }

    public SyslogMessage withMsg(final String msg) {
        return withMsg(new CharArrayWriter() {
            {
                append(msg);
            }
        });
    }
    
    public Set getSDElements() {
        Set ssde = sdElements;
        if (ssde == null) {
            ssde = new HashSet(0);
        }
        return ssde;
    }
    
    public void setSDElements(Set ssde) {
        this.sdElements = ssde;
    }
    
    public SyslogMessage withSDElement(SDElement sde) {
        if (sdElements == null) {
            sdElements = new HashSet();
        }
        sdElements.add(sde);
        return this;
    }

    /**
     * Generates a Syslog message complying to the RFC-5424 format
     * or to the RFC-3164 format.
     *
     * @param messageFormat message format, not {@code null}
     */
    public String toSyslogMessage(MessageFormat messageFormat) {
        switch (messageFormat) {
            case RFC_3164:
                return toRfc3164SyslogMessage();
            case RFC_5424:
                return toRfc5424SyslogMessage();
            default:
                throw new IllegalStateException("Unsupported message format '" + messageFormat + "'");
        }
    }

    /**
     * Generates a Syslog message complying to the RFC-5424 format
     * or to the RFC-3164 format.
     *
     * @param messageFormat message format
     * @param out                 output {@linkplain Writer}
     */
    public void toSyslogMessage(@Nonnull MessageFormat messageFormat, @Nonnull Writer out) throws IOException {
        switch (messageFormat) {
            case RFC_3164:
                toRfc3164SyslogMessage(out);
                break;
            case RFC_5424:
                toRfc5424SyslogMessage(out);
                break;
            default:
                throw new IllegalStateException("Unsupported message format '" + messageFormat + "'");
        }
    }

    /**
     * Generates an RFC-5424 message.
     */
    public String toRfc5424SyslogMessage() {

        StringWriter sw = new StringWriter(msg == null ? 32 : msg.size() + 32);
        try {
            toRfc5424SyslogMessage(sw);
        } catch (IOException e) {
            throw new IllegalStateException(e);
        }
        return sw.toString();
    }

    /**
     * Generates an RFC-5424 message.
     *
     * The priority is calculated by facility * 8 + severity, see
     * RFC-5424, Section 6.2.1
     */
    public void toRfc5424SyslogMessage(Writer out) throws IOException {

        int pri = facility.numericalCode() * 8 + severity.numericalCode();

        out.write('<');
        out.write(String.valueOf(pri));
        out.write('>');
        out.write('1'); // version
        out.write(SP);
        out.write(rfc3339DateFormat.format(timestamp == null ? new Date() : timestamp)); // message time
        out.write(SP);
        out.write(hostname == null ? localhostNameReference.get() : hostname); // emitting server hostname
        out.write(SP);
        writeNillableValue(appName, out); // appname
        out.write(SP);
        writeNillableValue(procId, out); // PID
        out.write(SP);
        writeNillableValue(msgId, out);// Message ID
        out.write(SP);
        writeStructuredDataOrNillableValue(sdElements, out);
        if (msg != null) {
            out.write(SP);
            msg.writeTo(out);
        }
    }

    /**
     * Generates an RFC-3164 message.
     *
     * @see #toRfc3164SyslogMessage(java.io.Writer)
     */
    public String toRfc3164SyslogMessage() {

        StringWriter sw = new StringWriter(msg == null ? 32 : msg.size() + 32);
        try {
            toRfc3164SyslogMessage(sw);
        } catch (IOException e) {
            throw new IllegalStateException(e);
        }
        return sw.toString();
    }

    /**
     * Generates an RFC-3164 message.
     */
    public void toRfc3164SyslogMessage(Writer out) throws IOException {

        int pri = facility.numericalCode() + severity.numericalCode();

        out.write('<');
        out.write(Integer.toString(pri));
        out.write('>');
        out.write(rfc3164DateFormat.format(timestamp == null ? new Date() : timestamp)); // message time
        out.write(SP);
        out.write((hostname == null) ? localhostNameReference.get() : hostname); // emitting server hostname
        out.write(SP);
        writeNillableValue(appName, out); // appname

        if (msg != null) {
            out.write(": ");
            msg.writeTo(out);
        }
    }

    protected void writeNillableValue(@Nullable String value, @Nonnull Writer out) throws IOException {
        if (value == null) {
            out.write(NILVALUE);
        } else {
            out.write(value);
        }
    }
    
    protected void writeStructuredDataOrNillableValue(@Nullable Set ssde, @Nonnull Writer out) throws IOException {
        if (ssde == null || ssde.isEmpty()) {
            out.write(NILVALUE);
        } else {
            for (SDElement sde : ssde) {
                writeSDElement(sde, out);
            }
        }
    }
    
    protected void writeSDElement(@Nonnull SDElement sde, @Nonnull Writer out) throws IOException {
        out.write("[");
        out.write(sde.getSdID());
        for (SDParam sdp : sde.getSdParams()) {
            writeSDParam(sdp, out);
        }
        out.write("]");
    }
    
    protected void writeSDParam(@Nonnull SDParam sdp, @Nonnull Writer out) throws IOException {
        out.write(SP);
        out.write(sdp.getParamName());
        out.write('=');
        out.write('"');
        out.write(getEscapedParamValue(sdp.getParamValue()));
        out.write('"');
    }
    
    protected String getEscapedParamValue(String paramValue) {
        StringBuilder sb = new StringBuilder(paramValue.length());
        
        for (int i = 0; i < paramValue.length(); i++) {
            char c = paramValue.charAt(i);
            switch (c) {
                // Falls through
                case '"':
                case '\\':
                case ']':
                    sb.append('\\');
                    break;
                default:
                    break;
            }
            sb.append(c);
        }
        
        return sb.toString();
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy