#!/usr/bin/php
<?php
/**
 * Wfsolr Plugin https://github.com/lexsimon/contrib/master/plugins/solr/wfsolr_
 * "Wf" stands for "RBS Web Factory" (http://www.rbs.fr.fr/webfactory/)
 * @author : alexandre.simon@rbs.fr
 *
 * Derived from nicolas.moussikian@shopbot-inc.com's plugin (https://raw.github.com/munin-monitoring/contrib/master/plugins/solr/solr-stats)

 * This plugin allows to graph any data present in the stats report on a
 * multi-core Solr instance
 * AKA : http://127.0.0.1:8080/solr/[name of the core]/admin/stats.jsp
 * Verify the server where the munin-node instance is can access that URL
 *
 * You need to have a PHP 5.2.6+ CLI installed too with curl extension or
 * allow_url_fopen directive on
 * 
 * Once the plugin is available you can symlink it with the following naming convention :
 * wfsolr-[name of the core]-[name of the stats section - ex.: CORE]-[name of the entry in the xml - ex.: searcher]-[name of the stat to graph - ex.: numDocs]
 *
 * Alexandre SIMON additions:
 * - wfsolr-<coreName>-alias ; use suggest to get the list of available aliases
 * - suggest implementation
 * - support for solr_(host|port|webapp) environment variables
 * - default core handling
 * - error handling
 * - unit conversion
 * - use curl to get URL contents instead of relying on allow_url_fopen
 */

$action = isset($argv[1]) ? $argv[1] : '';
$core = null;
$category = null;

$tabParams = explode('-', $argv[0]);
$tabParamsCount = count($tabParams);

$pathAliases = array("numDocs" => array("CORE", "searcher", "numDocs"),
		"avgTimePerRequest" => array("QUERYHANDLER", "/select", "avgTimePerRequest"),
		"avgRequestsPerSecond" => array("QUERYHANDLER", "/select", "avgRequestsPerSecond"),
		"errors" => array("QUERYHANDLER", "/select", "errors"),
		"timeouts" => array("QUERYHANDLER", "/select", "timeouts"),
		"indexSize" => array("QUERYHANDLER", "/replication", "indexSize"),
		"queryResultCacheSize" => array("CACHE", "queryResultCache", "size"),
		"queryResultCacheHitRatio" => array("CACHE", "queryResultCache", "hitratio"),
		"queryResultCacheLookups" => array("CACHE", "queryResultCache", "lookups"),
		"queryResultCacheWarmupTime" => array("CACHE", "queryResultCache", "warmupTime"),
		"documentCacheSize" => array("CACHE", "documentCache", "size"),
		"documentCacheHitRatio" => array("CACHE", "documentCache", "hitratio"),
		"documentCacheLookups" => array("CACHE", "documentCache", "lookups"),
		"documentCacheWarmupTime" => array("CACHE", "documentCache", "warmupTime"),
		"fieldValueCacheSize" => array("CACHE", "fieldValueCache", "size"),
		"fieldValueCacheHitRatio" => array("CACHE", "fieldValueCache", "hitratio"),
		"fieldValueCacheLookups" => array("CACHE", "fieldValueCache", "lookups"),
		"fieldValueCacheWarmupTime" => array("CACHE", "filterCache", "warmupTime"),
		"filterCacheSize" => array("CACHE", "filterCache", "size"),
		"filterCacheHitRatio" => array("CACHE", "filterCache", "hitratio"),
		"filterCacheLookups" => array("CACHE", "filterCache", "lookups"),
		"filterCacheWarmupTime" => array("CACHE", "filterCache", "warmupTime"));

if ($tabParamsCount == 5)
{
	$core = $tabParams[1];
	$category = $tabParams[2];
	$item = $tabParams[3];
	$property = $tabParams[4];
}
elseif ($tabParamsCount == 3)
{
	$core = $tabParams[1];
	$pathAlias = $tabParams[2];
}
elseif ($tabParamsCount == 2)
{
	$pathAlias = $tabParams[1];
}

if (isset($pathAlias))
{
	if (isset($pathAliases[$pathAlias]))
	{
		list($category, $item, $property) = $pathAliases[$pathAlias];
	}
	else
	{
		echo "Unknown alias: $pathAlias\n";
		exit(1);
	}
}

function getenvdef($name, $defaultValue)
{
	$val = getenv($name);
	if ($val === false)
	{
		return $defaultValue;
	}
	return $val;
}

function getSolrAdminUrl($core = null)
{
	$solrHost = getenvdef("solr_host", "127.0.0.1");
	$solrPort = getenvdef("solr_port", "8080");
	$solrWebappName = getenvdef("solr_webapp", "solr");
	$url = "http://$solrHost:$solrPort/$solrWebappName/";
	if ($core !== null)
	{
		$url .= "$core/";
	}
	$url .= "admin";
	return $url;
}

/**
 * Assure some conversions. KB, MB and GB are converted to Bytes
 */
function wffloatval($val)
{
	$fVal = floatval(str_replace(",", ".", $val));
	$valEnd = substr($val, -2);
	if ($valEnd == "KB")
	{
		$fVal = $fVal * 1024;
	}
	elseif ($valEnd == "MB")
	{
		$fVal = $fVal * 1048576;
	}
	elseif ($valEnd == "GB")
	{
		$fVal = $fVal * 1073741824;
	}
	return $fVal;
}

function wfGetUrl($url)
{
	if (extension_loaded("curl"))
	{
		$ch = curl_init();

                $options = array(CURLOPT_URL => $url);
                $options[CURLOPT_TIMEOUT] = 5;
                $options[CURLOPT_CONNECTTIMEOUT] = 5;
		$options[CURLOPT_RETURNTRANSFER] = true;

                curl_setopt_array($ch, $options);

                $content = curl_exec($ch);
                curl_close($ch);
	}
	else
	{
		$content = file_get_contents($url);
	}
	if ($content === false)
	{
		throw new Exception("Could not get $url", 8);
	}

	return $content;
}

try
{
	if ("config" == $action)
	{
		if ($property == "indexSize")
		{
			echo "graph_args --base 1024 -l 0\n";
		}
		echo "graph_category search $core\n";
		echo "graph_title $item $property\n";
		echo "graph_vlabel $property\n";
		if ($core !== null)
		{
			echo $core;
		}
		else
		{
			echo "Default_core";
		}
		echo $item . $property . 'solr.label ' . $property . "\n";
	}
	elseif ("suggest" == $action)
	{
		$url = getSolrAdminUrl()."/cores?action=STATUS";
		$doc = new DOMDocument();
		if (!$doc->loadXML(wfGetUrl($url)))
		{
			echo "Could not load $url as XML\n";
			exit(4);
		}
		$xpath = new DOMXpath($doc);
		$names = $xpath->query("/response/lst[@name='status']/lst/str[@name='name']");
		$aliases = array_keys($pathAliases);
		foreach ($names as $nameAttr)
		{
			$coreName = trim($nameAttr->textContent);
			foreach ($aliases as $alias)
			{
				if ($coreName)
				{
					echo "$coreName-";
				}
				echo "$alias\n";
			}
		}
	}
	else
	{
		if ($category === null)
		{
			echo "No core defined\n";
			exit(5);
		}
		$url = getSolrAdminUrl($core)."/stats.jsp";
		$doc = new DOMDocument();
		if (!$doc->loadXML(wfGetUrl($url)))
		{
			echo "Could not load $url as XML\n";
			exit(6);
		}

		$xpath = new DOMXpath($doc);
		$elements = $xpath->query('/solr/solr-info/' . $category . '/entry');

		foreach($elements as $element)
		{
			if($item == trim($element->getElementsByTagName('name')->item(0)->textContent))
			{
				$stats = $element->getElementsByTagName('stat');
				foreach($stats as $stat)
				{
					if($property == trim($stat->getAttribute('name')))
					{
						echo $core . $item . $property . 'solr.value ' . wffloatval(trim($stat->textContent)) . "\n";
						exit(0);
					}
				}
			}
		}
		echo "Bad path: $category | $item | $property\n";
		exit(7);
	}
}
catch (Exception $e)
{
	echo "ERROR: ".$e->getMessage()."\n";
	$exitCode = ($e->getCode() != 0) ? $e->getCode() : 1;
	exit($exitCode);
}
