org.hyperic.hq.plugin.iis.IisRtPlugin.java Source code

Java tutorial

Introduction

Here is the source code for org.hyperic.hq.plugin.iis.IisRtPlugin.java

Source

/*
 * NOTE: This copyright does *not* cover user programs that use HQ
 * program services by normal system calls through the application
 * program interfaces provided as part of the Hyperic Plug-in Development
 * Kit or the Hyperic Client Development Kit - this is merely considered
 * normal use of the program, and does *not* fall under the heading of
 * "derived work".
 * 
 * Copyright (C) [2004, 2005, 2006], Hyperic, Inc.
 * This file is part of HQ.
 * 
 * HQ is free software; you can redistribute it and/or modify
 * it under the terms version 2 of the GNU General Public License 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 for more
 * details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
 * USA.
 */

package org.hyperic.hq.plugin.iis;

import org.hyperic.hq.product.TypeInfo;
import org.hyperic.hq.product.RtPlugin;
import org.hyperic.hq.product.ProductPlugin;
import org.hyperic.util.config.ConfigResponse;
import org.hyperic.util.config.ConfigSchema;
import org.hyperic.util.config.SchemaBuilder;
import org.hyperic.util.StringUtil;

import org.hyperic.hq.product.logparse.BaseLogParser;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.novadeck.jxla.LogParse;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Hashtable;
import java.util.Properties;
import java.util.StringTokenizer;

public class IisRtPlugin extends RtPlugin {

    private static final String FIELDS_FMT = "#Fields: ";

    // A cache of log formats to remove the need to scan the file
    // every time we parse the file for response time.
    private Hashtable logFormats = new Hashtable();

    // Static lookup table for specifiying the JXLA parser format
    private static Hashtable tokens;

    static {
        tokens = new Hashtable();

        tokens.put("date", "y-m-d");
        tokens.put("time", "h");
        tokens.put("c-ip", "$remote_ip");
        tokens.put("cs-username", "*");
        tokens.put("s-sitename", "*");
        tokens.put("s-computername", "*");
        tokens.put("s-ip", "*");
        tokens.put("s-port", "*");
        tokens.put("cs-method", "*");
        tokens.put("cs-uri-stem", "$uri");
        tokens.put("cs-uri-query", "$query");
        tokens.put("sc-status", "$status");
        tokens.put("sc-substatus", "*");
        tokens.put("sc-win32-status", "*");
        tokens.put("sc-bytes", "$size");
        tokens.put("cs-bytes", "*");
        tokens.put("time-taken", "$time_taken");
        tokens.put("cs-version", "*");
        tokens.put("cs-host", "$remote_host");
        tokens.put("cs(User-Agent)", "*");
        tokens.put("cs(Cookie)", "*");
        tokens.put("cs(Referer)", "*");
    }

    private static final Log log = LogFactory.getLog("IisRtPlugin");

    public BaseLogParser getParser() {
        return new LogParse();
    }

    public String getLogFormat(ConfigResponse config) {
        return "";
    }

    /**
     * Generate the JXLA format from the IIS log format.
     */
    public String convertFormat(String fmt) {
        String jxlaFmt = new String();

        if (fmt == null)
            return "";

        StringTokenizer st = new StringTokenizer(fmt);

        while (st.hasMoreTokens()) {
            String temp = (String) tokens.get(st.nextToken());
            if (temp == null) {
                jxlaFmt += "*";
            } else {
                jxlaFmt += temp;
            }
            if (st.hasMoreTokens()) {
                jxlaFmt += " ";
            }
        }

        return jxlaFmt;
    }

    /**
     * Scan the IIS logs looking for the #Fields: component
     *
     * The response time logging requires that the 'Time Taken'
     * field is being logged.  If we do not find this, log an
     * error and skip the log.
     *
     * Getting the log format is a one time operation.  If we
     * cannot get it the first time from the file, we will not
     * try again.  (Only again on agent restart when the cache
     * is cleared).  This will reduce thrashing induced by 
     * re-reading log files over and over, only to fail each time.
     *
     * @return The JXLA format for parsing this IIS log.
     *
     **/
    private String getLogFormat(String fname) {
        BufferedReader logf = null;
        String format;

        // First look for the format in the cache
        format = (String) this.logFormats.get(fname);
        if (format != null)
            return format;

        // No match on the cache.. Read the file for the format.
        try {
            logf = new BufferedReader(new FileReader(fname));
            String line;

            while ((line = logf.readLine()) != null) {
                if (line.startsWith(FIELDS_FMT)) {
                    // A match.  See if the time-taken field is being logged.
                    if (line.indexOf("time-taken") != -1) {
                        format = line.substring(FIELDS_FMT.length()).trim();
                        String jxlaFmt = convertFormat(format);

                        this.logFormats.put(fname, jxlaFmt);
                        return jxlaFmt;
                    }
                }
            }

            // Finished the loop, but didn't find anything.
            log.error("Unable to determine log file format for file: " + fname + ".  No valid " + FIELDS_FMT
                    + " token " + "found");

        } catch (IOException e) {
            // We're unable to scan the file looking for the format.
            // Return an empty format, the parser will do the error
            // handling for not being able to open the file.
            log.error("Unable to determine log format for file: " + fname + ": " + e.getMessage());
        } finally {
            if (logf != null) {
                try {
                    logf.close();
                } catch (IOException ingore) {
                }
            }
        }

        format = "";
        this.logFormats.put(fname, format);
        return format;
    }

    /**
     * End user response time not yet supported for IIS.
     */
    public String getEULogFormat(ConfigResponse config) {
        return "";
    }

    /**
     * End user response time not yet supported for IIS.
     */
    public boolean supportsEndUser() {
        return false;
    }

    /**
     * Generate a default config schema for IIS RT
     */
    public ConfigSchema getConfigSchema(TypeInfo info, ConfigResponse config) {
        int type = info.getType();

        // Only services support response time
        if (type != TypeInfo.TYPE_SERVICE) {
            return new ConfigSchema();
        }

        SchemaBuilder schema = new SchemaBuilder(config);

        String serverRoot = config.getValue(ProductPlugin.PROP_INSTALLPATH);

        // Add required fields
        schema.add(CONFIG_LOGDIR, "Full path to log directory", serverRoot + "\\LogFiles");
        schema.add(CONFIG_LOGMASK, "The filenames of your log files with wildcards", "*.log");
        schema.add(CONFIG_INTERVAL, "Interval between parsing log files (seconds)", 60);

        // Add optional fields for URL transforms and URL's to not log
        schema.addRegex(CONFIG_TRANSFORM, "Regular expressions to apply to all URLS, " + "space separated", null)
                .setOptional(true);

        schema.addStringArray(CONFIG_DONTLOG,
                "Regular expressions specifying which " + "URLs not to log, space separated", null)
                .setOptional(true);

        return schema.getSchema();
    }

    public int getSvcType() {
        return WEBSERVER;
    }

    /**
     * Main method for parsing the log
     *
     * Much of this is duplicated from the BaseRTPlugin, mainly due
     * to the file format being specified in the log file itself.  This
     * needs to be abstracted.
     *
     */
    public Collection getTimes(Integer svcID, Properties alreadyParsedFiles, String logdir, String logmask,
            String logfmt, int svcType, String transforms, ArrayList noLog, boolean collectIPs) throws IOException {
        Hashtable urls = new Hashtable();

        // Setup the parser
        lp = getParser();
        lp.setTimeMultiplier(this.getTimeMultiplier());
        lp.urlDontLog(noLog);

        // Get the list of logs to parse
        ParsedFile[] flist = generateFileList(alreadyParsedFiles, logdir, logmask);

        // For each log, parse out the response time info
        for (int i = 0; i < flist.length; i++) {

            long flen[] = new long[1];

            ParsedFile f = flist[i];

            logfmt = getLogFormat(f.fname);
            if (logfmt == "") {
                // If we cannot determine the log format, don't bother
                // passing the file through the parser.
                log.debug("Not parsing " + f.fname + ": No log format");
                continue;
            }

            long start = System.currentTimeMillis();
            log.debug("Parsing log: " + f.fname);

            Hashtable rv = lp.parseLog(f.fname, logfmt, f.oldLen, svcID, svcType, flen, collectIPs);

            if (log.isDebugEnabled()) {
                long elapsed = System.currentTimeMillis() - start;
                log.debug("Done parsing log, " + rv.keySet().size() + " elements ("
                        + StringUtil.formatDuration(elapsed, 0, true) + ")");
            }

            alreadyParsedFiles.put(f.fname, Long.toString(flen[0]));
            combineUrls(rv, urls, transforms);
        }

        log.debug("Returning parsed data " + urls.values().size() + " entries");

        return urls.values();
    }
}