1 #region Copyright & License
2 //
3 // Copyright 2001-2005 The Apache Software Foundation
4 //
5 // Licensed under the Apache License, Version 2.0 (the "License");
6 // you may not use this file except in compliance with the License.
7 // 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 #endregion
18 
19 using System;
20 using System.Runtime.Serialization;
21 using System.Collections;
22 using System.IO;
23 #if (!NETCF)
24 using System.Security.Principal;
25 #endif
26 
27 using log4net.Util;
28 using log4net.Repository;
29 
30 namespace log4net.Core
31 {
32 	/// <summary>
33 	/// Portable data structure used by <see cref="LoggingEvent"/>
34 	/// </summary>
35 	/// <remarks>
36 	/// <para>
37 	/// Portable data structure used by <see cref="LoggingEvent"/>
38 	/// </para>
39 	/// </remarks>
40 	/// <author>Nicko Cadell</author>
41 	public struct LoggingEventData
42 	{
43 		#region Public Instance Fields
44 
45 		/// <summary>
46 		/// The logger name.
47 		/// </summary>
48 		/// <remarks>
49 		/// <para>
50 		/// The logger name.
51 		/// </para>
52 		/// </remarks>
53 		public string LoggerName;
54 
55 		/// <summary>
56 		/// Level of logging event.
57 		/// </summary>
58 		/// <remarks>
59 		/// <para>
60 		/// Level of logging event. Level cannot be Serializable
61 		/// because it is a flyweight.  Due to its special serialization it
62 		/// cannot be declared final either.
63 		/// </para>
64 		/// </remarks>
65 		public Level Level;
66 
67 		/// <summary>
68 		/// The application supplied message.
69 		/// </summary>
70 		/// <remarks>
71 		/// <para>
72 		/// The application supplied message of logging event.
73 		/// </para>
74 		/// </remarks>
75 		public string Message;
76 
77 		/// <summary>
78 		/// The name of thread
79 		/// </summary>
80 		/// <remarks>
81 		/// <para>
82 		/// The name of thread in which this logging event was generated
83 		/// </para>
84 		/// </remarks>
85 		public string ThreadName;
86 
87 		/// <summary>
88 		/// The time the event was logged
89 		/// </summary>
90 		/// <remarks>
91 		/// <para>
92 		/// The TimeStamp is stored in the local time zone for this computer.
93 		/// </para>
94 		/// </remarks>
95 		public DateTime TimeStamp;
96 
97 		/// <summary>
98 		/// Location information for the caller.
99 		/// </summary>
100 		/// <remarks>
101 		/// <para>
102 		/// Location information for the caller.
103 		/// </para>
104 		/// </remarks>
105 		public LocationInfo LocationInfo;
106 
107 		/// <summary>
108 		/// String representation of the user
109 		/// </summary>
110 		/// <remarks>
111 		/// <para>
112 		/// String representation of the user's windows name,
113 		/// like DOMAIN\username
114 		/// </para>
115 		/// </remarks>
116 		public string UserName;
117 
118 		/// <summary>
119 		/// String representation of the identity.
120 		/// </summary>
121 		/// <remarks>
122 		/// <para>
123 		/// String representation of the current thread's principal identity.
124 		/// </para>
125 		/// </remarks>
126 		public string Identity;
127 
128 		/// <summary>
129 		/// The string representation of the exception
130 		/// </summary>
131 		/// <remarks>
132 		/// <para>
133 		/// The string representation of the exception
134 		/// </para>
135 		/// </remarks>
136 		public string ExceptionString;
137 
138 		/// <summary>
139 		/// String representation of the AppDomain.
140 		/// </summary>
141 		/// <remarks>
142 		/// <para>
143 		/// String representation of the AppDomain.
144 		/// </para>
145 		/// </remarks>
146 		public string Domain;
147 
148 		/// <summary>
149 		/// Additional event specific properties
150 		/// </summary>
151 		/// <remarks>
152 		/// <para>
153 		/// A logger or an appender may attach additional
154 		/// properties to specific events. These properties
155 		/// have a string key and an object value.
156 		/// </para>
157 		/// </remarks>
158 		public PropertiesDictionary Properties;
159 
160 		#endregion Public Instance Fields
161 	}
162 
163 	/// <summary>
164 	/// Flags passed to the <see cref="LoggingEvent.Fix"/> property
165 	/// </summary>
166 	/// <remarks>
167 	/// <para>
168 	/// Flags passed to the <see cref="LoggingEvent.Fix"/> property
169 	/// </para>
170 	/// </remarks>
171 	/// <author>Nicko Cadell</author>
172 	[Flags] public enum FixFlags
173 	{
174 		/// <summary>
175 		/// Fix the MDC
176 		/// </summary>
177 		[Obsolete("Replaced by composite Properties")]
178 		Mdc = 0x01,
179 
180 		/// <summary>
181 		/// Fix the NDC
182 		/// </summary>
183 		Ndc = 0x02,
184 
185 		/// <summary>
186 		/// Fix the rendered message
187 		/// </summary>
188 		Message = 0x04,
189 
190 		/// <summary>
191 		/// Fix the thread name
192 		/// </summary>
193 		ThreadName = 0x08,
194 
195 		/// <summary>
196 		/// Fix the callers location information
197 		/// </summary>
198 		/// <remarks>
199 		/// CAUTION: Very slow to generate
200 		/// </remarks>
201 		LocationInfo = 0x10,
202 
203 		/// <summary>
204 		/// Fix the callers windows user name
205 		/// </summary>
206 		/// <remarks>
207 		/// CAUTION: Slow to generate
208 		/// </remarks>
209 		UserName = 0x20,
210 
211 		/// <summary>
212 		/// Fix the domain friendly name
213 		/// </summary>
214 		Domain = 0x40,
215 
216 		/// <summary>
217 		/// Fix the callers principal name
218 		/// </summary>
219 		/// <remarks>
220 		/// CAUTION: May be slow to generate
221 		/// </remarks>
222 		Identity = 0x80,
223 
224 		/// <summary>
225 		/// Fix the exception text
226 		/// </summary>
227 		Exception = 0x100,
228 
229 		/// <summary>
230 		/// Fix the event properties
231 		/// </summary>
232 		Properties = 0x200,
233 
234 		/// <summary>
235 		/// No fields fixed
236 		/// </summary>
237 		None = 0x0,
238 
239 		/// <summary>
240 		/// All fields fixed
241 		/// </summary>
242 		All = 0xFFFFFFF,
243 
244 		/// <summary>
245 		/// Partial fields fixed
246 		/// </summary>
247 		/// <remarks>
248 		/// <para>
249 		/// This set of partial fields gives good performance. The following fields are fixed:
250 		/// </para>
251 		/// <list type="bullet">
252 		/// <item><description><see cref="Message"/></description></item>
253 		/// <item><description><see cref="ThreadName"/></description></item>
254 		/// <item><description><see cref="Exception"/></description></item>
255 		/// <item><description><see cref="Domain"/></description></item>
256 		/// <item><description><see cref="Properties"/></description></item>
257 		/// </list>
258 		/// </remarks>
259 		Partial = Message | ThreadName | Exception | Domain | Properties,
260 	}
261 
262 	/// <summary>
263 	/// The internal representation of logging events.
264 	/// </summary>
265 	/// <remarks>
266 	/// <para>
267 	/// When an affirmative decision is made to log then a
268 	/// <see cref="LoggingEvent"/> instance is created. This instance
269 	/// is passed around to the different log4net components.
270 	/// </para>
271 	/// <para>
272 	/// This class is of concern to those wishing to extend log4net.
273 	/// </para>
274 	/// <para>
275 	/// Some of the values in instances of <see cref="LoggingEvent"/>
276 	/// are considered volatile, that is the values are correct at the
277 	/// time the event is delivered to appenders, but will not be consistent
278 	/// at any time afterwards. If an event is to be stored and then processed
279 	/// at a later time these volatile values must be fixed by calling
280 	/// <see cref="FixVolatileData()"/>. There is a performance penalty
281 	/// for incurred by calling <see cref="FixVolatileData()"/> but it
282 	/// is essential to maintaining data consistency.
283 	/// </para>
284 	/// </remarks>
285 	/// <author>Nicko Cadell</author>
286 	/// <author>Gert Driesen</author>
287 	/// <author>Douglas de la Torre</author>
288 	/// <author>Daniel Cazzulino</author>
289 #if !NETCF
290 	[Serializable]
291 #endif
292 	public class LoggingEvent
293 #if !NETCF
294 		: ISerializable
295 #endif
296 	{
297 		#region Public Instance Constructors
298 
299 		/// <summary>
300 		/// Initializes a new instance of the <see cref="LoggingEvent" /> class
301 		/// from the supplied parameters.
302 		/// </summary>
303 		/// <param name="callerStackBoundaryDeclaringType">The declaring type of the method that is
304 		/// the stack boundary into the logging system for this call.</param>
305 		/// <param name="repository">The repository this event is logged in.</param>
306 		/// <param name="loggerName">The name of the logger of this event.</param>
307 		/// <param name="level">The level of this event.</param>
308 		/// <param name="message">The message of this event.</param>
309 		/// <param name="exception">The exception for this event.</param>
310 		/// <remarks>
311 		/// <para>
312 		/// Except <see cref="TimeStamp"/>, <see cref="Level"/> and <see cref="LoggerName"/>,
313 		/// all fields of <c>LoggingEvent</c> are filled when actually needed. Call
314 		/// <see cref="FixVolatileData()"/> to cache all data locally
315 		/// to prevent inconsistencies.
316 		/// </para>
317 		/// <para>This method is called by the log4net framework
318 		/// to create a logging event.
319 		/// </para>
320 		/// </remarks>
LoggingEvent(Type callerStackBoundaryDeclaringType, log4net.Repository.ILoggerRepository repository, string loggerName, Level level, object message, Exception exception)321 		public LoggingEvent(Type callerStackBoundaryDeclaringType, log4net.Repository.ILoggerRepository repository, string loggerName, Level level, object message, Exception exception)
322 		{
323 			m_callerStackBoundaryDeclaringType = callerStackBoundaryDeclaringType;
324 			m_message = message;
325 			m_repository = repository;
326 			m_thrownException = exception;
327 
328 			m_data.LoggerName = loggerName;
329 			m_data.Level = level;
330 
331 			// Store the event creation time
332 			m_data.TimeStamp = DateTime.Now;
333 		}
334 
335 		/// <summary>
336 		/// Initializes a new instance of the <see cref="LoggingEvent" /> class
337 		/// using specific data.
338 		/// </summary>
339 		/// <param name="callerStackBoundaryDeclaringType">The declaring type of the method that is
340 		/// the stack boundary into the logging system for this call.</param>
341 		/// <param name="repository">The repository this event is logged in.</param>
342 		/// <param name="data">Data used to initialize the logging event.</param>
343 		/// <param name="fixedData">The fields in the <paranref name="data"/> struct that have already been fixed.</param>
344 		/// <remarks>
345 		/// <para>
346 		/// This constructor is provided to allow a <see cref="LoggingEvent" />
347 		/// to be created independently of the log4net framework. This can
348 		/// be useful if you require a custom serialization scheme.
349 		/// </para>
350 		/// <para>
351 		/// Use the <see cref="GetLoggingEventData(FixFlags)"/> method to obtain an
352 		/// instance of the <see cref="LoggingEventData"/> class.
353 		/// </para>
354 		/// <para>
355 		/// The <paramref name="fixedData"/> parameter should be used to specify which fields in the
356 		/// <paramref name="data"/> struct have been preset. Fields not specified in the <paramref name="fixedData"/>
357 		/// will be captured from the environment if requested or fixed.
358 		/// </para>
359 		/// </remarks>
LoggingEvent(Type callerStackBoundaryDeclaringType, log4net.Repository.ILoggerRepository repository, LoggingEventData data, FixFlags fixedData)360 		public LoggingEvent(Type callerStackBoundaryDeclaringType, log4net.Repository.ILoggerRepository repository, LoggingEventData data, FixFlags fixedData)
361 		{
362 			m_callerStackBoundaryDeclaringType = callerStackBoundaryDeclaringType;
363 			m_repository = repository;
364 
365 			m_data = data;
366 			m_fixFlags = fixedData;
367 		}
368 
369 		/// <summary>
370 		/// Initializes a new instance of the <see cref="LoggingEvent" /> class
371 		/// using specific data.
372 		/// </summary>
373 		/// <param name="callerStackBoundaryDeclaringType">The declaring type of the method that is
374 		/// the stack boundary into the logging system for this call.</param>
375 		/// <param name="repository">The repository this event is logged in.</param>
376 		/// <param name="data">Data used to initialize the logging event.</param>
377 		/// <remarks>
378 		/// <para>
379 		/// This constructor is provided to allow a <see cref="LoggingEvent" />
380 		/// to be created independently of the log4net framework. This can
381 		/// be useful if you require a custom serialization scheme.
382 		/// </para>
383 		/// <para>
384 		/// Use the <see cref="GetLoggingEventData(FixFlags)"/> method to obtain an
385 		/// instance of the <see cref="LoggingEventData"/> class.
386 		/// </para>
387 		/// <para>
388 		/// This constructor sets this objects <see cref="Fix"/> flags to <see cref="FixFlags.All"/>,
389 		/// this assumes that all the data relating to this event is passed in via the <paramref name="data"/>
390 		/// parameter and no other data should be captured from the environment.
391 		/// </para>
392 		/// </remarks>
LoggingEvent(Type callerStackBoundaryDeclaringType, log4net.Repository.ILoggerRepository repository, LoggingEventData data)393 		public LoggingEvent(Type callerStackBoundaryDeclaringType, log4net.Repository.ILoggerRepository repository, LoggingEventData data) : this(callerStackBoundaryDeclaringType, repository, data, FixFlags.All)
394 		{
395 		}
396 
397 		/// <summary>
398 		/// Initializes a new instance of the <see cref="LoggingEvent" /> class
399 		/// using specific data.
400 		/// </summary>
401 		/// <param name="data">Data used to initialize the logging event.</param>
402 		/// <remarks>
403 		/// <para>
404 		/// This constructor is provided to allow a <see cref="LoggingEvent" />
405 		/// to be created independently of the log4net framework. This can
406 		/// be useful if you require a custom serialization scheme.
407 		/// </para>
408 		/// <para>
409 		/// Use the <see cref="GetLoggingEventData(FixFlags)"/> method to obtain an
410 		/// instance of the <see cref="LoggingEventData"/> class.
411 		/// </para>
412 		/// <para>
413 		/// This constructor sets this objects <see cref="Fix"/> flags to <see cref="FixFlags.All"/>,
414 		/// this assumes that all the data relating to this event is passed in via the <paramref name="data"/>
415 		/// parameter and no other data should be captured from the environment.
416 		/// </para>
417 		/// </remarks>
LoggingEvent(LoggingEventData data)418 		public LoggingEvent(LoggingEventData data) : this(null, null, data)
419 		{
420 		}
421 
422 		#endregion Public Instance Constructors
423 
424 		#region Protected Instance Constructors
425 
426 #if !NETCF
427 
428 		/// <summary>
429 		/// Serialization constructor
430 		/// </summary>
431 		/// <param name="info">The <see cref="SerializationInfo" /> that holds the serialized object data.</param>
432 		/// <param name="context">The <see cref="StreamingContext" /> that contains contextual information about the source or destination.</param>
433 		/// <remarks>
434 		/// <para>
435 		/// Initializes a new instance of the <see cref="LoggingEvent" /> class
436 		/// with serialized data.
437 		/// </para>
438 		/// </remarks>
LoggingEvent(SerializationInfo info, StreamingContext context)439 		protected LoggingEvent(SerializationInfo info, StreamingContext context)
440 		{
441 			m_data.LoggerName = info.GetString("LoggerName");
442 
443 			// Note we are deserializing the whole level object. That is the
444 			// name and the value. This value is correct for the source
445 			// hierarchy but may not be for the target hierarchy that this
446 			// event may be re-logged into. If it is to be re-logged it may
447 			// be necessary to re-lookup the level based only on the name.
448 			m_data.Level = (Level)info.GetValue("Level", typeof(Level));
449 
450 			m_data.Message = info.GetString("Message");
451 			m_data.ThreadName = info.GetString("ThreadName");
452 			m_data.TimeStamp = info.GetDateTime("TimeStamp");
453 			m_data.LocationInfo = (LocationInfo) info.GetValue("LocationInfo", typeof(LocationInfo));
454 			m_data.UserName = info.GetString("UserName");
455 			m_data.ExceptionString = info.GetString("ExceptionString");
456 			m_data.Properties = (PropertiesDictionary) info.GetValue("Properties", typeof(PropertiesDictionary));
457 			m_data.Domain = info.GetString("Domain");
458 			m_data.Identity = info.GetString("Identity");
459 
460 			// We have restored all the values of this instance, i.e. all the values are fixed
461 			// Set the fix flags otherwise the data values may be overwritten from the current environment.
462 			m_fixFlags = FixFlags.All;
463 		}
464 
465 #endif
466 
467 		#endregion Protected Instance Constructors
468 
469 		#region Public Instance Properties
470 
471 		/// <summary>
472 		/// Gets the time when the current process started.
473 		/// </summary>
474 		/// <value>
475 		/// This is the time when this process started.
476 		/// </value>
477 		/// <remarks>
478 		/// <para>
479 		/// The TimeStamp is stored in the local time zone for this computer.
480 		/// </para>
481 		/// <para>
482 		/// Tries to get the start time for the current process.
483 		/// Failing that it returns the time of the first call to
484 		/// this property.
485 		/// </para>
486 		/// <para>
487 		/// Note that AppDomains may be loaded and unloaded within the
488 		/// same process without the process terminating and therefore
489 		/// without the process start time being reset.
490 		/// </para>
491 		/// </remarks>
492 		public static DateTime StartTime
493 		{
494 			get { return SystemInfo.ProcessStartTime; }
495 		}
496 
497 		/// <summary>
498 		/// Gets the <see cref="Level" /> of the logging event.
499 		/// </summary>
500 		/// <value>
501 		/// The <see cref="Level" /> of the logging event.
502 		/// </value>
503 		/// <remarks>
504 		/// <para>
505 		/// Gets the <see cref="Level" /> of the logging event.
506 		/// </para>
507 		/// </remarks>
508 		public Level Level
509 		{
510 			get { return m_data.Level; }
511 		}
512 
513 		/// <summary>
514 		/// Gets the time of the logging event.
515 		/// </summary>
516 		/// <value>
517 		/// The time of the logging event.
518 		/// </value>
519 		/// <remarks>
520 		/// <para>
521 		/// The TimeStamp is stored in the local time zone for this computer.
522 		/// </para>
523 		/// </remarks>
524 		public DateTime TimeStamp
525 		{
526 			get { return m_data.TimeStamp; }
527 		}
528 
529 		/// <summary>
530 		/// Gets the name of the logger that logged the event.
531 		/// </summary>
532 		/// <value>
533 		/// The name of the logger that logged the event.
534 		/// </value>
535 		/// <remarks>
536 		/// <para>
537 		/// Gets the name of the logger that logged the event.
538 		/// </para>
539 		/// </remarks>
540 		public string LoggerName
541 		{
542 			get { return m_data.LoggerName; }
543 		}
544 
545 		/// <summary>
546 		/// Gets the location information for this logging event.
547 		/// </summary>
548 		/// <value>
549 		/// The location information for this logging event.
550 		/// </value>
551 		/// <remarks>
552 		/// <para>
553 		/// The collected information is cached for future use.
554 		/// </para>
555 		/// <para>
556 		/// See the <see cref="LocationInfo"/> class for more information on
557 		/// supported frameworks and the different behavior in Debug and
558 		/// Release builds.
559 		/// </para>
560 		/// </remarks>
561 		public LocationInfo LocationInformation
562 		{
563 			get
564 			{
565 				if (m_data.LocationInfo == null  && this.m_cacheUpdatable)
566 				{
567 					m_data.LocationInfo = new LocationInfo(m_callerStackBoundaryDeclaringType);
568 				}
569 				return m_data.LocationInfo;
570 			}
571 		}
572 
573 		/// <summary>
574 		/// Gets the message object used to initialize this event.
575 		/// </summary>
576 		/// <value>
577 		/// The message object used to initialize this event.
578 		/// </value>
579 		/// <remarks>
580 		/// <para>
581 		/// Gets the message object used to initialize this event.
582 		/// Note that this event may not have a valid message object.
583 		/// If the event is serialized the message object will not
584 		/// be transferred. To get the text of the message the
585 		/// <see cref="RenderedMessage"/> property must be used
586 		/// not this property.
587 		/// </para>
588 		/// <para>
589 		/// If there is no defined message object for this event then
590 		/// null will be returned.
591 		/// </para>
592 		/// </remarks>
593 		public object MessageObject
594 		{
595 			get { return m_message; }
596 		}
597 
598 		/// <summary>
599 		/// Gets the exception object used to initialize this event.
600 		/// </summary>
601 		/// <value>
602 		/// The exception object used to initialize this event.
603 		/// </value>
604 		/// <remarks>
605 		/// <para>
606 		/// Gets the exception object used to initialize this event.
607 		/// Note that this event may not have a valid exception object.
608 		/// If the event is serialized the exception object will not
609 		/// be transferred. To get the text of the exception the
610 		/// <see cref="GetExceptionString"/> method must be used
611 		/// not this property.
612 		/// </para>
613 		/// <para>
614 		/// If there is no defined exception object for this event then
615 		/// null will be returned.
616 		/// </para>
617 		/// </remarks>
618 		public Exception ExceptionObject
619 		{
620 			get { return m_thrownException; }
621 		}
622 
623 		/// <summary>
624 		/// The <see cref="ILoggerRepository"/> that this event was created in.
625 		/// </summary>
626 		/// <remarks>
627 		/// <para>
628 		/// The <see cref="ILoggerRepository"/> that this event was created in.
629 		/// </para>
630 		/// </remarks>
631 		public ILoggerRepository Repository
632 		{
633 			get { return m_repository; }
634 		}
635 
636 		/// <summary>
637 		/// Ensure that the repository is set.
638 		/// </summary>
639 		/// <param name="repository">the value for the repository</param>
EnsureRepository(ILoggerRepository repository)640 		internal void EnsureRepository(ILoggerRepository repository)
641 		{
642 			if (repository != null)
643 			{
644 				m_repository = repository;
645 			}
646 		}
647 
648 		/// <summary>
649 		/// Gets the message, rendered through the <see cref="ILoggerRepository.RendererMap" />.
650 		/// </summary>
651 		/// <value>
652 		/// The message rendered through the <see cref="ILoggerRepository.RendererMap" />.
653 		/// </value>
654 		/// <remarks>
655 		/// <para>
656 		/// The collected information is cached for future use.
657 		/// </para>
658 		/// </remarks>
659 		public string RenderedMessage
660 		{
661 			get
662 			{
663 				if (m_data.Message == null && this.m_cacheUpdatable)
664 				{
665 					if (m_message == null)
666 					{
667 						m_data.Message = "";
668 					}
669 					else if (m_message is string)
670 					{
671 						m_data.Message = (m_message as string);
672 					}
673 					else if (m_repository != null)
674 					{
675 						m_data.Message = m_repository.RendererMap.FindAndRender(m_message);
676 					}
677 					else
678 					{
679 						// Very last resort
680 						m_data.Message = m_message.ToString();
681 					}
682 				}
683 				return m_data.Message;
684 			}
685 		}
686 
687 		/// <summary>
688 		/// Write the rendered message to a TextWriter
689 		/// </summary>
690 		/// <param name="writer">the writer to write the message to</param>
691 		/// <remarks>
692 		/// <para>
693 		/// Unlike the <see cref="RenderedMessage"/> property this method
694 		/// does store the message data in the internal cache. Therefore
695 		/// if called only once this method should be faster than the
696 		/// <see cref="RenderedMessage"/> property, however if the message is
697 		/// to be accessed multiple times then the property will be more efficient.
698 		/// </para>
699 		/// </remarks>
WriteRenderedMessage(TextWriter writer)700 		public void WriteRenderedMessage(TextWriter writer)
701 		{
702 			if (m_data.Message != null)
703 			{
704 				writer.Write(m_data.Message);
705 			}
706 			else
707 			{
708 				if (m_message != null)
709 				{
710 					if (m_message is string)
711 					{
712 						writer.Write(m_message as string);
713 					}
714 					else if (m_repository != null)
715 					{
716 						m_repository.RendererMap.FindAndRender(m_message, writer);
717 					}
718 					else
719 					{
720 						// Very last resort
721 						writer.Write(m_message.ToString());
722 					}
723 				}
724 			}
725 		}
726 
727 		/// <summary>
728 		/// Gets the name of the current thread.
729 		/// </summary>
730 		/// <value>
731 		/// The name of the current thread, or the thread ID when
732 		/// the name is not available.
733 		/// </value>
734 		/// <remarks>
735 		/// <para>
736 		/// The collected information is cached for future use.
737 		/// </para>
738 		/// </remarks>
739 		public string ThreadName
740 		{
741 			get
742 			{
743 				if (m_data.ThreadName == null && this.m_cacheUpdatable)
744 				{
745 #if NETCF
746 					// Get thread ID only
747 					m_data.ThreadName = SystemInfo.CurrentThreadId.ToString(System.Globalization.NumberFormatInfo.InvariantInfo);
748 #else
749 					m_data.ThreadName = System.Threading.Thread.CurrentThread.Name;
750 					if (m_data.ThreadName == null || m_data.ThreadName.Length == 0)
751 					{
752 						// The thread name is not available. Therefore we
753 						// go the the AppDomain to get the ID of the
754 						// current thread. (Why don't Threads know their own ID?)
755 						try
756 						{
757 							m_data.ThreadName = SystemInfo.CurrentThreadId.ToString(System.Globalization.NumberFormatInfo.InvariantInfo);
758 						}
759 						catch(System.Security.SecurityException)
760 						{
761 							// This security exception will occur if the caller does not have
762 							// some undefined set of SecurityPermission flags.
763 							LogLog.Debug("LoggingEvent: Security exception while trying to get current thread ID. Error Ignored. Empty thread name.");
764 
765 							// As a last resort use the hash code of the Thread object
766 							m_data.ThreadName = System.Threading.Thread.CurrentThread.GetHashCode().ToString(System.Globalization.CultureInfo.InvariantCulture);
767 						}
768 					}
769 #endif
770 				}
771 				return m_data.ThreadName;
772 			}
773 		}
774 
775 		/// <summary>
776 		/// Gets the name of the current user.
777 		/// </summary>
778 		/// <value>
779 		/// The name of the current user, or <c>NOT AVAILABLE</c> when the
780 		/// underlying runtime has no support for retrieving the name of the
781 		/// current user.
782 		/// </value>
783 		/// <remarks>
784 		/// <para>
785 		/// Calls <c>WindowsIdentity.GetCurrent().Name</c> to get the name of
786 		/// the current windows user.
787 		/// </para>
788 		/// <para>
789 		/// To improve performance, we could cache the string representation of
790 		/// the name, and reuse that as long as the identity stayed constant.
791 		/// Once the identity changed, we would need to re-assign and re-render
792 		/// the string.
793 		/// </para>
794 		/// <para>
795 		/// However, the <c>WindowsIdentity.GetCurrent()</c> call seems to
796 		/// return different objects every time, so the current implementation
797 		/// doesn't do this type of caching.
798 		/// </para>
799 		/// <para>
800 		/// Timing for these operations:
801 		/// </para>
802 		/// <list type="table">
803 		///   <listheader>
804 		///     <term>Method</term>
805 		///     <description>Results</description>
806 		///   </listheader>
807 		///   <item>
808 		///	    <term><c>WindowsIdentity.GetCurrent()</c></term>
809 		///	    <description>10000 loops, 00:00:00.2031250 seconds</description>
810 		///   </item>
811 		///   <item>
812 		///	    <term><c>WindowsIdentity.GetCurrent().Name</c></term>
813 		///	    <description>10000 loops, 00:00:08.0468750 seconds</description>
814 		///   </item>
815 		/// </list>
816 		/// <para>
817 		/// This means we could speed things up almost 40 times by caching the
818 		/// value of the <c>WindowsIdentity.GetCurrent().Name</c> property, since
819 		/// this takes (8.04-0.20) = 7.84375 seconds.
820 		/// </para>
821 		/// </remarks>
822 		public string UserName
823 		{
824 			get
825 			{
826 				if (m_data.UserName == null  && this.m_cacheUpdatable)
827 				{
828 #if (NETCF || SSCLI)
829 					// On compact framework there's no notion of current Windows user
830 					m_data.UserName = SystemInfo.NotAvailableText;
831 #else
832 					try
833 					{
834 						WindowsIdentity windowsIdentity = WindowsIdentity.GetCurrent();
835 						if (windowsIdentity != null && windowsIdentity.Name != null)
836 						{
837 							m_data.UserName = windowsIdentity.Name;
838 						}
839 						else
840 						{
841 							m_data.UserName = "";
842 						}
843 					}
844 					catch(System.Security.SecurityException)
845 					{
846 						// This security exception will occur if the caller does not have
847 						// some undefined set of SecurityPermission flags.
848 						LogLog.Debug("LoggingEvent: Security exception while trying to get current windows identity. Error Ignored. Empty user name.");
849 
850 						m_data.UserName = "";
851 					}
852 #endif
853 				}
854 				return m_data.UserName;
855 			}
856 		}
857 
858 		/// <summary>
859 		/// Gets the identity of the current thread principal.
860 		/// </summary>
861 		/// <value>
862 		/// The string name of the identity of the current thread principal.
863 		/// </value>
864 		/// <remarks>
865 		/// <para>
866 		/// Calls <c>System.Threading.Thread.CurrentPrincipal.Identity.Name</c> to get
867 		/// the name of the current thread principal.
868 		/// </para>
869 		/// </remarks>
870 		public string Identity
871 		{
872 			get
873 			{
874 				if (m_data.Identity == null  && this.m_cacheUpdatable)
875 				{
876 #if (NETCF || SSCLI)
877 					// On compact framework there's no notion of current thread principals
878 					m_data.Identity = SystemInfo.NotAvailableText;
879 #else
880 					try
881 					{
882 						if (System.Threading.Thread.CurrentPrincipal != null &&
883 							System.Threading.Thread.CurrentPrincipal.Identity != null &&
884 							System.Threading.Thread.CurrentPrincipal.Identity.Name != null)
885 						{
886 							m_data.Identity = System.Threading.Thread.CurrentPrincipal.Identity.Name;
887 						}
888 						else
889 						{
890 							m_data.Identity = "";
891 						}
892 					}
893 					catch(System.Security.SecurityException)
894 					{
895 						// This security exception will occur if the caller does not have
896 						// some undefined set of SecurityPermission flags.
897 						LogLog.Debug("LoggingEvent: Security exception while trying to get current thread principal. Error Ignored. Empty identity name.");
898 
899 						m_data.Identity = "";
900 					}
901 #endif
902 				}
903 				return m_data.Identity;
904 			}
905 		}
906 
907 		/// <summary>
908 		/// Gets the AppDomain friendly name.
909 		/// </summary>
910 		/// <value>
911 		/// The AppDomain friendly name.
912 		/// </value>
913 		/// <remarks>
914 		/// <para>
915 		/// Gets the AppDomain friendly name.
916 		/// </para>
917 		/// </remarks>
918 		public string Domain
919 		{
920 			get
921 			{
922 				if (m_data.Domain == null  && this.m_cacheUpdatable)
923 				{
924 					m_data.Domain = SystemInfo.ApplicationFriendlyName;
925 				}
926 				return m_data.Domain;
927 			}
928 		}
929 
930 		/// <summary>
931 		/// Additional event specific properties.
932 		/// </summary>
933 		/// <value>
934 		/// Additional event specific properties.
935 		/// </value>
936 		/// <remarks>
937 		/// <para>
938 		/// A logger or an appender may attach additional
939 		/// properties to specific events. These properties
940 		/// have a string key and an object value.
941 		/// </para>
942 		/// <para>
943 		/// This property is for events that have been added directly to
944 		/// this event. The aggregate properties (which include these
945 		/// event properties) can be retrieved using <see cref="LookupProperty"/>
946 		/// and <see cref="GetProperties"/>.
947 		/// </para>
948 		/// <para>
949 		/// Once the properties have been fixed <see cref="Fix"/> this property
950 		/// returns the combined cached properties. This ensures that updates to
951 		/// this property are always reflected in the underlying storage. When
952 		/// returning the combined properties there may be more keys in the
953 		/// Dictionary than expected.
954 		/// </para>
955 		/// </remarks>
956 		public PropertiesDictionary Properties
957 		{
958 			get
959 			{
960 				// If we have cached properties then return that otherwise changes will be lost
961 				if (m_data.Properties != null)
962 				{
963 					return m_data.Properties;
964 				}
965 
966 				if (m_eventProperties == null)
967 				{
968 					m_eventProperties = new PropertiesDictionary();
969 				}
970 				return m_eventProperties;
971 			}
972 		}
973 
974 		/// <summary>
975 		/// The fixed fields in this event
976 		/// </summary>
977 		/// <value>
978 		/// The set of fields that are fixed in this event
979 		/// </value>
980 		/// <remarks>
981 		/// <para>
982 		/// Fields will not be fixed if they have previously been fixed.
983 		/// It is not possible to 'unfix' a field.
984 		/// </para>
985 		/// </remarks>
986 		public FixFlags Fix
987 		{
988 			get { return m_fixFlags; }
989 			set { this.FixVolatileData(value); }
990 		}
991 
992 		#endregion Public Instance Properties
993 
994 		#region Implementation of ISerializable
995 
996 #if !NETCF
997 
998 		/// <summary>
999 		/// Serializes this object into the <see cref="SerializationInfo" /> provided.
1000 		/// </summary>
1001 		/// <param name="info">The <see cref="SerializationInfo" /> to populate with data.</param>
1002 		/// <param name="context">The destination for this serialization.</param>
1003 		/// <remarks>
1004 		/// <para>
1005 		/// The data in this event must be fixed before it can be serialized.
1006 		/// </para>
1007 		/// <para>
1008 		/// The <see cref="FixVolatileData()"/> method must be called during the
1009 		/// <see cref="log4net.Appender.IAppender.DoAppend"/> method call if this event
1010 		/// is to be used outside that method.
1011 		/// </para>
1012 		/// </remarks>
1013 		[System.Security.Permissions.SecurityPermissionAttribute(System.Security.Permissions.SecurityAction.Demand, SerializationFormatter=true)]
GetObjectData(SerializationInfo info, StreamingContext context)1014 		public virtual void GetObjectData(SerializationInfo info, StreamingContext context)
1015 		{
1016 			// The caller must call FixVolatileData before this object
1017 			// can be serialized.
1018 
1019 			info.AddValue("LoggerName", m_data.LoggerName);
1020 			info.AddValue("Level", m_data.Level);
1021 			info.AddValue("Message", m_data.Message);
1022 			info.AddValue("ThreadName", m_data.ThreadName);
1023 			info.AddValue("TimeStamp", m_data.TimeStamp);
1024 			info.AddValue("LocationInfo", m_data.LocationInfo);
1025 			info.AddValue("UserName", m_data.UserName);
1026 			info.AddValue("ExceptionString", m_data.ExceptionString);
1027 			info.AddValue("Properties", m_data.Properties);
1028 			info.AddValue("Domain", m_data.Domain);
1029 			info.AddValue("Identity", m_data.Identity);
1030 		}
1031 
1032 #endif
1033 
1034 		#endregion Implementation of ISerializable
1035 
1036 		#region Public Instance Methods
1037 
1038 		/// <summary>
1039 		/// Gets the portable data for this <see cref="LoggingEvent" />.
1040 		/// </summary>
1041 		/// <returns>The <see cref="LoggingEventData"/> for this event.</returns>
1042 		/// <remarks>
1043 		/// <para>
1044 		/// A new <see cref="LoggingEvent"/> can be constructed using a
1045 		/// <see cref="LoggingEventData"/> instance.
1046 		/// </para>
1047 		/// <para>
1048 		/// Does a <see cref="FixFlags.Partial"/> fix of the data
1049 		/// in the logging event before returning the event data.
1050 		/// </para>
1051 		/// </remarks>
GetLoggingEventData()1052 		public LoggingEventData GetLoggingEventData()
1053 		{
1054 			return GetLoggingEventData(FixFlags.Partial);
1055 		}
1056 
1057 		/// <summary>
1058 		/// Gets the portable data for this <see cref="LoggingEvent" />.
1059 		/// </summary>
1060 		/// <param name="fixFlags">The set of data to ensure is fixed in the LoggingEventData</param>
1061 		/// <returns>The <see cref="LoggingEventData"/> for this event.</returns>
1062 		/// <remarks>
1063 		/// <para>
1064 		/// A new <see cref="LoggingEvent"/> can be constructed using a
1065 		/// <see cref="LoggingEventData"/> instance.
1066 		/// </para>
1067 		/// </remarks>
GetLoggingEventData(FixFlags fixFlags)1068 		public LoggingEventData GetLoggingEventData(FixFlags fixFlags)
1069 		{
1070 			Fix = fixFlags;
1071 			return m_data;
1072 		}
1073 
1074 		/// <summary>
1075 		/// Returns this event's exception's rendered using the
1076 		/// <see cref="ILoggerRepository.RendererMap" />.
1077 		/// </summary>
1078 		/// <returns>
1079 		/// This event's exception's rendered using the <see cref="ILoggerRepository.RendererMap" />.
1080 		/// </returns>
1081 		/// <remarks>
1082 		/// <para>
1083 		/// <b>Obsolete. Use <see cref="GetExceptionString"/> instead.</b>
1084 		/// </para>
1085 		/// </remarks>
1086 		[Obsolete("Use GetExceptionString instead")]
GetExceptionStrRep()1087 		public string GetExceptionStrRep()
1088 		{
1089 			return GetExceptionString();
1090 		}
1091 
1092 		/// <summary>
1093 		/// Returns this event's exception's rendered using the
1094 		/// <see cref="ILoggerRepository.RendererMap" />.
1095 		/// </summary>
1096 		/// <returns>
1097 		/// This event's exception's rendered using the <see cref="ILoggerRepository.RendererMap" />.
1098 		/// </returns>
1099 		/// <remarks>
1100 		/// <para>
1101 		/// Returns this event's exception's rendered using the
1102 		/// <see cref="ILoggerRepository.RendererMap" />.
1103 		/// </para>
1104 		/// </remarks>
GetExceptionString()1105 		public string GetExceptionString()
1106 		{
1107 			if (m_data.ExceptionString == null  && this.m_cacheUpdatable)
1108 			{
1109 				if (m_thrownException != null)
1110 				{
1111 					if (m_repository != null)
1112 					{
1113 						// Render exception using the repositories renderer map
1114 						m_data.ExceptionString = m_repository.RendererMap.FindAndRender(m_thrownException);
1115 					}
1116 					else
1117 					{
1118 						// Very last resort
1119 						m_data.ExceptionString = m_thrownException.ToString();
1120 					}
1121 				}
1122 				else
1123 				{
1124 					m_data.ExceptionString = "";
1125 				}
1126 			}
1127 			return m_data.ExceptionString;
1128 		}
1129 
1130 		/// <summary>
1131 		/// Fix instance fields that hold volatile data.
1132 		/// </summary>
1133 		/// <remarks>
1134 		/// <para>
1135 		/// Some of the values in instances of <see cref="LoggingEvent"/>
1136 		/// are considered volatile, that is the values are correct at the
1137 		/// time the event is delivered to appenders, but will not be consistent
1138 		/// at any time afterwards. If an event is to be stored and then processed
1139 		/// at a later time these volatile values must be fixed by calling
1140 		/// <see cref="FixVolatileData()"/>. There is a performance penalty
1141 		/// incurred by calling <see cref="FixVolatileData()"/> but it
1142 		/// is essential to maintaining data consistency.
1143 		/// </para>
1144 		/// <para>
1145 		/// Calling <see cref="FixVolatileData()"/> is equivalent to
1146 		/// calling <see cref="FixVolatileData(bool)"/> passing the parameter
1147 		/// <c>false</c>.
1148 		/// </para>
1149 		/// <para>
1150 		/// See <see cref="FixVolatileData(bool)"/> for more
1151 		/// information.
1152 		/// </para>
1153 		/// </remarks>
1154 		[Obsolete("Use Fix property")]
FixVolatileData()1155 		public void FixVolatileData()
1156 		{
1157 			Fix = FixFlags.All;
1158 		}
1159 
1160 		/// <summary>
1161 		/// Fixes instance fields that hold volatile data.
1162 		/// </summary>
1163 		/// <param name="fastButLoose">Set to <c>true</c> to not fix data that takes a long time to fix.</param>
1164 		/// <remarks>
1165 		/// <para>
1166 		/// Some of the values in instances of <see cref="LoggingEvent"/>
1167 		/// are considered volatile, that is the values are correct at the
1168 		/// time the event is delivered to appenders, but will not be consistent
1169 		/// at any time afterwards. If an event is to be stored and then processed
1170 		/// at a later time these volatile values must be fixed by calling
1171 		/// <see cref="FixVolatileData()"/>. There is a performance penalty
1172 		/// for incurred by calling <see cref="FixVolatileData()"/> but it
1173 		/// is essential to maintaining data consistency.
1174 		/// </para>
1175 		/// <para>
1176 		/// The <paramref name="fastButLoose"/> param controls the data that
1177 		/// is fixed. Some of the data that can be fixed takes a long time to
1178 		/// generate, therefore if you do not require those settings to be fixed
1179 		/// they can be ignored by setting the <paramref name="fastButLoose"/> param
1180 		/// to <c>true</c>. This setting will ignore the <see cref="LocationInformation"/>
1181 		/// and <see cref="UserName"/> settings.
1182 		/// </para>
1183 		/// <para>
1184 		/// Set <paramref name="fastButLoose"/> to <c>false</c> to ensure that all
1185 		/// settings are fixed.
1186 		/// </para>
1187 		/// </remarks>
1188 		[Obsolete("Use Fix property")]
FixVolatileData(bool fastButLoose)1189 		public void FixVolatileData(bool fastButLoose)
1190 		{
1191 			if (fastButLoose)
1192 			{
1193 				Fix = FixFlags.Partial;
1194 			}
1195 			else
1196 			{
1197 				Fix = FixFlags.All;
1198 			}
1199 		}
1200 
1201 		/// <summary>
1202 		/// Fix the fields specified by the <see cref="FixFlags"/> parameter
1203 		/// </summary>
1204 		/// <param name="flags">the fields to fix</param>
1205 		/// <remarks>
1206 		/// <para>
1207 		/// Only fields specified in the <paramref name="flags"/> will be fixed.
1208 		/// Fields will not be fixed if they have previously been fixed.
1209 		/// It is not possible to 'unfix' a field.
1210 		/// </para>
1211 		/// </remarks>
FixVolatileData(FixFlags flags)1212 		protected void FixVolatileData(FixFlags flags)
1213 		{
1214 			object forceCreation = null;
1215 
1216 			//Unlock the cache so that new values can be stored
1217 			//This may not be ideal if we are no longer in the correct context
1218 			//and someone calls fix.
1219 			m_cacheUpdatable=true;
1220 
1221 			// determine the flags that we are actually fixing
1222 			FixFlags updateFlags = (FixFlags)((flags ^ m_fixFlags) & flags);
1223 
1224 			if (updateFlags > 0)
1225 			{
1226 				if ((updateFlags & FixFlags.Message) != 0)
1227 				{
1228 					// Force the message to be rendered
1229 					forceCreation = this.RenderedMessage;
1230 
1231 					m_fixFlags |= FixFlags.Message;
1232 				}
1233 				if ((updateFlags & FixFlags.ThreadName) != 0)
1234 				{
1235 					// Grab the thread name
1236 					forceCreation = this.ThreadName;
1237 
1238 					m_fixFlags |= FixFlags.ThreadName;
1239 				}
1240 
1241 				if ((updateFlags & FixFlags.LocationInfo) != 0)
1242 				{
1243 					// Force the location information to be loaded
1244 					forceCreation = this.LocationInformation;
1245 
1246 					m_fixFlags |= FixFlags.LocationInfo;
1247 				}
1248 				if ((updateFlags & FixFlags.UserName) != 0)
1249 				{
1250 					// Grab the user name
1251 					forceCreation = this.UserName;
1252 
1253 					m_fixFlags |= FixFlags.UserName;
1254 				}
1255 				if ((updateFlags & FixFlags.Domain) != 0)
1256 				{
1257 					// Grab the domain name
1258 					forceCreation = this.Domain;
1259 
1260 					m_fixFlags |= FixFlags.Domain;
1261 				}
1262 				if ((updateFlags & FixFlags.Identity) != 0)
1263 				{
1264 					// Grab the identity
1265 					forceCreation = this.Identity;
1266 
1267 					m_fixFlags |= FixFlags.Identity;
1268 				}
1269 
1270 				if ((updateFlags & FixFlags.Exception) != 0)
1271 				{
1272 					// Force the exception text to be loaded
1273 					forceCreation = GetExceptionString();
1274 
1275 					m_fixFlags |= FixFlags.Exception;
1276 				}
1277 
1278 				if ((updateFlags & FixFlags.Properties) != 0)
1279 				{
1280 					CacheProperties();
1281 
1282 					m_fixFlags |= FixFlags.Properties;
1283 				}
1284 			}
1285 
1286 			// avoid warning CS0219
1287 			if (forceCreation != null)
1288 			{
1289 			}
1290 
1291 			//Finaly lock everything we've cached.
1292 			m_cacheUpdatable=false;
1293 		}
1294 
1295 		#endregion Public Instance Methods
1296 
1297 		#region Protected Instance Methods
1298 
CreateCompositeProperties()1299 		private void CreateCompositeProperties()
1300 		{
1301 			m_compositeProperties = new CompositeProperties();
1302 
1303 			if (m_eventProperties != null)
1304 			{
1305 				m_compositeProperties.Add(m_eventProperties);
1306 			}
1307 #if !NETCF
1308 			PropertiesDictionary logicalThreadProperties = LogicalThreadContext.Properties.GetProperties(false);
1309 			if (logicalThreadProperties != null)
1310 			{
1311 				m_compositeProperties.Add(logicalThreadProperties);
1312 			}
1313 #endif
1314 			PropertiesDictionary threadProperties = ThreadContext.Properties.GetProperties(false);
1315 			if (threadProperties != null)
1316 			{
1317 				m_compositeProperties.Add(threadProperties);
1318 			}
1319 
1320 			// TODO: Add Repository Properties
1321 
1322 			m_compositeProperties.Add(GlobalContext.Properties.GetReadOnlyProperties());
1323 		}
1324 
CacheProperties()1325 		private void CacheProperties()
1326 		{
1327 			if (m_data.Properties == null  && this.m_cacheUpdatable)
1328 			{
1329 				if (m_compositeProperties == null)
1330 				{
1331 					CreateCompositeProperties();
1332 				}
1333 
1334 				PropertiesDictionary flattenedProperties = m_compositeProperties.Flatten();
1335 
1336 				PropertiesDictionary fixedProperties = new PropertiesDictionary();
1337 
1338 				// Validate properties
1339 				foreach(DictionaryEntry entry in flattenedProperties)
1340 				{
1341 					string key = entry.Key as string;
1342 
1343 					if (key != null)
1344 					{
1345 						object val = entry.Value;
1346 
1347 						// Fix any IFixingRequired objects
1348 						IFixingRequired fixingRequired = val as IFixingRequired;
1349 						if (fixingRequired != null)
1350 						{
1351 							val = fixingRequired.GetFixedObject();
1352 						}
1353 
1354 						// Strip keys with null values
1355 						if (val != null)
1356 						{
1357 							fixedProperties[key] = val;
1358 						}
1359 					}
1360 				}
1361 
1362 				m_data.Properties = fixedProperties;
1363 			}
1364 		}
1365 
1366 		/// <summary>
1367 		/// Lookup a composite property in this event
1368 		/// </summary>
1369 		/// <param name="key">the key for the property to lookup</param>
1370 		/// <returns>the value for the property</returns>
1371 		/// <remarks>
1372 		/// <para>
1373 		/// This event has composite properties that combine together properties from
1374 		/// several different contexts in the following order:
1375 		/// <list type="definition">
1376 		///		<item>
1377 		/// 		<term>this events properties</term>
1378 		/// 		<description>
1379 		/// 		This event has <see cref="Properties"/> that can be set. These
1380 		/// 		properties are specific to this event only.
1381 		/// 		</description>
1382 		/// 	</item>
1383 		/// 	<item>
1384 		/// 		<term>the thread properties</term>
1385 		/// 		<description>
1386 		/// 		The <see cref="ThreadContext.Properties"/> that are set on the current
1387 		/// 		thread. These properties are shared by all events logged on this thread.
1388 		/// 		</description>
1389 		/// 	</item>
1390 		/// 	<item>
1391 		/// 		<term>the global properties</term>
1392 		/// 		<description>
1393 		/// 		The <see cref="GlobalContext.Properties"/> that are set globally. These
1394 		/// 		properties are shared by all the threads in the AppDomain.
1395 		/// 		</description>
1396 		/// 	</item>
1397 		/// </list>
1398 		/// </para>
1399 		/// </remarks>
LookupProperty(string key)1400 		public object LookupProperty(string key)
1401 		{
1402 			if (m_data.Properties != null)
1403 			{
1404 				return m_data.Properties[key];
1405 			}
1406 			if (m_compositeProperties == null)
1407 			{
1408 				CreateCompositeProperties();
1409 			}
1410 			return m_compositeProperties[key];
1411 		}
1412 
1413 		/// <summary>
1414 		/// Get all the composite properties in this event
1415 		/// </summary>
1416 		/// <returns>the <see cref="PropertiesDictionary"/> containing all the properties</returns>
1417 		/// <remarks>
1418 		/// <para>
1419 		/// See <see cref="LookupProperty"/> for details of the composite properties
1420 		/// stored by the event.
1421 		/// </para>
1422 		/// <para>
1423 		/// This method returns a single <see cref="PropertiesDictionary"/> containing all the
1424 		/// properties defined for this event.
1425 		/// </para>
1426 		/// </remarks>
GetProperties()1427 		public PropertiesDictionary GetProperties()
1428 		{
1429 			if (m_data.Properties != null)
1430 			{
1431 				return m_data.Properties;
1432 			}
1433 			if (m_compositeProperties == null)
1434 			{
1435 				CreateCompositeProperties();
1436 			}
1437 			return m_compositeProperties.Flatten();
1438 		}
1439 
1440 		#endregion Public Instance Methods
1441 
1442 		#region Private Instance Fields
1443 
1444 		/// <summary>
1445 		/// The internal logging event data.
1446 		/// </summary>
1447 		private LoggingEventData m_data;
1448 
1449 		/// <summary>
1450 		/// The internal logging event data.
1451 		/// </summary>
1452 		private CompositeProperties m_compositeProperties;
1453 
1454 		/// <summary>
1455 		/// The internal logging event data.
1456 		/// </summary>
1457 		private PropertiesDictionary m_eventProperties;
1458 
1459 		/// <summary>
1460 		/// The fully qualified Type of the calling
1461 		/// logger class in the stack frame (i.e. the declaring type of the method).
1462 		/// </summary>
1463 		private readonly Type m_callerStackBoundaryDeclaringType;
1464 
1465 		/// <summary>
1466 		/// The application supplied message of logging event.
1467 		/// </summary>
1468 		private readonly object m_message;
1469 
1470 		/// <summary>
1471 		/// The exception that was thrown.
1472 		/// </summary>
1473 		/// <remarks>
1474 		/// This is not serialized. The string representation
1475 		/// is serialized instead.
1476 		/// </remarks>
1477 		private readonly Exception m_thrownException;
1478 
1479 		/// <summary>
1480 		/// The repository that generated the logging event
1481 		/// </summary>
1482 		/// <remarks>
1483 		/// This is not serialized.
1484 		/// </remarks>
1485 		private ILoggerRepository m_repository = null;
1486 
1487 		/// <summary>
1488 		/// The fix state for this event
1489 		/// </summary>
1490 		/// <remarks>
1491 		/// These flags indicate which fields have been fixed.
1492 		/// Not serialized.
1493 		/// </remarks>
1494 		private FixFlags m_fixFlags = FixFlags.None;
1495 
1496 		/// <summary>
1497 		/// Indicated that the internal cache is updateable (ie not fixed)
1498 		/// </summary>
1499 		/// <remarks>
1500 		/// This is a seperate flag to m_fixFlags as it allows incrementel fixing and simpler
1501 		/// changes in the caching strategy.
1502 		/// </remarks>
1503 		private bool m_cacheUpdatable = true;
1504 
1505 		#endregion Private Instance Fields
1506 
1507 		#region Constants
1508 
1509 		/// <summary>
1510 		/// The key into the Properties map for the host name value.
1511 		/// </summary>
1512 		public const string HostNameProperty = "log4net:HostName";
1513 
1514 		/// <summary>
1515 		/// The key into the Properties map for the thread identity value.
1516 		/// </summary>
1517 		public const string IdentityProperty = "log4net:Identity";
1518 
1519 		/// <summary>
1520 		/// The key into the Properties map for the user name value.
1521 		/// </summary>
1522 		public const string UserNameProperty = "log4net:UserName";
1523 
1524 		#endregion
1525 	}
1526 }
1527