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.IO; 21 using System.Collections; 22 23 using log4net.Filter; 24 using log4net.Util; 25 using log4net.Layout; 26 using log4net.Core; 27 28 namespace log4net.Appender 29 { 30 /// <summary> 31 /// Abstract base class implementation of <see cref="IAppender"/>. 32 /// </summary> 33 /// <remarks> 34 /// <para> 35 /// This class provides the code for common functionality, such 36 /// as support for threshold filtering and support for general filters. 37 /// </para> 38 /// <para> 39 /// Appenders can also implement the <see cref="IOptionHandler"/> interface. Therefore 40 /// they would require that the <see cref="IOptionHandler.ActivateOptions()"/> method 41 /// be called after the appenders properties have been configured. 42 /// </para> 43 /// </remarks> 44 /// <author>Nicko Cadell</author> 45 /// <author>Gert Driesen</author> 46 public abstract class AppenderSkeleton : IAppender, IBulkAppender, IOptionHandler 47 { 48 #region Protected Instance Constructors 49 50 /// <summary> 51 /// Default constructor 52 /// </summary> 53 /// <remarks> 54 /// <para>Empty default constructor</para> 55 /// </remarks> AppenderSkeleton()56 protected AppenderSkeleton() 57 { 58 m_errorHandler = new OnlyOnceErrorHandler(this.GetType().Name); 59 } 60 61 #endregion Protected Instance Constructors 62 63 #region Finalizer 64 65 /// <summary> 66 /// Finalizes this appender by calling the implementation's 67 /// <see cref="Close"/> method. 68 /// </summary> 69 /// <remarks> 70 /// <para> 71 /// If this appender has not been closed then the <c>Finalize</c> method 72 /// will call <see cref="Close"/>. 73 /// </para> 74 /// </remarks> ~AppenderSkeleton()75 ~AppenderSkeleton() 76 { 77 // An appender might be closed then garbage collected. 78 // There is no point in closing twice. 79 if (!m_closed) 80 { 81 LogLog.Debug("AppenderSkeleton: Finalizing appender named ["+m_name+"]."); 82 Close(); 83 } 84 } 85 86 #endregion Finalizer 87 88 #region Public Instance Properties 89 90 /// <summary> 91 /// Gets or sets the threshold <see cref="Level"/> of this appender. 92 /// </summary> 93 /// <value> 94 /// The threshold <see cref="Level"/> of the appender. 95 /// </value> 96 /// <remarks> 97 /// <para> 98 /// All log events with lower level than the threshold level are ignored 99 /// by the appender. 100 /// </para> 101 /// <para> 102 /// In configuration files this option is specified by setting the 103 /// value of the <see cref="Threshold"/> option to a level 104 /// string, such as "DEBUG", "INFO" and so on. 105 /// </para> 106 /// </remarks> 107 public Level Threshold 108 { 109 get { return m_threshold; } 110 set { m_threshold = value; } 111 } 112 113 /// <summary> 114 /// Gets or sets the <see cref="IErrorHandler"/> for this appender. 115 /// </summary> 116 /// <value>The <see cref="IErrorHandler"/> of the appender</value> 117 /// <remarks> 118 /// <para> 119 /// The <see cref="AppenderSkeleton"/> provides a default 120 /// implementation for the <see cref="ErrorHandler"/> property. 121 /// </para> 122 /// </remarks> 123 virtual public IErrorHandler ErrorHandler 124 { 125 get { return this.m_errorHandler; } 126 set 127 { 128 lock(this) 129 { 130 if (value == null) 131 { 132 // We do not throw exception here since the cause is probably a 133 // bad config file. 134 LogLog.Warn("AppenderSkeleton: You have tried to set a null error-handler."); 135 } 136 else 137 { 138 m_errorHandler = value; 139 } 140 } 141 } 142 } 143 144 /// <summary> 145 /// The filter chain. 146 /// </summary> 147 /// <value>The head of the filter chain filter chain.</value> 148 /// <remarks> 149 /// <para> 150 /// Returns the head Filter. The Filters are organized in a linked list 151 /// and so all Filters on this Appender are available through the result. 152 /// </para> 153 /// </remarks> 154 virtual public IFilter FilterHead 155 { 156 get { return m_headFilter; } 157 } 158 159 /// <summary> 160 /// Gets or sets the <see cref="ILayout"/> for this appender. 161 /// </summary> 162 /// <value>The layout of the appender.</value> 163 /// <remarks> 164 /// <para> 165 /// See <see cref="RequiresLayout"/> for more information. 166 /// </para> 167 /// </remarks> 168 /// <seealso cref="RequiresLayout"/> 169 virtual public ILayout Layout 170 { 171 get { return m_layout; } 172 set { m_layout = value; } 173 } 174 175 #endregion 176 177 #region Implementation of IOptionHandler 178 179 /// <summary> 180 /// Initialize the appender based on the options set 181 /// </summary> 182 /// <remarks> 183 /// <para> 184 /// This is part of the <see cref="IOptionHandler"/> delayed object 185 /// activation scheme. The <see cref="ActivateOptions"/> method must 186 /// be called on this object after the configuration properties have 187 /// been set. Until <see cref="ActivateOptions"/> is called this 188 /// object is in an undefined state and must not be used. 189 /// </para> 190 /// <para> 191 /// If any of the configuration properties are modified then 192 /// <see cref="ActivateOptions"/> must be called again. 193 /// </para> 194 /// </remarks> ActivateOptions()195 virtual public void ActivateOptions() 196 { 197 } 198 199 #endregion Implementation of IOptionHandler 200 201 #region Implementation of IAppender 202 203 /// <summary> 204 /// Gets or sets the name of this appender. 205 /// </summary> 206 /// <value>The name of the appender.</value> 207 /// <remarks> 208 /// <para> 209 /// The name uniquely identifies the appender. 210 /// </para> 211 /// </remarks> 212 public string Name 213 { 214 get { return m_name; } 215 set { m_name = value; } 216 } 217 218 /// <summary> 219 /// Closes the appender and release resources. 220 /// </summary> 221 /// <remarks> 222 /// <para> 223 /// Release any resources allocated within the appender such as file handles, 224 /// network connections, etc. 225 /// </para> 226 /// <para> 227 /// It is a programming error to append to a closed appender. 228 /// </para> 229 /// <para> 230 /// This method cannot be overridden by subclasses. This method 231 /// delegates the closing of the appender to the <see cref="OnClose"/> 232 /// method which must be overridden in the subclass. 233 /// </para> 234 /// </remarks> Close()235 public void Close() 236 { 237 // This lock prevents the appender being closed while it is still appending 238 lock(this) 239 { 240 if (!m_closed) 241 { 242 OnClose(); 243 m_closed = true; 244 } 245 } 246 } 247 248 /// <summary> 249 /// Performs threshold checks and invokes filters before 250 /// delegating actual logging to the subclasses specific 251 /// <see cref="Append(LoggingEvent)"/> method. 252 /// </summary> 253 /// <param name="loggingEvent">The event to log.</param> 254 /// <remarks> 255 /// <para> 256 /// This method cannot be overridden by derived classes. A 257 /// derived class should override the <see cref="Append(LoggingEvent)"/> method 258 /// which is called by this method. 259 /// </para> 260 /// <para> 261 /// The implementation of this method is as follows: 262 /// </para> 263 /// <para> 264 /// <list type="bullet"> 265 /// <item> 266 /// <description> 267 /// Checks that the severity of the <paramref name="loggingEvent"/> 268 /// is greater than or equal to the <see cref="Threshold"/> of this 269 /// appender.</description> 270 /// </item> 271 /// <item> 272 /// <description> 273 /// Checks that the <see cref="IFilter"/> chain accepts the 274 /// <paramref name="loggingEvent"/>. 275 /// </description> 276 /// </item> 277 /// <item> 278 /// <description> 279 /// Calls <see cref="PreAppendCheck()"/> and checks that 280 /// it returns <c>true</c>.</description> 281 /// </item> 282 /// </list> 283 /// </para> 284 /// <para> 285 /// If all of the above steps succeed then the <paramref name="loggingEvent"/> 286 /// will be passed to the abstract <see cref="Append(LoggingEvent)"/> method. 287 /// </para> 288 /// </remarks> DoAppend(LoggingEvent loggingEvent)289 public void DoAppend(LoggingEvent loggingEvent) 290 { 291 // This lock is absolutely critical for correct formatting 292 // of the message in a multi-threaded environment. Without 293 // this, the message may be broken up into elements from 294 // multiple thread contexts (like get the wrong thread ID). 295 296 lock(this) 297 { 298 if (m_closed) 299 { 300 ErrorHandler.Error("Attempted to append to closed appender named ["+m_name+"]."); 301 return; 302 } 303 304 // prevent re-entry 305 if (m_recursiveGuard) 306 { 307 return; 308 } 309 310 try 311 { 312 m_recursiveGuard = true; 313 314 if (FilterEvent(loggingEvent) && PreAppendCheck()) 315 { 316 this.Append(loggingEvent); 317 } 318 } 319 catch(Exception ex) 320 { 321 ErrorHandler.Error("Failed in DoAppend", ex); 322 } 323 #if !MONO && !NET_2_0 324 // on .NET 2.0 (and higher) and Mono (all profiles), 325 // exceptions that do not derive from System.Exception will be 326 // wrapped in a RuntimeWrappedException by the runtime, and as 327 // such will be catched by the catch clause above 328 catch 329 { 330 // Catch handler for non System.Exception types 331 ErrorHandler.Error("Failed in DoAppend (unknown exception)"); 332 } 333 #endif 334 finally 335 { 336 m_recursiveGuard = false; 337 } 338 } 339 } 340 341 #endregion Implementation of IAppender 342 343 #region Implementation of IBulkAppender 344 345 /// <summary> 346 /// Performs threshold checks and invokes filters before 347 /// delegating actual logging to the subclasses specific 348 /// <see cref="Append(LoggingEvent[])"/> method. 349 /// </summary> 350 /// <param name="loggingEvents">The array of events to log.</param> 351 /// <remarks> 352 /// <para> 353 /// This method cannot be overridden by derived classes. A 354 /// derived class should override the <see cref="Append(LoggingEvent[])"/> method 355 /// which is called by this method. 356 /// </para> 357 /// <para> 358 /// The implementation of this method is as follows: 359 /// </para> 360 /// <para> 361 /// <list type="bullet"> 362 /// <item> 363 /// <description> 364 /// Checks that the severity of the <paramref name="loggingEvent"/> 365 /// is greater than or equal to the <see cref="Threshold"/> of this 366 /// appender.</description> 367 /// </item> 368 /// <item> 369 /// <description> 370 /// Checks that the <see cref="IFilter"/> chain accepts the 371 /// <paramref name="loggingEvent"/>. 372 /// </description> 373 /// </item> 374 /// <item> 375 /// <description> 376 /// Calls <see cref="PreAppendCheck()"/> and checks that 377 /// it returns <c>true</c>.</description> 378 /// </item> 379 /// </list> 380 /// </para> 381 /// <para> 382 /// If all of the above steps succeed then the <paramref name="loggingEvents"/> 383 /// will be passed to the <see cref="Append(LoggingEvent[])"/> method. 384 /// </para> 385 /// </remarks> DoAppend(LoggingEvent[] loggingEvents)386 public void DoAppend(LoggingEvent[] loggingEvents) 387 { 388 // This lock is absolutely critical for correct formatting 389 // of the message in a multi-threaded environment. Without 390 // this, the message may be broken up into elements from 391 // multiple thread contexts (like get the wrong thread ID). 392 393 lock(this) 394 { 395 if (m_closed) 396 { 397 ErrorHandler.Error("Attempted to append to closed appender named ["+m_name+"]."); 398 return; 399 } 400 401 // prevent re-entry 402 if (m_recursiveGuard) 403 { 404 return; 405 } 406 407 try 408 { 409 m_recursiveGuard = true; 410 411 ArrayList filteredEvents = new ArrayList(loggingEvents.Length); 412 413 foreach(LoggingEvent loggingEvent in loggingEvents) 414 { 415 if (FilterEvent(loggingEvent)) 416 { 417 filteredEvents.Add(loggingEvent); 418 } 419 } 420 421 if (filteredEvents.Count > 0 && PreAppendCheck()) 422 { 423 this.Append((LoggingEvent[])filteredEvents.ToArray(typeof(LoggingEvent))); 424 } 425 } 426 catch(Exception ex) 427 { 428 ErrorHandler.Error("Failed in Bulk DoAppend", ex); 429 } 430 #if !MONO && !NET_2_0 431 // on .NET 2.0 (and higher) and Mono (all profiles), 432 // exceptions that do not derive from System.Exception will be 433 // wrapped in a RuntimeWrappedException by the runtime, and as 434 // such will be catched by the catch clause above 435 catch 436 { 437 // Catch handler for non System.Exception types 438 ErrorHandler.Error("Failed in Bulk DoAppend (unknown exception)"); 439 } 440 #endif 441 finally 442 { 443 m_recursiveGuard = false; 444 } 445 } 446 } 447 448 #endregion Implementation of IBulkAppender 449 450 /// <summary> 451 /// Test if the logging event should we output by this appender 452 /// </summary> 453 /// <param name="loggingEvent">the event to test</param> 454 /// <returns><c>true</c> if the event should be output, <c>false</c> if the event should be ignored</returns> 455 /// <remarks> 456 /// <para> 457 /// This method checks the logging event against the threshold level set 458 /// on this appender and also against the filters specified on this 459 /// appender. 460 /// </para> 461 /// <para> 462 /// The implementation of this method is as follows: 463 /// </para> 464 /// <para> 465 /// <list type="bullet"> 466 /// <item> 467 /// <description> 468 /// Checks that the severity of the <paramref name="loggingEvent"/> 469 /// is greater than or equal to the <see cref="Threshold"/> of this 470 /// appender.</description> 471 /// </item> 472 /// <item> 473 /// <description> 474 /// Checks that the <see cref="IFilter"/> chain accepts the 475 /// <paramref name="loggingEvent"/>. 476 /// </description> 477 /// </item> 478 /// </list> 479 /// </para> 480 /// </remarks> FilterEvent(LoggingEvent loggingEvent)481 virtual protected bool FilterEvent(LoggingEvent loggingEvent) 482 { 483 if (!IsAsSevereAsThreshold(loggingEvent.Level)) 484 { 485 return false; 486 } 487 488 IFilter f = this.FilterHead; 489 490 while(f != null) 491 { 492 switch(f.Decide(loggingEvent)) 493 { 494 case FilterDecision.Deny: 495 return false; // Return without appending 496 497 case FilterDecision.Accept: 498 f = null; // Break out of the loop 499 break; 500 501 case FilterDecision.Neutral: 502 f = f.Next; // Move to next filter 503 break; 504 } 505 } 506 507 return true; 508 } 509 510 #region Public Instance Methods 511 512 /// <summary> 513 /// Adds a filter to the end of the filter chain. 514 /// </summary> 515 /// <param name="filter">the filter to add to this appender</param> 516 /// <remarks> 517 /// <para> 518 /// The Filters are organized in a linked list. 519 /// </para> 520 /// <para> 521 /// Setting this property causes the new filter to be pushed onto the 522 /// back of the filter chain. 523 /// </para> 524 /// </remarks> AddFilter(IFilter filter)525 virtual public void AddFilter(IFilter filter) 526 { 527 if (filter == null) 528 { 529 throw new ArgumentNullException("filter param must not be null"); 530 } 531 532 if (m_headFilter == null) 533 { 534 m_headFilter = m_tailFilter = filter; 535 } 536 else 537 { 538 m_tailFilter.Next = filter; 539 m_tailFilter = filter; 540 } 541 } 542 543 /// <summary> 544 /// Clears the filter list for this appender. 545 /// </summary> 546 /// <remarks> 547 /// <para> 548 /// Clears the filter list for this appender. 549 /// </para> 550 /// </remarks> ClearFilters()551 virtual public void ClearFilters() 552 { 553 m_headFilter = m_tailFilter = null; 554 } 555 556 #endregion Public Instance Methods 557 558 #region Protected Instance Methods 559 560 /// <summary> 561 /// Checks if the message level is below this appender's threshold. 562 /// </summary> 563 /// <param name="level"><see cref="Level"/> to test against.</param> 564 /// <remarks> 565 /// <para> 566 /// If there is no threshold set, then the return value is always <c>true</c>. 567 /// </para> 568 /// </remarks> 569 /// <returns> 570 /// <c>true</c> if the <paramref name="level"/> meets the <see cref="Threshold"/> 571 /// requirements of this appender. 572 /// </returns> IsAsSevereAsThreshold(Level level)573 virtual protected bool IsAsSevereAsThreshold(Level level) 574 { 575 return ((m_threshold == null) || level >= m_threshold); 576 } 577 578 /// <summary> 579 /// Is called when the appender is closed. Derived classes should override 580 /// this method if resources need to be released. 581 /// </summary> 582 /// <remarks> 583 /// <para> 584 /// Releases any resources allocated within the appender such as file handles, 585 /// network connections, etc. 586 /// </para> 587 /// <para> 588 /// It is a programming error to append to a closed appender. 589 /// </para> 590 /// </remarks> OnClose()591 virtual protected void OnClose() 592 { 593 // Do nothing by default 594 } 595 596 /// <summary> 597 /// Subclasses of <see cref="AppenderSkeleton"/> should implement this method 598 /// to perform actual logging. 599 /// </summary> 600 /// <param name="loggingEvent">The event to append.</param> 601 /// <remarks> 602 /// <para> 603 /// A subclass must implement this method to perform 604 /// logging of the <paramref name="loggingEvent"/>. 605 /// </para> 606 /// <para>This method will be called by <see cref="DoAppend(LoggingEvent)"/> 607 /// if all the conditions listed for that method are met. 608 /// </para> 609 /// <para> 610 /// To restrict the logging of events in the appender 611 /// override the <see cref="PreAppendCheck()"/> method. 612 /// </para> 613 /// </remarks> Append(LoggingEvent loggingEvent)614 abstract protected void Append(LoggingEvent loggingEvent); 615 616 /// <summary> 617 /// Append a bulk array of logging events. 618 /// </summary> 619 /// <param name="loggingEvents">the array of logging events</param> 620 /// <remarks> 621 /// <para> 622 /// This base class implementation calls the <see cref="Append(LoggingEvent)"/> 623 /// method for each element in the bulk array. 624 /// </para> 625 /// <para> 626 /// A sub class that can better process a bulk array of events should 627 /// override this method in addition to <see cref="Append(LoggingEvent)"/>. 628 /// </para> 629 /// </remarks> Append(LoggingEvent[] loggingEvents)630 virtual protected void Append(LoggingEvent[] loggingEvents) 631 { 632 foreach(LoggingEvent loggingEvent in loggingEvents) 633 { 634 Append(loggingEvent); 635 } 636 } 637 638 /// <summary> 639 /// Called before <see cref="Append(LoggingEvent)"/> as a precondition. 640 /// </summary> 641 /// <remarks> 642 /// <para> 643 /// This method is called by <see cref="DoAppend(LoggingEvent)"/> 644 /// before the call to the abstract <see cref="Append(LoggingEvent)"/> method. 645 /// </para> 646 /// <para> 647 /// This method can be overridden in a subclass to extend the checks 648 /// made before the event is passed to the <see cref="Append(LoggingEvent)"/> method. 649 /// </para> 650 /// <para> 651 /// A subclass should ensure that they delegate this call to 652 /// this base class if it is overridden. 653 /// </para> 654 /// </remarks> 655 /// <returns><c>true</c> if the call to <see cref="Append(LoggingEvent)"/> should proceed.</returns> PreAppendCheck()656 virtual protected bool PreAppendCheck() 657 { 658 if ((m_layout == null) && RequiresLayout) 659 { 660 ErrorHandler.Error("AppenderSkeleton: No layout set for the appender named ["+m_name+"]."); 661 return false; 662 } 663 664 return true; 665 } 666 667 /// <summary> 668 /// Renders the <see cref="LoggingEvent"/> to a string. 669 /// </summary> 670 /// <param name="loggingEvent">The event to render.</param> 671 /// <returns>The event rendered as a string.</returns> 672 /// <remarks> 673 /// <para> 674 /// Helper method to render a <see cref="LoggingEvent"/> to 675 /// a string. This appender must have a <see cref="Layout"/> 676 /// set to render the <paramref name="loggingEvent"/> to 677 /// a string. 678 /// </para> 679 /// <para>If there is exception data in the logging event and 680 /// the layout does not process the exception, this method 681 /// will append the exception text to the rendered string. 682 /// </para> 683 /// <para> 684 /// Where possible use the alternative version of this method 685 /// <see cref="RenderLoggingEvent(TextWriter,LoggingEvent)"/>. 686 /// That method streams the rendering onto an existing Writer 687 /// which can give better performance if the caller already has 688 /// a <see cref="TextWriter"/> open and ready for writing. 689 /// </para> 690 /// </remarks> RenderLoggingEvent(LoggingEvent loggingEvent)691 protected string RenderLoggingEvent(LoggingEvent loggingEvent) 692 { 693 // Create the render writer on first use 694 if (m_renderWriter == null) 695 { 696 m_renderWriter = new ReusableStringWriter(System.Globalization.CultureInfo.InvariantCulture); 697 } 698 699 // Reset the writer so we can reuse it 700 m_renderWriter.Reset(c_renderBufferMaxCapacity, c_renderBufferSize); 701 702 RenderLoggingEvent(m_renderWriter, loggingEvent); 703 return m_renderWriter.ToString(); 704 } 705 706 /// <summary> 707 /// Renders the <see cref="LoggingEvent"/> to a string. 708 /// </summary> 709 /// <param name="loggingEvent">The event to render.</param> 710 /// <param name="writer">The TextWriter to write the formatted event to</param> 711 /// <remarks> 712 /// <para> 713 /// Helper method to render a <see cref="LoggingEvent"/> to 714 /// a string. This appender must have a <see cref="Layout"/> 715 /// set to render the <paramref name="loggingEvent"/> to 716 /// a string. 717 /// </para> 718 /// <para>If there is exception data in the logging event and 719 /// the layout does not process the exception, this method 720 /// will append the exception text to the rendered string. 721 /// </para> 722 /// <para> 723 /// Use this method in preference to <see cref="RenderLoggingEvent(LoggingEvent)"/> 724 /// where possible. If, however, the caller needs to render the event 725 /// to a string then <see cref="RenderLoggingEvent(LoggingEvent)"/> does 726 /// provide an efficient mechanism for doing so. 727 /// </para> 728 /// </remarks> RenderLoggingEvent(TextWriter writer, LoggingEvent loggingEvent)729 protected void RenderLoggingEvent(TextWriter writer, LoggingEvent loggingEvent) 730 { 731 if (m_layout == null) 732 { 733 throw new InvalidOperationException("A layout must be set"); 734 } 735 736 if (m_layout.IgnoresException) 737 { 738 string exceptionStr = loggingEvent.GetExceptionString(); 739 if (exceptionStr != null && exceptionStr.Length > 0) 740 { 741 // render the event and the exception 742 m_layout.Format(writer, loggingEvent); 743 writer.WriteLine(exceptionStr); 744 } 745 else 746 { 747 // there is no exception to render 748 m_layout.Format(writer, loggingEvent); 749 } 750 } 751 else 752 { 753 // The layout will render the exception 754 m_layout.Format(writer, loggingEvent); 755 } 756 } 757 758 /// <summary> 759 /// Tests if this appender requires a <see cref="Layout"/> to be set. 760 /// </summary> 761 /// <remarks> 762 /// <para> 763 /// In the rather exceptional case, where the appender 764 /// implementation admits a layout but can also work without it, 765 /// then the appender should return <c>true</c>. 766 /// </para> 767 /// <para> 768 /// This default implementation always returns <c>true</c>. 769 /// </para> 770 /// </remarks> 771 /// <returns> 772 /// <c>true</c> if the appender requires a layout object, otherwise <c>false</c>. 773 /// </returns> 774 virtual protected bool RequiresLayout 775 { 776 get { return false; } 777 } 778 779 #endregion 780 781 #region Private Instance Fields 782 783 /// <summary> 784 /// The layout of this appender. 785 /// </summary> 786 /// <remarks> 787 /// See <see cref="Layout"/> for more information. 788 /// </remarks> 789 private ILayout m_layout; 790 791 /// <summary> 792 /// The name of this appender. 793 /// </summary> 794 /// <remarks> 795 /// See <see cref="Name"/> for more information. 796 /// </remarks> 797 private string m_name; 798 799 /// <summary> 800 /// The level threshold of this appender. 801 /// </summary> 802 /// <remarks> 803 /// <para> 804 /// There is no level threshold filtering by default. 805 /// </para> 806 /// <para> 807 /// See <see cref="Threshold"/> for more information. 808 /// </para> 809 /// </remarks> 810 private Level m_threshold; 811 812 /// <summary> 813 /// It is assumed and enforced that errorHandler is never null. 814 /// </summary> 815 /// <remarks> 816 /// <para> 817 /// It is assumed and enforced that errorHandler is never null. 818 /// </para> 819 /// <para> 820 /// See <see cref="ErrorHandler"/> for more information. 821 /// </para> 822 /// </remarks> 823 private IErrorHandler m_errorHandler; 824 825 /// <summary> 826 /// The first filter in the filter chain. 827 /// </summary> 828 /// <remarks> 829 /// <para> 830 /// Set to <c>null</c> initially. 831 /// </para> 832 /// <para> 833 /// See <see cref="IFilter"/> for more information. 834 /// </para> 835 /// </remarks> 836 private IFilter m_headFilter; 837 838 /// <summary> 839 /// The last filter in the filter chain. 840 /// </summary> 841 /// <remarks> 842 /// See <see cref="IFilter"/> for more information. 843 /// </remarks> 844 private IFilter m_tailFilter; 845 846 /// <summary> 847 /// Flag indicating if this appender is closed. 848 /// </summary> 849 /// <remarks> 850 /// See <see cref="Close"/> for more information. 851 /// </remarks> 852 private bool m_closed = false; 853 854 /// <summary> 855 /// The guard prevents an appender from repeatedly calling its own DoAppend method 856 /// </summary> 857 private bool m_recursiveGuard = false; 858 859 /// <summary> 860 /// StringWriter used to render events 861 /// </summary> 862 private ReusableStringWriter m_renderWriter = null; 863 864 #endregion Private Instance Fields 865 866 #region Constants 867 868 /// <summary> 869 /// Initial buffer size 870 /// </summary> 871 private const int c_renderBufferSize = 256; 872 873 /// <summary> 874 /// Maximum buffer size before it is recycled 875 /// </summary> 876 private const int c_renderBufferMaxCapacity = 1024; 877 878 #endregion 879 } 880 } 881