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

org.apache.camel.component.syslog.SyslogConverter Maven / Gradle / Ivy

There is a newer version: 4.8.1
Show newest version
/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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 org.apache.camel.component.syslog;

import java.net.InetAddress;
import java.net.UnknownHostException;
import java.nio.ByteBuffer;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.Map;

import jakarta.xml.bind.DatatypeConverter;

import org.apache.camel.Converter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import static org.apache.camel.util.BufferCaster.cast;

@Converter(generateLoader = true)
public final class SyslogConverter {

    private static final Logger LOG = LoggerFactory.getLogger(SyslogConverter.class);

    private enum MONTHS {
        jan,
        feb,
        mar,
        apr,
        may,
        jun,
        jul,
        aug,
        sep,
        oct,
        nov,
        dec
    }

    private static Map monthValueMap = new HashMap() {
        private static final long serialVersionUID = 1L;

        {
            put("jan", MONTHS.jan);
            put("feb", MONTHS.feb);
            put("mar", MONTHS.mar);
            put("apr", MONTHS.apr);
            put("may", MONTHS.may);
            put("jun", MONTHS.jun);
            put("jul", MONTHS.jul);
            put("aug", MONTHS.aug);
            put("sep", MONTHS.sep);
            put("oct", MONTHS.oct);
            put("nov", MONTHS.nov);
            put("dec", MONTHS.dec);
        }
    };

    private SyslogConverter() {
        // Utility class
    }

    @Converter
    public static String toString(SyslogMessage message) {

        boolean isRfc5424 = message instanceof Rfc5424SyslogMessage;

        StringBuilder sbr = new StringBuilder();
        sbr.append("<");
        if (message.getFacility() == null) {
            message.setFacility(SyslogFacility.USER);
        }
        if (message.getSeverity() == null) {
            message.setSeverity(SyslogSeverity.INFO);
        }
        if (message.getHostname() == null) {
            // This is massively ugly..
            try {
                message.setHostname(InetAddress.getLocalHost().toString());
            } catch (UnknownHostException e) {
                message.setHostname("UNKNOWN_HOST");
            }
        }
        sbr.append(message.getFacility().ordinal() * 8 + message.getSeverity().ordinal());
        sbr.append(">");

        // version number
        if (isRfc5424) {
            sbr.append("1");
            sbr.append(" ");
        }

        if (message.getTimestamp() == null) {
            message.setTimestamp(Calendar.getInstance());
        }

        if (isRfc5424) {
            sbr.append(DatatypeConverter.printDateTime(message.getTimestamp()));
        } else {
            addRfc3164TimeStamp(sbr, message);
        }
        sbr.append(" ");

        sbr.append(message.getHostname());
        sbr.append(" ");

        if (isRfc5424) {
            Rfc5424SyslogMessage rfc5424SyslogMessage = (Rfc5424SyslogMessage) message;

            sbr.append(rfc5424SyslogMessage.getAppName());
            sbr.append(" ");

            sbr.append(rfc5424SyslogMessage.getProcId());
            sbr.append(" ");

            sbr.append(rfc5424SyslogMessage.getMsgId());
            sbr.append(" ");

            sbr.append(rfc5424SyslogMessage.getStructuredData());
            sbr.append(" ");
        }

        sbr.append(message.getLogMessage());

        return sbr.toString();
    }

    @Converter
    public static SyslogMessage toSyslogMessage(String body) {
        return parseMessage(body.getBytes());
    }

    public static SyslogMessage parseMessage(byte[] bytes) {
        ByteBuffer byteBuffer = ByteBuffer.allocate(bytes.length);
        byteBuffer.put(bytes);
        cast(byteBuffer).rewind();

        Character charFound = (char) byteBuffer.get();

        SyslogFacility foundFacility = null;
        SyslogSeverity foundSeverity = null;

        while (charFound != '<') {
            // Ignore noise in beginning of message.
            charFound = (char) byteBuffer.get();
        }
        char priChar = 0;
        if (charFound == '<') {
            int facility = 0;

            while (Character.isDigit(priChar = (char) (byteBuffer.get() & 0xff))) {
                facility *= 10;
                facility += Character.digit(priChar, 10);
            }
            foundFacility = SyslogFacility.values()[facility >> 3];
            foundSeverity = SyslogSeverity.values()[facility & 0x07];
        }

        if (priChar != '>') {
            // Invalid character - this is not a well defined syslog message.
            LOG.error("Invalid syslog message, missing a > in the Facility/Priority part");
        }

        SyslogMessage syslogMessage = new SyslogMessage();
        boolean isRfc5424 = false;
        // Read next character
        charFound = (char) byteBuffer.get();
        // If next character is a 1, we have probably found an rfc 5424 message
        // message
        if (charFound == '1') {
            syslogMessage = new Rfc5424SyslogMessage();
            isRfc5424 = true;
        } else {
            // go back one to parse the rfc3164 date
            byteBuffer.position(byteBuffer.position() - 1);
        }

        syslogMessage.setFacility(foundFacility);
        syslogMessage.setSeverity(foundSeverity);

        if (!isRfc5424) {
            // Parse rfc 3164 date
            syslogMessage.setTimestamp(parseRfc3164Date(byteBuffer));
        } else {

            charFound = (char) byteBuffer.get();
            if (charFound != ' ') {
                LOG.error("Invalid syslog message, missing a mandatory space after version");
            }

            // This should be the timestamp
            StringBuilder date = new StringBuilder();
            while ((charFound = (char) (byteBuffer.get() & 0xff)) != ' ') {
                date.append(charFound);
            }

            syslogMessage.setTimestamp(DatatypeConverter.parseDateTime(date.toString()));
        }

        // The host is the char sequence until the next ' '

        StringBuilder host = new StringBuilder();
        while ((charFound = (char) (byteBuffer.get() & 0xff)) != ' ') {
            host.append(charFound);
        }

        syslogMessage.setHostname(host.toString());

        if (isRfc5424) {
            Rfc5424SyslogMessage rfc5424SyslogMessage = (Rfc5424SyslogMessage) syslogMessage;
            StringBuilder appName = new StringBuilder();
            while ((charFound = (char) (byteBuffer.get() & 0xff)) != ' ') {
                appName.append(charFound);
            }
            rfc5424SyslogMessage.setAppName(appName.toString());

            StringBuilder procId = new StringBuilder();
            while ((charFound = (char) (byteBuffer.get() & 0xff)) != ' ') {
                procId.append(charFound);
            }
            rfc5424SyslogMessage.setProcId(procId.toString());

            StringBuilder msgId = new StringBuilder();
            while ((charFound = (char) (byteBuffer.get() & 0xff)) != ' ') {
                msgId.append(charFound);
            }
            rfc5424SyslogMessage.setMsgId(msgId.toString());

            StringBuilder structuredData = new StringBuilder();
            boolean inblock = false;
            while ((charFound = (char) (byteBuffer.get() & 0xff)) != ' ' || inblock) {
                if (charFound == '[') {
                    inblock = true;
                }
                if (charFound == ']') {
                    inblock = false;
                }
                structuredData.append(charFound);
            }
            rfc5424SyslogMessage.setStructuredData(structuredData.toString());
        }

        StringBuilder msg = new StringBuilder();
        while (byteBuffer.hasRemaining()) {
            charFound = (char) (byteBuffer.get() & 0xff);
            msg.append(charFound);
        }

        syslogMessage.setLogMessage(msg.toString());
        LOG.trace("Syslog message : {}", syslogMessage);

        return syslogMessage;
    }

    private static void addRfc3164TimeStamp(StringBuilder sbr, SyslogMessage message) {
        // SDF isn't going to help much here.

        Calendar cal = message.getTimestamp();

        String firstLetter = MONTHS.values()[cal.get(Calendar.MONTH)].toString().substring(0, 1); // Get
        // first
        // letter
        String remainder = MONTHS.values()[cal.get(Calendar.MONTH)].toString().substring(1); // Get
        // remainder
        // of
        // word.
        String capitalized = firstLetter.toUpperCase() + remainder.toLowerCase();

        sbr.append(capitalized);
        sbr.append(" ");

        if (cal.get(Calendar.DAY_OF_MONTH) < 10) {
            sbr.append(" ").append(cal.get(Calendar.DAY_OF_MONTH));
        } else {
            sbr.append(cal.get(Calendar.DAY_OF_MONTH));
        }

        sbr.append(" ");

        if (cal.get(Calendar.HOUR_OF_DAY) < 10) {
            sbr.append("0").append(cal.get(Calendar.HOUR_OF_DAY));
        } else {
            sbr.append(cal.get(Calendar.HOUR_OF_DAY));
        }
        sbr.append(":");

        if (cal.get(Calendar.MINUTE) < 10) {
            sbr.append("0").append(cal.get(Calendar.MINUTE));
        } else {
            sbr.append(cal.get(Calendar.MINUTE));
        }
        sbr.append(":");

        if (cal.get(Calendar.SECOND) < 10) {
            sbr.append("0").append(cal.get(Calendar.SECOND));
        } else {
            sbr.append(cal.get(Calendar.SECOND));
        }
    }

    private static Calendar parseRfc3164Date(ByteBuffer byteBuffer) {
        char charFound;

        // Done parsing severity and facility
        // <169>Oct 22 10:52:01 TZ-6 scapegoat.dmz.example.org 10.1.2.3
        // sched[0]: That's All Folks!
        // Need to parse the date.

        /**
         * The TIMESTAMP field is the local time and is in the format of "Mmm dd hh:mm:ss" (without the quote marks)
         * where: Mmm is the English language abbreviation for the month of the year with the first character in
         * uppercase and the other two characters in lowercase. The following are the only acceptable values: Jan, Feb,
         * Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec dd is the day of the month. If the day of the month is less
         * than 10, then it MUST be represented as a space and then the number. For example, the 7th day of August would
         * be represented as "Aug 7", with two spaces between the "g" and the "7". hh:mm:ss is the local time. The hour
         * (hh) is represented in a 24-hour format. Valid entries are between 00 and 23, inclusive. The minute (mm) and
         * second (ss) entries are between 00 and 59 inclusive.
         */

        char[] month = new char[3];
        for (int i = 0; i < 3; i++) {
            month[i] = (char) (byteBuffer.get() & 0xff);
        }
        charFound = (char) byteBuffer.get();
        if (charFound != ' ') {
            // Invalid Message - missing mandatory space.
            LOG.error("Invalid syslog message, missing a mandatory space after month");
        }
        charFound = (char) (byteBuffer.get() & 0xff);

        int day = 0;
        if (charFound == ' ') {
            // Extra space for the day - this is okay.
            // Just ignored per the spec.
        } else {
            day *= 10;
            day += Character.digit(charFound, 10);
        }

        while (Character.isDigit(charFound = (char) (byteBuffer.get() & 0xff))) {
            day *= 10;
            day += Character.digit(charFound, 10);
        }

        int hour = 0;
        while (Character.isDigit(charFound = (char) (byteBuffer.get() & 0xff))) {
            hour *= 10;
            hour += Character.digit(charFound, 10);
        }

        int minute = 0;
        while (Character.isDigit(charFound = (char) (byteBuffer.get() & 0xff))) {
            minute *= 10;
            minute += Character.digit(charFound, 10);
        }

        int second = 0;
        while (Character.isDigit(charFound = (char) (byteBuffer.get() & 0xff))) {
            second *= 10;
            second += Character.digit(charFound, 10);
        }

        Calendar calendar = new GregorianCalendar();
        calendar.set(Calendar.MONTH, monthValueMap.get(String.valueOf(month).toLowerCase()).ordinal());
        calendar.set(Calendar.DAY_OF_MONTH, day);
        calendar.set(Calendar.HOUR_OF_DAY, hour);
        calendar.set(Calendar.MINUTE, minute);
        calendar.set(Calendar.SECOND, second);

        return calendar;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy