org.opendaylight.streamhandler.impl.LogCollector.java Source code

Java tutorial

Introduction

Here is the source code for org.opendaylight.streamhandler.impl.LogCollector.java

Source

/*
 * Copyright (c) 2015 Tata Consultancy services and others.  All rights reserved.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
 * and is available at http://www.eclipse.org/legal/epl-v10.html
 */

package org.opendaylight.streamhandler.impl;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Future;
import java.util.regex.Pattern;

import org.codehaus.jettison.json.JSONException;
import org.codehaus.jettison.json.JSONObject;
import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.streamhandler.rev150105.EventBodyType;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.streamhandler.rev150105.PersistEventInputBuilder;
import org.opendaylight.yangtools.yang.common.RpcResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.common.base.Preconditions;
import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.ClientHandlerException;
import com.sun.jersey.api.client.ClientResponse;
import com.sun.jersey.api.client.WebResource;

public class LogCollector extends Thread {
    private static final Logger LOG = LoggerFactory.getLogger(LogCollector.class);
    CommonServices commonServices = CommonServices.getInstance();

    public void run() {
        // Unsecured connection
        Socket conn = null;
        ServerSocket s = null;
        try {

            s = new ServerSocket(Integer.parseInt(commonServices.syslogPort));
            conn = s.accept();
            new ClientHandler(conn).start();
        } catch (Exception e) {
            LOG.error("Exception while connecting " + e.getMessage(), e);
        } finally {
            if (s != null)
                try {
                    s.close();
                } catch (IOException e) {
                    LOG.error("IO Exception while closing connection from un-secured Logcollector :: "
                            + e.getMessage());
                }
        }
    }
}

class ClientHandler extends Thread {
    PrintWriter out = null;
    private Socket conn;
    private static final int RFC3164_LENGTH = 15;
    private static final Pattern SPACES_TWO_CHECK = Pattern.compile("  ");
    private static final DateTimeFormatter RFC3164_FORMAT_DATETIME = DateTimeFormat.forPattern("MMM d HH:mm:ss")
            .withZoneUTC();
    private static final int RFC5424_LEN_PREFIX = 19;
    private static final String TIMEPAT = "yyyy-MM-dd'T'HH:mm:ss";
    private DateTimeFormatter timeParser = DateTimeFormat.forPattern(TIMEPAT).withZoneUTC();

    JSONObject data = null;
    PersistEventInputBuilder input = null;
    StreamhandlerImpl streamHandlerImpl = new StreamhandlerImpl();
    private static final Logger LOG = LoggerFactory.getLogger(ClientHandler.class);
    public static final Client client = Client.create();
    CommonServices commonServices = CommonServices.getInstance();

    ClientHandler(Socket conn) {
        this.conn = conn;
    }

    public void run() {
        String line = null;
        try {
            // get socket writing and reading streams
            BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream()));
            // Send welcome message to client
            LOG.info("Welcome to the Server");
            // Now start reading input from client
            input = new PersistEventInputBuilder();
            input.setEventBodyType(EventBodyType.Avro);
            List<String> keyList = new ArrayList<String>();
            keyList.add("log_time");
            keyList.add("message");
            input.setEventKeys(keyList);
            input.setEventType("stringdata");
            while (((line = br.readLine()) != null) && (!(line.equals("")))
                    && ConfigurationChangeImpl.collectThread) {
                try {
                    try {
                        data = parseLogMessage(line);
                        line = null;
                    } catch (JSONException e) {
                        LOG.error("Exception while converting getting JSON from parseLogMessage " + e.getMessage(),
                                e);
                    }
                    // start Persisting Log event into Hbase
                    input.setEventBody(data.toString());
                    // end Persisting Log event into Hbase
                    Future<RpcResult<Void>> persistEvent = streamHandlerImpl.persistEvent(input.build());
                    // end Persisting Log event into Hbase
                    // if persisted successfully send it to graylog
                    if (persistEvent.get().isSuccessful()) {

                        WebResource webResource = client.resource("http://" + commonServices.graylogHostname
                                + StreamConstants.COLON + commonServices.gelfPort + "/gelf");
                        try {
                            webResource.type("application/json").post(ClientResponse.class, data.toString());
                        } catch (ClientHandlerException clientHandlerExceptionFlume) {
                            LOG.error("Cannot connect to Graylog.Check specifications. Graylog Hostname -> "
                                    + commonServices.graylogHostname + " /Graylog Port -> "
                                    + commonServices.gelfPort);
                        }
                    }
                } catch (Exception e) {
                    LOG.error("Unable to parse message: " + " Error Message > " + e.getMessage(), e);

                }

            }
        } catch (IOException e) {
            LOG.error("IOException on socket from run: " + e);
        } finally {
            // conn = null;
            try {
                if (conn != null)
                    conn.close();

            } catch (IOException e) {
                LOG.error("IOException from run of un-secured logCollector :: " + e.getMessage());
            }
        }

    }

    public JSONObject parseLogMessage(String logMessage) throws JSONException {
        JSONObject jsonLogEvent = new JSONObject();
        int cursorPosition = 0;
        int msgLength = logMessage.length();
        Preconditions.checkArgument(logMessage.charAt(cursorPosition) == '<',
                "Bad format: invalid priority: cannot find open bracket '<' (%s)", logMessage);

        int endBracPosition = logMessage.indexOf('>');
        Preconditions.checkArgument(endBracPosition > 0 && endBracPosition <= 6,
                "Bad format: invalid priority: cannot find end bracket '>' (%s)", logMessage);
        String priority = logMessage.substring(1, endBracPosition);
        int priIntValue = Integer.parseInt(priority);
        int facility = priIntValue / 8;
        int severity = priIntValue % 8;
        // saving priority and facility into JSONObject
        jsonLogEvent.put("facility", String.valueOf(facility));
        jsonLogEvent.put("severity", String.valueOf(severity));
        Preconditions.checkArgument(msgLength > endBracPosition + 1, "Bad format: no data except priority (%s)",
                logMessage);
        cursorPosition = endBracPosition + 1;
        if (msgLength > cursorPosition + 2 && "1 ".equals(logMessage.substring(cursorPosition, cursorPosition + 2)))
            cursorPosition += 2;
        // parsing timestamp and handling different timestamp formats
        long timeStamp;
        char chardateStart = logMessage.charAt(cursorPosition);
        try {
            // when no timestamp is specified relay current time is used
            if (chardateStart == '-') {
                timeStamp = System.currentTimeMillis();
                if (msgLength <= cursorPosition + 2) {
                    LOG.error("bad syslog format (missing hostname).Log string :- " + logMessage);
                    throw new IllegalArgumentException("bad syslog format (missing hostname)");
                }
                cursorPosition += 2;
            } else if (chardateStart >= 'A' && chardateStart <= 'Z') {
                if (msgLength <= cursorPosition + RFC3164_LENGTH) {
                    LOG.error("bad timestamp format " + logMessage);
                    throw new IllegalArgumentException("bad timestamp format");
                }
                timeStamp = rfc3164TimeStamp(logMessage.substring(cursorPosition, cursorPosition + RFC3164_LENGTH));
                cursorPosition += RFC3164_LENGTH + 1;
            } else {
                int nextSpaceIndex = logMessage.indexOf(' ', cursorPosition);
                if (nextSpaceIndex == -1) {
                    LOG.error("bad timestamp format " + logMessage);
                    throw new IllegalArgumentException("bad timestamp format");
                }
                timeStamp = rfc5424DateTime(logMessage.substring(cursorPosition, nextSpaceIndex));
                cursorPosition = nextSpaceIndex + 1;
            }
        } catch (IllegalArgumentException ex) {
            LOG.error("Unable to parse message: " + logMessage);
            throw new IllegalArgumentException("Unable to parse message: " + logMessage, ex);
        }
        jsonLogEvent.put("log_time", String.valueOf(timeStamp));
        int nextSpaceIndex = logMessage.indexOf(' ', cursorPosition);
        if (nextSpaceIndex == -1) {
            throw new IllegalArgumentException("bad syslog format (missing hostname)");
        }
        String hostname = new String(logMessage.substring(cursorPosition, nextSpaceIndex));
        jsonLogEvent.put("hostname", hostname);
        String messageData = "";
        if (msgLength > nextSpaceIndex + 1) {
            cursorPosition = nextSpaceIndex + 1;
            messageData = logMessage.substring(cursorPosition);
        } else {

            messageData = logMessage;
        }
        jsonLogEvent.put("message", messageData);
        return jsonLogEvent;
    }

    // parsing RFC3164 timestamp
    protected long rfc3164TimeStamp(String timeStamp) {
        DateTime currentDateTime = DateTime.now();
        int yearCurrent = currentDateTime.getYear();
        timeStamp = SPACES_TWO_CHECK.matcher(timeStamp).replaceFirst(" ");
        DateTime dateReturned;
        try {
            dateReturned = RFC3164_FORMAT_DATETIME.parseDateTime(timeStamp);
        } catch (IllegalArgumentException e) {
            LOG.error("rfc3164 date parse failed on (" + timeStamp + "): invalid format", e);
            return 0;
        }
        if (dateReturned != null) {
            DateTime fixedDate = dateReturned.withYear(yearCurrent);
            if (fixedDate.isAfter(currentDateTime) && fixedDate.minusMonths(1).isAfter(currentDateTime)) {
                fixedDate = dateReturned.withYear(yearCurrent - 1);
            } else if (fixedDate.isBefore(currentDateTime) && fixedDate.plusMonths(1).isBefore(currentDateTime)) {
                fixedDate = dateReturned.withYear(yearCurrent + 1);
            }
            dateReturned = fixedDate;
        }
        if (dateReturned == null) {
            return 0;
        }
        return dateReturned.getMillis();
    }

    // parsing Rfc5424 timestamp
    protected long rfc5424DateTime(String message) {
        int msgLength = message.length();
        int curPosition = 0;
        Long timeStamp = null;
        Preconditions.checkArgument(msgLength > RFC5424_LEN_PREFIX, "Bad format: Not a valid RFC5424 timestamp: %s",
                message);
        String timeStampPrefix = message.substring(curPosition, RFC5424_LEN_PREFIX);
        timeStamp = timeParser.parseMillis(timeStampPrefix);
        curPosition += RFC5424_LEN_PREFIX;
        Preconditions.checkArgument(timeStamp != null, "Parsing error: timestamp is null");
        if (message.charAt(curPosition) == '.') {
            boolean endFound = false;
            int endMillisPosition = curPosition + 1;
            if (msgLength <= endMillisPosition) {
                throw new IllegalArgumentException("bad timestamp format (no TZ)");
            }
            while (!endFound) {
                char curDigit = message.charAt(endMillisPosition);
                if (curDigit >= '0' && curDigit <= '9') {
                    endMillisPosition++;
                } else {
                    endFound = true;
                }
            }
            if (endMillisPosition - (curPosition + 1) > 0) {
                float frac = Float.parseFloat(message.substring(curPosition, endMillisPosition));
                long milliseconds = (long) (frac * 1000f);
                timeStamp += milliseconds;
            } else {
                throw new IllegalArgumentException(
                        "Bad format: Invalid timestamp (fractional portion): " + message);
            }
            curPosition = endMillisPosition;
        }
        char timeZoneFirst = message.charAt(curPosition);
        if (timeZoneFirst != 'Z') {
            if (timeZoneFirst == '+' || timeZoneFirst == '-') {
                Preconditions.checkArgument(msgLength > curPosition + 5, "Bad format: Invalid timezone (%s)",
                        message);
                int polarity;
                if (timeZoneFirst == '+') {
                    polarity = +1;
                } else {
                    polarity = -1;
                }
                char[] charAtPos = new char[5];
                for (int i = 0; i < 5; i++) {
                    charAtPos[i] = message.charAt(curPosition + 1 + i);
                }
                if (charAtPos[0] >= '0' && charAtPos[0] <= '9' && charAtPos[1] >= '0' && charAtPos[1] <= '9'
                        && charAtPos[2] == ':' && charAtPos[3] >= '0' && charAtPos[3] <= '9' && charAtPos[4] >= '0'
                        && charAtPos[4] <= '9') {
                    int hourOffset = Integer.parseInt(message.substring(curPosition + 1, curPosition + 3));
                    int minOffset = Integer.parseInt(message.substring(curPosition + 4, curPosition + 6));
                    timeStamp = timeStamp - polarity * ((hourOffset * 60) + minOffset) * 60000;
                } else {
                    throw new IllegalArgumentException("Bad format: Invalid timezone: " + message);
                }
            }
        }
        return timeStamp;
    }

}