org.rhq.core.pluginapi.event.log.LogFileEventPoller.java Source code

Java tutorial

Introduction

Here is the source code for org.rhq.core.pluginapi.event.log.LogFileEventPoller.java

Source

/*
 * RHQ Management Platform
 * Copyright (C) 2005-2012 Red Hat, Inc.
 * All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License, version 2, as
 * published by the Free Software Foundation, and/or the GNU Lesser
 * General Public License, version 2.1, also as published by the Free
 * Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License and the GNU Lesser General Public License
 * for more details.
 *
 * You should have received a copy of the GNU General Public License
 * and the GNU Lesser General Public License along with this program;
 * if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 */
package org.rhq.core.pluginapi.event.log;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
import java.util.Set;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hyperic.sigar.FileInfo;
import org.hyperic.sigar.SigarException;
import org.hyperic.sigar.SigarProxy;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import org.rhq.core.domain.event.Event;
import org.rhq.core.pluginapi.event.EventContext;
import org.rhq.core.pluginapi.event.EventPoller;

/**
 * An Event poller that polls a log file for new entries. 
 *
 * @author Ian Springer
 */
public class LogFileEventPoller implements EventPoller {
    private final Log log = LogFactory.getLog(this.getClass());

    private String eventType;
    private File logFile;
    private FileInfo logFileInfo;
    private LogEntryProcessor entryProcessor;
    private EventContext eventContext;
    private boolean initialized;

    public LogFileEventPoller(EventContext eventContext, String eventType, File logFile,
            LogEntryProcessor entryProcessor) {
        this.eventType = eventType;
        this.logFile = logFile;
        this.entryProcessor = entryProcessor;
        this.eventContext = eventContext;
    }

    @NotNull
    public String getEventType() {
        return this.eventType;
    }

    @NotNull
    public String getSourceLocation() {
        return this.logFile.getPath();
    }

    @Nullable
    public Set<Event> poll() {
        if (!this.initialized) {
            init();
        }
        if (this.logFileInfo == null) {
            // This means SIGAR, which we require, is unavailable, so just return null. 
            return null;
        }

        if (!this.logFile.exists()) {
            log.warn("Log file [" + this.logFile + "] being polled does not exist.");
            return null;
        }
        if (this.logFile.isDirectory()) {
            log.error("Log file [" + this.logFile + "] being polled is a directory, not a regular file.");
            return null;
        }

        try {
            if (!this.logFileInfo.changed()) {
                return null;
            }
        } catch (SigarException e) {
            throw new RuntimeException(e);
        }
        return processNewLines(this.logFileInfo);
    }

    /**
     * This performs any initialization that requires using the EventContext. It must *not* be called from our
     * constructor, because pollers are constructed during PC initialization, and at that time the PC EventManager,
     * which the EventContext relies on, is not yet available. Instead it is called from {@link #poll()} on the first
     * invocation of that method, at which point the PC will be initialized.
     */
    protected void init() {
        SigarProxy sigar = this.eventContext.getSigar();
        if (sigar != null) {
            try {
                this.logFileInfo = new LogFileInfo(sigar.getFileInfo(logFile.getPath()));
            } catch (SigarException e) {
                throw new RuntimeException("Failed to obtain file info for log file [" + this.logFile + "].", e);
            }
        } else {
            log.warn("SIGAR is unavailable - cannot poll log file [" + this.logFile + "] for events.");
        }

        this.initialized = true;
    }

    private Set<Event> processNewLines(FileInfo fileInfo) {
        Set<Event> events = null;
        Reader reader = null;
        try {
            reader = new FileReader(this.logFile);

            long offset = getOffset(fileInfo);

            if (offset > 0) {
                reader.skip(offset);
            }
            BufferedReader bufferedReader = new BufferedReader(reader);
            events = this.entryProcessor.processLines(bufferedReader);
        } catch (IOException e) {
            log.error("Failed to read log file being tailed: " + this.logFile, e);
        } finally {
            if (reader != null) {
                //noinspection EmptyCatchBlock
                try {
                    reader.close();
                } catch (IOException e) {
                }
            }
        }
        return events;
    }

    private long getOffset(FileInfo fileInfo) {
        FileInfo previousFileInfo = fileInfo.getPreviousInfo();

        if (previousFileInfo == null) {
            if (log.isDebugEnabled()) {
                log.debug(this.logFile + ": first stat");
            }
            return fileInfo.getSize();
        }

        if (fileInfo.getInode() != previousFileInfo.getInode()) {
            if (log.isDebugEnabled()) {
                log.debug(this.logFile + ": file inode changed");
            }
            return -1;
        }

        if (fileInfo.getSize() < previousFileInfo.getSize()) {
            if (log.isDebugEnabled()) {
                log.debug(this.logFile + ": file truncated");
            }
            return -1;
        }

        if (log.isDebugEnabled()) {
            long diff = fileInfo.getSize() - previousFileInfo.getSize();
            log.debug(this.logFile + ": " + diff + " new bytes");
        }

        return previousFileInfo.getSize();
    }
}