All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.welen.jmole.collector.MBeanCollectorImpl Maven / Gradle / Ivy

There is a newer version: 2.0.2
Show newest version
package net.welen.jmole.collector;

import java.text.DecimalFormat;

/*
 * #%L
 * JMole, https://bitbucket.org/awelen/jmole
 * %%
 * Copyright (C) 2015 - 2020 Anders Welén, [email protected]
 * %%
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 * 
 * 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 Lesser Public License for more details.
 * 
 * You should have received a copy of the GNU General Lesser Public
 * License along with this program.  If not, see
 * .
 * #L%
 */

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.HashMap;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.management.MBeanServer;

import javax.management.ObjectName;
import javax.management.MBeanException;
import javax.management.AttributeNotFoundException;
import javax.management.InstanceNotFoundException;
import javax.management.ReflectionException;
import javax.management.Attribute;
import javax.management.AttributeList;

import net.welen.jmole.Utils;

/**
 * The impl, of a MBeanCollector
 */
public class MBeanCollectorImpl implements MBeanCollector {
	private final static Logger LOG = Logger.getLogger(MBeanCollectorImpl.class.getName());

	private MBeanServer server = Utils.getMBeanServer();

	private String name = "%s";
	private List nameAttributes = null;
	private List nameParameters = null;
	private List nameDomainNameParts = null;

	private Map counterIntervals = new HashMap();
	private Map lastFetchMap = new HashMap();

	private List attributes = new ArrayList();
	private Map attributeExtractors = new HashMap();
	private Map attributeRecalculations = new HashMap();
	private Map attributeFormatPatterns = new HashMap();

	private static class LastFetch {
		public LastFetch(long fetchTime, Double value, Double lastCalculatedValue) {
			this.fetchTime = fetchTime;
			this.value = value;
			this.lastCalculatedValue = lastCalculatedValue;
		}

		long fetchTime;
		Double value;
		Double lastCalculatedValue;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getName() {
		return name;
	}

	public void setNameAttributes(List nameAttributes) {
		this.nameAttributes = nameAttributes;
	}

	public void setNameParameters(List nameParameters) {
		this.nameParameters = nameParameters;
	}

	public void setNameDomainNameParts(List nameDomainNameParts) {
		this.nameDomainNameParts = nameDomainNameParts;
	}

	public Map getCounterIntervals() {
		return counterIntervals;
	}

	public void setCounterIntervals(Map counterIntervals) {
		this.counterIntervals = counterIntervals;
	}

	private String getNameSubstitution(ObjectName objectName)
			throws AttributeNotFoundException, InstanceNotFoundException, MBeanException, ReflectionException {
		StringBuilder tmp = new StringBuilder();
		if (nameDomainNameParts != null) {
			String[] domainNameParts = objectName.getDomain().split("\\.");
			for (Integer pos : nameDomainNameParts) {
				if (tmp.length() > 0) {
					tmp.append(" ");
				}
				tmp.append(domainNameParts[pos]);
			}
		}
		if (nameAttributes != null) {
			for (String part : nameAttributes) {
				if (tmp.length() > 0) {
					tmp.append(" ");
				}
				tmp.append(server.getAttribute(objectName, part).toString());
			}
		}
		if (nameParameters != null) {
			for (String part : nameParameters) {
				if (tmp.length() > 0) {
					tmp.append(" ");
				}
				tmp.append(objectName.getKeyProperty(part));
			}
		}
		if (tmp.length() == 0) {
			return null;
		}
		return tmp.toString();
	}

	public void setAttributes(List attributes) {
		this.attributes = attributes;
	}

	public List getAttributes() {
		return attributes;
	}

	public void setDataCollectorExtractors(Map attributeExtractors) {
		this.attributeExtractors = attributeExtractors;
	}

	public void setAttributeRecalculations(Map attributeRecalculations) {
		this.attributeRecalculations = attributeRecalculations;
	}

	public void setAttributeFormatPatterns(Map attributeFormatPatterns) {
		this.attributeFormatPatterns = attributeFormatPatterns;
	}

	@Override
	public String getConstructedName(ObjectName objectName)
			throws MBeanException, AttributeNotFoundException, InstanceNotFoundException, ReflectionException {

		String substition = getNameSubstitution(objectName);
		if (substition != null) {
			return String.format(name, substition);
		}
		return name;
	}

	public Map getValues(ObjectName objectName)
			throws InstanceNotFoundException, ReflectionException, AttributeNotFoundException, MBeanException {
		LOG.log(Level.FINE, "Getting the values for ObjectName: " + objectName);

		LOG.log(Level.FINE, "Attribute list: " + attributes);
		AttributeList attributeList = null;
		try {
			// WildFly 14 seems not to handle attributes that is not found, even if the javadoc says it's ok
			// so we remove all attributes that are handled by DataCollectorExtractors
			List tmpAttributes = new ArrayList(attributes);
			for (DataCollectorExtractor extractor : attributeExtractors.values()) {
				if (tmpAttributes.contains(extractor.getAttribute())) {
					tmpAttributes.remove(extractor.getAttribute());
				}
			}			
			attributeList = server.getAttributes(objectName, tmpAttributes.toArray(new String[0]));
		} catch (RuntimeException e) {
			LOG.log(Level.SEVERE, "Couldn't get the attributes: " + attributes + " for MBean: " + objectName, e);
			throw e;
		}
		LOG.log(Level.FINE, "AttributeList: " + attributeList);

		// Quick fix #1 for old JBoss MBeanServer impl. that return to many
		// attributes/values from getAttributes()
		if (attributeList.size() > attributes.size()) {
			LOG.log(Level.FINE,
					"Fixing JBoss MBean server bug. Got: " + attributeList + " expected only: " + attributes);
			AttributeList fixed = new AttributeList();
			for (Attribute value : attributeList.asList()) {
				if (attributes.contains(value.getName())) {
					fixed.add(value);
				}
			}
			attributeList = fixed;
		}

		// Quick fix #2 for old JBoss MBeanServer impl. where getAttributes()
		// doesn't seem to return super class attributes
		if (attributeList.size() != attributes.size()) {
			for (String attribute : attributes) {
				if (!attributeList.contains(attribute)) {
					try {
						attributeList.add(new Attribute(attribute, server.getAttribute(objectName, attribute)));
						LOG.log(Level.FINE, "Fixing JBoss MBean server bug for MBean: " + objectName
								+ " and attribute: " + attribute);
					} catch (InstanceNotFoundException e) {
						// Do nothing, just continue
						LOG.log(Level.FINE, e.getMessage(), e);
					} catch (ReflectionException e) {
						// Do nothing, just continue
						LOG.log(Level.FINE, e.getMessage(), e);
					} catch (AttributeNotFoundException e) {
						// Do nothing, just continue
						LOG.log(Level.FINE, e.getMessage(), e);
					} catch (MBeanException e) {
						// Do nothing, just continue }
						LOG.log(Level.FINE, e.getMessage(), e);
					}
				}
			}
		}

		Map answer = new HashMap();

		// Collect all attribute values
		for (Attribute attribute : attributeList.asList()) {
			String attributeName = attribute.getName();
			Object value;
			try {
				value = attribute.getValue();
			} catch (Throwable t) {
				LOG.log(Level.SEVERE, t.getMessage(), t);
				continue;
			}

			// Ignore any DataCollectorExtractors based attributes
			boolean extractorHandled = false;
			for (DataCollectorExtractor extractor : attributeExtractors.values()) {
				if (extractor.getAttribute().equals(attributeName)) {
					extractorHandled = true;
					break;
				}
			}
			if (!extractorHandled) {
				answer.put(attributeName, handleValue(objectName, attributeName, value));
			}
		}

		// Collect any DataCollectorExtractors based attributes
		LOG.log(Level.FINE, "DataCollectorExtractor attributes: " + attributeExtractors.keySet());
		for (DataCollectorExtractor extractor : attributeExtractors.values()) {
			LOG.log(Level.FINE,
					"DataCollectorExtractor found  ObjectName: " + objectName + " Attribute: "
							+ extractor.getAttribute() + " Properties: " + extractor.getProperties());							
			Object value;
			try {
				 value = extractor.extractData(objectName);
			} catch (Throwable t) {
				LOG.log(Level.SEVERE, t.getMessage(), t);
				continue;
			}

			answer.put(extractor.getAttribute(), handleValue(objectName, extractor.getAttribute(), value));
		}

		LOG.log(Level.FINE, "Returning: " + answer);
		return answer;

	}

	private Object handleValue(ObjectName objectName, String attributeName, Object value) {

		LOG.log(Level.FINE, "Attribute : " + attributeName + " value = " + value);

		// Check if we have a counter interval and calculate the value instead
		if (counterIntervals.containsKey(attributeName)) {
			value = calculateCounterValue(objectName + "->" + attributeName, Double.parseDouble(value.toString()),
					counterIntervals.get(attributeName));
		}
		if (value == null) {
			LOG.log(Level.FINE, "Attribute: " + attributeName + " is null for ObjectName: " + objectName);
			return null;
		}

		// Any recalculation?
		if (attributeRecalculations.containsKey(attributeName)) {
			try {
				Double doubleValue = Double.parseDouble(value.toString());
				String reCalculation = attributeRecalculations.get(attributeName);
				value = Double.parseDouble(Utils.rpnCalculate(doubleValue + "," + reCalculation));
			} catch (NumberFormatException e) {
				LOG.log(Level.SEVERE, "Can't do recalculation on non decimal value: " + objectName + " " + value, e);
			}
		}

		// Any formatting?
		if (attributeFormatPatterns.containsKey(attributeName)) {
			try {
				Double doubleValue = Double.parseDouble(value.toString());
				String pattern = attributeFormatPatterns.get(attributeName);
				DecimalFormat decimalFormat = new DecimalFormat(pattern);
				value = decimalFormat.format(doubleValue);
			} catch (NumberFormatException e) {
				LOG.log(Level.SEVERE, "Can't do formatting on non decimal value: " + objectName + " " + value, e);
			}
		}

		LOG.log(Level.FINE, "Attribute: " + attributeName + " is " + value + " for ObjectName: " + objectName);

		return value;
	}

	private Double calculateCounterValue(String key, Double value, int counterInterval) {
		LOG.log(Level.FINE, "Checking " + key);

		long now = System.currentTimeMillis();
		LastFetch lastFetch = lastFetchMap.get(key);

		if (lastFetch == null) {
			LOG.log(Level.FINE, "No earlier fetch available, skipping");
			lastFetchMap.put(key, new LastFetch(now, value, null));
			return null;
		}
		if (lastFetch.value > value) {
			LOG.log(Level.FINE, "Skipping and reset due to that " + lastFetch.value + " > " + value);
			lastFetchMap.put(key, new LastFetch(now, value, null));
			return null;
		}
		if (lastFetch.fetchTime + counterInterval > now) {
			LOG.log(Level.FINE, "Returning last know calculated value due to that the counter interval "
					+ counterInterval + " ms is not reached: " + (lastFetch.fetchTime + counterInterval) + " > " + now);
			return lastFetch.lastCalculatedValue;
		}

		// Calculate the value
		Double calculatedValue = (value - lastFetch.value) / ((now - lastFetch.fetchTime) / (double) counterInterval);

		// Save fetchTime and value
		lastFetchMap.put(key, new LastFetch(now, value, calculatedValue));

		LOG.log(Level.FINE, "Returning calculated value: " + calculatedValue);
		return calculatedValue;
	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy