/*************************************************************************
* Copyright 2009-2014 Eucalyptus Systems, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 3 of the License.
*
* 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 Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://www.gnu.org/licenses/.
*
* Please contact Eucalyptus Systems, Inc., 6755 Hollister Ave., Goleta
* CA 93117, USA or visit http://www.eucalyptus.com/licenses/ if you need
* additional information or have any questions.
************************************************************************/
package com.eucalyptus.stats;
import com.eucalyptus.stats.configuration.StatsConfiguration;
import com.eucalyptus.stats.emitters.EventEmitter;
import com.eucalyptus.system.Threads;
import com.eucalyptus.util.Exceptions;
import org.apache.log4j.Logger;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ScheduledExecutorService;
/**
* The service to which monitoring events are submitted for
* propagation outside the JVM.
*/
public class EventEmitterService {
private static final Logger LOG = Logger.getLogger(EventEmitterService.class);
protected LinkedBlockingQueue<SystemMetric> eventQueue;
protected ScheduledExecutorService writerThreadPool;
protected volatile boolean acceptNewEvents;
private static EventEmitterService serviceInstance;
public EventEmitterService() {
this.eventQueue = new LinkedBlockingQueue<>();
this.writerThreadPool =
Executors.newSingleThreadScheduledExecutor( Threads.threadFactory( "ts-event-emitter-pool-%d" ) );
this.acceptNewEvents = false;
}
public static synchronized EventEmitterService getInstance() {
if (serviceInstance == null) {
serviceInstance = new EventEmitterService();
}
return serviceInstance;
}
public void init() {
//No-op
}
public void start() {
this.acceptNewEvents = true;
this.writerThreadPool.execute(new EventWriterThread(eventQueue, getEmitterInstance()));
}
/**
* Is the emitter service ready and able to operate. Does not guarantee successful
* delivery, just checks prereqs
*/
public void check() throws Exception {
if(this.eventQueue == null ||
this.writerThreadPool == null ||
this.writerThreadPool.isShutdown() ||
this.writerThreadPool.isTerminated() || getEmitterInstance() == null) {
throw new Exception("Event emitter check failed. Event emitter service not ready");
}
try {
getEmitterInstance().check();
} catch(Exception e) {
LOG.error("Event emitter service failed check because of exception from emitter instance", e);
throw new Exception("Event emitter service not ready", e);
}
}
protected static EventEmitter getEmitterInstance() {
try {
Class emitterClass = StatsConfiguration.getEmitterClass();
return (EventEmitter) emitterClass.newInstance();
} catch (Exception e) {
LOG.error("Could not load event emitter config, cannot initialize the monitoring system", e);
throw Exceptions.toUndeclared("Error loading emitter configuration", e);
}
}
public boolean offer(SystemMetric systemMetric) {
return this.acceptNewEvents && this.eventQueue.offer(systemMetric);
}
public void stop() {
this.acceptNewEvents = false;
this.writerThreadPool.shutdownNow();
}
/**
* Dangerous! Use for testing only
* Used for testing and special cases where the entire queue should be flushed before shutdown. Will cause events to be rejected.
*/
protected void softStop() {
this.acceptNewEvents = false;
while (!this.eventQueue.isEmpty()) ; //wait for flushing
this.writerThreadPool.shutdown();
}
private class EventWriterThread implements Runnable {
BlockingQueue<SystemMetric> eventQ;
EventEmitter emitter;
public EventWriterThread(BlockingQueue<SystemMetric> eventQueueToWatch, EventEmitter eventEmitter) {
this.eventQ = eventQueueToWatch;
this.emitter = eventEmitter;
}
@Override
public void run() {
//blocking wait for an event to write
try {
while (true) {
SystemMetric event = this.eventQ.take();
emitter.emit(event);
}
} catch (InterruptedException ex) {
LOG.warn("Event emitter interrupted");
}
}
}
}