org.jahia.loganalyzer.internal.JahiaLogAnalyzerImpl.java Source code

Java tutorial

Introduction

Here is the source code for org.jahia.loganalyzer.internal.JahiaLogAnalyzerImpl.java

Source

package org.jahia.loganalyzer.internal;

/*
 * #%L
 * Jahia Log Analyzer
 * $Id:$
 * $HeadURL:$
 * %%
 * Copyright (C) 2007 - 2016 Jahia
 * %%
 * 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.
 * #L%
 */

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.jgoodies.looks.plastic.PlasticXPLookAndFeel;
import org.apache.commons.io.FileUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jahia.loganalyzer.JahiaLogAnalyzer;
import org.jahia.loganalyzer.api.LogEntryWriterFactory;
import org.jahia.loganalyzer.api.ProcessedLogFile;
import org.jahia.loganalyzer.configuration.LogParserConfiguration;
import org.jahia.loganalyzer.services.taskexecutor.MonitorInputStream;
import org.jahia.loganalyzer.services.taskexecutor.Task;
import org.jahia.loganalyzer.writers.ElasticSearchService;
import org.osgi.framework.BundleContext;
import org.osgi.framework.InvalidSyntaxException;
import org.osgi.framework.ServiceReference;

import javax.swing.*;
import java.io.*;
import java.net.JarURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.util.*;
import java.util.jar.Attributes;
import java.util.jar.JarFile;
import java.util.jar.Manifest;

/**
 * Main class of the Jahia Log Analyzer, this is where the application is started and performs all the most high-level
 * operations
 */
public class JahiaLogAnalyzerImpl implements JahiaLogAnalyzer {

    private static final Log log = LogFactory.getLog(JahiaLogAnalyzerImpl.class);
    ElasticSearchService elasticSearchService;
    private String buildNumber = "Unknown";
    private Date buildTimestamp = null;
    private String version = "DEVELOPMENT";
    private LogParserConfiguration logParserConfiguration = new LogParserConfiguration();
    private BundleContext bundleContext;

    public JahiaLogAnalyzerImpl() {
    }

    public static void main(String[] args) {
        JahiaLogAnalyzer jahiaLogAnalyzer = new JahiaLogAnalyzerImpl();
        File inputFile = null;
        if (args != null && args.length > 0) {
            inputFile = new File(args[0]);
            if (inputFile.exists()) {
                log.info("Analyzing logs in " + inputFile + "...");
            } else {
                inputFile = null;
            }
        } else {
            initUI();
        }
        jahiaLogAnalyzer.start(inputFile, null);
    }

    public static void initUI() {
        try {
            for (UIManager.LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) {
                if ("Nimbus".equals(info.getName())) {
                    UIManager.setLookAndFeel(info.getClassName());
                    break;
                }
            }
        } catch (Exception e) {
            // If Nimbus is not available, you can set the GUI to another look and feel.
            try {
                UIManager.setLookAndFeel(new PlasticXPLookAndFeel());
            } catch (Throwable t) {
                log.error("Error setting look and feel", t);
            }
        }
    }

    public void setElasticSearchService(ElasticSearchService elasticSearchService) {
        this.elasticSearchService = elasticSearchService;
    }

    public void setBundleContext(BundleContext bundleContext) {
        this.bundleContext = bundleContext;
    }

    public void start() {
        System.out.println("Starting Jahia Log Analyzer main service...");
        retrieveBuildInformation();
        System.out.println("Jahia Log Analyzer main service started !");
    }

    public void stop() {
        System.out.println("Stopping Jahia Log Analyzer main service...");
    }

    @Override
    public void start(File inputFile, Task task) {
        retrieveBuildInformation();
        if (inputFile == null) {
            log.error("Missing input file !");
            System.exit(0);
        } else {
            try {
                Collection<ServiceReference<LogEntryWriterFactory>> logEntryWriterFactoryReferences = bundleContext
                        .getServiceReferences(LogEntryWriterFactory.class, null);
                List<LogEntryWriterFactory> logEntryWriterFactories = new ArrayList<>();
                for (ServiceReference<LogEntryWriterFactory> logEntryWriterFactoryServiceReference : logEntryWriterFactoryReferences) {
                    LogEntryWriterFactory logEntryWriterFactory = bundleContext
                            .getService(logEntryWriterFactoryServiceReference);
                    if (logEntryWriterFactory != null) {
                        logEntryWriterFactories.add(logEntryWriterFactory);
                    }
                }
                logParserConfiguration.setLogEntryWriterFactories(logEntryWriterFactories);
                logParserConfiguration.setInputFile(inputFile);
                if (analyze(null, task)) {
                    log.info("Analysis completed. ");
                } else {
                    log.info("Previous analysis found, using previous data.");
                }
                /*
                if (!elasticSearchService.isRemote()) {
                log.info("You can access ElasticSearch plugin at http://localhost:9200/_plugin/loganalyzer");
                log.info("If you have Kibana 4+ running, you can access it at http://localhost:5601");
                log.info("Keeping embedded ElasticSearch server running, press CTRL-C to quit...");
                while (true) {
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        // ignore
                    }
                }
                }
                */
            } catch (IOException e) {
                log.error("Error during log analysis", e);
            } catch (InvalidSyntaxException e) {
                log.error("Error during log analysis", e);
            }
        }
    }

    @Override
    public boolean analyze(java.awt.Component uiComponent, Task task) throws IOException {
        File inputFile = logParserConfiguration.getInputFile();
        if (!inputFile.exists()) {
            log.warn("Couldn't find file " + inputFile);
            return true;
        }
        String jvmIdentifier = "jvm";
        long totalBytesToProcess = 0;
        if (inputFile.isDirectory()) {
            SortedSet<File> sortedFiles = new TreeSet<File>(FileUtils.listFiles(inputFile, null, true));
            for (File file : sortedFiles) {
                if (file.isFile()) {
                    totalBytesToProcess += file.length();
                }
            }
            if (!logParserConfiguration.getOutputDirectory().exists()) {
                createOutputDirectory(logParserConfiguration);
            }
            List<ProcessedLogFile> processedLogFiles = getProcessedLogFiles();
            LogParserImpl logParser = new LogParserImpl();
            logParser.setElasticSearchService(elasticSearchService);
            logParser.setLogParserConfiguration(logParserConfiguration);
            long totalBytesRead = 0;
            for (File file : sortedFiles) {
                if (file.getCanonicalPath()
                        .startsWith(logParserConfiguration.getOutputDirectory().getCanonicalPath())) {
                    continue;
                }

                ProcessedLogFile processedLogFile = new ProcessedLogFile(logParserConfiguration.getInputFile(),
                        file);
                if (processedLogFiles.contains(processedLogFile)) {
                    log.info("File " + file + " already parsed previously, skipping");
                    continue;
                }
                String filePath = file.getPath();
                int jvmIdentifierPos = filePath.indexOf("jvm-");
                if (jvmIdentifierPos >= 0) {
                    int fileSeparatorPos = filePath.indexOf(File.separator, jvmIdentifierPos);
                    if (fileSeparatorPos >= 0) {
                        jvmIdentifier = filePath.substring(jvmIdentifierPos + "jvm-".length(), fileSeparatorPos);
                    } else {
                        jvmIdentifier = filePath.substring(jvmIdentifierPos + "jvm-".length());
                    }
                }
                Reader reader = getFileReader(uiComponent, file,
                        new TotalBytesMonitor(task, totalBytesToProcess, totalBytesRead));
                log.info("Parsing file " + file + "...");
                processedLogFile = logParser.parse(reader, file, jvmIdentifier,
                        processedLogFile.getLastParsedTimestamp());
                log.info("Parsing of file " + file + " completed.");
                reader.close();
                totalBytesRead += file.length();
                processedLogFiles.add(processedLogFile);
            }
            logParser.stop();
            saveProcessedLogFiles(processedLogFiles);
        } else {
            long totalBytesRead = 0;
            File file = logParserConfiguration.getInputFile();
            if (!logParserConfiguration.getOutputDirectory().exists()) {
                createOutputDirectory(logParserConfiguration);
            }
            List<ProcessedLogFile> processedLogFiles = getProcessedLogFiles();
            ProcessedLogFile processedLogFile = new ProcessedLogFile(
                    logParserConfiguration.getInputFile().getParentFile(), file);
            if (processedLogFiles.contains(processedLogFile)) {
                // we instantiate the log parser just to make sure the embedded ElasticSearch is started.
                LogParserImpl logParser = new LogParserImpl();
                logParser.setElasticSearchService(elasticSearchService);
                logParser.setLogParserConfiguration(logParserConfiguration);
                logParser.stop();
            } else {
                LogParserImpl logParser = new LogParserImpl();
                logParser.setElasticSearchService(elasticSearchService);
                logParser.setLogParserConfiguration(logParserConfiguration);
                Reader reader = getFileReader(uiComponent, file,
                        new TotalBytesMonitor(task, totalBytesToProcess, totalBytesRead));
                log.info("Parsing file " + file + "...");
                processedLogFile = logParser.parse(reader, file, jvmIdentifier,
                        processedLogFile.getLastParsedTimestamp());
                log.info("Parsing of file " + file + " completed.");
                reader.close();
                totalBytesRead += file.length();
                logParser.stop();
                processedLogFiles.add(processedLogFile);
                saveProcessedLogFiles(processedLogFiles);
            }
        }
        return true;
    }

    private void createOutputDirectory(LogParserConfiguration logParserConfiguration) {
        File outputDirectory = logParserConfiguration.getOutputDirectory();
        if (!outputDirectory.exists()) {
            outputDirectory.mkdirs();
        }
    }

    private List<ProcessedLogFile> getProcessedLogFiles() {
        File outputDirectory = logParserConfiguration.getOutputDirectory();
        if (!outputDirectory.exists()) {
            return new ArrayList<ProcessedLogFile>();
        }
        File processedFilesFile = new File(outputDirectory, "processed.json");
        if (!processedFilesFile.exists()) {
            return new ArrayList<ProcessedLogFile>();
        }
        ObjectMapper mapper = new ObjectMapper();
        try {
            List<ProcessedLogFile> processedLogFiles = mapper.readValue(processedFilesFile,
                    new TypeReference<List<ProcessedLogFile>>() {
                    });
            return processedLogFiles;
        } catch (IOException e) {
            log.error("Error reading loading processed file list from " + processedFilesFile, e);
        }
        return new ArrayList<ProcessedLogFile>();
    }

    private void saveProcessedLogFiles(List<ProcessedLogFile> processedLogFiles) {
        File outputDirectory = logParserConfiguration.getOutputDirectory();
        if (!outputDirectory.exists()) {
            return;
        }
        File processedFilesFile = new File(outputDirectory, "processed.json");
        if (!processedFilesFile.getParentFile().exists()) {
            processedFilesFile.getParentFile().mkdirs();
        }
        ObjectMapper mapper = new ObjectMapper();
        try {
            mapper.writeValue(processedFilesFile, processedLogFiles);
        } catch (IOException e) {
            log.error("Error writing processed log file " + processedFilesFile, e);
        }
    }

    private Reader getFileReader(java.awt.Component uiComponent, File file, MonitorInputStream.Monitor monitor)
            throws FileNotFoundException {
        if (uiComponent != null) {
            InputStream in = new BufferedInputStream(
                    new ProgressMonitorInputStream(uiComponent, "Reading " + file, new FileInputStream(file)));
            return new InputStreamReader(in);
        } else {
            return new InputStreamReader(new MonitorInputStream(monitor, new FileInputStream(file)));
        }
    }

    @Override
    public void retrieveBuildInformation() {
        try {
            URL urlToMavenPom = JahiaLogAnalyzerImpl.class.getClassLoader()
                    .getResource("/META-INF/jahia-loganalyzer-marker.txt");
            if (urlToMavenPom != null) {
                URLConnection urlConnection = urlToMavenPom.openConnection();
                if (urlConnection instanceof JarURLConnection) {
                    JarURLConnection conn = (JarURLConnection) urlConnection;
                    JarFile jarFile = conn.getJarFile();
                    Manifest manifest = jarFile.getManifest();
                    Attributes attributes = manifest.getMainAttributes();
                    buildNumber = attributes.getValue("Implementation-Build");
                    version = attributes.getValue("Implementation-Version");
                    String buildTimestampValue = attributes.getValue("Implementation-Timestamp");
                    if (buildTimestampValue != null) {
                        try {
                            long buildTimestampTime = Long.parseLong(buildTimestampValue);
                            buildTimestamp = new Date(buildTimestampTime);
                        } catch (NumberFormatException nfe) {
                            nfe.printStackTrace();
                        }
                    }
                }
            }
        } catch (IOException ioe) {
            log.error("Error while trying to retrieve build information", ioe);
        } catch (NumberFormatException nfe) {
            log.error("Error while trying to retrieve build information", nfe);
        }
    }

    @Override
    public String getBuildNumber() {
        return buildNumber;
    }

    @Override
    public Date getBuildTimestamp() {
        return buildTimestamp;
    }

    @Override
    public String getVersion() {
        return version;
    }

    public LogParserConfiguration getLogParserConfiguration() {
        return logParserConfiguration;
    }

    public class TotalBytesMonitor implements MonitorInputStream.Monitor {

        private Task task;
        private long totalBytesToProcess;
        private long totalBytesReadUntilNow;
        private long streamTotalAvailableBytes;

        public TotalBytesMonitor(Task task, long totalBytesToProcess, long totalBytesReadUntilNow) {
            this.task = task;
            this.totalBytesToProcess = totalBytesToProcess;
            this.totalBytesReadUntilNow = totalBytesReadUntilNow;
        }

        @Override
        public void setTotalBytes(long totalBytes) {
            this.streamTotalAvailableBytes = totalBytes;
        }

        @Override
        public void setProgress(long bytesRead) {
            if (task != null) {
                task.setCompletionPourcentage(
                        (totalBytesReadUntilNow + bytesRead * 1.0) / (totalBytesToProcess * 1.0));
            }
        }
    }
}