/*
* Copyright 2010-2011 Ning, Inc.
*
* Ning licenses this file to you under the Apache License, version 2.0
* (the "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package com.ning.metrics.eventtracker;
import com.ning.metrics.serialization.event.Event;
import com.ning.metrics.serialization.event.ThriftEnvelopeEvent;
import com.ning.metrics.serialization.thrift.ThriftEnvelope;
import com.ning.metrics.serialization.thrift.ThriftField;
import org.apache.thrift.TException;
import org.joda.time.DateTime;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.testng.Assert;
import org.testng.annotations.AfterTest;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.Test;
import java.io.File;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
@Test(enabled = false)
public class TestPerformance
{
private final File temporarySpoolDir = new File(System.getProperty("java.io.tmpdir"), "collector");
private final File tmpDir = new File(temporarySpoolDir, "_tmp");
private static final Logger logger = LoggerFactory.getLogger(TestPerformance.class);
private int responsesLeft;
private DateTime flushStart;
private final int numTestEvents = 10000;
@BeforeTest(alwaysRun = true)
private void setupTmpDir() throws Exception
{
if (!temporarySpoolDir.exists() && !temporarySpoolDir.mkdirs()) {
throw new RuntimeException("Failed to create: " + temporarySpoolDir);
}
if (!temporarySpoolDir.isDirectory()) {
throw new RuntimeException("Path points to something that's not a directory: " + temporarySpoolDir);
}
}
@AfterTest(alwaysRun = true)
private void cleanupTmpDir()
{
temporarySpoolDir.delete();
}
// // TODO this is a mess. Figure out how to make it work while still using a CollectorController.
// @Test(enabled = false)
// public void testSmile() throws IOException, InterruptedException
// {
// // stall so that jconsole can connect
//// Thread.sleep(15000);
//
// System.setProperty("eventtracker.type", "COLLECTOR");
// System.setProperty("eventtracker.directory", temporarySpoolDir.getAbsolutePath());
//// System.setProperty("eventtracker.collector.host", "127.0.0.1");
//// System.setProperty("eventtracker.collector.host", "z12209f.ningops.com");
// System.setProperty("eventtracker.collector.host", "10.18.81.135");
// System.setProperty("eventtracker.collector.port", "8080");
// System.setProperty("eventtracker.diskspool.flush-event-queue-size", "50");
//
// EventTrackerConfig config = new ConfigurationObjectFactory(System.getProperties()).build(EventTrackerConfig.class);
//
// // set up a writer using a receiveResponse handler (hacky)
// DiskSpoolEventWriter writer = new DiskSpoolEventWriterProvider(config,
// new HttpSender(config)
// {
// private CallbackHandler overrideHandler = new CallbackHandler()
// {
//
// @Override
// public void onSuccess(Event event)
// {
// receiveSmileResponse();
// }
//
// @Override
// public void onError(Throwable t, Event event)
// {
// Assert.fail();
// }
// };
//
// // UBERhack. Ignore the handler argument and use this one instead!
// @Override
// public void send(Event event, CallbackHandler handler)
// {
// super.send(event, overrideHandler);
// }
// },
// new ScheduledThreadPoolExecutor(1, Executors.defaultThreadFactory())
// ).get();
//
// List<SmileEnvelopeEvent> events = makeSmileEvents(numTestEvents);
//
// long writeCommitStart = new DateTime().getMillis();
// // commit and flush and all that jazz
//
// for (int i=0; i<1000; i++) {
// for (Event event : events) {
// writer.write(event);
// }
// writer.commit();
// flushStart = new DateTime();
// writer.flush();
// long commitTimeDiff = flushStart.getMillis() - writeCommitStart;
// logger.info(String.format("SMILE: wrote and committed all events in %d.%d seconds", commitTimeDiff / 1000, commitTimeDiff % 1000));
// Thread.sleep(15000);
// }
// }
private void receiveSmileResponse()
{
DateTime sendFinishTime = new DateTime();
responsesLeft--;
synchronized (this) {
long timeDiff = sendFinishTime.getMillis() - flushStart.getMillis();
logger.info("SMILE: event sent in {}.{} seconds", timeDiff / 1000, timeDiff % 1000);
if (responsesLeft == 0) {
logger.info("SMILE: all events sent within {}.{} seconds", timeDiff / 1000, timeDiff % 1000);
Assert.assertEquals(tmpDir.listFiles().length, 0);
// don't output this stuff again
responsesLeft = -1;
}
Assert.assertTrue(responsesLeft >= -1, "Something is wrong with how this test was written. It receives more responses than it expects!");
}
}
// @Test(enabled = false)
// public void testThrift() throws Exception
// {
// // stall so that jconsole can connect
//// Thread.sleep(15000);
//
// System.setProperty("eventtracker.type", "SCRIBE");
// System.setProperty("eventtracker.directory", temporarySpoolDir.getAbsolutePath());
//// System.setProperty("eventtracker.scribe.host", "127.0.0.1");
// System.setProperty("eventtracker.scribe.host", "10.18.81.135");
//// System.setProperty("eventtracker.scribe.host", "z12209f.ningops.com");
// System.setProperty("eventtracker.scribe.port", "7911");
//
// Injector injector = Guice.createInjector(new CollectorControllerModule());
// CollectorController controller = injector.getInstance(CollectorController.class);
// ScribeSender sender = (ScribeSender) injector.getInstance(EventSender.class);
//
// sender.createConnection();
//
// List<ThriftEnvelopeEvent> events = makeThriftEvents(numTestEvents);
//
// sendThriftEvents(controller, events);
//
// sender.shutdown();
// }
private LinkedList<ThriftEnvelopeEvent> makeThriftEvents(int numEvents) throws TException
{
LinkedList<ThriftEnvelopeEvent> events = new LinkedList<ThriftEnvelopeEvent>();
long sampleTime = new DateTime().getMillis();
DateTime startTime = new DateTime();
ArrayList<ThriftField> data = new ArrayList<ThriftField>();
String eventName;
data.add(ThriftField.createThriftField(sampleTime, (short) 1));
data.add(ThriftField.createThriftField("foo", (short) 2));
data.add(ThriftField.createThriftField("bar", (short) 3));
data.add(ThriftField.createThriftField(3.14159, (short) 4));
data.add(ThriftField.createThriftField(10001000000L, (short) 5));
for (int i = 0; i < numEvents; i++) {
switch (i % 3) {
case 0:
eventName = "A";
break;
case 1:
eventName = "B";
break;
default:
eventName = "C";
}
events.add(new ThriftEnvelopeEvent(startTime, new ThriftEnvelope(eventName, data)));
}
DateTime endTime = new DateTime();
long timeTaken = endTime.getMillis() - startTime.getMillis();
logger.info("THRIFT: %d events created in {}.{} seconds", new Object[] {numEvents, timeTaken/1000, timeTaken%1000}); // TODO output time in a friendly format
return events;
}
private void sendThriftEvents(CollectorController controller, List<ThriftEnvelopeEvent> events) throws Exception
{
DateTime writeCommitStart = new DateTime();
for(Event event : events) {
controller.offerEvent(event);
}
controller.commit();
flushStart = new DateTime();
controller.flush();
// thrift events are simpler. once flush completes, the events are sent! not complicated by async
DateTime flushFinish = new DateTime();
long commitTimeDiff = flushStart.getMillis() - writeCommitStart.getMillis();
long timeDiff = flushFinish.getMillis() - flushStart.getMillis();
logger.info("THRIFT: wrote and committed all events in {}.{} seconds", commitTimeDiff/1000, commitTimeDiff%1000);
logger.info("THRIFT: events sent in {}.{} seconds", timeDiff/1000, timeDiff%1000);
}
}