1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18 #include <log4cxx/spi/loggingevent.h>
19 #include <log4cxx/ndc.h>
20
21 #include <log4cxx/level.h>
22 #include <log4cxx/helpers/loglog.h>
23 #include <log4cxx/helpers/system.h>
24 #include <log4cxx/helpers/socket.h>
25 #if !defined(LOG4CXX)
26 #define LOG4CXX 1
27 #endif
28 #include <log4cxx/helpers/aprinitializer.h>
29 #include <log4cxx/helpers/threadspecificdata.h>
30 #include <log4cxx/helpers/transcoder.h>
31
32 #include <apr_time.h>
33 #include <apr_portable.h>
34 #include <apr_strings.h>
35 #include <log4cxx/helpers/stringhelper.h>
36 #include <log4cxx/helpers/objectoutputstream.h>
37 #include <log4cxx/helpers/bytebuffer.h>
38 #include <log4cxx/logger.h>
39 #include <log4cxx/private/log4cxx_private.h>
40
41 using namespace log4cxx;
42 using namespace log4cxx::spi;
43 using namespace log4cxx::helpers;
44
IMPLEMENT_LOG4CXX_OBJECT(LoggingEvent)45 IMPLEMENT_LOG4CXX_OBJECT(LoggingEvent)
46
47
48 //
49 // Accessor for start time.
50 //
51 log4cxx_time_t LoggingEvent::getStartTime()
52 {
53 return log4cxx::helpers::APRInitializer::initialize();
54 }
55
LoggingEvent()56 LoggingEvent::LoggingEvent() :
57 ndc(0),
58 mdcCopy(0),
59 properties(0),
60 ndcLookupRequired(true),
61 mdcCopyLookupRequired(true),
62 timeStamp(0),
63 locationInfo()
64 {
65 }
66
LoggingEvent(const LogString & logger1,const LevelPtr & level1,const LogString & message1,const LocationInfo & locationInfo1)67 LoggingEvent::LoggingEvent(
68 const LogString& logger1, const LevelPtr& level1,
69 const LogString& message1, const LocationInfo& locationInfo1) :
70 logger(logger1),
71 level(level1),
72 ndc(0),
73 mdcCopy(0),
74 properties(0),
75 ndcLookupRequired(true),
76 mdcCopyLookupRequired(true),
77 message(message1),
78 timeStamp(apr_time_now()),
79 locationInfo(locationInfo1),
80 threadName(getCurrentThreadName())
81 {
82 }
83
~LoggingEvent()84 LoggingEvent::~LoggingEvent()
85 {
86 delete ndc;
87 delete mdcCopy;
88 delete properties;
89 }
90
getNDC(LogString & dest) const91 bool LoggingEvent::getNDC(LogString& dest) const
92 {
93 if (ndcLookupRequired)
94 {
95 ndcLookupRequired = false;
96 LogString val;
97
98 if (NDC::get(val))
99 {
100 ndc = new LogString(val);
101 }
102 }
103
104 if (ndc)
105 {
106 dest.append(*ndc);
107 return true;
108 }
109
110 return false;
111 }
112
getMDC(const LogString & key,LogString & dest) const113 bool LoggingEvent::getMDC(const LogString& key, LogString& dest) const
114 {
115 // Note the mdcCopy is used if it exists. Otherwise we use the MDC
116 // that is associated with the thread.
117 if (mdcCopy != 0 && !mdcCopy->empty())
118 {
119 MDC::Map::const_iterator it = mdcCopy->find(key);
120
121 if (it != mdcCopy->end())
122 {
123 if (!it->second.empty())
124 {
125 dest.append(it->second);
126 return true;
127 }
128 }
129 }
130
131 return MDC::get(key, dest);
132
133 }
134
getMDCKeySet() const135 LoggingEvent::KeySet LoggingEvent::getMDCKeySet() const
136 {
137 LoggingEvent::KeySet set;
138
139 if (mdcCopy != 0 && !mdcCopy->empty())
140 {
141 MDC::Map::const_iterator it;
142
143 for (it = mdcCopy->begin(); it != mdcCopy->end(); it++)
144 {
145 set.push_back(it->first);
146
147 }
148 }
149 else
150 {
151 ThreadSpecificData* data = ThreadSpecificData::getCurrentData();
152
153 if (data != 0)
154 {
155 MDC::Map& m = data->getMap();
156
157 for (MDC::Map::const_iterator it = m.begin(); it != m.end(); it++)
158 {
159 set.push_back(it->first);
160 }
161 }
162 }
163
164 return set;
165 }
166
getMDCCopy() const167 void LoggingEvent::getMDCCopy() const
168 {
169 if (mdcCopyLookupRequired)
170 {
171 mdcCopyLookupRequired = false;
172 // the clone call is required for asynchronous logging.
173 ThreadSpecificData* data = ThreadSpecificData::getCurrentData();
174
175 if (data != 0)
176 {
177 mdcCopy = new MDC::Map(data->getMap());
178 }
179 else
180 {
181 mdcCopy = new MDC::Map();
182 }
183 }
184 }
185
getProperty(const LogString & key,LogString & dest) const186 bool LoggingEvent::getProperty(const LogString& key, LogString& dest) const
187 {
188 if (properties == 0)
189 {
190 return false;
191 }
192
193 std::map<LogString, LogString>::const_iterator it = properties->find(key);
194
195 if (it != properties->end())
196 {
197 dest.append(it->second);
198 return true;
199 }
200
201 return false;
202 }
203
getPropertyKeySet() const204 LoggingEvent::KeySet LoggingEvent::getPropertyKeySet() const
205 {
206 LoggingEvent::KeySet set;
207
208 if (properties != 0)
209 {
210 std::map<LogString, LogString>::const_iterator it;
211
212 for (it = properties->begin(); it != properties->end(); it++)
213 {
214 set.push_back(it->first);
215 }
216 }
217
218 return set;
219 }
220
221
getCurrentThreadName()222 const LogString LoggingEvent::getCurrentThreadName()
223 {
224 #if APR_HAS_THREADS
225 #if defined(_WIN32)
226 char result[20];
227 DWORD threadId = GetCurrentThreadId();
228 apr_snprintf(result, sizeof(result), LOG4CXX_WIN32_THREAD_FMTSPEC, threadId);
229 #else
230 // apr_os_thread_t encoded in HEX takes needs as many characters
231 // as two times the size of the type, plus an additional null byte.
232 char result[sizeof(apr_os_thread_t) * 3 + 10];
233 apr_os_thread_t threadId = apr_os_thread_current();
234 apr_snprintf(result, sizeof(result), LOG4CXX_APR_THREAD_FMTSPEC, (void*) &threadId);
235 #endif
236 LOG4CXX_DECODE_CHAR(str, (const char*) result);
237 return str;
238 #else
239 return LOG4CXX_STR("0x00000000");
240 #endif
241 }
242
243
setProperty(const LogString & key,const LogString & value)244 void LoggingEvent::setProperty(const LogString& key, const LogString& value)
245 {
246 if (properties == 0)
247 {
248 properties = new std::map<LogString, LogString>;
249 }
250
251 (*properties)[key] = value;
252 }
253
254
255
writeProlog(ObjectOutputStream & os,Pool & p)256 void LoggingEvent::writeProlog(ObjectOutputStream& os, Pool& p)
257 {
258 unsigned char classDesc[] =
259 {
260 0x72, 0x00, 0x21,
261 0x6F, 0x72, 0x67, 0x2E, 0x61, 0x70, 0x61, 0x63,
262 0x68, 0x65, 0x2E, 0x6C, 0x6F, 0x67, 0x34, 0x6A,
263 0x2E, 0x73, 0x70, 0x69, 0x2E, 0x4C, 0x6F, 0x67,
264 0x67, 0x69, 0x6E, 0x67, 0x45, 0x76, 0x65, 0x6E,
265 0x74, 0xF3, 0xF2, 0xB9, 0x23, 0x74, 0x0B, 0xB5,
266 0x3F, 0x03, 0x00, 0x0A, 0x5A, 0x00, 0x15, 0x6D,
267 0x64, 0x63, 0x43, 0x6F, 0x70, 0x79, 0x4C, 0x6F,
268 0x6F, 0x6B, 0x75, 0x70, 0x52, 0x65, 0x71, 0x75,
269 0x69, 0x72, 0x65, 0x64, 0x5A, 0x00, 0x11, 0x6E,
270 0x64, 0x63, 0x4C, 0x6F, 0x6F, 0x6B, 0x75, 0x70,
271 0x52, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64,
272 0x4A, 0x00, 0x09, 0x74, 0x69, 0x6D, 0x65, 0x53,
273 0x74, 0x61, 0x6D, 0x70, 0x4C, 0x00, 0x0C, 0x63,
274 0x61, 0x74, 0x65, 0x67, 0x6F, 0x72, 0x79, 0x4E,
275 0x61, 0x6D, 0x65, 0x74, 0x00, 0x12, 0x4C, 0x6A,
276 0x61, 0x76, 0x61, 0x2F, 0x6C, 0x61, 0x6E, 0x67,
277 0x2F, 0x53, 0x74, 0x72, 0x69, 0x6E, 0x67, 0x3B,
278 0x4C, 0x00, 0x0C, 0x6C, 0x6F, 0x63, 0x61, 0x74,
279 0x69, 0x6F, 0x6E, 0x49, 0x6E, 0x66, 0x6F, 0x74,
280 0x00, 0x23, 0x4C, 0x6F, 0x72, 0x67, 0x2F, 0x61,
281 0x70, 0x61, 0x63, 0x68, 0x65, 0x2F, 0x6C, 0x6F,
282 0x67, 0x34, 0x6A, 0x2F, 0x73, 0x70, 0x69, 0x2F,
283 0x4C, 0x6F, 0x63, 0x61, 0x74, 0x69, 0x6F, 0x6E,
284 0x49, 0x6E, 0x66, 0x6F, 0x3B, 0x4C, 0x00, 0x07,
285 0x6D, 0x64, 0x63, 0x43, 0x6F, 0x70, 0x79, 0x74,
286 0x00, 0x15, 0x4C, 0x6A, 0x61, 0x76, 0x61, 0x2F,
287 0x75, 0x74, 0x69, 0x6C, 0x2F, 0x48, 0x61, 0x73,
288 0x68, 0x74, 0x61, 0x62, 0x6C, 0x65, 0x3B, 0x4C,
289 0x00, 0x03, 0x6E, 0x64, 0x63,
290 0x74, 0x00, 0x12, 0x4C, 0x6A,
291 0x61, 0x76, 0x61, 0x2F, 0x6C, 0x61, 0x6E, 0x67,
292 0x2F, 0x53, 0x74, 0x72, 0x69, 0x6E, 0x67, 0x3B,
293 0x4C, 0x00, 0x0F, 0x72, 0x65, 0x6E,
294 0x64, 0x65, 0x72, 0x65, 0x64, 0x4D, 0x65, 0x73,
295 0x73, 0x61, 0x67, 0x65,
296 0x74, 0x00, 0x12, 0x4C, 0x6A,
297 0x61, 0x76, 0x61, 0x2F, 0x6C, 0x61, 0x6E, 0x67,
298 0x2F, 0x53, 0x74, 0x72, 0x69, 0x6E, 0x67, 0x3B,
299 0x4C, 0x00, 0x0A, 0x74, 0x68, 0x72, 0x65,
300 0x61, 0x64, 0x4E, 0x61, 0x6D, 0x65,
301 0x74, 0x00, 0x12, 0x4C, 0x6A,
302 0x61, 0x76, 0x61, 0x2F, 0x6C, 0x61, 0x6E, 0x67,
303 0x2F, 0x53, 0x74, 0x72, 0x69, 0x6E, 0x67, 0x3B,
304 0x4C, 0x00, 0x0D, 0x74, 0x68,
305 0x72, 0x6F, 0x77, 0x61, 0x62, 0x6C, 0x65, 0x49,
306 0x6E, 0x66, 0x6F, 0x74, 0x00, 0x2B, 0x4C, 0x6F,
307 0x72, 0x67, 0x2F, 0x61, 0x70, 0x61, 0x63, 0x68,
308 0x65, 0x2F, 0x6C, 0x6F, 0x67, 0x34, 0x6A, 0x2F,
309 0x73, 0x70, 0x69, 0x2F, 0x54, 0x68, 0x72, 0x6F,
310 0x77, 0x61, 0x62, 0x6C, 0x65, 0x49, 0x6E, 0x66,
311 0x6F, 0x72, 0x6D, 0x61, 0x74, 0x69, 0x6F, 0x6E,
312 0x3B, 0x78, 0x70
313 };
314
315 os.writeProlog("org.apache.log4j.spi.LoggingEvent",
316 8, (char*) classDesc, sizeof(classDesc), p);
317 }
318
write(helpers::ObjectOutputStream & os,Pool & p) const319 void LoggingEvent::write(helpers::ObjectOutputStream& os, Pool& p) const
320 {
321 writeProlog(os, p);
322 // mdc and ndc lookup required should always be false
323 char lookupsRequired[] = { 0, 0 };
324 os.writeBytes(lookupsRequired, sizeof(lookupsRequired), p);
325 os.writeLong(timeStamp / 1000, p);
326 os.writeObject(logger, p);
327 locationInfo.write(os, p);
328
329 if (mdcCopy == 0 || mdcCopy->size() == 0)
330 {
331 os.writeNull(p);
332 }
333 else
334 {
335 os.writeObject(*mdcCopy, p);
336 }
337
338 if (ndc == 0)
339 {
340 os.writeNull(p);
341 }
342 else
343 {
344 os.writeObject(*ndc, p);
345 }
346
347 os.writeObject(message, p);
348 os.writeObject(threadName, p);
349 // throwable
350 os.writeNull(p);
351 os.writeByte(ObjectOutputStream::TC_BLOCKDATA, p);
352 os.writeByte(0x04, p);
353 os.writeInt(level->toInt(), p);
354 os.writeNull(p);
355 os.writeByte(ObjectOutputStream::TC_ENDBLOCKDATA, p);
356 }
357
358