/* * 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.dotnet; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.hyperic.hq.product.*; import org.hyperic.sigar.win32.Pdh; import org.hyperic.sigar.win32.Win32Exception; import org.hyperic.util.StringUtil; import org.hyperic.util.config.ConfigResponse; public class DotNetMeasurementPlugin extends Win32MeasurementPlugin { private static final String DATA_DOMAIN = ".NET CLR Data"; private static final String DATA_PREFIX = "SqlClient: "; private static final String RUNTIME_NAME = "_Global_"; private static Log log = LogFactory.getLog(DotNetMeasurementPlugin.class); private static final Map<String, List<String>> sqlPidsCache = new HashMap<String, List<String>>(); private static final Map<String, List<String>> oraclePidsCache = new HashMap<String, List<String>>(); @Override public MetricValue getValue(Metric metric) throws PluginException, MetricNotFoundException, MetricUnreachableException { MetricValue val = null; if (metric.getDomainName().equalsIgnoreCase("pdh")) { val = getPDHMetric(metric); } else if (metric.getDomainName().equalsIgnoreCase("pdhSQLDP")) { val = getPDHSQLPDMetric(metric, sqlPidsCache, DotNetDetector.SQL_SERVER_PROVIDER_STR); } else if (metric.getDomainName().equalsIgnoreCase("pdhOracleDP")) { val = getPDHSQLPDMetric(metric, oraclePidsCache, DotNetDetector.ORACLE_PROVIDER_STR); } else { try { val = super.getValue(metric); if (metric.isAvail()) { val = new MetricValue(Metric.AVAIL_UP); } } catch (MetricNotFoundException ex) { if (metric.isAvail()) { val = new MetricValue(Metric.AVAIL_DOWN); } else { throw ex; } } } return val; } @Override protected String getAttributeName(Metric metric) { //avoiding Metric parse errors on ':' in DATA_PREFIX. if (metric.getDomainName().equals(DATA_DOMAIN)) { return DATA_PREFIX + metric.getAttributeName(); } else { return metric.getAttributeName(); } } @Override public String translate(String template, ConfigResponse config) { if (log.isDebugEnabled()) { log.debug("[translate] >> template=" + template); for (String key : config.getKeys()) { if (key.toLowerCase().startsWith("app")) { log.debug("[translate] > " + key + "=" + config.getValue(key)); } } } template = super.translate(template, config); template = StringUtil.replace(template, "__percent__", "%"); // default value for .net server final String prop = DotNetDetector.PROP_APP; template = StringUtil.replace(template, "${" + prop + "}", config.getValue(prop, RUNTIME_NAME)); log.debug("[translate] << template=" + template); return template; } private MetricValue getPDHSQLPDMetric(Metric metric, Map<String, List<String>> pidsCache, String providerStr) { if (metric.isAvail()) { pidsCache.clear(); } if (pidsCache.isEmpty()) { try { String[] instances = Pdh.getInstances(providerStr); Pattern regex = Pattern.compile("([^\\[]*)\\[([^\\]]*)\\]"); // name[pid] for (int i = 0; i < instances.length; i++) { String instance = instances[i]; log.debug("[getPDHSQLPDMetric] " + providerStr + " instance = " + instance); Matcher m = regex.matcher(instance); if (m.find()) { String nonTrimmedName = m.group(1); String name = nonTrimmedName.trim(); if (name.length() == 0) { continue; } List<String> pids = pidsCache.get(name); if (pids == null) { pids = new ArrayList<String>(); pidsCache.put(name, pids); } // nira oracle is of the form "app [x,y]" //sql is of the form "app[x] // if there are spaces in between we will include them in the pid //(so pid of oracle will be " [x,y]") // the pid of sql server will be "[x]" String spaces = nonTrimmedName.substring(nonTrimmedName.indexOf(name)+name.length()); String pid = spaces+"["+m.group(2)+"]"; pids.add(pid); } } } catch (Win32Exception e) { log.debug("Error getting PIDs data for '.NET Data Provider for SqlServer': " + e, e); } log.debug("[getPDHSQLPDMetric] pidsCache = " + pidsCache); } log.debug("[getPDHSQLPDMetric] metric:'" + metric); String appName = metric.getObjectPropString(); List<String> pids = pidsCache.get(appName); MetricValue res; if (pids == null) { pidsCache.clear(); if (metric.isAvail()) { res = new MetricValue(Metric.AVAIL_DOWN); } else { res = MetricValue.NONE; } } else { if (metric.isAvail()) { res = new MetricValue(pids.size() > 0 ? Metric.AVAIL_UP : Metric.AVAIL_DOWN); } else if (metric.getAttributeName().equalsIgnoreCase("instances")) { res = new MetricValue(pids.size()); } else if (pids.isEmpty()) { res = MetricValue.NONE; } else { double val = 0; for (int i = 0; i < pids.size(); i++) { String pid = pids.get(i); String obj = "\\" + providerStr + "(" + appName + pid + ")\\" + metric.getAttributeName(); log.debug("[getPDHSQLPDMetric] obj:'" + obj); val += getPDHMetric(obj, metric.isAvail()).getValue(); } res = new MetricValue(val); } } return res; } private MetricValue getPDHMetric(Metric metric) { String obj = "\\" + metric.getObjectPropString(); if (!metric.isAvail()) { obj += "\\" + metric.getAttributeName(); } log.debug("[getPDHMetric] metric:'" + metric); log.debug("[getPDHMetric] obj:'" + obj); return getPDHMetric(obj, metric.isAvail()); } private MetricValue getPDHMetric(String obj, boolean avail) { MetricValue res; try { Double val = new Pdh().getFormattedValue(obj); res = new MetricValue(val); if (avail) { res = new MetricValue(Metric.AVAIL_UP); } } catch (Win32Exception ex) { if (avail) { res = new MetricValue(Metric.AVAIL_DOWN); log.debug("[getPDHMetric] error on obj:'" + obj + "' :" + ex.getLocalizedMessage(), ex); } else { res = MetricValue.NONE; log.debug("[getPDHMetric] error on obj:'" + obj + "' :" + ex.getLocalizedMessage()); } } return res; } }