/* * Copyright 2013 Netflix, Inc. * * Licensed 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.netflix.suro.input; import com.netflix.suro.ClientConfig; import com.netflix.suro.SuroServer4Test; import com.netflix.suro.client.SuroClient; import com.netflix.suro.connection.TestConnectionPool; import com.netflix.suro.message.Message; import org.apache.log4j.Level; import org.apache.log4j.spi.LoggingEvent; import org.junit.After; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TemporaryFolder; import org.mockito.ArgumentCaptor; import java.util.HashMap; import java.util.List; import java.util.Map; import static org.junit.Assert.assertEquals; import static org.mockito.Matchers.any; import static org.mockito.Mockito.*; public class TestLog4jAppender { @Rule public TemporaryFolder tempDir = new TemporaryFolder(); public static final int DEFAULT_WAIT_INTERVAL = 20; private Log4jAppender appender = new Log4jAppender(); private List<SuroServer4Test> servers; @Before public void setup() throws Exception { servers = TestConnectionPool.startServers(1); } @After public void clean() { TestConnectionPool.shutdownServers(servers); } private void sleepThrough(long millis) { long remaining = millis; while( remaining > 0 ) { long start = System.currentTimeMillis(); try{ Thread.sleep(remaining); } catch (InterruptedException e){ } remaining -= (System.currentTimeMillis() - start); } } private void waitAndVerify(long millis, Runnable assertion, long waitInterval) { long remaining = millis; while(remaining > 0) { try{ assertion.run(); // Assertion is successful, so we don't need to wait any more return; } catch(Throwable t) { sleepThrough(waitInterval); remaining -= waitInterval; } } // Last attempt after timeout, so we will get assertion failure if // there is one. assertion.run(); } private void waitAndVerify(long millis, Runnable assertion) { waitAndVerify(millis, assertion, DEFAULT_WAIT_INTERVAL); } @Test public void testMemory() throws Exception { appender.setLoadBalancerType("static"); appender.setLoadBalancerServer(TestConnectionPool.createConnectionString(servers)); appender.activateOptions(); LoggingEvent event = mock(LoggingEvent.class); when(event.getMessage()).thenReturn(createEventMap()); when(event.getLevel()).thenReturn(Level.INFO); appender.append(event); // Make sure client has enough time to drain the intermediary message queue waitAndVerify(5000, new Runnable(){ @Override public void run() { assertEquals(appender.getSentMessageCount(), 1); // it should be successful } }); appender.close(); } @Test public void testFile() throws Exception { appender.setAsyncQueueType("file"); appender.setAsyncFileQueuePath(tempDir.newFolder().getAbsolutePath()); appender.setLoadBalancerType("static"); appender.setLoadBalancerServer(TestConnectionPool.createConnectionString(servers)); appender.activateOptions(); LoggingEvent event = mock(LoggingEvent.class); when(event.getMessage()).thenReturn(createEventMap()); when(event.getLevel()).thenReturn(Level.INFO); appender.append(event); // Make sure client has enough time to drain the intermediary message queue waitAndVerify(15000, new Runnable() { public void run() { assertEquals(appender.getSentMessageCount(), 1); } }); appender.close(); } @Test public void testLog4jFormatter() { appender.setFormatterClass("com.netflix.suro.input.StaticLog4jFormatter"); appender.setLoadBalancerType("static"); appender.setLoadBalancerServer(TestConnectionPool.createConnectionString(servers)); appender.setClientType("sync"); appender.setRoutingKey("testRoutingKey"); appender.activateOptions(); appender.client = mock(SuroClient.class); doNothing().when(appender.client).send(any(Message.class)); LoggingEvent event = mock(LoggingEvent.class); when(event.getMessage()).thenReturn("string log"); when(event.getLevel()).thenReturn(Level.INFO); appender.append(event); ArgumentCaptor<Message> argument = ArgumentCaptor.forClass(Message.class); verify(appender.client).send(argument.capture()); assertEquals(argument.getValue().getRoutingKey(), "testRoutingKey"); String[] v0 = new String(argument.getValue().getPayload()).split("\t"); String[] v1 = new StaticLog4jFormatter(new ClientConfig()).format(event).split("\t"); assertEquals(v0.length, v1.length); for (int i = 0; i < v0.length; ++i) { if (i == 0) { assertEquals(v0[0].split(":")[0], v1[0].split(":")[0]); } else { assertEquals(v0[i], v1[i]); } } } private Map<String, String> createEventMap() { Map<String, String> map = new HashMap<String, String>(); map.put("one", "1"); map.put("two", "2"); map.put("three", "3"); map.put("routingKey", "routingKey"); return map; } }