/* * 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.product; import java.util.Arrays; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedList; import java.util.Properties; import java.util.StringTokenizer; import org.hyperic.sigar.win32.EventLog; import org.hyperic.sigar.win32.EventLogThread; import org.hyperic.sigar.FileWatcher; import org.hyperic.sigar.FileWatcherThread; import org.hyperic.util.StringUtil; import org.hyperic.util.config.ConfigOption; import org.hyperic.util.config.ConfigSchema; public abstract class TrackEventPluginManager extends PluginManager { public static final int DEFAULT_INTERVAL = 60 * 1 * 1000; public static final String PROP_INTERVAL = "track.interval"; //XXX probably better off in another file of somesort. private static final String[][] GENERIC_HELP = { { ConfigTrackPlugin.PROP_ENABLE, "Check to enable config tracking." }, { ConfigFileTrackPlugin.PROP_FILES, "Comma delimited list of configuration files to track. " + "Relative files are resolved to ${installpath}." }, { LogTrackPlugin.PROP_ENABLE, "Check to enable log tracking." }, { LogTrackPlugin.PROP_LEVEL, "Only track events of level greater than or equal to this level. " + "Order is: " + Arrays.asList(LogTrackPlugin.LOGLEVEL_LABELS) }, { LogTrackPlugin.PROP_INCLUDE, "Include messages that match the given regular expression. " + "The given pattern can be a substring to look for in log messages " + "or a regular expression. " + "See: " + "<a href=\"http://docs.oracle.com/javase/7/docs/api/java/util/regex/Pattern.html\">" + "java.util.regex.Pattern</a>." }, { LogTrackPlugin.PROP_EXCLUDE, "Exclude messages that match the given regular expression. " }, { LogFileTrackPlugin.PROP_FILES, "Comma delimited list of log files to track. " + "Relative files are resolved to ${installpath}." }, { Win32EventLogNotification.PROP_EVENT_LOGS, "Comma delimited list of Event Log names to track. " + "Value of <b>*</b> will track all existing Event Logs." } }; private long fileWatchInterval = 0; private long eventLogInterval = 0; private long runnableTrackInterval = 0; private HashMap eventLogs = new HashMap(); private FileWatcherThread fileWatcherThread = null; private RunnableTrackThread runnableTrackThread = null; // A list of in-memory events that are waiting to be flushed to // the AgentStorageProvider. The TrackerThread queries this list // periodically. This data may be lost if the agent crashes.. on // normal shutdown the list is flushed to disk before the // TrackerThread exits. private LinkedList events = new LinkedList(); public TrackEventPluginManager() { super(); } public TrackEventPluginManager(Properties props) { super(props); } public abstract String getName(); public void reportEvent(TrackEvent event) { synchronized(this.events) { this.events.add(event); } } public LinkedList getEvents() { LinkedList eventsToReport; if (this.events.isEmpty()) return new LinkedList(); synchronized(this.events) { // We have something to report. eventsToReport = (LinkedList)this.events.clone(); this.events.clear(); } return eventsToReport; } private long getInterval(PluginManager manager, String source) { String prop = PROP_INTERVAL + "." + source; String interval = manager.getProperty(prop, manager.getProperty(PROP_INTERVAL)); if (interval == null) { return DEFAULT_INTERVAL; } else { return Long.parseLong(interval) * 1000; } } public void init(PluginManager manager) throws PluginException { super.init(manager); this.fileWatchInterval = getInterval(manager, "files"); this.eventLogInterval = getInterval(manager, "eventlog"); this.runnableTrackInterval = getInterval(manager, "runnable"); } public void shutdown() throws PluginException { super.shutdown(); if (this.fileWatcherThread != null) { this.fileWatcherThread.doStop(); this.fileWatcherThread = null; } if (this.runnableTrackThread != null) { this.runnableTrackThread.doStop(); this.runnableTrackThread = null; } closeEventLogs(); ConfigFileTrackPlugin.cleanup(); LogFileTailPlugin.cleanup(); } private FileWatcherThread getFileWatcherThread() { if (this.fileWatcherThread == null) { this.fileWatcherThread = FileWatcherThread.getInstance(); if (this.fileWatchInterval != 0) { this.fileWatcherThread.setInterval(this.fileWatchInterval); } this.fileWatcherThread.doStart(); } return this.fileWatcherThread; } public void addFileWatcher(FileWatcher watcher) { getFileWatcherThread().add(watcher); } public void removeFileWatcher(FileWatcher watcher) { getFileWatcherThread().remove(watcher); } private EventLogThread getEventLogThread(String name) { name = name.toUpperCase(); EventLogThread instance = (EventLogThread)eventLogs.get(name); if (instance == null) { instance = new EventLogThread(); instance.setLogName(name); if (this.eventLogInterval != 0) { instance.setInterval(this.eventLogInterval); } instance.doStart(); eventLogs.put(name, instance); log.debug("Created EventLogThread(" + name + ")"); } return instance; } public void closeEventLogs() { for (Iterator it = eventLogs.values().iterator(); it.hasNext();) { EventLogThread eventLogThread = (EventLogThread)it.next(); eventLogThread.doStop(); } eventLogs.clear(); } private String[] getEventLogNames(Win32EventLogNotification notifier) throws PluginException { String[] eventLogs = EventLog.getLogNames(); String name = notifier.getLogName(); if (name.equals("*")) { return eventLogs; } else { //Validate the Event Log exists due to: //http://msdn2.microsoft.com/en-us/library/aa363672.aspx //"If a custom log cannot be found, //the event logging service opens the Application log" HashMap lcNames = new HashMap(); for (int i=0; i<eventLogs.length; i++) { lcNames.put(eventLogs[i].toLowerCase(), Boolean.TRUE); } StringTokenizer tok = new StringTokenizer(name, ","); int i=0, num = tok.countTokens(); String[] names = new String[num]; while (tok.hasMoreTokens()) { String logName = tok.nextToken(); if (lcNames.get(logName.toLowerCase()) != Boolean.TRUE) { String msg = "Event Log '" + logName + "' does not exist"; throw new PluginException(msg); } names[i++] = logName; } return names; } } public void addEventLogNotification(Win32EventLogNotification notifier) throws PluginException { String[] names = getEventLogNames(notifier); for (int i=0; i<names.length; i++) { getEventLogThread(names[i]).add(notifier); } } public void removeEventLogNotification(Win32EventLogNotification notifier) throws PluginException { String[] names = getEventLogNames(notifier); for (int i=0; i<names.length; i++) { getEventLogThread(names[i]).remove(notifier); } } private RunnableTrackThread getRunnableTrackThread() { if (this.runnableTrackThread == null) { this.runnableTrackThread = RunnableTrackThread.getInstance(); if (this.runnableTrackInterval != 0) { this.runnableTrackThread.setInterval(this.runnableTrackInterval); } this.runnableTrackThread.doStart(); } return this.runnableTrackThread; } public void addRunnableTracker(Runnable tracker) { getRunnableTrackThread().add(tracker); } public void removeRunnableTracker(Runnable tracker) { getRunnableTrackThread().remove(tracker); } static String getGenericHelp(LogTrackPluginManager ltpm, ConfigSchema schema, TypeInfo info) { StringBuffer buffer = null; boolean isPlatform = info.getType() == TypeInfo.TYPE_PLATFORM; String defaultDir = info.isWin32Platform() ? "\\" : "/"; LogTrackPlugin plugin = ltpm.getLogTrackPlugin(info.getName()); for (int i=0; i<GENERIC_HELP.length; i++) { String name = GENERIC_HELP[i][0]; String key = GenericPlugin.TYPE_LABELS[info.getType()] + name; String val = GENERIC_HELP[i][1]; ConfigOption option = schema.getOption(key); if (option == null) { option = schema.getOption(name); } if (option == null) { continue; } if (buffer == null) { buffer = new StringBuffer(); buffer.append("<p><h4>General Log and Config Track Properties</h4></p>\n"); buffer.append("<ul>\n"); } if (isPlatform) { //platforms have no installpath attribute val = StringUtil.replace(val, "${installpath}", defaultDir); } buffer.append("<li>").append(option.getDescription()). append(" - ").append(val); if (key.endsWith(LogTrackPlugin.PROP_LEVEL) && (plugin != null)) { String[] aliases = plugin.getLogLevelAliases(); String[] levels = LogTrackPlugin.LOGLEVEL_LABELS; if (aliases != levels) { buffer.append("<br>Mapping:<ul>\n"); for (int j=0; j<levels.length; j++) { buffer.append("<li>").append(aliases[j]). append(" -> ").append(levels[j]).append("</li>\n"); } buffer.append("</ul>\n"); } } buffer.append("</li>\n"); } if (buffer != null) { buffer.append("</ul>\n"); return buffer.toString(); } else { return null; } } }