Java tutorial
/** * 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 net.logstash.logback.encoder; import static org.apache.commons.io.IOUtils.*; import static org.hamcrest.MatcherAssert.*; import static org.hamcrest.Matchers.*; import static org.mockito.Mockito.*; import java.io.ByteArrayOutputStream; import java.util.Collections; import java.util.HashMap; import java.util.Map; import org.apache.commons.lang.time.FastDateFormat; import org.hamcrest.Matchers; import org.junit.Assert; import org.junit.Test; import org.slf4j.Marker; import org.slf4j.MarkerFactory; import ch.qos.logback.classic.Level; import ch.qos.logback.classic.spi.ILoggingEvent; import ch.qos.logback.classic.spi.IThrowableProxy; import ch.qos.logback.classic.spi.ThrowableProxy; import ch.qos.logback.classic.spi.ThrowableProxyUtil; import ch.qos.logback.core.Context; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; public abstract class LogstashEncoderTestCommon { private static final ObjectMapper MAPPER = new ObjectMapper(); private final String messageProperty; private final String tagsProperty; protected abstract LogstashEncoderBase encoder(); protected abstract ByteArrayOutputStream outputStream(); protected abstract JsonNode field(JsonNode node, String name); protected LogstashEncoderTestCommon(String messageProperty, String tagsProperty) { this.messageProperty = messageProperty; this.tagsProperty = tagsProperty; } @Test public void basicsAreIncluded() throws Exception { final long timestamp = System.currentTimeMillis(); ILoggingEvent event = mockBasicILoggingEvent(Level.ERROR); when(event.getTimeStamp()).thenReturn(timestamp); encoder().doEncode(event); closeQuietly(outputStream()); JsonNode node = MAPPER.readTree(outputStream().toByteArray()); assertThat(node.get("@timestamp").textValue(), is(FastDateFormat.getInstance("yyyy-MM-dd'T'HH:mm:ss.SSSZZ").format(timestamp))); assertThat(field(node, "logger_name").textValue(), is("LoggerName")); assertThat(field(node, "thread_name").textValue(), is("ThreadName")); assertThat(node.get(messageProperty).textValue(), is("My message")); assertThat(field(node, "level").textValue(), is("ERROR")); assertThat(field(node, "level_value").intValue(), is(40000)); } @Test public void closePutsSeparatorAtTheEnd() throws Exception { ILoggingEvent event = mockBasicILoggingEvent(Level.ERROR); encoder().doEncode(event); encoder().close(); closeQuietly(outputStream()); assertThat(outputStream().toString(), Matchers.endsWith(LINE_SEPARATOR)); } @Test public void includingThrowableProxyIncludesStackTrace() throws Exception { IThrowableProxy throwableProxy = new ThrowableProxy(new Exception("My goodness")); ILoggingEvent event = mockBasicILoggingEvent(Level.ERROR); when(event.getThrowableProxy()).thenReturn(throwableProxy); encoder().doEncode(event); closeQuietly(outputStream()); JsonNode node = MAPPER.readTree(outputStream().toByteArray()); assertThat(field(node, "stack_trace").textValue(), is(ThrowableProxyUtil.asString(throwableProxy))); } @Test public void propertiesInMDCAreIncluded() throws Exception { Map<String, String> mdcMap = new HashMap<String, String>(); mdcMap.put("thing_one", "One"); mdcMap.put("thing_two", "Three"); ILoggingEvent event = mockBasicILoggingEvent(Level.ERROR); when(event.getMDCPropertyMap()).thenReturn(mdcMap); encoder().doEncode(event); closeQuietly(outputStream()); JsonNode node = MAPPER.readTree(outputStream().toByteArray()); assertThat(field(node, "thing_one").textValue(), is("One")); assertThat(field(node, "thing_two").textValue(), is("Three")); } @Test public void nullMDCDoesNotCauseEverythingToBlowUp() throws Exception { ILoggingEvent event = mockBasicILoggingEvent(Level.ERROR); when(event.getMDCPropertyMap()).thenReturn(null); encoder().doEncode(event); closeQuietly(outputStream()); } @Test public void callerDataIsIncluded() throws Exception { ILoggingEvent event = mockBasicILoggingEvent(Level.ERROR); when(event.getMDCPropertyMap()).thenReturn(Collections.<String, String>emptyMap()); final StackTraceElement[] stackTraceElements = { new StackTraceElement("caller_class", "method_name", "file_name", 12345) }; when(event.getCallerData()).thenReturn(stackTraceElements); encoder().setIncludeCallerInfo(true); encoder().doEncode(event); closeQuietly(outputStream()); JsonNode node = MAPPER.readTree(outputStream().toByteArray()); assertThat(field(node, "caller_class_name").textValue(), is(stackTraceElements[0].getClassName())); assertThat(field(node, "caller_method_name").textValue(), is(stackTraceElements[0].getMethodName())); assertThat(field(node, "caller_file_name").textValue(), is(stackTraceElements[0].getFileName())); assertThat(field(node, "caller_line_number").intValue(), is(stackTraceElements[0].getLineNumber())); } @Test public void callerDataIsNotIncludedIfSwitchedOff() throws Exception { ILoggingEvent event = mock(ILoggingEvent.class); when(event.getLoggerName()).thenReturn("LoggerName"); when(event.getThreadName()).thenReturn("ThreadName"); when(event.getFormattedMessage()).thenReturn("My message"); when(event.getLevel()).thenReturn(Level.ERROR); when(event.getMDCPropertyMap()).thenReturn(Collections.<String, String>emptyMap()); final StackTraceElement[] stackTraceElements = { new StackTraceElement("caller_class", "method_name", "file_name", 12345) }; when(event.getCallerData()).thenReturn(stackTraceElements); encoder().setIncludeCallerInfo(false); encoder().doEncode(event); closeQuietly(outputStream()); JsonNode node = MAPPER.readTree(outputStream().toByteArray()); assertThat(field(node, "caller_class_name"), is(nullValue())); assertThat(field(node, "caller_method_name"), is(nullValue())); assertThat(field(node, "caller_file_name"), is(nullValue())); assertThat(field(node, "caller_line_number"), is(nullValue())); } @Test public void propertiesInContextAreIncluded() throws Exception { Map<String, String> propertyMap = new HashMap<String, String>(); propertyMap.put("thing_one", "One"); propertyMap.put("thing_two", "Three"); final Context context = mock(Context.class); when(context.getCopyOfPropertyMap()).thenReturn(propertyMap); ILoggingEvent event = mockBasicILoggingEvent(Level.ERROR); encoder().setContext(context); encoder().doEncode(event); closeQuietly(outputStream()); JsonNode node = MAPPER.readTree(outputStream().toByteArray()); assertThat(field(node, "thing_one").textValue(), is("One")); assertThat(field(node, "thing_two").textValue(), is("Three")); } @Test public void markerIncludesItselfAsTag() throws Exception { Marker marker = MarkerFactory.getMarker("hoosh"); ILoggingEvent event = mockBasicILoggingEvent(Level.INFO); when(event.getMarker()).thenReturn(marker); encoder().doEncode(event); closeQuietly(outputStream()); JsonNode node = MAPPER.readTree(outputStream().toByteArray()); assertJsonArray(node.findValue(tagsProperty), "hoosh"); } @Test public void markerReferencesAreIncludedAsTags() throws Exception { Marker marker = MarkerFactory.getMarker("bees"); marker.add(MarkerFactory.getMarker("knees")); ILoggingEvent event = mockBasicILoggingEvent(Level.INFO); when(event.getMarker()).thenReturn(marker); encoder().doEncode(event); closeQuietly(outputStream()); JsonNode node = MAPPER.readTree(outputStream().toByteArray()); assertJsonArray(node.findValue(tagsProperty), "bees", "knees"); } @Test public void nullMarkerIsIgnored() throws Exception { ILoggingEvent event = mockBasicILoggingEvent(Level.INFO); when(event.getMarker()).thenReturn(null); encoder().doEncode(event); closeQuietly(outputStream()); JsonNode node = MAPPER.readTree(outputStream().toByteArray()); assertJsonArray(node.findValue(tagsProperty)); } @Test public void immediateFlushIsSane() { encoder().setImmediateFlush(true); assertThat(encoder().isImmediateFlush(), is(true)); encoder().setImmediateFlush(false); assertThat(encoder().isImmediateFlush(), is(false)); } private void assertJsonArray(JsonNode jsonNode, String... expected) { String[] values = new String[jsonNode.size()]; for (int i = 0; i < values.length; i++) { values[i] = jsonNode.get(i).asText(); } Assert.assertArrayEquals(expected, values); } private ILoggingEvent mockBasicILoggingEvent(Level level) { ILoggingEvent event = mock(ILoggingEvent.class); when(event.getLoggerName()).thenReturn("LoggerName"); when(event.getThreadName()).thenReturn("ThreadName"); when(event.getFormattedMessage()).thenReturn("My message"); when(event.getLevel()).thenReturn(level); return event; } }