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