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

net.welen.jmole.protocols.munin.MuninSocketHandler Maven / Gradle / Ivy

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

/*
 * #%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.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.SocketTimeoutException;
import java.util.Locale;
import java.util.Map.Entry;
import java.util.logging.Level;
import java.util.logging.Logger;

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

import net.welen.jmole.Configuration;
import net.welen.jmole.collector.MBeanCollector;
import net.welen.jmole.finder.MBeanFinder;
import net.welen.jmole.presentation.PresentationInformation;
import net.welen.jmole.threshold.Threshold;
import net.welen.jmole.threshold.ThresholdValues;

public class MuninSocketHandler extends Thread {
	
	private final static Logger LOG = Logger.getLogger(MuninSocketHandler.class.getName());

	private Socket socket;
	private Munin setup;

	public MuninSocketHandler(Socket socket, Munin setup) {
		this.socket = socket;
		this.setup = setup;
		this.setName("JMole Munin protocol thread #" + setup.currentThreads);
	}

	public void run() {		
		try {
			setup.currentThreads++;
			socket.setSoTimeout(setup.getTcpReadTimeOut());
			BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream(), "UTF-8"));
			PrintWriter out = new PrintWriter(new OutputStreamWriter(socket.getOutputStream(), "UTF-8"), true);
			boolean multigraph = false;
			boolean dirtyconfig = false;
			
			// Send greeting
			out.println("# munin node at "
					+ socket.getLocalAddress().getHostAddress() + ":"
					+ socket.getLocalPort());
			int maxThreads = setup.getMaxThreads();
			if (setup.currentThreads > maxThreads) {
				out.println("# Max number of clients reached: " + maxThreads + ". Hanging up.");
				throw new IOException("Max number of clients reached: " + maxThreads);
			}
			while (true) {
				String command = reader.readLine();
				if (command == null) {
					break;
				}

				// Strip/cleanup command
				command = command.replaceAll("\\b\\s{2,}\\b", " ").trim().toLowerCase(Locale.ENGLISH);
				
				// Parse command
				if (command.equals("quit")) {					// quit
					socket.close();
					return;
				} else if (command.equals("version")) {			// version				
					out.println("Munin JMole node version: " + this.getClass().getPackage().getImplementationVersion());
				} else if (command.equals("list")) {			// list					
					if (multigraph) {
						out.println("jmole");
					} else {
						LOG.log(Level.SEVERE, "cap multigraph not sent from server. Returning nothing.");
						out.println("");
					}
				} else if (command.startsWith("cap")) {			// cap				
					if (command.contains("multigraph")) {
						multigraph = true;						
					}
					if (command.contains("dirtyconfig")) {
						dirtyconfig = true;						
					}
					out.println("cap multigraph dirtyconfig");
				} else if (command.startsWith("config")) {		// config
					if (command.equals("config jmole")) {						
						out.println(executeConfig(dirtyconfig));
					} else {
						out.println("# Unknown service\n.");
					}
				} else if (command.startsWith("fetch")) {		// fetch
					if (command.matches("fetch\\s+jmole")) {						
						out.println(executeFetch());
					} else {
						out.println("# Unknown service\n.");
					}
				} else {
					out.println("# Unknown command");
				}
			}
		} catch (SocketTimeoutException e) {
			LOG.log(Level.WARNING, e.getMessage(), e);
		} catch (Exception e) {
			LOG.log(Level.SEVERE, e.getMessage(), e);			
		} finally {
			setup.currentThreads--;
			try {
				socket.close();
			} catch (IOException e) {
				LOG.log(Level.SEVERE, e.getMessage(), e);
			}
		}
	}
	
	private String executeConfig(boolean dirtyconfig) throws AttributeNotFoundException, InstanceNotFoundException, MBeanException, ReflectionException {
		StringBuilder answer = new StringBuilder();
		 
		for (Configuration configuration : setup.jmole.getConfiguration()) {
			MBeanFinder finder = configuration.getMBeanFinder();
			if (finder.getMatchingObjectNames().isEmpty()) {
				continue;
			}
			MBeanCollector collector = configuration.getMBeanCollector();
			PresentationInformation presentationInformation = configuration.getPresentationInformation();
					
			for (ObjectName objectName : finder.getMatchingObjectNames()) {
				answer.append("multigraph " + fixForMunin(collector.getConstructedName(objectName)) + "\n");
				if (presentationInformation.getCategory() != null) {
					answer.append("graph_category " + presentationInformation.getCategory() + "\n");
				}
				answer.append("graph_title " + collector.getConstructedName(objectName) + "\n");
				if (presentationInformation.getUnit() != null) {
					answer.append("graph_vlabel " + presentationInformation.getUnit() + "\n");
				}
				if (presentationInformation.getDescription() != null) {
					answer.append("graph_info " + presentationInformation.getDescription() + "\n");
				}
				// Hardcoded layout
				answer.append("graph_printf %.0lf\n");			
				
				for (String attribute : collector.getAttributes()) {
					String fixedAttribute = fixForMunin(attribute);
					answer.append(fixedAttribute + ".label " + presentationInformation.translateAttributeLabel(attribute) + "\n");
					
					String description = presentationInformation.getAttributeDescription(attribute);
					if (description != null) {
						answer.append(fixedAttribute + ".info " + description + "\n");
					}
					
					Threshold threshold = configuration.getThresholds().get(attribute);					
					if (threshold != null) {

						ThresholdValues individualValues = threshold.getIndividualThresholds().get(collector.getConstructedName(objectName));
						String low;
						String high;
						
						// Warnings
						if (individualValues == null) {
							low = threshold.getWarningLowThreshold();	
							high = threshold.getWarningHighThreshold();
						} else {
							low = individualValues.getWarningLowThreshold();
							high = individualValues.getWarningHighThreshold();
						}
						// TODO When Munin Ticket 1016 is impl. the calculation may not be needed					
						String tmp = Threshold.calculateThreshold(low, collector, objectName, attribute)
								+ ":" 
								+ Threshold.calculateThreshold(high, collector, objectName, attribute);						
						if (!tmp.equals(":")) {							
							answer.append(fixedAttribute + ".warning " + tmp + "\n");
						}

						// Critical
						if (individualValues == null) {
							low = threshold.getCriticalLowThreshold();	
							high = threshold.getCriticalHighThreshold();
						} else {
							low = individualValues.getCriticalLowThreshold();
							high = individualValues.getCriticalHighThreshold();
						}
						// TODO When Munin Ticket 1016 is impl. the calculation may not be needed					
						tmp = Threshold.calculateThreshold(low, collector, objectName, attribute) 
								+ ":" 
								+ Threshold.calculateThreshold(high, collector, objectName, attribute);
						if (!tmp.equals(":")) {
							answer.append(fixedAttribute + ".critical " + tmp + "\n");
						}
					}
				}

				if (dirtyconfig) {
					for (Entry entry : collector.getValues(objectName).entrySet()) {
						String valueString = translateValue(entry.getValue());
						answer.append(fixForMunin(entry.getKey()) + ".value " + valueString + "\n");
					}
				}
			}
		}
		return answer.append(".\n").toString();
	}
	
	private String executeFetch() throws InstanceNotFoundException, ReflectionException, AttributeNotFoundException, MBeanException {
		StringBuilder answer = new StringBuilder();
		 
		for (Configuration configuration : setup.jmole.getConfiguration()) {
			MBeanFinder finder = configuration.getMBeanFinder();
			MBeanCollector collector = configuration.getMBeanCollector();
						
			for (ObjectName objectName : finder.getMatchingObjectNames()){
				answer.append("multigraph " + fixForMunin(collector.getConstructedName(objectName)) + "\n");
				for (Entry entry : collector.getValues(objectName).entrySet()) {
					String valueString = translateValue(entry.getValue());
					answer.append(fixForMunin(entry.getKey()) + ".value " + valueString + "\n");
				}
			}			
		}
		return answer.append(".\n").toString();
	}

	// Munin can only handle numeric values
	private String translateValue(Object value) {
		if (value == null) {
			// TODO Or should we return 0?
			return "";
		}
		if (value instanceof Boolean) {
			if ((Boolean) value) {
				return "1";
			}
			return "0";
		}
		return value.toString();
	}
	
	// Munin can't handle special characters
	private String fixForMunin(String input) {
		return input.replaceAll("[^a-zA-Z0-9]", "_");
	}
	
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy