info.fetter.logstashforwarder.Forwarder.java Source code

Java tutorial

Introduction

Here is the source code for info.fetter.logstashforwarder.Forwarder.java

Source

package info.fetter.logstashforwarder;

/*
 * Copyright 2015 Didier Fetter
 *
 * 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.
 *
 */

import static org.apache.log4j.Level.*;

import java.io.IOException;
import java.util.List;
import java.util.Random;

import info.fetter.logstashforwarder.config.ConfigurationManager;
import info.fetter.logstashforwarder.config.FilesSection;
import info.fetter.logstashforwarder.protocol.LumberjackClient;
import info.fetter.logstashforwarder.util.AdapterException;

import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.GnuParser;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.OptionBuilder;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.apache.log4j.Appender;
import org.apache.log4j.BasicConfigurator;
import org.apache.log4j.ConsoleAppender;
import org.apache.log4j.Layout;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import org.apache.log4j.PatternLayout;
import org.apache.log4j.RollingFileAppender;
import org.apache.log4j.spi.RootLogger;

public class Forwarder {
    private static final String SINCEDB = ".logstash-forwarder-java";
    private static Logger logger = Logger.getLogger(Forwarder.class);
    private static int spoolSize = 1024;
    private static int idleTimeout = 5000;
    private static int networkTimeout = 15000;
    private static String config;
    private static ConfigurationManager configManager;
    private static FileWatcher watcher;
    private static FileReader fileReader;
    private static InputReader inputReader;
    private static Level logLevel = INFO;
    private static boolean debugWatcherSelected = false;
    private static ProtocolAdapter adapter;
    private static Random random = new Random();
    private static int signatureLength = 4096;
    private static boolean tailSelected = false;
    private static String logfile = null;
    private static String logfileSize = "10MB";
    private static int logfileNumber = 5;
    private static String sincedbFile = SINCEDB;

    public static void main(String[] args) {
        try {
            parseOptions(args);
            setupLogging();
            watcher = new FileWatcher();
            watcher.setMaxSignatureLength(signatureLength);
            watcher.setTail(tailSelected);
            watcher.setSincedb(sincedbFile);
            configManager = new ConfigurationManager(config);
            configManager.readConfiguration();
            for (FilesSection files : configManager.getConfig().getFiles()) {
                for (String path : files.getPaths()) {
                    watcher.addFilesToWatch(path, new Event(files.getFields()),
                            files.getDeadTimeInSeconds() * 1000);
                }
            }
            watcher.initialize();
            fileReader = new FileReader(spoolSize);
            inputReader = new InputReader(spoolSize, System.in);
            connectToServer();
            infiniteLoop();
        } catch (Exception e) {
            e.printStackTrace();
            System.exit(3);
        }
    }

    private static void infiniteLoop() throws IOException, InterruptedException {
        while (true) {
            try {
                watcher.checkFiles();
                while (watcher.readFiles(fileReader) == spoolSize)
                    ;
                while (watcher.readStdin(inputReader) == spoolSize)
                    ;
                Thread.sleep(idleTimeout);
            } catch (AdapterException e) {
                logger.error("Lost server connection");
                Thread.sleep(networkTimeout);
                connectToServer();
            }
        }
    }

    private static void connectToServer() {
        int randomServerIndex = 0;
        List<String> serverList = configManager.getConfig().getNetwork().getServers();
        networkTimeout = configManager.getConfig().getNetwork().getTimeout() * 1000;
        if (adapter != null) {
            try {
                adapter.close();
            } catch (AdapterException e) {
                logger.error("Error while closing connection to " + adapter.getServer() + ":" + adapter.getPort());
            } finally {
                adapter = null;
            }
        }
        while (adapter == null) {
            try {
                randomServerIndex = random.nextInt(serverList.size());
                String[] serverAndPort = serverList.get(randomServerIndex).split(":");
                logger.info("Trying to connect to " + serverList.get(randomServerIndex));
                adapter = new LumberjackClient(configManager.getConfig().getNetwork().getSslCA(), serverAndPort[0],
                        Integer.parseInt(serverAndPort[1]), networkTimeout);
                fileReader.setAdapter(adapter);
                inputReader.setAdapter(adapter);
            } catch (Exception ex) {
                if (logger.isDebugEnabled()) {
                    logger.error("Failed to connect to server " + serverList.get(randomServerIndex) + " : ", ex);
                } else {
                    logger.error("Failed to connect to server " + serverList.get(randomServerIndex) + " : "
                            + ex.getMessage());
                }
                try {
                    Thread.sleep(networkTimeout);
                } catch (InterruptedException e) {
                    logger.error(e.getMessage());
                }
            }
        }
    }

    @SuppressWarnings("static-access")
    static void parseOptions(String[] args) {
        Options options = new Options();
        Option helpOption = new Option("help", "print this message");
        Option quietOption = new Option("quiet", "operate in quiet mode - only emit errors to log");
        Option debugOption = new Option("debug", "operate in debug mode");
        Option debugWatcherOption = new Option("debugwatcher", "operate watcher in debug mode");
        Option traceOption = new Option("trace", "operate in trace mode");
        Option tailOption = new Option("tail", "read new files from the end");

        Option spoolSizeOption = OptionBuilder.withArgName("number of events").hasArg()
                .withDescription("event count spool threshold - forces network flush").create("spoolsize");
        Option idleTimeoutOption = OptionBuilder.withArgName("").hasArg()
                .withDescription("time between file reads in seconds").create("idletimeout");
        Option configOption = OptionBuilder.withArgName("config file").hasArg().isRequired()
                .withDescription("path to logstash-forwarder configuration file").create("config");
        Option signatureLengthOption = OptionBuilder.withArgName("signature length").hasArg()
                .withDescription("Maximum length of file signature").create("signaturelength");
        Option logfileOption = OptionBuilder.withArgName("logfile name").hasArg().withDescription("Logfile name")
                .create("logfile");
        Option logfileSizeOption = OptionBuilder.withArgName("logfile size").hasArg()
                .withDescription("Logfile size (default 10M)").create("logfilesize");
        Option logfileNumberOption = OptionBuilder.withArgName("number of logfiles").hasArg()
                .withDescription("Number of logfiles (default 5)").create("logfilenumber");
        Option sincedbOption = OptionBuilder.withArgName("sincedb file").hasArg()
                .withDescription("Sincedb file name").create("sincedb");

        options.addOption(helpOption).addOption(idleTimeoutOption).addOption(spoolSizeOption).addOption(quietOption)
                .addOption(debugOption).addOption(debugWatcherOption).addOption(traceOption).addOption(tailOption)
                .addOption(signatureLengthOption).addOption(configOption).addOption(logfileOption)
                .addOption(logfileNumberOption).addOption(logfileSizeOption).addOption(sincedbOption);

        CommandLineParser parser = new GnuParser();
        try {
            CommandLine line = parser.parse(options, args);
            if (line.hasOption("spoolsize")) {
                spoolSize = Integer.parseInt(line.getOptionValue("spoolsize"));
            }
            if (line.hasOption("idletimeout")) {
                idleTimeout = Integer.parseInt(line.getOptionValue("idletimeout"));
            }
            if (line.hasOption("config")) {
                config = line.getOptionValue("config");
            }
            if (line.hasOption("signaturelength")) {
                signatureLength = Integer.parseInt(line.getOptionValue("signaturelength"));
            }
            if (line.hasOption("quiet")) {
                logLevel = ERROR;
            }
            if (line.hasOption("debug")) {
                logLevel = DEBUG;
            }
            if (line.hasOption("trace")) {
                logLevel = TRACE;
            }
            if (line.hasOption("debugwatcher")) {
                debugWatcherSelected = true;
            }
            if (line.hasOption("tail")) {
                tailSelected = true;
            }
            if (line.hasOption("logfile")) {
                logfile = line.getOptionValue("logfile");
            }
            if (line.hasOption("logfilesize")) {
                logfileSize = line.getOptionValue("logfilesize");
            }
            if (line.hasOption("logfilenumber")) {
                logfileNumber = Integer.parseInt(line.getOptionValue("logfilenumber"));
            }
            if (line.hasOption("sincedb")) {
                sincedbFile = line.getOptionValue("sincedb");
            }
        } catch (ParseException e) {
            printHelp(options);
            System.exit(1);
            ;
        } catch (NumberFormatException e) {
            System.err.println("Value must be an integer");
            printHelp(options);
            System.exit(2);
            ;
        }
    }

    private static void printHelp(Options options) {
        HelpFormatter formatter = new HelpFormatter();
        formatter.printHelp("logstash-forwarder", options);
    }

    private static void setupLogging() throws IOException {
        Appender appender;
        Layout layout = new PatternLayout("%d %p %c{1} - %m%n");
        if (logfile == null) {
            appender = new ConsoleAppender(layout);
        } else {
            RollingFileAppender rolling = new RollingFileAppender(layout, logfile, true);
            rolling.setMaxFileSize(logfileSize);
            rolling.setMaxBackupIndex(logfileNumber);
            appender = rolling;
        }
        BasicConfigurator.configure(appender);
        RootLogger.getRootLogger().setLevel(logLevel);
        if (debugWatcherSelected) {
            Logger.getLogger(FileWatcher.class).addAppender(appender);
            Logger.getLogger(FileWatcher.class).setLevel(DEBUG);
            Logger.getLogger(FileWatcher.class).setAdditivity(false);
        }
        //         Logger.getLogger(FileReader.class).addAppender((Appender)RootLogger.getRootLogger().getAllAppenders().nextElement());
        //         Logger.getLogger(FileReader.class).setLevel(TRACE);
        //         Logger.getLogger(FileReader.class).setAdditivity(false);
    }

}