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