org.glassfish.admin.monitor.MonitoringBootstrap Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of payara-micro Show documentation
Show all versions of payara-micro Show documentation
Micro Distribution of the Payara Project for IBM JDK
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright (c) 2009-2013 Oracle and/or its affiliates. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
* and Distribution License("CDDL") (collectively, the "License"). You
* may not use this file except in compliance with the License. You can
* obtain a copy of the License at
* https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
* or packager/legal/LICENSE.txt. See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each
* file and include the License file at packager/legal/LICENSE.txt.
*
* GPL Classpath Exception:
* Oracle designates this particular file as subject to the "Classpath"
* exception as provided by Oracle in the GPL Version 2 section of the License
* file that accompanied this code.
*
* Modifications:
* If applicable, add the following below the License Header, with the fields
* enclosed by brackets [] replaced by your own identifying information:
* "Portions Copyright [year] [name of copyright owner]"
*
* Contributor(s):
* If you wish your version of this file to be governed by only the CDDL or
* only the GPL Version 2, indicate your decision by adding "[Contributor]
* elects to include this software in this distribution under the [CDDL or GPL
* Version 2] license." If you don't indicate a single choice of license, a
* recipient has the option to distribute your version of this file under
* either the CDDL, the GPL Version 2 or to extend the choice of license to
* its licensees as provided above. However, if you add GPL Version 2 code
* and therefore, elected the GPL Version 2 license, then the option applies
* only if the new code is made subject to such option by the copyright
* holder.
*/
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package org.glassfish.admin.monitor;
import java.beans.PropertyChangeEvent;
import java.net.URISyntaxException;
import java.util.*;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.glassfish.api.admin.ServerEnvironment;
import org.glassfish.external.probe.provider.StatsProviderInfo;
import org.glassfish.hk2.api.PostConstruct;
import org.glassfish.hk2.api.PreDestroy;
import org.glassfish.hk2.api.ServiceLocator;
import org.glassfish.hk2.runlevel.RunLevel;
import org.glassfish.external.probe.provider.StatsProviderManager;
import com.sun.enterprise.config.serverbeans.*;
import org.glassfish.flashlight.MonitoringRuntimeDataRegistry;
import org.jvnet.hk2.annotations.Optional;
import org.jvnet.hk2.annotations.Service;
import org.jvnet.hk2.config.ConfigBeanProxy;
import org.jvnet.hk2.config.ConfigListener;
import org.jvnet.hk2.config.UnprocessedChangeEvents;
import com.sun.enterprise.module.Module;
import com.sun.enterprise.module.ModuleState;
import com.sun.enterprise.module.ModuleDefinition;
import com.sun.enterprise.module.ModulesRegistry;
import com.sun.enterprise.module.ModuleLifecycleListener;
import java.io.File;
import java.io.FileInputStream;
import java.io.FilenameFilter;
import java.io.IOException;
import java.lang.management.ManagementFactory;
import java.net.URI;
import java.util.jar.Manifest;
import java.util.jar.Attributes;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.WeakHashMap;
import java.util.Collections;
import java.util.HashMap;
import java.util.StringTokenizer;
import org.glassfish.external.amx.AMXGlassfish;
import org.glassfish.api.event.Events;
import org.glassfish.api.event.EventListener;
import org.glassfish.api.event.EventTypes;
import org.glassfish.api.monitoring.ContainerMonitoring;
import org.glassfish.flashlight.client.ProbeClientMediator;
import org.glassfish.flashlight.impl.client.AgentAttacher;
import org.glassfish.flashlight.provider.ProbeProviderFactory;
import org.glassfish.flashlight.provider.ProbeProviderEventListener;
import org.glassfish.flashlight.provider.ProbeRegistry;
import org.glassfish.internal.api.InitRunLevel;
import org.glassfish.internal.api.LogManager;
import org.jvnet.hk2.config.Transactions;
import javax.inject.Inject;
import javax.inject.Named;
import static org.glassfish.admin.monitor.MLogger.*;
/**
*
* @author abbagani
*/
@Service
@RunLevel(InitRunLevel.VAL)
public class MonitoringBootstrap implements PostConstruct, PreDestroy, EventListener, ModuleLifecycleListener, ConfigListener {
@SuppressWarnings("unused")
@Inject @Optional
private LogManager dependency0; // The LogManager must come up prior to this service
@Inject
private MonitoringRuntimeDataRegistry mrdr;
@Inject
private ModulesRegistry registry;
@Inject
protected ProbeProviderFactory probeProviderFactory;
@Inject
protected ProbeClientMediator pcm;
@Inject
Events events;
@Inject
ServerEnvironment serverEnv;
@Inject
@Named(ServerEnvironment.DEFAULT_INSTANCE_NAME)
@Optional
MonitoringService monitoringService = null;
@Inject
private org.glassfish.flashlight.provider.ProbeRegistry probeRegistry;
@Inject
ServiceLocator habitat;
@Inject
Transactions transactions;
//Don't inject ConfigBeans to avoid getting every event on them
private Domain domain;
Map map = Collections.synchronizedMap(new WeakHashMap());
List appList = Collections.synchronizedList(new ArrayList());
private static final String INSTALL_ROOT_URI_PROPERTY_NAME = "com.sun.aas.installRootURI";
private static final Logger logger = getLogger();
private static final String PROBE_PROVIDER_CLASS_NAMES = "probe-provider-class-names";
private static final String PROBE_PROVIDER_XML_FILE_NAMES = "probe-provider-xml-file-names";
private static final String DELIMITER = ",";
private StatsProviderManagerDelegateImpl spmd;
private boolean monitoringEnabled = false;
private boolean hasDiscoveredXMLProviders = false;
@Override
public void postConstruct() {
domain = habitat.getService(Domain.class);
transactions.addListenerForType(ContainerMonitoring.class, this);
transactions.addListenerForType(MonitoringService.class, this);
transactions.addListenerForType(ModuleMonitoringLevels.class, this);
// wbn: This value sticks for the life of the bootstrapping. If the user changes it
// somehow during bootstrapping we would have some problems so we just get the value
// and run with it...
boolean enableMonitoring = (monitoringService != null) ?
Boolean.parseBoolean(monitoringService.getMonitoringEnabled())
&& monitoringService.isAnyModuleOn() :
false;
//Don't listen for any events and dont process any probeProviders or statsProviders (dont set delegate)
if (enableMonitoring) {
enableMonitoring(false);
}
}
private void enableMonitoring(boolean isDiscoverXMLProbeProviders) {
// Register as ModuleLifecycleListener
events.register(this);
enableMonitoringForProbeProviders(isDiscoverXMLProbeProviders);
AgentAttacher.attachAgent();
//Lets do the catch up for all the statsProviders (we might have ignored the module level changes earlier)
if (spmd != null) {
spmd.updateAllStatsProviders();
}
monitoringEnabled = true;
}
private void discoverProbeProviders() {
// Iterate thru existing modules
if (logger.isLoggable(Level.FINE))
logger.log(Level.FINE, "Discovering the ProbeProviders");
for (Module m : registry.getModules()) {
if ((m.getState() == ModuleState.READY) || (m.getState() == ModuleState.RESOLVED)) {
if (logger.isLoggable(Level.FINE))
logger.fine(" In (discoverProbeProviders) ModuleState - " + m.getState() + " : " + m.getName());
verifyModule(m);
}
}
}
public void preDestroy() {
//We need to do the cleanup for preventing errors from server starting in Embedded mode
ProbeRegistry.cleanup();
if (spmd != null) {
spmd = new StatsProviderManagerDelegateImpl(pcm, probeRegistry, mrdr, domain, serverEnv.getInstanceName(),
monitoringService);
StatsProviderManager.setStatsProviderManagerDelegate(spmd);
}
}
public void event(Event event) {
if (event.is(EventTypes.SERVER_READY)) {
// Process the XMLProviders in lib/monitor dir. Should be the last thing to do in server startup.
if (logger.isLoggable(Level.FINE))
logger.log(Level.FINE, "Discovering the XML ProbeProviders from lib/monitor");
discoverXMLProviders();
}
}
public void setStatsProviderManagerDelegate() {
// only run the code one time!
if(spmd != null)
return;
//Set the StatsProviderManagerDelegate, so we can start processing the StatsProviders
spmd = new StatsProviderManagerDelegateImpl(pcm, probeRegistry, mrdr, domain, serverEnv.getInstanceName(),
monitoringService);
StatsProviderManager.setStatsProviderManagerDelegate(spmd);
StatsProviderUtil.setStatsProviderManagerDelegate(spmd);
if (logger.isLoggable(Level.FINE))
logger.fine(" StatsProviderManagerDelegate is assigned");
// Register listener for AMX DomainRoot loaded
final AMXGlassfish amxg = AMXGlassfish.DEFAULT;
amxg.listenForDomainRoot(ManagementFactory.getPlatformMBeanServer(), spmd);
}
public void moduleResolved(Module module) {
if (module == null) return;
verifyModule(module);
}
public synchronized void moduleStarted(Module module) {
if (module == null) return;
verifyModule(module);
}
private synchronized void verifyModule(Module module) {
if (module == null) return;
String str = module.getName();
if (!map.containsKey(str)) {
map.put(str, module);
addProvider(module);
}
}
/**
* An application that has probes can be registered.
* @param appName application-name
* @param appDir directory where application bits are present.
* @param cl classloader that is used to load application files.
*/
public synchronized void registerProbes(String appName, File appDir, ClassLoader cl) {
if (appName == null) return;
if (cl == null) {
if (logger.isLoggable(Level.FINE)){
logger.log(Level.FINE, "Null classloader passed for application : {0}", appName);
}
return;
}
if (!appList.contains(appName)) {
appList.add(appName);
addProvider(appDir, cl);
}
}
// noop to satisfy interface
@Override
public synchronized void moduleStopped(Module module) {
}
// noop to satisfy interface
@Override
public void moduleInstalled(Module module) {
}
// noop to satisfy interface
@Override
public void moduleUpdated(Module module) {
}
private void addProvider(Module module) {
if (logger.isLoggable(Level.FINE))
logger.fine(" Adding the Provider - verified the module");
ClassLoader mcl = module.getClassLoader();
//get manifest entries and process
ModuleDefinition md = module.getModuleDefinition();
Manifest mf = null;
if (md != null) {
mf = md.getManifest();
}
if (mf != null) {
processManifest(mf, mcl);
}
handleFutureStatsProviders();
}
private void addProvider(File appDir, ClassLoader classLoader) {
//get manifest entries and process
File manifestFile = new File(appDir, "META-INF" + File.separator + "MANIFEST.MF");
String appDirPath = "";
Manifest mf;
try {
appDirPath = appDir.getCanonicalPath();
FileInputStream fis = new FileInputStream(manifestFile);
mf = new Manifest(fis);
} catch (IOException ex) {
if (logger.isLoggable(Level.FINE)) {
logger.log(Level.FINE,"Can''t access "+"META-INF{0}" + "MANIFEST.MF" + " for {1}",
new Object[]{File.separator, appDirPath});
logger.fine(ex.getLocalizedMessage());
}
return;
}
processManifest(mf, classLoader);
handleFutureStatsProviders();
}
private void processManifest(Manifest mf, ClassLoader mcl) {
if (mf != null) {
Attributes attrs = mf.getMainAttributes();
String cnames = null;
String xnames = null;
if (attrs != null) {
cnames = attrs.getValue(PROBE_PROVIDER_CLASS_NAMES);
if (cnames != null) {
if (logger.isLoggable(Level.FINE))
logger.fine("probe providers = " + cnames);
StringTokenizer st = new StringTokenizer(cnames, DELIMITER);
while (st.hasMoreTokens()) {
try {
if (mcl != null)
processProbeProviderClass(mcl.loadClass(st.nextToken().trim()));
} catch (Exception e) {
logger.log(Level.SEVERE, unableToLoadProbeProvider, e);
}
}
}
xnames = attrs.getValue(PROBE_PROVIDER_XML_FILE_NAMES);
if (xnames != null) {
if (logger.isLoggable(Level.FINE))
logger.fine("xnames = " + xnames);
StringTokenizer st = new StringTokenizer(xnames, DELIMITER);
while (st.hasMoreTokens()) {
processProbeProviderXML(mcl, st.nextToken(), true);
}
}
}
}
}
public void handleFutureStatsProviders() {
// we just registered a Probe Provider
// If there are any future items -- let's try to register them again.
if(FutureStatsProviders.isEmpty())
return; // Performance note -- this should be the case almost always
List removeList = new ArrayList();
Iterator it = FutureStatsProviders.iterator();
// the iterator does not allow the remove operation - thus the complexity!
while(it.hasNext()) {
StatsProviderInfo spInfo = it.next();
try {
spmd.tryToRegister(spInfo);
removeList.add(spInfo);
}
catch(RuntimeException re) {
// no probe registered yet...
}
}
for(StatsProviderInfo spInfo : removeList) {
FutureStatsProviders.remove(spInfo);
}
}
private void discoverXMLProviders() {
// Dont process if already discovered, Ideally we should do this whenever a new XML is dropped in lib/monitor
if (hasDiscoveredXMLProviders)
return;
try {
URI xmlProviderDirStr = new URI(System.getProperty(INSTALL_ROOT_URI_PROPERTY_NAME) + "/" + "lib" + "/" + "monitor");
if (logger.isLoggable(Level.FINE))
logger.fine("ProviderXML's Dir = " + xmlProviderDirStr.getPath());
File xmlProviderDir = new File(xmlProviderDirStr.getPath());
//File scriptFile = new File ("/space/GFV3_BLD/glassfish/domains/domain1/applications/scripts/InvokeJavaFromJavascript.js");
if (logger.isLoggable(Level.FINE)) {
logger.fine("ProviderXML's Dir exists = " + xmlProviderDir.exists());
logger.fine("ProviderXML's Dir path - " + xmlProviderDir.getAbsolutePath());
}
loadXMLProviders(xmlProviderDir);
hasDiscoveredXMLProviders = true;
} catch (URISyntaxException ex) {
logger.log(Level.SEVERE, unableToProcessXMLProbeProvider, ex);
}
}
private void loadXMLProviders(File xmlProvidersDir) {
// Creates a filter which will return only xml files
FilenameFilter filter = new FilenameFilter() {
public boolean accept(File dir, String name) {
return name.endsWith(".xml");
}
};
// Retrieves all the provider XML's
File[] files = xmlProvidersDir.listFiles(filter);
if (files == null)
return;
Map providerMap = new HashMap();
for (File file : files) {
if (logger.isLoggable(Level.FINE))
logger.fine("Found the provider xml - " + file.getAbsolutePath());
int index = file.getName().indexOf("-:");
if (index != -1) {
String moduleName = file.getName().substring(0,index);
providerMap.put(moduleName, file);
if (logger.isLoggable(Level.FINE))
logger.fine(" The provider xml belongs to - \"" + moduleName + "\"");
if (!map.containsKey(moduleName)) {
continue;
}
if (logger.isLoggable(Level.FINE))
logger.fine (" Module found (containsKey)");
Module module = map.get(moduleName);
if (module == null) {
logger.log(Level.SEVERE,
monitoringMissingModuleFromXmlProbeProviders,
new Object[] {moduleName});
} else {
ClassLoader mcl = module.getClassLoader();
if (logger.isLoggable(Level.FINE)) {
logger.fine("ModuleClassLoader = " + mcl);
logger.fine("XML File path = " + file.getAbsolutePath());
}
processProbeProviderXML(mcl, file.getAbsolutePath(), false);
}
}
}
}
private void processProbeProviderClass(Class cls) {
if (logger.isLoggable(Level.FINE))
logger.fine("processProbeProviderClass for " + cls);
try {
probeProviderFactory.getProbeProvider(cls);
} catch (InstantiationException ex) {
logger.log(Level.SEVERE, unableToLoadProbeProvider, ex);
} catch (IllegalAccessException ex) {
logger.log(Level.SEVERE, unableToLoadProbeProvider, ex);
}
}
private void processProbeProviderXML(ClassLoader mcl, String xname, boolean inBundle) {
probeProviderFactory.processXMLProbeProviders(mcl, xname, inBundle);
}
/*public void event(Event event) {
if (event.name().equals(EventTypes.PREPARE_SHUTDOWN_NAME)) {
spmd.unregisterAll();
}
}*/
public UnprocessedChangeEvents changed(PropertyChangeEvent[] propertyChangeEvents) {
if (logger.isLoggable(Level.FINE))
logger.fine(" spmd = " + spmd);
StatsProviderRegistry spr = (spmd == null) ? null : spmd.getStatsProviderRegistry();
if (logger.isLoggable(Level.FINE))
logger.fine("spr = " + spr);
for (PropertyChangeEvent event : propertyChangeEvents) {
// let's get out of here ASAP if it is not our stuff!!
if(event == null)
continue;
if (!isCurrentInstanceMatchingTarget(event)) {
continue;
}
String propName = event.getPropertyName();
Object oldVal = event.getOldValue();
Object newVal = event.getNewValue();
if(newVal == null || newVal.equals(oldVal))
continue; // no change!!
if(!ok(propName))
continue;
String level_change_mesg = "Level change event received, {0} New Level = {1}, Old Level = {2}";
if (event.getSource() instanceof ModuleMonitoringLevels) {
String newEnabled = newVal.toString().toUpperCase(Locale.ENGLISH);
String oldEnabled = (oldVal == null) ? "OFF" : oldVal.toString().toUpperCase(Locale.ENGLISH);
if (logger.isLoggable(Level.FINE))
logger.log(Level.FINE, level_change_mesg,
new Object[]{propName, newEnabled, oldEnabled});
if (!newEnabled.equals(oldEnabled)) {
handleLevelChange(propName, newEnabled);
}
}
else if (event.getSource() instanceof ContainerMonitoring) {
ContainerMonitoring cm = (ContainerMonitoring)event.getSource();
String newEnabled = newVal.toString().toUpperCase(Locale.ENGLISH);
String oldEnabled = (oldVal == null) ? "OFF" : oldVal.toString().toUpperCase(Locale.ENGLISH);
if (logger.isLoggable(Level.FINE))
logger.log(Level.FINE, level_change_mesg,
new Object[]{propName, newEnabled, oldEnabled});
if (!newEnabled.equals(oldEnabled)) {
handleLevelChange(cm.getName(), newEnabled);
}
}
else if(event.getSource() instanceof MonitoringService) {
// we don't want to get fooled because config allows ANY string.
// e.g. "false" --> "foo" --> "fals" are all NOT changes!
// so we convert to boolean and then compare...
boolean newEnabled = Boolean.parseBoolean(newVal.toString());
boolean oldEnabled = (oldVal == null) ? !newEnabled : Boolean.parseBoolean(oldVal.toString());
if (logger.isLoggable(Level.FINE))
logger.log(Level.FINE, level_change_mesg,
new Object[]{propName, newEnabled, oldEnabled});
if(newEnabled != oldEnabled) {
handleServiceChange(spr, propName, newEnabled);
}
}
}
return null;
}
private boolean isCurrentInstanceMatchingTarget(PropertyChangeEvent event) {
// DAS receive all the events, so we need to figure out
// whether we should take action on DAS depending on the event.
if(serverEnv.isInstance()) {
return true;
}
ConfigBeanProxy proxy = (ConfigBeanProxy)(event.getSource());
while(proxy != null && !(proxy instanceof Config)) {
proxy = proxy.getParent();
}
if (proxy != null) {
Config config = (Config)proxy;
return config.isDas();
}
return false;
}
private void handleLevelChange(String propName, String enabledStr) {
if (logger.isLoggable(Level.FINE))
logger.fine("In handleLevelChange(), spmd = " + spmd + " Enabled="+enabledStr);
if(!ok(propName))
return;
if (!monitoringEnabled && !"OFF".equals(enabledStr)) {
enableMonitoring(true);
}
if(spmd == null)
return; // nothing to do!
if (parseLevelsBoolean(enabledStr)) {
if (logger.isLoggable(Level.FINE))
logger.log(Level.FINE,
"Enabling {0} monitoring to {1}", new Object[] {propName, enabledStr});
try {
spmd.enableStatsProviders(propName);
} catch(RuntimeException rte) {
logger.log(Level.INFO, UNHANDLED_EXCEPTION_INFO, rte);
}
} else {
if (logger.isLoggable(Level.FINE))
logger.log(Level.FINE,
"Disabling {0} monitoring", propName);
spmd.disableStatsProviders(propName);
}
}
private void handleServiceChange(StatsProviderRegistry spr, String propName, boolean enabled) {
if(!ok(propName))
return;
if (propName.equals("mbean-enabled")) {
if(spr == null) // required!
return;
if(enabled) {
logger.log(Level.INFO, mbeanEnabled);
spmd.registerAllGmbal();
} else {
logger.log(Level.INFO, mbeanDisabled);
spmd.unregisterAllGmbal();
}
}
else if(propName.equals("dtrace-enabled")) {
logger.log(Level.INFO,dtraceEnabled);
probeProviderFactory.dtraceEnabledChanged(enabled);
}
else if(propName.equals("monitoring-enabled")) {
//This we do it so we can (un)expose probes as DTrace
probeProviderFactory.monitoringEnabledChanged(enabled);
if(enabled) {
logger.log(Level.INFO,monitoringEnabledLogMsg);
enableMonitoring(true);
} else { // if disabled
logger.log(Level.INFO,monitoringDisabledLogMsg);
disableMonitoringForProbeProviders();
if (spmd != null) {
spmd.disableAllStatsProviders();
}
}
}
}
private void enableMonitoringForProbeProviders(boolean isDiscoverXMLProviders) {
//Process all ProbeProviders from modules loaded
discoverProbeProviders();
//Start listening to any new Modules that are coming in now
registry.register(this);
//Don't do this the first time, since we need to wait till the server starts
// We should try to do this in a seperate thread, as we dont want to get held up in server start
if (isDiscoverXMLProviders) {
//Process all XMLProbeProviders from lib/monitor directory
discoverXMLProviders();
}
//Start registering the cached StatsProviders and also those that are coming in new
setStatsProviderManagerDelegate();
//register probeprocee listener
probeProviderFactory.addProbeProviderEventListener(new ProcessProbes());
}
private void disableMonitoringForProbeProviders() {
//Cannot do a whole lot here. The providers that are registered will remain registered.
//Just disable the StatsProviders, so you remove the listening overhead
registry.unregister(this);
}
private boolean ok(String s) {
return s != null && s.length() > 0;
}
private boolean parseLevelsBoolean(String s) {
if (ok(s) && s.equals("OFF"))
return false;
return true;
}
private class ProcessProbes implements ProbeProviderEventListener {
public void probeProviderAdded(String moduleProviderName, String moduleName,
String probeProviderName, String invokerId, Class providerClazz, T provider) {
handleFutureStatsProviders();
}
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy