/** * 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.server.tracing; import java.net.URI; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.Iterator; import java.util.Set; import java.util.concurrent.TimeoutException; import org.helios.apmrouter.catalog.MetricCatalogService; import org.helios.apmrouter.metric.AgentIdentity; import org.helios.apmrouter.metric.ICEMetric; import org.helios.apmrouter.metric.IMetric; import org.helios.apmrouter.metric.catalog.ICEMetricCatalog; import org.helios.apmrouter.metric.catalog.IDelegateMetric; import org.helios.apmrouter.metric.catalog.IMetricCatalog; import org.helios.apmrouter.server.ServerComponentBean; import org.helios.apmrouter.server.net.listener.netty.handlers.AgentMetricHandler; import org.helios.apmrouter.server.tracing.virtual.VirtualAgentManager; import org.helios.apmrouter.trace.ITracer; import org.helios.apmrouter.trace.ITracerFactory; import org.helios.apmrouter.trace.MetricSubmitter; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jmx.export.annotation.ManagedMetric; import org.springframework.jmx.support.MetricType; /** * <p>Title: ServerTracerFactory</p> * <p>Description: An alternate implementation of the client side <code>TracerFactory</code> that sends traced metrics directly to the pattern router. </p> * <p>Company: Helios Development Group LLC</p> * @author Whitehead (nwhitehead AT heliosdev DOT org) * <p><code>org.helios.apmrouter.server.tracing.ServerTracerFactory</code></p> */ public class ServerTracerFactory extends ServerComponentBean implements MetricSubmitter, ITracerFactory { /** The default tracer */ protected ITracer defaultTracer = new ServerTracerImpl(APMROUTER_HOST_NAME, APMROUTER_AGENT_NAME, this); /** The metric catalog service */ protected MetricCatalogService metricCatalogService = null; /** The metric catalog */ protected IMetricCatalog metricCatalog = ICEMetricCatalog.getInstance(); /** The delegate metricSubmitter */ protected MetricSubmitter metricSubmitter = null; /** The virtual agent manager */ protected VirtualAgentManager vaManager = null; /** The local sender URI */ public static final String LOCAL_SENDER_URI = "local:%s"; /** The APMRouter agent name */ public static final String APMROUTER_AGENT_NAME = "APMRouterServer"; /** The APMRouter host name */ public static final String APMROUTER_HOST_NAME = AgentIdentity.ID.getHostName(); /** The singleton instance */ private static volatile ServerTracerFactory instance = null; /** The singleton instance ctor lock */ private static final Object lock = new Object(); /** * Creates a new ServerTracerFactory */ private ServerTracerFactory() { } /** * {@inheritDoc} * @see org.helios.apmrouter.server.ServerComponentBean#doStart() */ @Override protected void doStart() throws Exception { metricCatalogService.hostAgentState(true, APMROUTER_HOST_NAME, "", APMROUTER_AGENT_NAME, String.format(LOCAL_SENDER_URI, 0)); metricSubmitter = applicationContext.getBean(AgentMetricHandler.class); } /** * {@inheritDoc} * @see org.helios.apmrouter.server.ServerComponentBean#doStop() */ @Override protected void doStop() { metricCatalogService.hostAgentState(false, APMROUTER_HOST_NAME, "", APMROUTER_AGENT_NAME, String.format(LOCAL_SENDER_URI, 0)); metricSubmitter = null; super.doStop(); } /** * Acquires the ServerTracerFactory singleton instance * @return the ServerTracerFactory singleton instance */ public static ServerTracerFactory getInstance() { if(instance==null) { synchronized(lock) { if(instance==null) { instance = new ServerTracerFactory(); } } } return instance; } /** * Returns the default tracer instance * @return the default tracer instance */ public ITracer getTracer() { return defaultTracer; } private static URI makeURI(String string) { try { return new URI(string); } catch (Exception e) { throw new RuntimeException(e); } } /** * Returns a tracer instance for the passed host and agent * @param host The host name to create a tracer for * @param agent The agent name to create a tracer for * @param tracerName The tracer name * @param timeout The tracer timeout in ms. * @return a tracer instance */ @Override public ITracer getTracer(String host, String agent, String tracerName, long timeout) { return vaManager.getVirtualTracer(host, agent, tracerName, timeout); } /** * Sets the metric submitter the server tracerExpiryQueue will send to * @param metricSubmitter the metric submitter to use */ public void setMetricSubmitter(MetricSubmitter metricSubmitter) { this.metricSubmitter = metricSubmitter; } /** * {@inheritDoc} * @see org.helios.apmrouter.sender.ISender#getSentMetrics() */ @Override @ManagedMetric(category="ServerSender", metricType=MetricType.COUNTER, description="The number of metrics sent") public long getSentMetrics() { return metricSubmitter.getSentMetrics(); } /** * {@inheritDoc} * @see org.helios.apmrouter.sender.ISender#getDroppedMetrics() */ @Override @ManagedMetric(category="ServerSender", metricType=MetricType.COUNTER, description="the number of metrics dropped") public long getDroppedMetrics() { return metricSubmitter.getDroppedMetrics(); } /** * Returns the number of failed metric submissions * @return the number of failed metric submissions */ @ManagedMetric(category="ServerSender", metricType=MetricType.COUNTER, description="the number of metrics failed") public long getFailedMetrics() { return getMetricValue("MetricsFailed"); } /** * Returns the number of assigned metric tokens * @return the number of assigned metric tokens */ @ManagedMetric(category="ServerSender", metricType=MetricType.COUNTER, description="the number of assigned metric tokens") public long getTokensAssigned() { return getMetricValue("TokensAssigned"); } /** * Returns the number of metrics dropped because of a token lookup failure * @return the number of metrics dropped because of a token lookup failure */ @ManagedMetric(category="ServerSender", metricType=MetricType.COUNTER, description="the number of metrics dropped because of a token lookup failure") public long getTokensLookupDrops() { return getMetricValue("TokenLookupDrop"); } /** * {@inheritDoc} * @see org.helios.apmrouter.trace.MetricSubmitter#submitDirect(org.helios.apmrouter.metric.IMetric, long) */ @Override public void submitDirect(IMetric metric, long timeout) throws TimeoutException { submit(Collections.singletonList(metric)); } /** * Processes submitted metrics through the metric catalog * @param metrics A collection of metrics * @return the number of metrics left in the collection after processing */ protected int processMetrics(Collection<IMetric> metrics) { int cnt = 0; for(Iterator<IMetric> iter = metrics.iterator(); iter.hasNext();) { IMetric metric = iter.next(); if(metric.getToken()==-1) { long token = -1; token = metricCatalogService.isAssigned(metric.getHost(), metric.getAgent(), metric.getNamespaceF(), metric.getName()); if(token==-1) { token = metricCatalogService.getID(metric.getToken(), metric.getHost(), metric.getAgent(), metric.getType().ordinal(), metric.getNamespaceF(), metric.getName()); } if(token!=-1) { metricCatalog.setToken(metric.getHost(), metric.getAgent(), metric.getName(), metric.getType(), metric.getNamespace()); metric.getMetricId().setToken(token); } } IDelegateMetric metricId = metricCatalogService.getMetricID(metric.getToken()); if(metricId==null) { iter.remove(); debug("Token Lookup Miss [", metric.getToken(), "]"); incr("TokenLookupDrop"); } else { cnt++; ((ICEMetric)metric).setMetricId(metricId); } } return cnt; } /** * {@inheritDoc} * @see org.helios.apmrouter.trace.MetricSubmitter#submit(java.util.Collection) */ @Override public void submit(Collection<IMetric> metrics) { final int metricCount = processMetrics(metrics); if(metricCount==0) return; try { if(metricSubmitter==null) { incr("MetricsDropped"); warn("ServerTracerFactory has not been started yet. Dropped [", metricCount, "] metrics"); return; } metricSubmitter.submit(metrics); incr("MetricsSent"); } catch (Exception e) { incr("MetricsFailed"); } } /** * {@inheritDoc} * @see org.helios.apmrouter.trace.MetricSubmitter#submit(org.helios.apmrouter.metric.IMetric[]) */ @Override public void submit(IMetric... metrics) { if(metrics!=null && metrics.length>0) { submit(new ArrayList<IMetric>(Arrays.asList(metrics))); } } /** * {@inheritDoc} * @see org.helios.apmrouter.server.ServerComponent#getSupportedMetricNames() */ @Override public Set<String> getSupportedMetricNames() { Set<String> metrics = new HashSet<String>(super.getSupportedMetricNames()); metrics.add("TokenLookupDrop"); metrics.add("MetricsSent"); metrics.add("MetricsDropped"); metrics.add("MetricsFailed"); metrics.add("TokensAssigned"); return metrics; } /** * {@inheritDoc} * @see org.helios.apmrouter.trace.MetricSubmitter#resetStats() */ @Override public void resetStats() { super.resetMetrics(); } /** * {@inheritDoc} * @see org.helios.apmrouter.trace.MetricSubmitter#getQueuedMetrics() */ @Override public long getQueuedMetrics() { return 0; } /** * Sets the metricCatalogService * @param metricCatalogService the metricCatalogService to set */ @Autowired(required=true) public void setMetricCatalogService(MetricCatalogService metricCatalogService) { this.metricCatalogService = metricCatalogService; } /** * Returns the virtual agent manager * @return the virtual agent manager */ public VirtualAgentManager getVaManager() { return vaManager; } /** * Sets the virtual agent manager * @param vaManager the vaManager to set */ @Autowired(required=true) public void setVirtualAgentManager(VirtualAgentManager vaManager) { this.vaManager = vaManager; } }