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