/* * 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.*; 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.util.config.ConfigResponse; import org.hyperic.hq.product.AutoServerDetector; import org.hyperic.hq.product.PluginException; import org.hyperic.hq.product.ServerDetector; import org.hyperic.hq.product.ServerResource; import org.hyperic.hq.product.ServiceResource; import org.hyperic.sigar.win32.Pdh; import org.hyperic.sigar.win32.RegistryKey; import org.hyperic.sigar.win32.Win32Exception; public class DotNetDetector extends ServerDetector implements AutoServerDetector { /** * service type, performance counter group, use service type on service * name, name prefix (back compatibility) */ private static final String[][] aspAppServices = { {"Application", ".NET CLR Loading", "false", ""}, {"ASP.NET App", "ASP.NET Applications", "true", ""}, {"ASP.NET App", "ASP.NET Apps v4.0.30319", "true", "V4 "}, {"ASP.NET App", "ASP.NET Apps v2.0.50727", "true", "V2 "} }; static final String PROP_APP = "app.name"; static final String PROP_PATH = "app.path"; private static final String REG_KEY = "SOFTWARE\\Microsoft\\.NETFramework"; private static Log log = LogFactory.getLog(DotNetDetector.class.getName()); private RegistryKey getRegistryKey(String path) throws Win32Exception { return RegistryKey.LocalMachine.openSubKey(path); } protected final static String ORACLE_PROVIDER_STR = "Oracle Data Provider for .NET"; protected final static String SQL_SERVER_PROVIDER_STR = ".NET Data Provider for SqlServer"; protected final static String SQL_SERVER_PROVIDER_TYPE_STR = "Data Provider for SqlServer"; protected final static String ORACLE_SERVER_PROVIDER_TYPE_STR = "Oracle Data Provider for .Net"; private String getVersion() { RegistryKey key = null; RegistryKey versionKey = null; SortedSet<String> versions = new TreeSet<String>(); try { key = getRegistryKey("SOFTWARE\\Microsoft\\NET Framework Setup\\NDP"); String[] names = key.getSubKeyNames(); for(String versionKeyName : names){ if (versionKeyName.startsWith("v") && !versionKeyName.startsWith("v4")){ versionKey = key.openSubKey(versionKeyName); findVersion(versionKey, versions); }else if(versionKeyName.startsWith("v4")){ versionKey = key.openSubKey(versionKeyName); for(String subKeyName : versionKey.getSubKeyNames()){ RegistryKey subKey = versionKey.openSubKey(subKeyName); findVersion(subKey, versions); } } } } catch (Win32Exception e) { log.debug(e,e); return null; } finally { if (key != null) { key.close(); } } log.debug("Found .NET versions=" + versions); //all runtime versions have the same metrics, //so just discover the highest version return (versions.size() > 0) ? versions.last() : ""; } private void findVersion(RegistryKey versionKey, SortedSet versions){ String versionValue = null; String installPath = null; Pattern regex = Pattern.compile("(\\d*\\.\\d*).*"); versionValue = versionKey.getStringValue("Version","").trim(); installPath = versionKey.getStringValue("InstallPath","").trim(); if(!"".equals(installPath)){ Matcher m = regex.matcher(versionValue); if (m.find()) { versions.add(m.group(1)); } } } private String getInstallPath() { RegistryKey key = null; try { key = getRegistryKey(REG_KEY); return key.getStringValue("InstallRoot").trim(); } catch (Win32Exception e) { return null; } finally { if (key != null) { key.close(); } } } public List getServerResources(ConfigResponse platformConfig) throws PluginException { String expectedVersion = getTypeInfo().getVersion(); String version = getVersion(); if (version == null) { return null; } String path = getInstallPath(); boolean valid = ((version.startsWith(expectedVersion)) && (path != null)); log.debug("Found .NET version=" + version + " (expectedVersion=" + expectedVersion + "), path=" + path + ", valid=" + valid); if (!valid) { return null; } ServerResource server = createServerResource(path); server.setProductConfig(); //server.setControlConfig(...); N/A server.setMeasurementConfig(); List servers = new ArrayList(); servers.add(server); return servers; } private Collection<ServiceResource> addDataProvidersServices(String dataProviderStr, String dataProviderTypeStr) { try { String[] instances = Pdh.getInstances(dataProviderStr); Pattern regex = Pattern.compile("([^\\[]*).*"); Set<String> names = new HashSet<String>(); for (int i = 0; i < instances.length; i++) { String instance = instances[i]; Matcher m = regex.matcher(instance); if (m.find()) { String n = m.group(1).trim(); log.debug("[discoverServices] instance = " + instance + " (" + n + ")"); if (n.length() > 0) { log.debug("[discoverServices] instance = " + instance + " (" + n + ") valid."); names.add(n); } } else { log.debug("[discoverServices] instance = " + instance + " skiped."); } } List<ServiceResource> services = new ArrayList<ServiceResource>(); for (Iterator<String> it = names.iterator(); it.hasNext();) { String name = it.next(); ServiceResource service = new ServiceResource(); service.setType(this, dataProviderTypeStr); service.setServiceName(dataProviderTypeStr + " " + name); ConfigResponse pc = new ConfigResponse(); pc.setValue(PROP_APP, name); service.setProductConfig(pc); service.setMeasurementConfig(); services.add(service); } return services; } catch (Win32Exception e) { log.debug("Error getting pdh data for '.NET Data Provider for:" + dataProviderStr + ":" + e, e); return Collections.emptyList(); } } @Override protected List discoverServices(ConfigResponse serverConfig) throws PluginException { List<ServiceResource> services = new ArrayList<ServiceResource>(); //Data providers. services.addAll(addDataProvidersServices(SQL_SERVER_PROVIDER_STR, SQL_SERVER_PROVIDER_TYPE_STR)); services.addAll(addDataProvidersServices(ORACLE_PROVIDER_STR, ORACLE_SERVER_PROVIDER_TYPE_STR)); // apps String instancesToSkipStr = getProperties().getProperty("dotnet.instances.to.skip", "_Global_"); List<String> instancesToSkip = Arrays.asList(instancesToSkipStr.toUpperCase().split(",")); log.debug("dotnet.instances.to.skip = " + instancesToSkip); for (int i = 0; i < aspAppServices.length; i++) { String serviceType = aspAppServices[i][0]; String counterName = aspAppServices[i][1]; boolean useServiceType = aspAppServices[i][2].equals("true"); try { String[] apps = Pdh.getInstances(counterName); for (int idx = 0; idx < apps.length; idx++) { String name = apps[idx]; if (!instancesToSkip.contains(name.toUpperCase())) { log.debug("instace '" + name + "' (" + counterName + ") valid."); ServiceResource service = new ServiceResource(); service.setType(this, serviceType); if (useServiceType) { service.setServiceName(serviceType + " " + aspAppServices[i][3] + name); } else { service.setServiceName(name); } ConfigResponse pc = new ConfigResponse(); pc.setValue(PROP_APP, name); pc.setValue(PROP_PATH, counterName); service.setProductConfig(pc); service.setMeasurementConfig(); services.add(service); } else { log.debug("instace '" + name + "' (" + counterName + ") skiped."); } } } catch (Win32Exception e) { log.debug("Error getting pdh data for '" + serviceType + "': " + e, e); } } return services; } }