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