net.logstash.logback.encoder.LogstashEncoderTestCommon.java Source code

Java tutorial

Introduction

Here is the source code for net.logstash.logback.encoder.LogstashEncoderTestCommon.java

Source

/**
 * 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;
    }

}