/**
* Helios, OpenSource Monitoring
* Brought to you by the Helios Development Group
*
* Copyright 2007, Helios Development Group and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This 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 2.1 of
* the License, or (at your option) any later version.
*
* This software 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*
*/
package org.helios.apmrouter.destination.wily;
import java.io.File;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import org.helios.apmrouter.destination.BaseDestination;
import org.helios.apmrouter.metric.IMetric;
import org.springframework.jmx.export.annotation.ManagedAttribute;
import org.springframework.jmx.export.annotation.ManagedMetric;
import org.springframework.jmx.support.MetricType;
/**
* <p>Title: WilyIntroscopeDestination</p>
* <p>Description: Destination to route metrics to a Wily Introscope Enterprise Manager instance.</p>
* <p>Company: Helios Development Group LLC</p>
* @author Whitehead (nwhitehead AT heliosdev DOT org)
* <p><code>org.helios.apmrouter.destination.wily.WilyIntroscopeDestination</code></p>
*/
public class WilyIntroscopeDestination extends BaseDestination {
/** The file name of the Introscope <code>agent.jar</code> */
protected String wilyAgentLib = null;
/** The file name of the Introscope agent configuration properties */
protected String wilyAgentProps = null;
/** The wily agent name for this apmrouter instance */
protected String wilyAgentName = null;
/** Indicates if the apm router host and agent name should be prepended to the wily metric name */
protected boolean includeHostAgent = true;
/** The wily agent tracer */
protected WilyIntroscopeTracer wilyTracer = null;
/** The classloader created to load the wily agent */
protected ClassLoader wilyClassLoader = null;
/** A cache of wily metric names keyed by the long hash code of the APMRouter metric's FQN */
protected final ConcurrentHashMap<Long, String> wilyMetricCache = new ConcurrentHashMap<Long, String>(1024);
/**
* <p>Initializes the wily agent.
* {@inheritDoc}
* @see org.helios.apmrouter.server.ServerComponentBean#doStart()
*/
public void doStart() throws Exception {
File agentJarFile = new File(wilyAgentLib);
if(!agentJarFile.canRead()) {
throw new Exception("The configured wily agent jar [" + wilyAgentLib + "] cannot be read", new Throwable());
}
// check to see if an agent name has been defined already
String agentName = System.getProperty(WilyIntroscopeTracer.AGENT_NAME_SYSPROP);
if(agentName==null || agentName.trim().isEmpty()) {
System.setProperty(WilyIntroscopeTracer.AGENT_NAME_SYSPROP, wilyAgentName);
} else {
wilyAgentName = agentName;
}
String agentProps = System.getProperty(WilyIntroscopeTracer.AGENT_CONFIG_SYSPROP);
if(agentProps==null || agentProps.trim().isEmpty()) {
System.setProperty(WilyIntroscopeTracer.AGENT_CONFIG_SYSPROP, wilyAgentProps);
} else {
wilyAgentProps = agentProps;
}
info("Wily Agent Name [", wilyAgentName, "]");
info("Wily Agent Props [", wilyAgentProps, "]");
URL agentJarURL = agentJarFile.toURI().toURL();
wilyClassLoader = new URLClassLoader(new URL[]{agentJarURL}, this.getClass().getClassLoader());
ClassLoader cl = Thread.currentThread().getContextClassLoader();
try {
Thread.currentThread().setContextClassLoader(wilyClassLoader);
wilyTracer = WilyIntroscopeTracer.getInstance();
info("Loaded Wily Agent Tracer");
super.doStart();
} finally {
Thread.currentThread().setContextClassLoader(cl);
}
}
/**
* {@inheritDoc}
* @see org.helios.apmrouter.destination.BaseDestination#doAcceptRoute(org.helios.apmrouter.metric.IMetric)
*/
protected void doAcceptRoute(IMetric routable) {
IMetric metric = routable.getUnmapped();
try {
switch (routable.getType()) {
case BLOB:
incr("MetricsDropped");
break;
case DELTA_COUNTER:
wilyTracer.recordCurrentValue(metric.getLongValue(), getWilyMetricName(metric));
incr("MetricsForwarded");
break;
case DELTA_GAUGE:
wilyTracer.recordCurrentValue(metric.getLongValue(), getWilyMetricName(metric));
incr("MetricsForwarded");
break;
case ERROR:
break;
case LONG_COUNTER:
wilyTracer.recordCurrentValue(metric.getLongValue(), getWilyMetricName(metric));
incr("MetricsForwarded");
break;
case LONG_GAUGE:
wilyTracer.recordCurrentValue(metric.getLongValue(), getWilyMetricName(metric));
incr("MetricsForwarded");
break;
case PDU:
incr("MetricsDropped");
break;
case STRING:
wilyTracer.recordDataPoint(metric.getValue().toString(), getWilyMetricName(metric));
info("Traced String value: [" + metric.getValue().toString() + "]");
incr("MetricsForwarded");
break;
default:
incr("MetricsDropped");
break;
}
} catch (Exception e) {
incr("MetricsFailed");
}
}
/**
* Returns the equivalent wily metric name for the passed metric
* @param metric The metric to get the wily metric name for
* @return the wily metric
*/
protected String getWilyMetricName(IMetric metric) {
String s = wilyMetricCache.get(metric.getLongHashCode());
if(s==null) {
String[] segs = new String[1 + metric.getNamespaceSize() + (includeHostAgent ? 2 : 0)];
int offset = 0;
if(includeHostAgent) {
segs[offset++] = metric.getHost();
segs[offset++] = metric.getAgent();
}
System.arraycopy(metric.getNamespace(), 0, segs, offset, metric.getNamespaceSize());
segs[segs.length-1] = metric.getName();
s = wilyTracer.buildMetricName(segs);
wilyMetricCache.putIfAbsent(metric.getLongHashCode(), s);
}
return s;
}
/**
* Creates a new WilyIntroscopeDestination
* @param patterns The routing patterns that this destination will accept
*/
public WilyIntroscopeDestination(String... patterns) {
super(patterns);
}
/**
* Creates a new WilyIntroscopeDestination
* @param patterns The routing patterns that this destination will accept
*/
public WilyIntroscopeDestination(Collection<String> patterns) {
super(patterns);
}
/**
* Creates a new WilyIntroscopeDestination
*/
public WilyIntroscopeDestination() {
}
/**
* Returns the file name of the Introscope <code>agent.jar</code>
* @return the Introscope <code>agent.jar</code>
*/
@ManagedAttribute(description="The file name of the agent jar")
public String getWilyAgentLib() {
return wilyAgentLib;
}
/**
* Sets the file name of the Introscope <code>agent.jar</code>
* @param wilyAgentLib the file name of the Introscope <code>agent.jar</code>
*/
public void setWilyAgentLib(String wilyAgentLib) {
this.wilyAgentLib = wilyAgentLib;
}
/**
* Returns the file name of the agent configuration properties file
* @return the file name of the agent configuration properties file
*/
@ManagedAttribute(description="The file name of the agent configuration properties file")
public String getWilyAgentProps() {
return wilyAgentProps;
}
/**
* Sets the file name of the agent configuration properties file
* @param wilyAgentProps the file name of the agent configuration properties file
*/
public void setWilyAgentProps(String wilyAgentProps) {
this.wilyAgentProps = wilyAgentProps;
}
/**
* Returns the wily agent name
* @return the wily agent name
*/
@ManagedAttribute(description="The wily agent name")
public String getWilyAgentName() {
return wilyAgentName;
}
/**
* Sets the wily agent name
* @param wilyAgentName the wily agent name
*/
public void setWilyAgentName(String wilyAgentName) {
this.wilyAgentName = wilyAgentName;
}
/**
* Indicates if the apm router host and agent name should be prepended to the wily metric name
* @return true if host and agent name should be prepended, false otherwise
*/
@ManagedAttribute(description="Indicates if the apm router host and agent name should be prepended to the wily metric name")
public boolean isIncludeHostAgent() {
return includeHostAgent;
}
/**
* Sets if the apm router host and agent name should be prepended to the wily metric name
* @param includeHostAgent true to prepend the host and agent, false otherwise
*/
public void setIncludeHostAgent(boolean includeHostAgent) {
this.includeHostAgent = includeHostAgent;
}
/**
* Returns the size of the wily metric cache
* @return the size of the wily metric cache
*/
@ManagedAttribute(description="The size of the wily metric cache")
public int getMetricCacheSize() {
return wilyMetricCache.size();
}
/**
* Returns the number of metrics forwarded to WilyIntroscope
* @return the number of metrics forwarded to WilyIntroscope
*/
@ManagedMetric(category="WilyIntroscope", metricType=MetricType.COUNTER, description="the number of metrics forwarded to WilyIntroscope")
public long getMetricsForwarded() {
return getMetricValue("MetricsForwarded");
}
/**
* Returns the number of metrics that failed on sending to WilyIntroscope
* @return the number of metrics that failed on sending to WilyIntroscope
*/
@ManagedMetric(category="WilyIntroscope", metricType=MetricType.COUNTER, description="the number of metrics that failed on sending to WilyIntroscope")
public long getMetricsForwardFailures() {
return getMetricValue("MetricsFailed");
}
/**
* Returns the number of metrics that were dropped because of unsupported types
* @return the number of metrics that were dropped because of unsupported types
*/
@ManagedMetric(category="WilyIntroscope", metricType=MetricType.COUNTER, description="the number of metrics that were dropped because of of unsupported types")
public long getMetricsDropped() {
return getMetricValue("MetricsDropped");
}
/**
* {@inheritDoc}
* @see org.helios.apmrouter.server.ServerComponent#getSupportedMetricNames()
*/
@Override
public Set<String> getSupportedMetricNames() {
Set<String> _metrics = new HashSet<String>(super.getSupportedMetricNames());
_metrics.add("MetricsForwarded");
_metrics.add("MetricsDropped");
_metrics.add("MetricsFailed");
return _metrics;
}
}