View Javadoc

1   /**
2    * Logback: the reliable, generic, fast and flexible logging framework.
3    * Copyright (C) 1999-2011, 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)
109           .getMessage();
110     } else {
111       formattedMessage = message;
112     }
113 
114     return formattedMessage;
115   }
116 
117   public Object[] getArgumentArray() {
118     return argumentArray;
119   }
120 
121   public IThrowableProxy getThrowableProxy() {
122     return throwableProxy;
123   }
124 
125   public StackTraceElement[] getCallerData() {
126     return callerDataArray;
127   }
128 
129   public boolean hasCallerData() {
130     return callerDataArray != null;
131   }
132 
133   public Marker getMarker() {
134     return marker;
135   }
136 
137   public long getTimeStamp() {
138     return timeStamp;
139   }
140 
141   public long getContextBirthTime() {
142     return loggerContextVO.getBirthTime();
143   }
144 
145   public LoggerContextVO getContextLoggerRemoteView() {
146     return loggerContextVO;
147   }
148 
149   public Map<String, String> getMDCPropertyMap() {
150     return mdcPropertyMap;
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,
179       ClassNotFoundException {
180     in.defaultReadObject();
181     int levelInt = in.readInt();
182     level = Level.toLevel(levelInt);
183 
184     int argArrayLen = in.readInt();
185     if (argArrayLen != NULL_ARGUMENT_ARRAY) {
186       argumentArray = new String[argArrayLen];
187       for (int i = 0; i < argArrayLen; i++) {
188         Object val = in.readObject();
189         if (!NULL_ARGUMENT_ARRAY_ELEMENT.equals(val)) {
190           argumentArray[i] = val;
191         }
192       }
193     }
194   }
195 
196   @Override
197   public int hashCode() {
198     final int prime = 31;
199     int result = 1;
200     result = prime * result + ((message == null) ? 0 : message.hashCode());
201     result = prime * result
202         + ((threadName == null) ? 0 : threadName.hashCode());
203     result = prime * result + (int) (timeStamp ^ (timeStamp >>> 32));
204     return result;
205   }
206 
207   @Override
208   public boolean equals(Object obj) {
209     if (this == obj)
210       return true;
211     if (obj == null)
212       return false;
213     if (getClass() != obj.getClass())
214       return false;
215     final LoggingEventVO other = (LoggingEventVO) obj;
216     if (message == null) {
217       if (other.message != null)
218         return false;
219     } else if (!message.equals(other.message))
220       return false;
221 
222     if (loggerName == null) {
223       if (other.loggerName != null)
224         return false;
225     } else if (!loggerName.equals(other.loggerName))
226       return false;
227 
228     if (threadName == null) {
229       if (other.threadName != null)
230         return false;
231     } else if (!threadName.equals(other.threadName))
232       return false;
233     if (timeStamp != other.timeStamp)
234       return false;
235 
236     if (marker == null) {
237       if (other.marker != null)
238         return false;
239     } else if (!marker.equals(other.marker))
240       return false;
241 
242     if (mdcPropertyMap == null) {
243       if (other.mdcPropertyMap != null)
244         return false;
245     } else if (!mdcPropertyMap.equals(other.mdcPropertyMap))
246       return false;
247     return true;
248   }
249 }