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

se.l4.vibe.internal.SampleCollector Maven / Gradle / Ivy

There is a newer version: 0.4.0
Show newest version
package se.l4.vibe.internal;

import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import se.l4.vibe.probes.AbstractSampler;
import se.l4.vibe.probes.SampleListener;
import se.l4.vibe.probes.SampledProbe;
import se.l4.vibe.probes.Sampler;
import se.l4.vibe.probes.Sampler.Entry;


/**
 * Sampler that will sample certain {@link SampledProbe}s at a given time
 * interval.
 * 
 * @author Andreas Holstenson
 *
 */
public class SampleCollector
{
	private static final Logger logger = LoggerFactory.getLogger(SampleCollector.class);
	
	private static final TimeSeriesImpl[] EMPTY = new TimeSeriesImpl[0];
	
	private final long sampleInterval;
	
	private final Lock seriesLock;
	protected volatile TimeSeriesImpl[] series;
	
	private final ScheduledExecutorService executor;

	public SampleCollector(ScheduledExecutorService executor, long sampleInterval, TimeUnit unit)
	{
		this.executor = executor;
		
		this.sampleInterval = unit.toMillis(sampleInterval);
		
		seriesLock = new ReentrantLock();
		series = EMPTY;
	}
	
	/**
	 * Add a statistic that should be sampled.
	 * 
	 * @param name
	 * @param stat
	 * @return
	 */
	public  Sampler add(SampledProbe stat)
	{
		TimeSeriesImpl series = new TimeSeriesImpl(stat);
		
		// Store in series array
		seriesLock.lock();
		try
		{
			TimeSeriesImpl[] current = this.series;
			TimeSeriesImpl[] newSeries = new TimeSeriesImpl[current.length + 1];
			System.arraycopy(current, 0, newSeries, 0, current.length);
			newSeries[current.length] = series;
			
			this.series = newSeries;
		}
		finally
		{
			seriesLock.unlock();
		}
		
		return series;
	}
	
	/**
	 * Start the sampling.
	 * 
	 * @return
	 */
	public void start()
	{
		Runnable r = new Runnable()
		{
			@Override
			public void run()
			{
				sample();
			}
		};
		
		long now = System.currentTimeMillis();
		long rounded = (now / sampleInterval) * sampleInterval + sampleInterval;
		executor.scheduleAtFixedRate(r, rounded - now, sampleInterval, TimeUnit.MILLISECONDS);
	}
	
	protected void sample()
	{
		long time = System.currentTimeMillis();
		
		TimeSeriesImpl[] series = this.series;
		for(TimeSeriesImpl s : series)
		{
			s.sample(time);
		}
	}
	
	private class TimeSeriesImpl
		extends AbstractSampler
	{
		private final SampledProbe probe;
		
		public TimeSeriesImpl(SampledProbe probe)
		{
			this.probe = probe;
		}

		public void sample(long time)
		{
			T value = probe.sample();
			
			SampleListener[] listeners = this.listeners;
			if(listeners.length > 0)
			{
				SampleEntry entry = new SampleEntry(time, value);
				
				for(SampleListener listener : listeners)
				{
					try
					{
						listener.sampleAcquired(probe, entry);
					}
					catch(Exception e)
					{
						logger.warn("Unable to execute listener; " + e.getMessage(), e);
					}
				}
			}
		}
		
		@Override
		public SampledProbe getProbe()
		{
			return probe;
		}
	}
	
	private static class SampleEntry
		implements Sampler.Entry
	{
		private final long time;
		private final T value;

		public SampleEntry(long time, T value)
		{
			this.time = time;
			this.value = value;
		}

		@Override
		public long getTime()
		{
			return time;
		}

		@Override
		public T getValue()
		{
			return value;
		}
		
		@Override
		public String toString()
		{
			return "Entry{time=" + time + ", value=" + value + "}";
		}
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy