001/** 002 * Logback: the reliable, generic, fast and flexible logging framework. 003 * Copyright (C) 1999-2015, QOS.ch. All rights reserved. 004 * 005 * This program and the accompanying materials are dual-licensed under 006 * either the terms of the Eclipse Public License v1.0 as published by 007 * the Eclipse Foundation 008 * 009 * or (per the licensee's choosing) 010 * 011 * under the terms of the GNU Lesser General Public License version 2.1 012 * as published by the Free Software Foundation. 013 */ 014package ch.qos.logback.classic.spi; 015 016import java.io.IOException; 017import java.io.ObjectInputStream; 018import java.io.ObjectOutputStream; 019import java.io.Serializable; 020import java.time.Instant; 021import java.util.List; 022import java.util.Map; 023 024import org.slf4j.Marker; 025import org.slf4j.event.KeyValuePair; 026import org.slf4j.helpers.MessageFormatter; 027 028import ch.qos.logback.classic.Level; 029 030// http://www.riehle.org/computer-science/research/1998/ubilab-tr-1998-10-1.html 031 032/** 033 * A read-only and serializable implementation of {@link ILoggingEvent}. 034 * 035 * @author Ceki Gülcü 036 * @since 0.9.16 037 */ 038public class LoggingEventVO implements ILoggingEvent, Serializable { 039 040 private static final long serialVersionUID = 6553722650255690312L; 041 042 private static final int NULL_ARGUMENT_ARRAY = -1; 043 private static final String NULL_ARGUMENT_ARRAY_ELEMENT = "NULL_ARGUMENT_ARRAY_ELEMENT"; 044 045 private String threadName; 046 private String loggerName; 047 private LoggerContextVO loggerContextVO; 048 049 private transient Level level; 050 private String message; 051 052 // we gain significant space at serialization time by marking 053 // formattedMessage as transient and constructing it lazily in 054 // getFormattedMessage() 055 private transient String formattedMessage; 056 057 private transient Object[] argumentArray; 058 059 private ThrowableProxyVO throwableProxy; 060 private StackTraceElement[] callerDataArray; 061 private List<Marker> markerList; 062 private List<KeyValuePair> keyValuePairList; 063 private Map<String, String> mdcPropertyMap; 064 065 private long timestamp; 066 private int nanoseconds; 067 068 private long sequenceNumber; 069 070 public static LoggingEventVO build(ILoggingEvent le) { 071 LoggingEventVO ledo = new LoggingEventVO(); 072 ledo.loggerName = le.getLoggerName(); 073 ledo.loggerContextVO = le.getLoggerContextVO(); 074 ledo.threadName = le.getThreadName(); 075 ledo.level = (le.getLevel()); 076 ledo.message = (le.getMessage()); 077 ledo.argumentArray = (le.getArgumentArray()); 078 ledo.markerList = le.getMarkerList(); 079 ledo.keyValuePairList = le.getKeyValuePairs(); 080 ledo.mdcPropertyMap = le.getMDCPropertyMap(); 081 ledo.timestamp = le.getTimeStamp(); 082 ledo.nanoseconds = le.getNanoseconds(); 083 ledo.sequenceNumber = le.getSequenceNumber(); 084 ledo.throwableProxy = ThrowableProxyVO.build(le.getThrowableProxy()); 085 // add caller data only if it is there already 086 // fixes http://jira.qos.ch/browse/LBCLASSIC-145 087 if (le.hasCallerData()) { 088 ledo.callerDataArray = le.getCallerData(); 089 } 090 return ledo; 091 } 092 093 public String getThreadName() { 094 return threadName; 095 } 096 097 public LoggerContextVO getLoggerContextVO() { 098 return loggerContextVO; 099 } 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}