001/**
002 * Logback: the reliable, generic, fast and flexible logging framework.
003 * Copyright (C) 1999-2015, QOS.ch. All rights reserved.
004 *
005 * This program and the accompanying materials are dual-licensed under
006 * either the terms of the Eclipse Public License v1.0 as published by
007 * the Eclipse Foundation
008 *
009 *   or (per the licensee's choosing)
010 *
011 * under the terms of the GNU Lesser General Public License version 2.1
012 * as published by the Free Software Foundation.
013 */
014package ch.qos.logback.classic.spi;
015
016import static org.junit.Assert.assertEquals;
017import static org.junit.Assert.assertNotNull;
018import static org.junit.Assert.assertNull;
019
020import java.io.ByteArrayInputStream;
021import java.io.ByteArrayOutputStream;
022import java.io.IOException;
023import java.io.ObjectInputStream;
024import java.io.ObjectOutputStream;
025import java.io.Serializable;
026import java.util.Map;
027
028import org.junit.After;
029import org.junit.Before;
030import org.junit.Test;
031import org.slf4j.MDC;
032import org.slf4j.Marker;
033import org.slf4j.MarkerFactory;
034
035import ch.qos.logback.classic.Level;
036import ch.qos.logback.classic.Logger;
037import ch.qos.logback.classic.LoggerContext;
038import ch.qos.logback.classic.net.LoggingEventPreSerializationTransformer;
039import ch.qos.logback.classic.net.server.HardenedLoggingEventInputStream;
040import ch.qos.logback.core.spi.PreSerializationTransformer;
041
042public class LoggingEventSerializationTest {
043
044    LoggerContext loggerContext;
045    Logger logger;
046
047    ByteArrayOutputStream bos;
048    ObjectOutputStream oos;
049    ObjectInputStream inputStream;
050    PreSerializationTransformer<ILoggingEvent> pst = new LoggingEventPreSerializationTransformer();
051
052    @Before
053    public void setUp() throws Exception {
054        loggerContext = new LoggerContext();
055        loggerContext.setName("testContext");
056        logger = loggerContext.getLogger(Logger.ROOT_LOGGER_NAME);
057        // create the byte output stream
058        bos = new ByteArrayOutputStream();
059        oos = new ObjectOutputStream(bos);
060    }
061
062    @After
063    public void tearDown() throws Exception {
064        loggerContext = null;
065        logger = null;
066        oos.close();
067    }
068
069    @Test
070    public void smoke() throws Exception {
071        ILoggingEvent event = createLoggingEvent();
072        ILoggingEvent remoteEvent = writeAndRead(event);
073        checkForEquality(event, remoteEvent);
074    }
075
076    @Test
077    public void context() throws Exception {
078        loggerContext.putProperty("testKey", "testValue");
079        ILoggingEvent event = createLoggingEvent();
080        ILoggingEvent remoteEvent = writeAndRead(event);
081        checkForEquality(event, remoteEvent);
082
083        assertNotNull(remoteEvent.getLoggerName());
084        assertEquals(Logger.ROOT_LOGGER_NAME, remoteEvent.getLoggerName());
085
086        LoggerContextVO loggerContextRemoteView = remoteEvent.getLoggerContextVO();
087        assertNotNull(loggerContextRemoteView);
088        assertEquals("testContext", loggerContextRemoteView.getName());
089        Map<String, String> props = loggerContextRemoteView.getPropertyMap();
090        assertNotNull(props);
091        assertEquals("testValue", props.get("testKey"));
092    }
093
094    @Test
095    public void MDC() throws Exception {
096        MDC.put("key", "testValue");
097        ILoggingEvent event = createLoggingEvent();
098        ILoggingEvent remoteEvent = writeAndRead(event);
099        checkForEquality(event, remoteEvent);
100        Map<String, String> MDCPropertyMap = remoteEvent.getMDCPropertyMap();
101        assertEquals("testValue", MDCPropertyMap.get("key"));
102    }
103
104    @Test
105    public void updatedMDC() throws Exception {
106        MDC.put("key", "testValue");
107        ILoggingEvent event1 = createLoggingEvent();
108        Serializable s1 = pst.transform(event1);
109        oos.writeObject(s1);
110
111        MDC.put("key", "updatedTestValue");
112        ILoggingEvent event2 = createLoggingEvent();
113        Serializable s2 = pst.transform(event2);
114        oos.writeObject(s2);
115
116        // create the input stream based on the ouput stream
117        ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
118        inputStream = new ObjectInputStream(bis);
119
120        // skip over one object
121        inputStream.readObject();
122        ILoggingEvent remoteEvent2 = (ILoggingEvent) inputStream.readObject();
123
124        // We observe the second logging event. It should provide us with
125        // the updated MDC property.
126        Map<String, String> MDCPropertyMap = remoteEvent2.getMDCPropertyMap();
127        assertEquals("updatedTestValue", MDCPropertyMap.get("key"));
128    }
129
130    @Test
131    public void nonSerializableParameters() throws Exception {
132        LoggingEvent event = createLoggingEvent();
133        LuckyCharms lucky0 = new LuckyCharms(0);
134        event.setArgumentArray(new Object[] { lucky0, null });
135        ILoggingEvent remoteEvent = writeAndRead(event);
136        checkForEquality(event, remoteEvent);
137
138        Object[] aa = remoteEvent.getArgumentArray();
139        assertNotNull(aa);
140        assertEquals(2, aa.length);
141        assertEquals("LC(0)", aa[0]);
142        assertNull(aa[1]);
143    }
144
145    @Test
146    public void testWithThrowable() throws Exception {
147        Throwable throwable = new Throwable("just testing");
148        LoggingEvent event = createLoggingEventWithThrowable(throwable);
149        ILoggingEvent remoteEvent = writeAndRead(event);
150        checkForEquality(event, remoteEvent);
151    }
152
153
154    @Test
155    public void testWithMarker() throws Exception {
156        Marker marker = MarkerFactory.getMarker("A_MARKER");
157        LoggingEvent event = createLoggingEvent();
158        
159        
160        event.setMarker(marker);
161        assertNotNull(event.getMarker());
162        
163        ILoggingEvent remoteEvent = writeAndRead(event);
164        checkForEquality(event, remoteEvent);
165
166        assertNotNull(remoteEvent.getMarker());
167        assertEquals(marker, remoteEvent.getMarker());
168    }
169    
170    @Test
171    public void testWithTwoMarkers() throws Exception {
172        Marker marker = MarkerFactory.getMarker("A_MARKER");
173        Marker marker2 = MarkerFactory.getMarker("B_MARKER");
174        marker.add(marker2);
175        LoggingEvent event = createLoggingEvent();
176        
177        event.setMarker(marker);
178        assertNotNull(event.getMarker());
179        
180        ILoggingEvent remoteEvent = writeAndRead(event);
181        checkForEquality(event, remoteEvent);
182
183        assertNotNull(remoteEvent.getMarker());
184        assertEquals(marker, remoteEvent.getMarker());
185    }
186    
187    @Test
188    public void testWithCallerData() throws Exception {
189        LoggingEvent event = createLoggingEvent();
190        event.getCallerData();
191        ILoggingEvent remoteEvent = writeAndRead(event);
192        checkForEquality(event, remoteEvent);
193    }
194
195    @Test
196    public void extendendeThrowable() throws Exception {
197        LoggingEvent event = createLoggingEvent();
198        Throwable throwable = new Throwable("just testing");
199        ThrowableProxy tp = new ThrowableProxy(throwable);
200        event.setThrowableProxy(tp);
201        tp.calculatePackagingData();
202        ILoggingEvent remoteEvent = writeAndRead(event);
203        checkForEquality(event, remoteEvent);
204    }
205
206    @Test
207    public void serializeLargeArgs() throws Exception {
208
209        StringBuilder buffer = new StringBuilder();
210        for (int i = 0; i < 100000; i++) {
211            buffer.append("X");
212        }
213        String largeString = buffer.toString();
214        Object[] argArray = new Object[] { new LuckyCharms(2), largeString };
215
216        LoggingEvent event = createLoggingEvent();
217        event.setArgumentArray(argArray);
218
219        ILoggingEvent remoteEvent = writeAndRead(event);
220        checkForEquality(event, remoteEvent);
221        Object[] aa = remoteEvent.getArgumentArray();
222        assertNotNull(aa);
223        assertEquals(2, aa.length);
224        String stringBack = (String) aa[1];
225        assertEquals(largeString, stringBack);
226    }
227
228    private LoggingEvent createLoggingEvent() {
229        return new LoggingEvent(this.getClass().getName(), logger, Level.DEBUG, "test message", null, null);
230    }
231
232    private LoggingEvent createLoggingEventWithThrowable(Throwable t) {
233        return new LoggingEvent(this.getClass().getName(), logger, Level.DEBUG, "test message", t, null);
234    }
235
236    private void checkForEquality(ILoggingEvent original, ILoggingEvent afterSerialization) {
237        assertEquals(original.getLevel(), afterSerialization.getLevel());
238        assertEquals(original.getFormattedMessage(), afterSerialization.getFormattedMessage());
239        assertEquals(original.getMessage(), afterSerialization.getMessage());
240
241        System.out.println();
242
243        ThrowableProxyVO witness = ThrowableProxyVO.build(original.getThrowableProxy());
244        assertEquals(witness, afterSerialization.getThrowableProxy());
245
246    }
247
248    private ILoggingEvent writeAndRead(ILoggingEvent event) throws IOException, ClassNotFoundException {
249        Serializable ser = pst.transform(event);
250        oos.writeObject(ser);
251        ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
252        inputStream = new HardenedLoggingEventInputStream(bis);
253        
254        return (ILoggingEvent) inputStream.readObject();
255    }
256
257}