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 java.io.IOException;
17  import java.io.ObjectInputStream;
18  import java.io.ObjectOutputStream;
19  import java.io.Serializable;
20  import java.time.Instant;
21  import java.util.List;
22  import java.util.Map;
23  
24  import org.slf4j.Marker;
25  import org.slf4j.event.KeyValuePair;
26  import org.slf4j.helpers.MessageFormatter;
27  
28  import ch.qos.logback.classic.Level;
29  
30  // http://www.riehle.org/computer-science/research/1998/ubilab-tr-1998-10-1.html
31  
32  /**
33   * A read-only and serializable implementation of {@link ILoggingEvent}.
34   * 
35   * @author Ceki Gülcü
36   * @since 0.9.16
37   */
38  public class LoggingEventVO implements ILoggingEvent, Serializable {
39  
40      private static final long serialVersionUID = 6553722650255690312L;
41  
42      private static final int NULL_ARGUMENT_ARRAY = -1;
43      private static final String NULL_ARGUMENT_ARRAY_ELEMENT = "NULL_ARGUMENT_ARRAY_ELEMENT";
44  
45      private String threadName;
46      private String loggerName;
47      private LoggerContextVO loggerContextVO;
48  
49      private transient Level level;
50      private String message;
51  
52      // we gain significant space at serialization time by marking
53      // formattedMessage as transient and constructing it lazily in
54      // getFormattedMessage()
55      private transient String formattedMessage;
56  
57      private transient Object[] argumentArray;
58  
59      private ThrowableProxyVO throwableProxy;
60      private StackTraceElement[] callerDataArray;
61      private List<Marker> markerList;
62      private List<KeyValuePair> keyValuePairList;
63      private Map<String, String> mdcPropertyMap;
64  
65      private long timestamp;
66      private int nanoseconds;
67  
68      private long sequenceNumber;
69  
70      public static LoggingEventVO build(ILoggingEvent le) {
71          LoggingEventVO ledo = new LoggingEventVO();
72          ledo.loggerName = le.getLoggerName();
73          ledo.loggerContextVO = le.getLoggerContextVO();
74          ledo.threadName = le.getThreadName();
75          ledo.level = (le.getLevel());
76          ledo.message = (le.getMessage());
77          ledo.argumentArray = (le.getArgumentArray());
78          ledo.markerList = le.getMarkerList();
79          ledo.keyValuePairList = le.getKeyValuePairs();
80          ledo.mdcPropertyMap = le.getMDCPropertyMap();
81          ledo.timestamp = le.getTimeStamp();
82          ledo.nanoseconds = le.getNanoseconds();
83          ledo.sequenceNumber = le.getSequenceNumber();
84          ledo.throwableProxy = ThrowableProxyVO.build(le.getThrowableProxy());
85          // add caller data only if it is there already
86          // fixes http://jira.qos.ch/browse/LBCLASSIC-145
87          if (le.hasCallerData()) {
88              ledo.callerDataArray = le.getCallerData();
89          }
90          return ledo;
91      }
92  
93      public String getThreadName() {
94          return threadName;
95      }
96  
97      public LoggerContextVO getLoggerContextVO() {
98          return loggerContextVO;
99      }
100 
101     public String getLoggerName() {
102         return loggerName;
103     }
104 
105     public Level getLevel() {
106         return level;
107     }
108 
109     public String getMessage() {
110         return message;
111     }
112 
113     public String getFormattedMessage() {
114         if (formattedMessage != null) {
115             return formattedMessage;
116         }
117 
118         if (argumentArray != null) {
119             formattedMessage = MessageFormatter.arrayFormat(message, argumentArray).getMessage();
120         } else {
121             formattedMessage = message;
122         }
123 
124         return formattedMessage;
125     }
126 
127     public Object[] getArgumentArray() {
128         return argumentArray;
129     }
130 
131     public IThrowableProxy getThrowableProxy() {
132         return throwableProxy;
133     }
134 
135     public StackTraceElement[] getCallerData() {
136         return callerDataArray;
137     }
138 
139     public boolean hasCallerData() {
140         return callerDataArray != null;
141     }
142 
143     public List<Marker> getMarkerList() {
144         return markerList;
145     }
146 
147     @Override
148     public long getTimeStamp() { return timestamp; }
149 
150     @Override
151     public int getNanoseconds() {  return nanoseconds; }
152 
153     public long getSequenceNumber() {
154         return sequenceNumber;
155     }
156 
157     public long getContextBirthTime() {
158         return loggerContextVO.getBirthTime();
159     }
160 
161     public LoggerContextVO getContextLoggerRemoteView() {
162         return loggerContextVO;
163     }
164 
165     public Map<String, String> getMDCPropertyMap() {
166         return mdcPropertyMap;
167     }
168 
169     public Map<String, String> getMdc() {
170         return mdcPropertyMap;
171     }
172 
173     @Override
174     public List<KeyValuePair> getKeyValuePairs() {
175         return this.keyValuePairList;
176     }
177 
178     public void prepareForDeferredProcessing() {
179     }
180 
181     private void writeObject(ObjectOutputStream out) throws IOException {
182         out.defaultWriteObject();
183         out.writeInt(level.levelInt);
184         if (argumentArray != null) {
185             int len = argumentArray.length;
186             out.writeInt(len);
187             for (int i = 0; i < argumentArray.length; i++) {
188                 if (argumentArray[i] != null) {
189                     out.writeObject(argumentArray[i].toString());
190                 } else {
191                     out.writeObject(NULL_ARGUMENT_ARRAY_ELEMENT);
192                 }
193             }
194         } else {
195             out.writeInt(NULL_ARGUMENT_ARRAY);
196         }
197 
198     }
199 
200     private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
201         in.defaultReadObject();
202         int levelInt = in.readInt();
203         level = Level.toLevel(levelInt);
204 
205         int argArrayLen = in.readInt();
206         if (argArrayLen != NULL_ARGUMENT_ARRAY) {
207             argumentArray = new String[argArrayLen];
208             for (int i = 0; i < argArrayLen; i++) {
209                 Object val = in.readObject();
210                 if (!NULL_ARGUMENT_ARRAY_ELEMENT.equals(val)) {
211                     argumentArray[i] = val;
212                 }
213             }
214         }
215     }
216 
217     @Override
218     public int hashCode() {
219         final int prime = 31;
220         long millis = getTimeStamp();
221 
222         int result = 1;
223         result = prime * result + ((message == null) ? 0 : message.hashCode());
224         result = prime * result + ((threadName == null) ? 0 : threadName.hashCode());
225         result = prime * result + (int) (millis ^ (millis >>> 32));
226         return result;
227     }
228 
229     @Override
230     public boolean equals(Object obj) {
231         if (this == obj)
232             return true;
233         if (obj == null)
234             return false;
235         if (getClass() != obj.getClass())
236             return false;
237         final LoggingEventVO other = (LoggingEventVO) obj;
238         if (message == null) {
239             if (other.message != null)
240                 return false;
241         } else if (!message.equals(other.message))
242             return false;
243 
244         if (loggerName == null) {
245             if (other.loggerName != null)
246                 return false;
247         } else if (!loggerName.equals(other.loggerName))
248             return false;
249 
250         if (threadName == null) {
251             if (other.threadName != null)
252                 return false;
253         } else if (!threadName.equals(other.threadName))
254             return false;
255         if (getTimeStamp() != other.getTimeStamp())
256             return false;
257 
258         if (markerList == null) {
259             if (other.markerList != null)
260                 return false;
261         } else if (!markerList.equals(other.markerList))
262             return false;
263 
264         if (mdcPropertyMap == null) {
265             if (other.mdcPropertyMap != null)
266                 return false;
267         } else if (!mdcPropertyMap.equals(other.mdcPropertyMap))
268             return false;
269         return true;
270     }
271 
272 }