View Javadoc
1   /**
2    * Logback: the reliable, generic, fast and flexible logging framework.
3    * Copyright (C) 1999-2015, QOS.ch. All rights reserved.
4    *
5    * This program and the accompanying materials are dual-licensed under
6    * either the terms of the Eclipse Public License v1.0 as published by
7    * the Eclipse Foundation
8    *
9    *   or (per the licensee's choosing)
10   *
11   * under the terms of the GNU Lesser General Public License version 2.1
12   * as published by the Free Software Foundation.
13   */
14  package ch.qos.logback.classic.spi;
15  
16  import ch.qos.logback.classic.Level;
17  import ch.qos.logback.classic.Logger;
18  import ch.qos.logback.classic.LoggerContext;
19  import ch.qos.logback.classic.net.LoggingEventPreSerializationTransformer;
20  import ch.qos.logback.classic.net.server.HardenedLoggingEventInputStream;
21  import ch.qos.logback.classic.util.LogbackMDCAdapter;
22  import ch.qos.logback.core.spi.PreSerializationTransformer;
23  import org.junit.jupiter.api.AfterEach;
24  import org.junit.jupiter.api.BeforeEach;
25  import org.junit.jupiter.api.Test;
26  import org.slf4j.MDC;
27  import org.slf4j.Marker;
28  import org.slf4j.MarkerFactory;
29  
30  import java.io.ByteArrayInputStream;
31  import java.io.ByteArrayOutputStream;
32  import java.io.IOException;
33  import java.io.ObjectInputStream;
34  import java.io.ObjectOutputStream;
35  import java.io.Serializable;
36  import java.util.Arrays;
37  import java.util.Map;
38  
39  import static org.junit.jupiter.api.Assertions.assertEquals;
40  import static org.junit.jupiter.api.Assertions.assertNotNull;
41  import static org.junit.jupiter.api.Assertions.assertNull;
42  
43  public class LoggingEventSerializationTest {
44  
45      LoggerContext loggerContext;
46      LogbackMDCAdapter logbackMDCAdapter = new LogbackMDCAdapter();
47      Logger logger;
48  
49      ByteArrayOutputStream bos;
50      ObjectOutputStream oos;
51      ObjectInputStream inputStream;
52      PreSerializationTransformer<ILoggingEvent> pst = new LoggingEventPreSerializationTransformer();
53  
54      @BeforeEach
55      public void setUp() throws Exception {
56          loggerContext = new LoggerContext();
57          loggerContext.setName("testContext");
58          loggerContext.setMDCAdapter(logbackMDCAdapter);
59          logger = loggerContext.getLogger(Logger.ROOT_LOGGER_NAME);
60          // create the byte output stream
61          bos = new ByteArrayOutputStream();
62          oos = new ObjectOutputStream(bos);
63      }
64  
65      @AfterEach
66      public void tearDown() throws Exception {
67          loggerContext = null;
68          logger = null;
69          oos.close();
70      }
71  
72      @Test
73      public void smoke() throws Exception {
74          ILoggingEvent event = createLoggingEvent();
75          ILoggingEvent remoteEvent = writeAndRead(event);
76          checkForEquality(event, remoteEvent);
77      }
78  
79      @Test
80      public void context() throws Exception {
81          loggerContext.putProperty("testKey", "testValue");
82          ILoggingEvent event = createLoggingEvent();
83          ILoggingEvent remoteEvent = writeAndRead(event);
84          checkForEquality(event, remoteEvent);
85  
86          assertNotNull(remoteEvent.getLoggerName());
87          assertEquals(Logger.ROOT_LOGGER_NAME, remoteEvent.getLoggerName());
88  
89          LoggerContextVO loggerContextRemoteView = remoteEvent.getLoggerContextVO();
90          assertNotNull(loggerContextRemoteView);
91          assertEquals("testContext", loggerContextRemoteView.getName());
92          Map<String, String> props = loggerContextRemoteView.getPropertyMap();
93          assertNotNull(props);
94          assertEquals("testValue", props.get("testKey"));
95      }
96  
97      @Test
98      public void MDC() throws Exception {
99          logbackMDCAdapter.put("key", "testValue");
100         ILoggingEvent event = createLoggingEvent();
101         ILoggingEvent remoteEvent = writeAndRead(event);
102         checkForEquality(event, remoteEvent);
103         Map<String, String> MDCPropertyMap = remoteEvent.getMDCPropertyMap();
104         assertEquals("testValue", MDCPropertyMap.get("key"));
105     }
106 
107     @Test
108     public void updatedMDC() throws Exception {
109         logbackMDCAdapter.put("key", "testValue");
110         ILoggingEvent event1 = createLoggingEvent();
111         Serializable s1 = pst.transform(event1);
112         oos.writeObject(s1);
113 
114         logbackMDCAdapter.put("key", "updatedTestValue");
115         ILoggingEvent event2 = createLoggingEvent();
116         Serializable s2 = pst.transform(event2);
117         oos.writeObject(s2);
118 
119         // create the input stream based on the output stream
120         ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
121         inputStream = new ObjectInputStream(bis);
122 
123         // skip over one object
124         inputStream.readObject();
125         ILoggingEvent remoteEvent2 = (ILoggingEvent) inputStream.readObject();
126 
127         // We observe the second logging event. It should provide us with
128         // the updated MDC property.
129         Map<String, String> MDCPropertyMap = remoteEvent2.getMDCPropertyMap();
130         assertEquals("updatedTestValue", MDCPropertyMap.get("key"));
131     }
132 
133     @Test
134     public void nonSerializableParameters() throws Exception {
135         LoggingEvent event = createLoggingEvent();
136         LuckyCharms lucky0 = new LuckyCharms(0);
137         event.setArgumentArray(new Object[] { lucky0, null });
138         ILoggingEvent remoteEvent = writeAndRead(event);
139         checkForEquality(event, remoteEvent);
140 
141         Object[] aa = remoteEvent.getArgumentArray();
142         assertNotNull(aa);
143         assertEquals(2, aa.length);
144         assertEquals("LC(0)", aa[0]);
145         assertNull(aa[1]);
146     }
147 
148     @Test
149     public void testWithThrowable() throws Exception {
150         Throwable throwable = new Throwable("just testing");
151         LoggingEvent event = createLoggingEventWithThrowable(throwable);
152         ILoggingEvent remoteEvent = writeAndRead(event);
153         checkForEquality(event, remoteEvent);
154     }
155 
156     @Test
157     public void testWithMarker() throws Exception {
158         Marker marker = MarkerFactory.getMarker("A_MARKER");
159         LoggingEvent event = createLoggingEvent();
160 
161         event.addMarker(marker);
162         assertNotNull(event.getMarkerList());
163 
164         ILoggingEvent remoteEvent = writeAndRead(event);
165         checkForEquality(event, remoteEvent);
166 
167         assertNotNull(remoteEvent.getMarkerList());
168         assertEquals(Arrays.asList(marker), remoteEvent.getMarkerList());
169     }
170 
171     @Test
172     public void testWithTwoMarkers() throws Exception {
173         Marker marker = MarkerFactory.getMarker("A_MARKER");
174         Marker marker2 = MarkerFactory.getMarker("B_MARKER");
175         marker.add(marker2);
176         LoggingEvent event = createLoggingEvent();
177 
178         event.addMarker(marker);
179         assertNotNull(event.getMarkerList());
180 
181         ILoggingEvent remoteEvent = writeAndRead(event);
182         checkForEquality(event, remoteEvent);
183 
184         assertNotNull(remoteEvent.getMarkerList());
185         assertEquals(Arrays.asList(marker), remoteEvent.getMarkerList());
186     }
187 
188     @Test
189     public void testWithCallerData() throws Exception {
190         LoggingEvent event = createLoggingEvent();
191         event.getCallerData();
192         ILoggingEvent remoteEvent = writeAndRead(event);
193         checkForEquality(event, remoteEvent);
194     }
195 
196     @Test
197     public void extendendeThrowable() throws Exception {
198         LoggingEvent event = createLoggingEvent();
199         Throwable throwable = new Throwable("just testing");
200         ThrowableProxy tp = new ThrowableProxy(throwable);
201         event.setThrowableProxy(tp);
202         tp.calculatePackagingData();
203         ILoggingEvent remoteEvent = writeAndRead(event);
204         checkForEquality(event, remoteEvent);
205     }
206 
207     @Test
208     public void serializeLargeArgs() throws Exception {
209 
210         StringBuilder buffer = new StringBuilder();
211         for (int i = 0; i < 100000; i++) {
212             buffer.append("X");
213         }
214         String largeString = buffer.toString();
215         Object[] argArray = new Object[] { new LuckyCharms(2), largeString };
216 
217         LoggingEvent event = createLoggingEvent();
218         event.setArgumentArray(argArray);
219 
220         ILoggingEvent remoteEvent = writeAndRead(event);
221         checkForEquality(event, remoteEvent);
222         Object[] aa = remoteEvent.getArgumentArray();
223         assertNotNull(aa);
224         assertEquals(2, aa.length);
225         String stringBack = (String) aa[1];
226         assertEquals(largeString, stringBack);
227     }
228 
229     private LoggingEvent createLoggingEvent() {
230         return new LoggingEvent(this.getClass().getName(), logger, Level.DEBUG, "test message", null, null);
231     }
232 
233     private LoggingEvent createLoggingEventWithThrowable(Throwable t) {
234         return new LoggingEvent(this.getClass().getName(), logger, Level.DEBUG, "test message", t, null);
235     }
236 
237     private void checkForEquality(ILoggingEvent original, ILoggingEvent afterSerialization) {
238         assertEquals(original.getLevel(), afterSerialization.getLevel());
239         assertEquals(original.getFormattedMessage(), afterSerialization.getFormattedMessage());
240         assertEquals(original.getMessage(), afterSerialization.getMessage());
241 
242         System.out.println();
243 
244         ThrowableProxyVO witness = ThrowableProxyVO.build(original.getThrowableProxy());
245         assertEquals(witness, afterSerialization.getThrowableProxy());
246 
247     }
248 
249     private ILoggingEvent writeAndRead(ILoggingEvent event) throws IOException, ClassNotFoundException {
250         Serializable ser = pst.transform(event);
251         oos.writeObject(ser);
252         ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
253         inputStream = new HardenedLoggingEventInputStream(bis);
254 
255         return (ILoggingEvent) inputStream.readObject();
256     }
257 
258 }