Log.cs :  » Web-Frameworks » Ingenious-MVC » Ingenious » Mvc » Util » C# / CSharp Open Source

Home
C# / CSharp Open Source
1.2.6.4 mono .net core
2.2.6.4 mono core
3.Aspect Oriented Frameworks
4.Bloggers
5.Build Systems
6.Business Application
7.Charting Reporting Tools
8.Chat Servers
9.Code Coverage Tools
10.Content Management Systems CMS
11.CRM ERP
12.Database
13.Development
14.Email
15.Forum
16.Game
17.GIS
18.GUI
19.IDEs
20.Installers Generators
21.Inversion of Control Dependency Injection
22.Issue Tracking
23.Logging Tools
24.Message
25.Mobile
26.Network Clients
27.Network Servers
28.Office
29.PDF
30.Persistence Frameworks
31.Portals
32.Profilers
33.Project Management
34.RSS RDF
35.Rule Engines
36.Script
37.Search Engines
38.Sound Audio
39.Source Control
40.SQL Clients
41.Template Engines
42.Testing
43.UML
44.Web Frameworks
45.Web Service
46.Web Testing
47.Wiki Engines
48.Windows Presentation Foundation
49.Workflows
50.XML Parsers
C# / C Sharp
C# / C Sharp by API
C# / CSharp Tutorial
C# / CSharp Open Source » Web Frameworks » Ingenious MVC 
Ingenious MVC » Ingenious » Mvc » Util » Log.cs
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Reflection;
using System.Text;

namespace Ingenious.Mvc.Util{
  /// <summary>
  /// Provides a thin wrapper around the <see cref="TraceSource"/> class to simplify logging code.
  /// </summary>
  /// <remarks>
  /// <para>
  /// The <c>Log</c> class provides a useful wrapper around the <see cref="TraceSource"/> class. It does so to simplify the
  /// code required to log messages.
  /// </para>
  /// <para>
  /// Instances of <c>Log</c> can be created based on the name of a <see cref="Type"/> (<see cref="CreateForType"/>),
  /// <see cref="Assembly"/> (<see cref="CreateForAssembly"/>) or namespace (<see cref="CreateForNamespace"/>). Alternatively,
  /// the <see cref="CreateNamed"/> method allows an arbitrary name to be used.
  /// </para>
  /// <para>
  /// The <see cref="Debug"/>, <see cref="Verbose"/>, <see cref="Information"/>, <see cref="Warning"/> and <see cref="Error"/>
  /// methods can be used to log messages. The <see cref="Debug"/> overloads are conditionally compiled for debug builds only.
  /// All of these methods have overloads that accept a format string and arguments.
  /// </para>
  /// <para>
  /// In addition, the <see cref="Write"/> method provides a general means of logging at any specified level. This can be
  /// useful where the log level is not known until runtime, or when the required level has no corresponding method such as
  /// the <see cref="LogLevel.Critical"/> level.
  /// </para>
  /// <para>
  /// The <see cref="IsVerboseEnabled"/>, <see cref="IsInformationEnabled"/>, <see cref="IsWarningEnabled"/> and
  /// <see cref="IsErrorEnabled"/> properties can be used to determine whether a specified log level is enabled. There is no
  /// <c>IsDebugEnabled</c> property, since that is determined at compile-time based on the <c>DEBUG</c> compiler symbol.
  /// </para>
  /// <para>
  /// In addition, the <see cref="ShouldWrite"/> method provides a general means of determining whether a specified log level
  /// is enabled. This can be useful where the log level is not known until runtime, or when the required level has no
  /// corresponding method such as the <see cref="LogLevel.Critical"/> level.
  /// </para>
  /// <para>
  /// The <see cref="Performance"/> methods can be used to measure the performance of a block of code. These methods return
  /// an <see cref="IDisposable"/> instance that will automatically log performance information when disposed.
  /// </para>
  /// <para>
  /// The <see cref="PushLogicalOperation"/> and <see cref="PopLogicalOperation"/> methods can be used to begin and end
  /// logical operations. <see cref="PushLogicalOperation"/> returns an <see cref="IDisposable"/> implementation that will
  /// automatically invoke <see cref="PopLogicalOperation"/> when disposed. As such, it can be used effectively from a
  /// <c>using</c> block.
  /// </para>
  /// <para>
  /// Logical operations are maintained in a stack. The stack of logical operations in progress can optionally be included in
  /// each logged message (except for debug messages). This allows you to diagnose the logical operations that were in progress
  /// when a message was logged.
  /// </para>
  /// </remarks>
  /// <example>
  /// The following code shows how a <c>Log</c> instance can be created for a specified type:
  /// <code>
  /// namespace MyNamespace
  /// {
  ///    public class MyClass
  ///    {
  ///      private static readonly Log _log = Log.CreateForType(typeof(MyClass));
  ///    }
  /// }
  /// </code>
  /// </example>
  /// <example>
  /// The following code shows how a <c>Log</c> instance can be created for use by an assembly:
  /// <code>
  /// namespace MyNamespace
  /// {
  ///    internal class MyClass
  ///    {
  ///      internal static readonly Log Log = Log.CreateForAssembly(typeof(MyClass));
  ///    }
  /// }
  /// </code>
  /// </example>
  /// <example>
  /// The following code logs some information to the log:
  /// <code>
  /// _log.Information("Here is some information.");
  /// </code>
  /// </example>
  /// <example>
  /// The following code logs some formatted information to the log:
  /// <code>
  /// _log.Information("Here is some information with a parameter at the end: {0}.", someValue);
  /// </code>
  /// </example>
  /// <example>
  /// The following code checks whether information will be logged before it attempts to do so:
  /// <code>
  /// if (_log.IsInformationEnabled)
  /// {
  ///    _log.Information("Here is some information with parameters: {0}, {1}, {2}.", val1, val2, val3);
  /// }
  /// </code>
  /// </example>
  /// <example>
  /// The following code logs a critical message:
  /// <code>
  ///  _log.Write(LogLevel.Critical, "Some critical message.");
  /// </code>
  /// </example>
  /// <example>
  /// The following code measures the performance of a block of code:
  /// <code>
  ///  using (_log.Performance("Some code I want measured"))
  /// {
  ///    //code to measure goes here
  /// }
  /// </code>
  /// </example>
  /// <example>
  /// The following code begins a logical operation and logs from inside and outside the operation:
  /// <code>
  ///  using (_log.PushLogicalOperation("My Operation"))
  /// {
  ///    _log.Information("We're inside the logical operation.");
  /// }
  /// 
  /// _log.Information("Now we're outside the logical operation.");
  /// </code>
  /// </example>
  /// <example>
  /// The following shows some example configuration for the <c>&lt;system.diagnostics&gt;</c> subsystem, assuming the
  /// existence of the class <c>MyClass</c> defined in the example above:
  /// <code>
  /// <![CDATA[
  /// <system.diagnostics>
  ///    <sources>
  ///      <source name="MyNamespace.MyClass"
  ///          switchName="MyNamespace.MyClass" 
  ///          switchType="System.Diagnostics.SourceSwitch">
  ///        <listeners>
  ///          <add name="listener"/>
  ///        </listeners>
  ///   </source>
  ///    </sources>
  ///    <switches>
  ///      <add name="MyNamespace.MyClass" value="Verbose"/>
  ///    </switches>
  ///    <sharedListeners>
  ///      <add name="listener" 
  ///          type="System.Diagnostics.ConsoleTraceListener" 
  ///          initializeData="false"
  ///          traceOutputOptions="DateTime,ThreadId,Timestamp,LogicalOperationStack"/>
  ///    </sharedListeners>
  ///    <trace autoflush="true">
  ///      <listeners>
  ///        <add name="listener"/>
  ///      </listeners>
  ///    </trace>
  /// </system.diagnostics>
  /// ]]>
  /// </code>
  /// </example>
  public sealed class Log
  {
    private readonly TraceSource _traceSource;
    //defines the accepted log levels - used to increase the performance of argument checking
    private static readonly LogLevel[] _logLevels = new LogLevel[] { LogLevel.Critical, LogLevel.Error, LogLevel.Information, LogLevel.Verbose, LogLevel.Warning };

    /// <summary>
    /// Gets the <see cref="TraceSource"/> that this <c>Log</c> wraps.
    /// </summary>
    /// <remarks>
    /// This property facilitates unit testing.
    /// </remarks>
    internal TraceSource TraceSource
    {
      get
      {
        return _traceSource;
      }
    }

    /// <summary>
    /// Gets the name of the underlying <see cref="TraceSource"/>.
    /// </summary>
    /// <remarks>
    /// This name is used to configure the <see cref="TraceSource"/> in the <c>&lt;system.diagnostics&gt;</c> section of the
    /// application's configuration file.
    /// </remarks>
    public string Name
    {
      get
      {
        return _traceSource.Name;
      }
    }

    /// <summary>
    /// Gets a value indicating whether <see cref="LogLevel.Verbose"/> messages will be logged.
    /// </summary>
    public bool IsVerboseEnabled
    {
      get
      {
        return _traceSource.Switch.ShouldTrace(TraceEventType.Verbose);
      }
    }

    /// <summary>
    /// Gets a value indicating whether <see cref="LogLevel.Information"/> messages will be logged.
    /// </summary>
    public bool IsInformationEnabled
    {
      get
      {
        return _traceSource.Switch.ShouldTrace(TraceEventType.Information);
      }
    }

    /// <summary>
    /// Gets a value indicating whether <see cref="LogLevel.Warning"/> messages will be logged.
    /// </summary>
    public bool IsWarningEnabled
    {
      get
      {
        return _traceSource.Switch.ShouldTrace(TraceEventType.Warning);
      }
    }

    /// <summary>
    /// Gets a value indicating whether <see cref="LogLevel.Error"/> messages will be logged.
    /// </summary>
    public bool IsErrorEnabled
    {
      get
      {
        return _traceSource.Switch.ShouldTrace(TraceEventType.Error);
      }
    }

    /// <summary>
    /// Creates an instance of <c>Log</c> for the specified type.
    /// </summary>
    /// <param name="type">
    /// The type for which the log is created.
    /// </param>
    /// <returns>
    /// The <c>Log</c> instance.
    /// </returns>
    public static Log CreateForType(Type type)
    {
      ArgumentHelper.AssertNotNull(type, "type");
      return new Log(type.FullName);
    }

    /// <summary>
    /// Creates an instance of <c>Log</c> for the namespace of the specified type.
    /// </summary>
    /// <param name="type">
    /// The type whose namespace is used to create the log.
    /// </param>
    /// <returns>
    /// The <c>Log</c> instance.
    /// </returns>
    public static Log CreateForNamespace(Type type)
    {
      ArgumentHelper.AssertNotNull(type, "type");
      return new Log(type.Namespace);
    }

    /// <summary>
    /// Creates an instance of <c>Log</c> for the assembly of the specified type.
    /// </summary>
    /// <param name="type">
    /// The type whose assembly is used to create the log.
    /// </param>
    /// <returns>
    /// The <c>Log</c> instance.
    /// </returns>
    public static Log CreateForAssembly(Type type)
    {
      ArgumentHelper.AssertNotNull(type, "type");
      return CreateForAssembly(type.Assembly);
    }

    /// <summary>
    /// Creates an instance of <c>Log</c> for the specified assembly.
    /// </summary>
    /// <param name="assembly">
    /// The assembly for which the log is created.
    /// </param>
    /// <returns>
    /// The <c>Log</c> instance.
    /// </returns>
    public static Log CreateForAssembly(Assembly assembly)
    {
      ArgumentHelper.AssertNotNull(assembly, "assembly");
      return new Log(assembly.GetName().Name);
    }

    /// <summary>
    /// Creates an instance of <c>Log</c> with an arbitrary name.
    /// </summary>
    /// <param name="name">
    /// The name for the log.
    /// </param>
    /// <returns>
    /// The <c>Log</c> instance.
    /// </returns>
    public static Log CreateNamed(string name)
    {
      ArgumentHelper.AssertNotNull(name, "name");
      return new Log(name);
    }

    private Log(string name)
    {
      _traceSource = new TraceSource(name);
    }

    /// <summary>
    /// Logs a debug message.
    /// </summary>
    /// <remarks>
    /// This method is conditional on the <c>DEBUG</c> compiler symbol. Therefore calls to the method will only be included
    /// in debug builds.
    /// </remarks>
    /// <param name="message">
    /// The message to log.
    /// </param>
    [Conditional("DEBUG")]
    [SuppressMessage("Microsoft.Performance", "CA1822", Justification = "The member is supposed to be access via a Log instance, even if that is not strictly required.")]
    public void Debug(string message)
    {
      ArgumentHelper.AssertNotNull(message, "message");
      System.Diagnostics.Debug.WriteLine(message);
    }

    /// <summary>
    /// Logs a debug message.
    /// </summary>
    /// <remarks>
    /// This method is conditional on the <c>DEBUG</c> compiler symbol. Therefore calls to the method will only be included
    /// in debug builds.
    /// </remarks>
    /// <param name="format">
    /// The message format to log.
    /// </param>
    /// <param name="args">
    /// Arguments to be substituted into <paramref name="format"/> prior to logging.
    /// </param>
    [Conditional("DEBUG")]
    [SuppressMessage("Microsoft.Performance", "CA1822", Justification = "The member is supposed to be access via a Log instance, even if that is not strictly required.")]
    public void Debug(string format, params object[] args)
    {
      ArgumentHelper.AssertNotNull(format, "format");
      ArgumentHelper.AssertNotNull(args, "args");
      System.Diagnostics.Debug.WriteLine(string.Format(CultureInfo.InvariantCulture, format, args));
    }

    /// <summary>
    /// Logs a verbose message.
    /// </summary>
    /// <param name="message">
    /// The message to log.
    /// </param>
    public void Verbose(string message)
    {
      Write(LogLevel.Verbose, message);
    }

    /// <summary>
    /// Logs a verbose message.
    /// </summary>
    /// <param name="format">
    /// The message format to log.
    /// </param>
    /// <param name="args">
    /// Arguments to be substituted into <paramref name="format"/> prior to logging.
    /// </param>
    public void Verbose(string format, params object[] args)
    {
      Write(LogLevel.Verbose, format, args);
    }

    /// <summary>
    /// Logs an informational message.
    /// </summary>
    /// <param name="message">
    /// The message to log.
    /// </param>
    public void Information(string message)
    {
      Write(LogLevel.Information, message);
    }

    /// <summary>
    /// Logs an informational message.
    /// </summary>
    /// <param name="format">
    /// The message format to log.
    /// </param>
    /// <param name="args">
    /// Arguments to be substituted into <paramref name="format"/> prior to logging.
    /// </param>
    public void Information(string format, params object[] args)
    {
      Write(LogLevel.Information, format, args);
    }

    /// <summary>
    /// Logs a warning message.
    /// </summary>
    /// <param name="message">
    /// The message to log.
    /// </param>
    public void Warning(string message)
    {
      Write(LogLevel.Warning, message);
    }

    /// <summary>
    /// Logs a warning message.
    /// </summary>
    /// <param name="format">
    /// The message format to log.
    /// </param>
    /// <param name="args">
    /// Arguments to be substituted into <paramref name="format"/> prior to logging.
    /// </param>
    public void Warning(string format, params object[] args)
    {
      Write(LogLevel.Warning, format, args);
    }

    /// <summary>
    /// Logs an error message.
    /// </summary>
    /// <param name="message">
    /// The message to log.
    /// </param>
    public void Error(string message)
    {
      Write(LogLevel.Error, message);
    }

    /// <summary>
    /// Logs an error message.
    /// </summary>
    /// <param name="format">
    /// The message format to log.
    /// </param>
    /// <param name="args">
    /// Arguments to be substituted into <paramref name="format"/> prior to logging.
    /// </param>
    public void Error(string format, params object[] args)
    {
      Write(LogLevel.Error, format, args);
    }

    /// <summary>
    /// Logs the details of an exception at the <see cref="LogLevel.Error"/> log level.
    /// </summary>
    /// <param name="ex">
    /// The exception whose details are to be logged.
    /// </param>
    public void Exception(Exception ex)
    {
      Exception(LogLevel.Error, ex);
    }

    /// <summary>
    /// Logs the details of an exception at a specified <see cref="LogLevel"/>.
    /// </summary>
    /// <param name="level">
    /// The <see cref="LogLevel"/> at which the exception details will be logged.
    /// </param>
    /// <param name="ex">
    /// The exception whose details are to be logged.
    /// </param>
    public void Exception(LogLevel level, Exception ex)
    {
      ArgumentHelper.AssertNotNull(ex, "ex");
      ArgumentHelper.AssertEnumMember(level);
      StringBuilder sb = new StringBuilder();

      while (ex != null)
      {
        sb.Append(ex.GetType().FullName).Append(" : ").AppendLine(ex.Message);
        sb.AppendLine(ex.StackTrace);

        ex = ex.InnerException;

        if (ex != null)
        {
          sb.AppendLine("--- INNER EXCEPTION ---");
        }
      }

      Write(level, sb.ToString());
    }

    /// <summary>
    /// Obtains an <see cref="IDisposable"/> instance that will log the performance of a block of code when disposed.
    /// </summary>
    /// <param name="message">
    /// The message to log along with the performance information.
    /// </param>
    /// <returns>
    /// An <see cref="IDisposable"/> that will log performance information when disposed.
    /// </returns>
    public IDisposable Performance(string message)
    {
      ArgumentHelper.AssertNotNullOrEmpty(message, "message", true);
      return new PerformanceLogger(this, message);
    }

    /// <summary>
    /// Obtains an <see cref="IDisposable"/> instance that will log the performance of a block of code when disposed.
    /// </summary>
    /// <param name="format">
    /// The message format to log.
    /// </param>
    /// <param name="args">
    /// Arguments to be substituted into <paramref name="format"/> prior to logging.
    /// </param>
    /// <returns>
    /// An <see cref="IDisposable"/> that will log performance information when disposed.
    /// </returns>
    public IDisposable Performance(string format, params object[] args)
    {
      ArgumentHelper.AssertNotNull(format, "format");
      ArgumentHelper.AssertNotNull(args, "args");
      return Performance(string.Format(CultureInfo.InvariantCulture, format, args));
    }

    /// <summary>
    /// Determines whether messages of the specified <see cref="LogLevel"/> will be written.
    /// </summary>
    /// <param name="level">
    /// The log level.
    /// </param>
    /// <returns>
    /// <see langword="true"/> if messages of the specified level will be logged, otherwise <see langword="false"/>.
    /// </returns>
    public bool ShouldWrite(LogLevel level)
    {
      ArgumentHelper.AssertEnumMember(level, _logLevels);
      return _traceSource.Switch.ShouldTrace((TraceEventType) level);
    }

    /// <summary>
    /// Writes a message at the specified level.
    /// </summary>
    /// <param name="level">
    /// The level at which the message will be logged.
    /// </param>
    /// <param name="message">
    /// The message to log.
    /// </param>
    public void Write(LogLevel level, string message)
    {
      ArgumentHelper.AssertEnumMember(level, _logLevels);
      ArgumentHelper.AssertNotNull(message, "message");
      _traceSource.TraceEvent((TraceEventType) level, 0, message);
    }

    /// <summary>
    /// Writes a formatted message at the specified level.
    /// </summary>
    /// <param name="level">
    /// The level at which the message will be logged.
    /// </param>
    /// <param name="format">
    /// The message format to log.
    /// </param>
    /// <param name="args">
    /// Arguments to be substituted into <paramref name="format"/> prior to logging.
    /// </param>
    public void Write(LogLevel level, string format, params object[] args)
    {
      ArgumentHelper.AssertEnumMember(level, _logLevels);
      ArgumentHelper.AssertNotNull(format, "format");
      ArgumentHelper.AssertNotNull(args, "args");
      _traceSource.TraceEvent((TraceEventType) level, 0, format, args);
    }

    /// <summary>
    /// Pushes a named logical operation onto the logical operation stack.
    /// </summary>
    /// <remarks>
    /// This method can be used to add a new logical operation to the logical operation stack. This stack can optionally be
    /// included in any log messages of any level (except for debug messages).
    /// </remarks>
    /// <param name="operationName">
    /// The name of the logical operation to begin.
    /// </param>
    /// <returns>
    /// An <see cref="IDisposable"/> implementation that will automatically invoke <see cref="PopLogicalOperation"/> when
    /// disposed.
    /// </returns>
    [SuppressMessage("Microsoft.Performance", "CA1822", Justification = "The member is supposed to be access via a Log instance, even if that is not strictly required.")]
    public IDisposable PushLogicalOperation(string operationName)
    {
      ArgumentHelper.AssertNotNullOrEmpty(operationName, "operationName", true);
      System.Diagnostics.Trace.CorrelationManager.StartLogicalOperation(operationName);
      return new LogicalOperationClosure();
    }

    /// <summary>
    /// Pushes a named logical operation onto the logical operation stack.
    /// </summary>
    /// <param name="format">
    /// The format of the operation name.
    /// </param>
    /// <param name="args">
    /// Any arguments to substitute into the operation name.
    /// </param>
    /// <returns>
    /// An <see cref="IDisposable"/> implementation that will automatically invoke <see cref="PopLogicalOperation"/> when
    /// disposed.
    /// </returns>
    [SuppressMessage("Microsoft.Performance", "CA1822", Justification = "The member is supposed to be access via a Log instance, even if that is not strictly required.")]
    public IDisposable PushLogicalOperation(string format, params object[] args)
    {
      ArgumentHelper.AssertNotNull(format, "format");
      ArgumentHelper.AssertNotNull(args, "args");
      return PushLogicalOperation(string.Format(CultureInfo.InvariantCulture, format, args));
    }

    /// <summary>
    /// Pops the last logical operation off the logical operation stack.
    /// </summary>
    /// <exception cref="InvalidOperationException">
    /// If there are no logical operations on the stack to be popped.
    /// </exception>
    [SuppressMessage("Microsoft.Performance", "CA1822", Justification = "The member is supposed to be access via a Log instance, even if that is not strictly required.")]
    public void PopLogicalOperation()
    {
      System.Diagnostics.Trace.CorrelationManager.StopLogicalOperation();
    }

    private sealed class LogicalOperationClosure : IDisposable
    {
      private bool _disposed;

      public void Dispose()
      {
        if (!_disposed)
        {
          _disposed = true;
          System.Diagnostics.Trace.CorrelationManager.StopLogicalOperation();
        }
      }
    }

    private sealed class PerformanceLogger : IDisposable
    {
      private Log _log;
      private string _message;
      private Stopwatch _stopwatch;
      private bool _disposed;

      public PerformanceLogger(Log log, string message)
      {
        System.Diagnostics.Debug.Assert(log != null);
        System.Diagnostics.Debug.Assert(message != null);
        _log = log;
        _message = message;
        _stopwatch = Stopwatch.StartNew();
      }

      public void Dispose()
      {
        if (!_disposed)
        {
          _stopwatch.Stop();
          _disposed = true;
          _log.Information("'{0}' took {1} to execute ({2}ms)", _message, _stopwatch.Elapsed, _stopwatch.ElapsedMilliseconds);
        }
      }
    }
  }
}
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.