blob: 9a9b4dad815373b43dd6a36ce22a918f2d21c537 [file] [log] [blame]
#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;
#if !NETSTANDARD1_3
using System.Configuration;
#endif
using System.Diagnostics;
namespace log4net.Util
{
/// <summary>
///
/// </summary>
/// <param name="source"></param>
/// <param name="e"></param>
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;
private readonly Type source;
private readonly DateTime timeStampUtc;
private readonly string prefix;
private readonly string message;
private readonly Exception exception;
/// <summary>
/// The Type that generated the internal message.
/// </summary>
public Type Source
{
get { return source; }
}
/// <summary>
/// The DateTime stamp of when the internal message was received.
/// </summary>
public DateTime TimeStamp
{
get { return timeStampUtc.ToLocalTime(); }
}
/// <summary>
/// The UTC DateTime stamp of when the internal message was received.
/// </summary>
public DateTime TimeStampUtc
{
get { return timeStampUtc; }
}
/// <summary>
/// A string indicating the severity of the internal message.
/// </summary>
/// <remarks>
/// "log4net: ",
/// "log4net:ERROR ",
/// "log4net:WARN "
/// </remarks>
public string Prefix
{
get { return prefix; }
}
/// <summary>
/// The internal log message.
/// </summary>
public string Message
{
get { return message; }
}
/// <summary>
/// The Exception related to the message.
/// </summary>
/// <remarks>
/// Optional. Will be null if no Exception was passed.
/// </remarks>
public Exception Exception
{
get { return exception; }
}
/// <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()
{
return Prefix + Source.Name + ": " + Message;
}
#region Private Instance Constructors
/// <summary>
/// Initializes a new instance of the <see cref="LogLog" /> class.
/// </summary>
/// <param name="source"></param>
/// <param name="prefix"></param>
/// <param name="message"></param>
/// <param name="exception"></param>
public LogLog(Type source, string prefix, string message, Exception exception)
{
timeStampUtc = DateTime.UtcNow;
this.source = source;
this.prefix = prefix;
this.message = message;
this.exception = exception;
}
#endregion Private Instance Constructors
#region Static Constructor
/// <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()
{
#if !NETCF
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 ex)
{
// 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.", ex);
}
#endif
}
#endregion Static Constructor
#region Public Static Properties
/// <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 { return s_debugEnabled; }
set { s_debugEnabled = value; }
}
/// <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 { return s_quietMode; }
set { s_quietMode = value; }
}
/// <summary>
///
/// </summary>
public static bool EmitInternalMessages
{
get { return s_emitInternalMessages; }
set { s_emitInternalMessages = value; }
}
#endregion Public Static Properties
#region Public Static Methods
/// <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)
{
if (LogReceived != null)
{
LogReceived(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
{
get { return s_debugEnabled && !s_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(PREFIX + message);
}
OnLogReceived(source, PREFIX, 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(PREFIX + message);
if (exception != null)
{
EmitOutLine(exception.ToString());
}
}
OnLogReceived(source, PREFIX, message, exception);
}
}
/// <summary>
/// Test if LogLog.Warn is enabled for output.
/// </summary>
/// <value>
/// <c>true</c> if Warn is enabled
/// </value>
/// <remarks>
/// <para>
/// Test if LogLog.Warn is enabled for output.
/// </para>
/// </remarks>
public static bool IsWarnEnabled
{
get { return !s_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(WARN_PREFIX + message);
}
OnLogReceived(source, WARN_PREFIX, 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(WARN_PREFIX + message);
if (exception != null)
{
EmitErrorLine(exception.ToString());
}
}
OnLogReceived(source, WARN_PREFIX, 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
{
get { return !s_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(ERR_PREFIX + message);
}
OnLogReceived(source, ERR_PREFIX, 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(ERR_PREFIX + message);
if (exception != null)
{
EmitErrorLine(exception.ToString());
}
}
OnLogReceived(source, ERR_PREFIX, message, exception);
}
}
#endregion Public Static Methods
/// <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.
/// 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 EmitOutLine(string message)
{
try
{
#if NETCF
Console.WriteLine(message);
//System.Diagnostics.Debug.WriteLine(message);
#else
Console.Out.WriteLine(message);
Trace.WriteLine(message);
#endif
}
catch
{
// 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
{
#if NETCF
Console.WriteLine(message);
//System.Diagnostics.Debug.WriteLine(message);
#else
Console.Error.WriteLine(message);
Trace.WriteLine(message);
#endif
}
catch
{
// Ignore exception, what else can we do? Not really a good idea to propagate back to the caller
}
}
#region Private Static Fields
/// <summary>
/// Default debug level
/// </summary>
private static bool s_debugEnabled = false;
/// <summary>
/// In quietMode not even errors generate any output.
/// </summary>
private static bool s_quietMode = false;
private static bool s_emitInternalMessages = true;
private const string PREFIX = "log4net: ";
private const string ERR_PREFIX = "log4net:ERROR ";
private const string WARN_PREFIX = "log4net:WARN ";
#endregion Private Static Fields
/// <summary>
/// Subscribes to the LogLog.LogReceived event and stores messages
/// to the supplied IList instance.
/// </summary>
public class LogReceivedAdapter : IDisposable
{
private readonly IList items;
private readonly LogReceivedEventHandler handler;
/// <summary>
///
/// </summary>
/// <param name="items"></param>
public LogReceivedAdapter(IList items)
{
this.items = items;
handler = new LogReceivedEventHandler(LogLog_LogReceived);
LogReceived += handler;
}
void LogLog_LogReceived(object source, LogReceivedEventArgs e)
{
items.Add(e.LogLog);
}
/// <summary>
///
/// </summary>
public IList Items
{
get { return items; }
}
/// <summary>
///
/// </summary>
public void Dispose()
{
LogReceived -= handler;
}
}
}
/// <summary>
///
/// </summary>
public class LogReceivedEventArgs : EventArgs
{
private readonly LogLog loglog;
/// <summary>
///
/// </summary>
/// <param name="loglog"></param>
public LogReceivedEventArgs(LogLog loglog)
{
this.loglog = loglog;
}
/// <summary>
///
/// </summary>
public LogLog LogLog
{
get { return loglog; }
}
}
}