| #region Apache License |
| // |
| // Licensed to the Apache Software Foundation (ASF) under one or more |
| // contributor license agreements. See the NOTICE file distributed with |
| // this work for additional information regarding copyright ownership. |
| // The ASF licenses this file to you under the Apache License, Version 2.0 |
| // (the "License"); you may not use this file except in compliance with |
| // the License. You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| // |
| #endregion |
| |
| using System; |
| using System.Collections; |
| using System.Collections.Generic; |
| using System.Diagnostics; |
| |
| namespace log4net.Util; |
| |
| /// <summary> |
| /// LogReceivedEventHandler |
| /// </summary> |
| [System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1003:Use generic event handler instances")] |
| [System.Diagnostics.CodeAnalysis.SuppressMessage("Naming", "CA1711:Identifiers should not have incorrect suffix")] |
| public delegate void LogReceivedEventHandler(object? source, LogReceivedEventArgs e); |
| |
| /// <summary> |
| /// Outputs log statements from within the log4net assembly. |
| /// </summary> |
| /// <remarks> |
| /// <para> |
| /// Log4net components cannot make log4net logging calls. However, it is |
| /// sometimes useful for the user to learn about what log4net is |
| /// doing. |
| /// </para> |
| /// <para> |
| /// All log4net internal debug calls go to the standard output stream |
| /// whereas internal error messages are sent to the standard error output |
| /// stream. |
| /// </para> |
| /// </remarks> |
| /// <author>Nicko Cadell</author> |
| /// <author>Gert Driesen</author> |
| public sealed class LogLog |
| { |
| /// <summary> |
| /// The event raised when an internal message has been received. |
| /// </summary> |
| public static event LogReceivedEventHandler? LogReceived; |
| |
| /// <summary> |
| /// The Type that generated the internal message. |
| /// </summary> |
| public Type Source { get; } |
| |
| /// <summary> |
| /// The DateTime stamp of when the internal message was received. |
| /// </summary> |
| public DateTime TimeStamp => TimeStampUtc.ToLocalTime(); |
| |
| /// <summary> |
| /// The UTC DateTime stamp of when the internal message was received. |
| /// </summary> |
| public DateTime TimeStampUtc { get; } |
| |
| /// <summary> |
| /// A string indicating the severity of the internal message. |
| /// </summary> |
| /// <remarks> |
| /// "log4net: ", |
| /// "log4net:ERROR ", |
| /// "log4net:WARN " |
| /// </remarks> |
| public string Prefix { get; } |
| |
| /// <summary> |
| /// The internal log message. |
| /// </summary> |
| public string Message { get; } |
| |
| /// <summary> |
| /// The Exception related to the message. |
| /// </summary> |
| /// <remarks> |
| /// Optional. Will be null if no Exception was passed. |
| /// </remarks> |
| public Exception? Exception { get; } |
| |
| /// <summary> |
| /// Formats Prefix, Source, and Message in the same format as the value |
| /// sent to Console.Out and Trace.Write. |
| /// </summary> |
| /// <returns></returns> |
| public override string ToString() => $"{Prefix}{Source.Name}: {Message}"; |
| |
| /// <summary> |
| /// Initializes a new instance of the <see cref="LogLog" /> class. |
| /// </summary> |
| public LogLog(Type source, string prefix, string message, Exception? exception) |
| { |
| TimeStampUtc = DateTime.UtcNow; |
| |
| Source = source; |
| Prefix = prefix; |
| Message = message; |
| Exception = exception; |
| } |
| |
| /// <summary> |
| /// Static constructor that initializes logging by reading |
| /// settings from the application configuration file. |
| /// </summary> |
| /// <remarks> |
| /// <para> |
| /// The <c>log4net.Internal.Debug</c> application setting |
| /// controls internal debugging. This setting should be set |
| /// to <c>true</c> to enable debugging. |
| /// </para> |
| /// <para> |
| /// The <c>log4net.Internal.Quiet</c> application setting |
| /// suppresses all internal logging including error messages. |
| /// This setting should be set to <c>true</c> to enable message |
| /// suppression. |
| /// </para> |
| /// </remarks> |
| static LogLog() |
| { |
| try |
| { |
| InternalDebugging = OptionConverter.ToBoolean(SystemInfo.GetAppSetting("log4net.Internal.Debug"), false); |
| QuietMode = OptionConverter.ToBoolean(SystemInfo.GetAppSetting("log4net.Internal.Quiet"), false); |
| EmitInternalMessages = OptionConverter.ToBoolean(SystemInfo.GetAppSetting("log4net.Internal.Emit"), true); |
| } |
| catch (Exception e) when (!e.IsFatal()) |
| { |
| // If an exception is thrown here then it looks like the config file does not |
| // parse correctly. |
| // |
| // We will leave debug OFF and print an Error message |
| Error(typeof(LogLog), "Exception while reading ConfigurationSettings. Check your .config file is well formed XML.", e); |
| } |
| } |
| |
| /// <summary> |
| /// Gets or sets a value indicating whether log4net internal logging |
| /// is enabled or disabled. |
| /// </summary> |
| /// <value> |
| /// <c>true</c> if log4net internal logging is enabled, otherwise |
| /// <c>false</c>. |
| /// </value> |
| /// <remarks> |
| /// <para> |
| /// When set to <c>true</c>, internal debug level logging will be |
| /// displayed. |
| /// </para> |
| /// <para> |
| /// This value can be set by setting the application setting |
| /// <c>log4net.Internal.Debug</c> in the application configuration |
| /// file. |
| /// </para> |
| /// <para> |
| /// The default value is <c>false</c>, i.e. debugging is |
| /// disabled. |
| /// </para> |
| /// </remarks> |
| /// <example> |
| /// <para> |
| /// The following example enables internal debugging using the |
| /// application configuration file : |
| /// </para> |
| /// <code lang="XML" escaped="true"> |
| /// <configuration> |
| /// <appSettings> |
| /// <add key="log4net.Internal.Debug" value="true" /> |
| /// </appSettings> |
| /// </configuration> |
| /// </code> |
| /// </example> |
| public static bool InternalDebugging { get; set; } |
| |
| /// <summary> |
| /// Gets or sets a value indicating whether log4net should generate no output |
| /// from internal logging, not even for errors. |
| /// </summary> |
| /// <value> |
| /// <c>true</c> if log4net should generate no output at all from internal |
| /// logging, otherwise <c>false</c>. |
| /// </value> |
| /// <remarks> |
| /// <para> |
| /// When set to <c>true</c> will cause internal logging at all levels to be |
| /// suppressed. This means that no warning or error reports will be logged. |
| /// This option overrides the <see cref="InternalDebugging"/> setting and |
| /// disables all debug also. |
| /// </para> |
| /// <para>This value can be set by setting the application setting |
| /// <c>log4net.Internal.Quiet</c> in the application configuration file. |
| /// </para> |
| /// <para> |
| /// The default value is <c>false</c>, i.e. internal logging is not |
| /// disabled. |
| /// </para> |
| /// </remarks> |
| /// <example> |
| /// The following example disables internal logging using the |
| /// application configuration file : |
| /// <code lang="XML" escaped="true"> |
| /// <configuration> |
| /// <appSettings> |
| /// <add key="log4net.Internal.Quiet" value="true" /> |
| /// </appSettings> |
| /// </configuration> |
| /// </code> |
| /// </example> |
| public static bool QuietMode { get; set; } |
| |
| /// <summary> |
| /// Configures whether internal messages are emitted to Console.Out and Console.Error. |
| /// </summary> |
| public static bool EmitInternalMessages { get; set; } = true; |
| |
| /// <summary> |
| /// Execute the callback with internal messages suppressed |
| /// </summary> |
| /// <param name="callback">Callback</param> |
| public static void ExecuteWithoutEmittingInternalMessages(Action callback) |
| { |
| callback.EnsureNotNull(); |
| bool oldEmitInternalMessages = EmitInternalMessages; |
| EmitInternalMessages = false; |
| try |
| { |
| callback(); |
| } |
| finally |
| { |
| EmitInternalMessages = oldEmitInternalMessages; |
| } |
| } |
| |
| /// <summary> |
| /// Raises the LogReceived event when an internal messages is received. |
| /// </summary> |
| /// <param name="source"></param> |
| /// <param name="prefix"></param> |
| /// <param name="message"></param> |
| /// <param name="exception"></param> |
| public static void OnLogReceived(Type source, string prefix, string message, Exception? exception) => LogReceived?.Invoke(null, new LogReceivedEventArgs(new LogLog(source, prefix, message, exception))); |
| |
| /// <summary> |
| /// Test if LogLog.Debug is enabled for output. |
| /// </summary> |
| /// <value> |
| /// <c>true</c> if Debug is enabled |
| /// </value> |
| /// <remarks> |
| /// <para> |
| /// Test if LogLog.Debug is enabled for output. |
| /// </para> |
| /// </remarks> |
| public static bool IsDebugEnabled => InternalDebugging && !QuietMode; |
| |
| /// <summary> |
| /// Writes log4net internal debug messages to the |
| /// standard output stream. |
| /// </summary> |
| /// <param name="source"></param> |
| /// <param name="message">The message to log.</param> |
| /// <remarks> |
| /// <para> |
| /// All internal debug messages are prepended with |
| /// the string "log4net: ". |
| /// </para> |
| /// </remarks> |
| public static void Debug(Type source, string message) |
| { |
| if (IsDebugEnabled) |
| { |
| if (EmitInternalMessages) |
| { |
| EmitOutLine(Log4NetPrefix + message); |
| } |
| |
| OnLogReceived(source, Log4NetPrefix, message, null); |
| } |
| } |
| |
| /// <summary> |
| /// Writes log4net internal debug messages to the |
| /// standard output stream. |
| /// </summary> |
| /// <param name="source">The Type that generated this message.</param> |
| /// <param name="message">The message to log.</param> |
| /// <param name="exception">An exception to log.</param> |
| /// <remarks> |
| /// <para> |
| /// All internal debug messages are prepended with |
| /// the string "log4net: ". |
| /// </para> |
| /// </remarks> |
| public static void Debug(Type source, string message, Exception? exception) |
| { |
| if (IsDebugEnabled) |
| { |
| if (EmitInternalMessages) |
| { |
| EmitOutLine(Log4NetPrefix + message); |
| if (exception is not null) |
| { |
| EmitOutLine(exception.ToString()); |
| } |
| } |
| |
| OnLogReceived(source, Log4NetPrefix, message, exception); |
| } |
| } |
| |
| /// <summary> |
| /// Test if LogLog.Warn is enabled for output. |
| /// </summary> |
| /// <value> |
| /// <c>true</c> if Warn is enabled |
| /// </value> |
| public static bool IsWarnEnabled => !QuietMode; |
| |
| /// <summary> |
| /// Writes log4net internal warning messages to the |
| /// standard error stream. |
| /// </summary> |
| /// <param name="source">The Type that generated this message.</param> |
| /// <param name="message">The message to log.</param> |
| /// <remarks> |
| /// <para> |
| /// All internal warning messages are prepended with |
| /// the string "log4net:WARN ". |
| /// </para> |
| /// </remarks> |
| public static void Warn(Type source, string message) |
| { |
| if (IsWarnEnabled) |
| { |
| if (EmitInternalMessages) |
| { |
| EmitErrorLine(WarnPrefix + message); |
| } |
| |
| OnLogReceived(source, WarnPrefix, message, null); |
| } |
| } |
| |
| /// <summary> |
| /// Writes log4net internal warning messages to the |
| /// standard error stream. |
| /// </summary> |
| /// <param name="source">The Type that generated this message.</param> |
| /// <param name="message">The message to log.</param> |
| /// <param name="exception">An exception to log.</param> |
| /// <remarks> |
| /// <para> |
| /// All internal warning messages are prepended with |
| /// the string "log4net:WARN ". |
| /// </para> |
| /// </remarks> |
| public static void Warn(Type source, string message, Exception? exception) |
| { |
| if (IsWarnEnabled) |
| { |
| if (EmitInternalMessages) |
| { |
| EmitErrorLine(WarnPrefix + message); |
| if (exception is not null) |
| { |
| EmitErrorLine(exception.ToString()); |
| } |
| } |
| |
| OnLogReceived(source, WarnPrefix, message, exception); |
| } |
| } |
| |
| /// <summary> |
| /// Test if LogLog.Error is enabled for output. |
| /// </summary> |
| /// <value> |
| /// <c>true</c> if Error is enabled |
| /// </value> |
| /// <remarks> |
| /// <para> |
| /// Test if LogLog.Error is enabled for output. |
| /// </para> |
| /// </remarks> |
| public static bool IsErrorEnabled => !QuietMode; |
| |
| /// <summary> |
| /// Writes log4net internal error messages to the |
| /// standard error stream. |
| /// </summary> |
| /// <param name="source">The Type that generated this message.</param> |
| /// <param name="message">The message to log.</param> |
| /// <remarks> |
| /// <para> |
| /// All internal error messages are prepended with |
| /// the string "log4net:ERROR ". |
| /// </para> |
| /// </remarks> |
| public static void Error(Type source, string message) |
| { |
| if (IsErrorEnabled) |
| { |
| if (EmitInternalMessages) |
| { |
| EmitErrorLine(ErrPrefix + message); |
| } |
| |
| OnLogReceived(source, ErrPrefix, message, null); |
| } |
| } |
| |
| /// <summary> |
| /// Writes log4net internal error messages to the |
| /// standard error stream. |
| /// </summary> |
| /// <param name="source">The Type that generated this message.</param> |
| /// <param name="message">The message to log.</param> |
| /// <param name="exception">An exception to log.</param> |
| /// <remarks> |
| /// <para> |
| /// All internal debug messages are prepended with |
| /// the string "log4net:ERROR ". |
| /// </para> |
| /// </remarks> |
| public static void Error(Type source, string message, Exception? exception) |
| { |
| if (IsErrorEnabled) |
| { |
| if (EmitInternalMessages) |
| { |
| EmitErrorLine(ErrPrefix + message); |
| if (exception is not null) |
| { |
| EmitErrorLine(exception.ToString()); |
| } |
| } |
| |
| OnLogReceived(source, ErrPrefix, message, exception); |
| } |
| } |
| |
| /// <summary> |
| /// Writes output to the standard output stream. |
| /// </summary> |
| /// <param name="message">The message to log.</param> |
| /// <remarks> |
| /// <para> |
| /// Writes to both Console.Out and System.Diagnostics.Trace. |
| /// </para> |
| /// <para> |
| /// If the AppDomain is not configured with a config file then |
| /// the call to System.Diagnostics.Trace may fail. This is only |
| /// an issue if you are programmatically creating your own AppDomains. |
| /// </para> |
| /// </remarks> |
| private static void EmitOutLine(string message) |
| { |
| try |
| { |
| Console.Out.WriteLine(message); |
| Trace.WriteLine(message); |
| } |
| catch (Exception e) when (!e.IsFatal()) |
| { |
| // Ignore exception, what else can we do? Not really a good idea to propagate back to the caller |
| } |
| } |
| |
| /// <summary> |
| /// Writes output to the standard error stream. |
| /// </summary> |
| /// <param name="message">The message to log.</param> |
| /// <remarks> |
| /// <para> |
| /// Writes to both Console.Error and System.Diagnostics.Trace. |
| /// Note that the System.Diagnostics.Trace is not supported |
| /// on the Compact Framework. |
| /// </para> |
| /// <para> |
| /// If the AppDomain is not configured with a config file then |
| /// the call to System.Diagnostics.Trace may fail. This is only |
| /// an issue if you are programmatically creating your own AppDomains. |
| /// </para> |
| /// </remarks> |
| private static void EmitErrorLine(string message) |
| { |
| try |
| { |
| Console.Error.WriteLine(message); |
| Trace.WriteLine(message); |
| } |
| catch (Exception e) when (!e.IsFatal()) |
| { |
| // Ignore exception, what else can we do? Not really a good idea to propagate back to the caller |
| } |
| } |
| |
| private const string Log4NetPrefix = "log4net: "; |
| private const string ErrPrefix = "log4net:ERROR "; |
| private const string WarnPrefix = "log4net:WARN "; |
| |
| /// <summary> |
| /// Subscribes to the LogLog.LogReceived event and stores messages |
| /// to the supplied IList instance. |
| /// </summary> |
| [System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1063:Implement IDisposable Correctly")] |
| [System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1002:Do not expose generic lists")] |
| public class LogReceivedAdapter : IDisposable |
| { |
| private readonly LogReceivedEventHandler _handler; |
| |
| /// <inheritdoc/> |
| public LogReceivedAdapter(List<LogLog> items) |
| { |
| Items = items; |
| _handler = LogLog_LogReceived; |
| LogReceived += _handler; |
| } |
| |
| void LogLog_LogReceived(object? source, LogReceivedEventArgs e) |
| { |
| lock (((ICollection)Items).SyncRoot) |
| { |
| Items.Add(e.LogLog); |
| } |
| } |
| |
| /// <summary> |
| /// |
| /// </summary> |
| public List<LogLog> Items { get; } |
| |
| /// <inheritdoc/> |
| public void Dispose() => LogReceived -= _handler; |
| } |
| } |
| |
| /// <summary> |
| /// |
| /// </summary> |
| public class LogReceivedEventArgs : EventArgs |
| { |
| /// <summary> |
| /// |
| /// </summary> |
| /// <param name="loglog"></param> |
| public LogReceivedEventArgs(LogLog loglog) |
| { |
| this.LogLog = loglog; |
| } |
| |
| /// <summary> |
| /// |
| /// </summary> |
| public LogLog LogLog { get; } |
| } |