Setting up Semantic Logging Application Block to log events to SQL database

Logs are automatically written to a SQL table called ‘Traces’

In the Global.asax file, you setup a connection to your database where the ‘Traces’ table exists.

You also enable which evetns will be logged. Below I’ve enable the EventLevel:Error loggin in 2 classes that exist in the UI project.

I’ve also enabled the EventLevel:Error  logging in the Infrastructure project.

So at the web/UI level, I can enable which events are going to be logged in each sub-project (project dependencies)

(this video was very helpful: http://channel9.msdn.com/posts/Introducing-Semantic-Logging)

Global.asax.cs


using Microsoft.Practices.EnterpriseLibrary.SemanticLogging;
using System.Diagnostics.Tracing;

protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();

            RegisterGlobalFilters(GlobalFilters.Filters);
            RegisterRoutes(RouteTable.Routes);

            string logConnString =
                System.Configuration.ConfigurationManager.ConnectionStrings["logConnString"].ToString();

            var sqlListener = SqlDatabaseLog.CreateListener("UI", logConnString);
            sqlListener.EnableEvents(BasicLogger.Log, EventLevel.Error);
            sqlListener.EnableEvents(Logger.Log, EventLevel.Error);

            var sqlListener2 = SqlDatabaseLog.CreateListener("Infrastructure", logConnString);
            sqlListener2.EnableEvents(FileTransferMgmt.Infrastructure.InfrLogger.Log, EventLevel.Error);

        }

OR using appSettings in the web.config, I have set it up as follows

<!-- If you enable any level of Logging, it will enable that level and any level more severe. Enabling 'Warning' would enable 'Critical' and 'Error' automatically. -->
    <add key="Logging_LogCritical" value="" />
    <add key="Logging_LogError" value="" />
    <add key="Logging_LogWarning" value="True" />
    <add key="Logging_LogInformation" value="" />
protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();

            RegisterGlobalFilters(GlobalFilters.Filters);
            RegisterRoutes(RouteTable.Routes);

            SetupSemanticLoggingApplicationBlock();

        }

        protected void SetupSemanticLoggingApplicationBlock()
        {
              //EventTracing setup
            string logConnString =
                System.Configuration.ConfigurationManager.ConnectionStrings["LogConnString"].ToString();

            var sqlListener1 = SqlDatabaseLog.CreateListener("UI", logConnString);
            var sqlListener2 = SqlDatabaseLog.CreateListener("Infrastructure", logConnString);
            var sqlListener3 = SqlDatabaseLog.CreateListener("Service", logConnString);

            //get web.config value for logging level
            bool critcal = System.Configuration.ConfigurationManager.AppSettings["Logging_LogCritical"].ToLower() ==
                           "true";
            bool error = System.Configuration.ConfigurationManager.AppSettings["Logging_LogError"].ToLower() ==
                           "true";
            bool warning = System.Configuration.ConfigurationManager.AppSettings["Logging_LogWarning"].ToLower() ==
                           "true";
            bool info = System.Configuration.ConfigurationManager.AppSettings["Logging_LogInformation"].ToLower() ==
                          "true";

            //Enable the level of logging based on settings in web.config
            if (critcal)
            {
                sqlListener1.EnableEvents(Logger.Log, EventLevel.Critical );
                sqlListener2.EnableEvents(OmniaSup.Infrastructure.InfrLogger.Log, EventLevel.Critical);
                sqlListener3.EnableEvents(OmniaSup.Service.SrvLogger.Log, EventLevel.Critical);
            }
            if (error)
            {
                sqlListener1.EnableEvents(Logger.Log, EventLevel.Error);
                sqlListener2.EnableEvents(OmniaSup.Infrastructure.InfrLogger.Log, EventLevel.Error);
                sqlListener3.EnableEvents(OmniaSup.Service.SrvLogger.Log, EventLevel.Error);
            }
            if (warning)
            {
                sqlListener1.EnableEvents(Logger.Log, EventLevel.Warning);
                sqlListener2.EnableEvents(OmniaSup.Infrastructure.InfrLogger.Log, EventLevel.Warning);
                sqlListener3.EnableEvents(OmniaSup.Service.SrvLogger.Log, EventLevel.Warning);
            }
            if (info)
            {
                sqlListener1.EnableEvents(Logger.Log, EventLevel.Informational);
                sqlListener2.EnableEvents(OmniaSup.Infrastructure.InfrLogger.Log, EventLevel.Informational);
                sqlListener3.EnableEvents(OmniaSup.Service.SrvLogger.Log, EventLevel.Informational);
            }
        }

You need to create a class that inherits from EventSource

Here are the 2 Logging classes in my UI, and the one UI class in my Infrastructure project.

using System;
using System.Diagnostics;
using System.Diagnostics.Tracing;

namespace FileTransferMgmt.UI
{
    public class LogHelper
    {
        public static readonly LogHelper Log = new LogHelper();
        public void Error(Exception ex)
        {
            string message = ex.Message;
            string innerMessage = "";
            if (ex.InnerException != null)
                innerMessage = ex.InnerException.Message;

            StackTrace st = new StackTrace();
            string methName = st.GetFrame(1).GetMethod().Name;
            string stack = st.ToString();
            Logger.Log.Error(message, innerMessage, methName, stack);

        }
        public void Error(string message)
        {
            StackTrace st = new StackTrace();
            string methName = st.GetFrame(1).GetMethod().Name;
            string stack = st.ToString();
            Logger.Log.Error(message, "", methName, stack);
        }

        public void Critical(string message)
        {
            StackTrace st = new StackTrace();
            string methName = st.GetFrame(1).GetMethod().Name;
            string stack = st.ToString();
            Logger.Log.Critical(message, methName, stack);
        }

        public void Warning(string message)
        {
            StackTrace st = new StackTrace();
            string methName = st.GetFrame(1).GetMethod().Name;
            string stack = st.ToString();
            Logger.Log.Warning(message, methName, stack);
        }
        public void Information(string message)
        {
            StackTrace st = new StackTrace();
            string methName = st.GetFrame(1).GetMethod().Name;
            string stack = st.ToString();
            Logger.Log.Information(message, methName, stack);
        }
    }

    public class Logger: EventSource
    {
        public static readonly Logger Log = new Logger();

        [Event(1000, Message = "{0}", Level = EventLevel.Critical)]
        public void Critical(string message, string method, string stack)
        {
            object[] parms = new object[] { message, method, stack };
            if (IsEnabled()) WriteEvent(1000, parms);
        }
        [Event(1001, Message = "{0}", Level = EventLevel.Error)]
        public void Error(string message, string innerExceptionMessage, string method, string stack)
        {
            object[] parms = new object[] { message, innerExceptionMessage, method, stack };
            if (IsEnabled()) WriteEvent(1001, parms);
        }

        [Event(1002, Message = "{0}", Level = EventLevel.Warning)]
        public void Warning(string message, string method, string stack)
        {
            object[] parms = new object[] { message, method, stack };
            if (IsEnabled()) WriteEvent(1002, parms);
        }

        [Event(1003, Message = "{0}", Level = EventLevel.Informational)]
        public void Information(string message, string method, string stack)
        {
            object[] parms = new object[] { message, method, stack };
            if (IsEnabled()) WriteEvent(1003, parms);
        }
    }
}
using System.Diagnostics;
using System.Diagnostics.Tracing;

namespace FileTransferMgmt.UI.lib
{
    public class BasicLogger: EventSource
    {
        public static readonly BasicLogger Log = new BasicLogger();

        [Event(1, Message = "{0}", Level = EventLevel.Critical)]
        public void Critcal(string message)
        {
            if(IsEnabled()) WriteEvent(1,message);
        }

        [Event(2, Message = "{0}", Level = EventLevel.Error)]
        public void Error(string message)
        {
            System.Diagnostics.StackTrace st = new StackTrace();
            string methName = st.GetFrame(1).GetMethod().Name;
            string stack = st.ToString();

            if(IsEnabled()) WriteEvent(2,message + " :: " + methName + " :: " + stack);
        }

        [Event(3, Message = "{0}", Level = EventLevel.Warning)]
        public void Warning(string message)
        {
            if(IsEnabled()) WriteEvent(3,message);
        }

        public void LogTest(string message)
        {
            string dateTime = System.DateTime.Now.ToString();
            pTest(message,dateTime);
        }

        [Event(5, Message = "{0}/{1}", Level = EventLevel.Error)]
        private void pTest(string message, string time)
        {
            object[] parms = new object[]{message,time};
            if (IsEnabled()) WriteEvent(5, parms);
        }
    }
}

using System.Diagnostics;
using System.Diagnostics.Tracing;

namespace FileTransferMgmt.Infrastructure
{
    public class InfrLogger: EventSource
    {
        public static readonly InfrLogger Log = new InfrLogger();

        public void Error(string message)
        {
            StackTrace st = new StackTrace();
            string methName = st.GetFrame(1).GetMethod().Name;
            string stack = st.ToString();
            DoError(message, methName, stack);
        }

        public void Critical(string message)
        {
            StackTrace st = new StackTrace();
            string methName = st.GetFrame(1).GetMethod().Name;
            string stack = st.ToString();
            DoCritical(message, methName, stack);
        }

        public void Warning(string message)
        {
            StackTrace st = new StackTrace();
            string methName = st.GetFrame(1).GetMethod().Name;
            string stack = st.ToString();
            DoWarning(message, methName, stack);
        }

        public void Information(string message)
        {
            StackTrace st = new StackTrace();
            string methName = st.GetFrame(1).GetMethod().Name;
            string stack = st.ToString();
            DoInformation(message, methName, stack);
        }

        [Event(1000, Level = EventLevel.Critical)]
        private void DoCritical(string message, string method, string stack)
        {
            object[] parms = new object[] { message, method, stack };
            if (IsEnabled()) WriteEvent(1000, parms);
        }
        [Event(1001, Level = EventLevel.Error)]
        private void DoError(string message, string method, string stack)
        {
            object[] parms = new object[] { message, method, stack };
            if (IsEnabled()) WriteEvent(1001, parms);
        }

        [Event(1002, Message = "{0}", Level = EventLevel.Warning)]
        private void DoWarning(string message, string method, string stack)
        {
            object[] parms = new object[] { message, method, stack };
            if (IsEnabled()) WriteEvent(1002, parms);
        }

        [Event(1003, Message = "{0}", Level = EventLevel.Informational)]
        private void DoInformation(string message, string method, string stack)
        {
            object[] parms = new object[] { message, method, stack };
            if (IsEnabled()) WriteEvent(1003, parms);
        }
    }
}

Typically you would want to log exceptions, or special events. I’m just going to initiate logging from a controller loading event in my Home/Index action:

public ActionResult Index()
        {
            LogHelper.Log.Warning("static ninject Home/Index loaded.");
            LogHelper.Log.Error("static ninject Home/Index loaded.");
            LogHelper.Log.Critical("static ninject Home/Index loaded.");
            LogHelper.Log.Information("static ninject Home/Index loaded.");

            BasicLogger.Log.Warning("Home/Index loaded.");
            BasicLogger.Log.Error("Home/Index loaded.");
            BasicLogger.Log.Critcal("Home/Index loaded.");
            BasicLogger.Log.LogTest("Home/Index loaded");
            ViewBag.Message = "Welcome to ASP.NET MVC!";

            return View();
        }

The database shows the following after the Home/Index action is fired:

Initial setup

Nuget: Enterprise Library: Semantic Logging Application Block – SQL Server Sink

(it will download dependencies including the Enterprise Library: Semantic Logging Application Block (base)).

After installing, there will be a SQL script to run on your database to ensure that the table, procedures, types, fuctions are setup in the db. The script is [solution]\packages\EnterpriseLibrary.SemanticLogging.Database.1.0.1304.0\scripts\CreateSemanticLoggingDatabaseObjects.sql

Here is that script:

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO

CREATE TYPE TracesType AS TABLE
(
  [InstanceName] [nvarchar](1000),
            [ProviderId] [uniqueidentifier],
            [ProviderName] [nvarchar](500),
            [EventId] [int],
            [EventKeywords] [bigint],
            [Level] [int],
            [Opcode] [int],
            [Task] [int],
            [Timestamp] [datetimeoffset](7),
            [Version] [int],
            [FormattedMessage] [nvarchar](4000),
            [Payload] [nvarchar](4000)
);

GO

CREATE PROCEDURE [dbo].[WriteTrace]
(
            @InstanceName [nvarchar](1000),
            @ProviderId [uniqueidentifier],
            @ProviderName [nvarchar](500),
            @EventId [int],
            @EventKeywords [bigint],
            @Level [int],
            @Opcode [int],
            @Task [int],
            @Timestamp [datetimeoffset](7),
            @Version [int],
            @FormattedMessage [nvarchar](4000),
            @Payload [nvarchar](4000),
            @TraceId [bigint] OUTPUT
)
AS
BEGIN
            SET NOCOUNT ON;

            INSERT INTO [Traces] (
                        [InstanceName],
                        [ProviderId],
                        [ProviderName],
                        [EventId],
                        [EventKeywords],
                        [Level],
                        [Opcode],
                        [Task],
                        [Timestamp],
                        [Version],
                        [FormattedMessage],
                        [Payload]
            )
            VALUES (
                        @InstanceName,
                @ProviderId,
                @ProviderName,
                        @EventId,
                        @EventKeywords,
                        @Level,
                        @Opcode,
                        @Task,
                        @Timestamp,
                        @Version,
                        @FormattedMessage,
                        @Payload)

            SET @TraceId = @@IDENTITY
            RETURN @TraceId
END

GO

CREATE PROCEDURE [dbo].[WriteTraces]
(
  @InsertTraces TracesType READONLY
)
AS
BEGIN
  INSERT INTO [Traces] (
                        [InstanceName],
                        [ProviderId],
                        [ProviderName],
                        [EventId],
                        [EventKeywords],
                        [Level],
                        [Opcode],
                        [Task],
                        [Timestamp],
                        [Version],
                        [FormattedMessage],
                        [Payload]
            )
  SELECT * FROM @InsertTraces;
END

GO
CREATE TABLE [dbo].[Traces](
            [id] [bigint] IDENTITY(1,1) NOT NULL,
            [InstanceName] [nvarchar](1000) NOT NULL,
            [ProviderId] [uniqueidentifier] NOT NULL,
            [ProviderName] [nvarchar](500) NOT NULL,
            [EventId] [int] NOT NULL,
            [EventKeywords] [bigint] NOT NULL,
            [Level] [int] NOT NULL,
            [Opcode] [int] NOT NULL,
            [Task] [int] NOT NULL,
            [Timestamp] [datetimeoffset](7) NOT NULL,
            [Version] [int] NOT NULL,
            [FormattedMessage] [nvarchar](4000) NULL,
            [Payload] [nvarchar](4000) NULL,
 CONSTRAINT [PK_Traces] PRIMARY KEY CLUSTERED
(
            [id] ASC
)WITH (STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF)
)

GO

After moving the code to the server, I tried to run it and got this error: System.Security.VerificationException: Operation could destabilize the runtime.

I then applied this update to the server to fix the error:
http://support.microsoft.com/kb/2748646 (for 2012 server)
http://support.microsoft.com/kb/2748645 (for 2008 r2 server)

PartialView’s submit function runs when the Parent form is submitted.

A partialView is having it’s Post function called when I submit the containing form. This was resolved by changing the name of the PartialView’s post function.

Originally in the partialView’s controller I had:

[ChildActionOnly]
public ActionResult EditPartial(FileLocationViewModel vm)
{
...
return PartialView(vm);
}

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult EditPartial(FileLocationViewModel vm, FormCollection fc)
{
...
}

Changed the Post function signature as follows to resolve the issue:

[ChildActionOnly]
public ActionResult EditPartial(FileLocationViewModel vm)
{
...
}

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult EditPartialSubmit(FileLocationViewModel vm, FormCollection fc)
{
...
}