Simple way to perform error logging?

109,887

Solution 1

I wouldn't dig too much on external libraries since your logging needs are simple.

.NET Framework already ships with this feature in the namespace System.Diagnostics, you could write all the logging you need there by simply calling methods under the Trace class:

Trace.TraceInformation("Your Information");
Trace.TraceError("Your Error");
Trace.TraceWarning("Your Warning");

And then configure all the trace listeners that fit your needs on your app.config file:

<configuration>
  // other config
  <system.diagnostics>
    <trace autoflush="true" indentsize="4">
      <listeners>
        <add name="consoleListener" type="System.Diagnostics.ConsoleTraceListener"/>
        <add name="textWriterListener" type="System.Diagnostics.TextWriterTraceListener" initializeData="YourLogFile.txt"/>
        <add name="eventLogListener" type="System.Diagnostics.EventLogTraceListener" initializeData="YourEventLogSource" />
        <remove name="Default"/>
      </listeners>
    </trace>
  </system.diagnostics>
  // other config
</configuration>

or if you prefer, you can also configure your listeners in your application, without depending on a config file:

Trace.Listeners.Add(new TextWriterTraceListener("MyTextFile.log"));

Remember to set the Trace.AutoFlush property to true, for the Text log to work properly.

Solution 2

You could use SimpleLog.

It's a simple, but robust and powerful one-class logging solution, easy to understand, easy to integrate and easy to use. No need to spend days for setting up and customize log4Net, with that class, you're done in minutes.

Though it currently logs to a file, it should be easily customizable to log to a database.

http://www.codeproject.com/Tips/585796/Simple-Log

Solution 3

An optimal solution, in my opinion, would be to use NLog: http://nlog-project.org/

Just install the config package from NuGet: http://www.nuget.org/packages/NLog.Config/ and you will end up with the library and a pre-configured file logger...

Then in your code you just need:

// A logger member field:

private readonly Logger logger = LogManager.GetCurrentClassLogger(); // creates a logger using the class name

// use it:
logger.Info(...);
logger.Error(...);

// and also:
logger.ErrorException("text", ex); // which will log the stack trace.

In the config file you get, you need to uncomment the sections that you need:

<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">

    <!-- 
        See http://nlog-project.org/wiki/Configuration_file 
        for information on customizing logging rules and outputs.
    -->
    <targets>
        <!-- add your targets here -->

        <!-- UNCOMMENT THIS!
        <target xsi:type="File" name="f" fileName="${basedir}/logs/${shortdate}.log"
                layout="${longdate} ${uppercase:${level}} ${message}" />
        -->
    </targets>

    <rules>
        <!-- add your logging rules here -->

        <!-- UNCOMMENT THIS!
        <logger name="*" minlevel="Trace" writeTo="f" />
        -->
    </rules>
</nlog>

Edit the properties of the nlog.config file to

Copy to Output Directory: Copy always

Solution 4

Well log4net works like a brick. It may be a bit hard to configure, but its worth it. It also allows you to configure file locking of those log files etc.

http://www.codeproject.com/Articles/140911/log4net-Tutorial

Solution 5

Create a class called Log.cs I am using Linq To SQl to save to the database

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Text;
public static partial class Log
{
    /// <summary>
    /// Saves the exception details to ErrorLogging db with Low Priority
    /// </summary>
    /// <param name="ex">The exception.</param>
    public static void Save(this Exception ex)
    {
        Save(ex, ImpactLevel.Low, "");
    }

    /// <summary>
    /// Saves the exception details to ErrorLogging db with specified ImpactLevel
    /// </summary>
    /// <param name="ex">The exception.</param>
    /// <param name="impactLevel">The Impact level.</param>
    public static void Save(this Exception ex, ImpactLevel impactLevel)
    {
        Save(ex, impactLevel,"");
    }
    /// <summary>
    /// Saves the exception details to ErrorLogging db with specified ImpactLevel and user message
    /// </summary>
    /// <param name="ex">The exception</param>
    /// <param name="impactLevel">The impact level.</param>
    /// <param name="errorDescription">The error Description.</param>
    public static void Save(this Exception ex, ImpactLevel impactLevel, string errorDescription)
    {
        using (var db = new ErrorLoggingDataContext())
        {
            Log log = new Log();

            if (errorDescription != null && errorDescription != "")
            {
                log.ErrorShortDescription = errorDescription;
            }
            log.ExceptionType = ex.GetType().FullName;
            var stackTrace = new StackTrace(ex, true);
            var allFrames = stackTrace.GetFrames().ToList();
            foreach (var frame in allFrames)
            {
                log.FileName = frame.GetFileName();
                log.LineNumber = frame.GetFileLineNumber();
                var method = frame.GetMethod();
                log.MethodName = method.Name;
                log.ClassName = frame.GetMethod().DeclaringType.ToString();
            }

            log.ImpactLevel = impactLevel.ToString();
            try
            {
                log.ApplicationName = Assembly.GetCallingAssembly().GetName().Name;
            }
            catch
            {
                log.ApplicationName = "";
            }

            log.ErrorMessage = ex.Message;
            log.StackTrace = ex.StackTrace;
            if (ex.InnerException != null)
            {
                log.InnerException = ex.InnerException.ToString();
                log.InnerExceptionMessage = ex.InnerException.Message;
            }
            log.IpAddress = ""; //get the ip address

            if (System.Diagnostics.Debugger.IsAttached)
            {
                log.IsProduction = false;
            }

            try
            {
                db.Logs.InsertOnSubmit(log);
                db.SubmitChanges();
            }
            catch (Exception eex)
            {

            }
        }
    }
}

Create the following table

USE [database Name]
GO

/****** Object:  Table [dbo].[Log]    Script Date: 9/27/2016 11:52:32 AM ******/
SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

SET ANSI_PADDING ON
GO

CREATE TABLE [dbo].[Log](
    [LogId] [INT] IDENTITY(1,1) NOT NULL,
    [ErrorDate] [DATETIME] NOT NULL CONSTRAINT [DF_Log_Date]  DEFAULT (GETDATE()),
    [ErrorShortDescription] [VARCHAR](1000) NULL,
    [ExceptionType] [VARCHAR](255) NULL,
    [FileName] [VARCHAR](1000) NULL,
    [LineNumber] [INT] NULL,
    [MethodName] [VARCHAR](255) NULL,
    [ClassName] [VARCHAR](150) NULL,
    [ImpactLevel] [VARCHAR](50) NOT NULL,
    [ApplicationName] [VARCHAR](255) NULL,
    [ErrorMessage] [VARCHAR](4000) NULL,
    [StackTrace] [VARCHAR](MAX) NULL,
    [InnerException] [VARCHAR](2000) NULL,
    [InnerExceptionMessage] [VARCHAR](2000) NULL,
    [IpAddress] [VARCHAR](150) NULL,
    [IsProduction] [BIT] NOT NULL CONSTRAINT [DF_Log_IsProduction]  DEFAULT ((1)),
    [LastModified] [DATETIME] NOT NULL CONSTRAINT [DF_Log_LastModified]  DEFAULT (GETDATE()),
 CONSTRAINT [PK_Log] PRIMARY KEY CLUSTERED 
(
    [LogId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]

GO

SET ANSI_PADDING OFF
GO

EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'This table holds all the exceptions. 
ErrorData = when error happened
,[ErrorShortDescription] == short desc about the error entered by the developers
      ,[FileName] = file where error happened full path
      ,[LineNumber] = line number where code failed
      ,[MethodName] = method name where exception happened
      ,[ClassName] = class where exception happened
      ,[ImpactLevel] = high, medium, low
      ,[ApplicationName] = name of the application where error came from
      ,[ErrorMessage] = exception error messge
      ,[StackTrace] = C# stack trace
      ,[InnerException] = inner exception of strack trace
      ,[InnerExceptionMessage] = inner message
      ,[IpAddress]
      ,[IsProduction]' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'Log'
GO

Impact Level is basically Enum

 public enum ImpactLevel
    {
        High = 0,
        Medium = 1,
        Low = 2,
    }

You can use it as following

try
{


}
catch(Exception ex)
{
    //this will save the exception details and mark exception as low priority
    ex.Save();
}


try
{


}
catch(Exception ex)
{
    //this will save the exception details with  priority you define: High, Medium,Low
    ex.Save(ImpactLevel.Medium);
}

try
{


}
catch(Exception ex)
{
    //this will save the exception details with  priority you define: High, Medium,Low
    ex.Save(ImpactLevel.Medium, "You can enter an details you want here ");
}
Share:
109,887
Analytic Lunatic
Author by

Analytic Lunatic

Software Developer by Day, Web Designer by Night.

Updated on July 09, 2022

Comments

  • Analytic Lunatic
    Analytic Lunatic almost 2 years

    I've created a small C# winforms application, as an added feature I was considering adding some form of error logging into it. Anyone have any suggestions for good ways to go about this? This is a feature I've never looked into adding to previous projects, so I'm open to suggestions from Developers who have more experience.

    I was considering something along the lines of writing exceptions to a specified text file, or possibly a database table. This is an application that will be in use for a few months and then discarded when a larger product is finished.

  • Analytic Lunatic
    Analytic Lunatic over 10 years
    That's what I was thinking, but wanted an outside opinion. Currently I am catching exceptions and displaying them as follows: catch (Exception ex) { MessageBox.Show("Source:\t" + ex.Source + "\nMessage: \t" + ex.Message + "\nData:\t" + ex.Data); }. Any ideas for how I could make this more useful when writing to the error log? (Besides like adding the Date/Time).
  • Analytic Lunatic
    Analytic Lunatic over 10 years
    Seems like it might be something worth trying, and I'd definitely be interested in learning more in any case. Can you help me out with figuring out the app.config, dll, and set-up in code? Seems a little confusing in your link.
  • KSdev
    KSdev over 10 years
    The Exception is going to point you to the place in the codebase to investigate so besides the Date/Time you really wont need much else. Maybe the StackTrace
  • Lee Hiles
    Lee Hiles over 10 years
    One additional note if using error.XXXException(string,exception)... you'll need to modify the target layout with ${exception} to get the exception message or ${exception:format=tostring} to get the full tostring value.
  • Panu Oksala
    Panu Oksala over 10 years
    If you want, I can write a short description about how to use log4net as an answer.
  • Panu Oksala
    Panu Oksala over 10 years
    It was very hard to insert that XML config, could not do better styling :(.
  • Phantômaxx
    Phantômaxx almost 10 years
    Please don't post link-only answers
  • Eamon Nerbonne
    Eamon Nerbonne almost 10 years
    Log4net is pretty slow+heavy, however. Since I've added static readonly log = LogManager.GetLogger(...) statements to the various classes in my app, I've noticed startup times spike, and (particularly annoyingly) unit test startup times take a long time.
  • Panu Oksala
    Panu Oksala almost 10 years
    Start-up time might be a bit slower (I haven't tested that much), but log writing is VERY fast.
  • Chrysalis
    Chrysalis over 9 years
    kudos on concisely showing what's to be done in config and code... thanks!
  • Zapnologica
    Zapnologica over 8 years
    Where does it log this to? A text file?
  • Mauro2
    Mauro2 over 8 years
    The output on this approach relies on the listeners you configure. That is, to log to a text file, just configure a System.Diagnostics.TextWriterTraceListener.
  • Zero3
    Zero3 about 8 years
    Claiming that this third party library is "The best solution" is perhaps a too aggressive claim. I think a more objective wording would be appreciated.
  • Zapnologica
    Zapnologica over 7 years
    Would be nice if it was a nuget pacakge
  • Chirag K
    Chirag K over 7 years
    Hi, This works but it generates an exception :An exception of type 'System.Security.SecurityException' occurred in System.dll but was not handled in user code. So, It writes to logs but doesn't have permission to do so. stackoverflow.com/questions/20389248/…
  • Mauro2
    Mauro2 over 7 years
    You're right! In case of the EventLogListener, the Event Source key must be created beforehand. You can use a simple Powershell script on a website for example, but if it's software that's being shipped usually installers take care of this.
  • Andrew Truckle
    Andrew Truckle about 7 years
    Well, it took two seconds to download the ZIP and add the source file to my application. Thanks. :)
  • Sterling Diaz
    Sterling Diaz over 6 years
    Good contribution. Just what I was almost doing. Thanks!