Click here to Skip to main content
Click here to Skip to main content

Using NLog.net in SOA with ILogReceiverServer

, 25 Apr 2014 CPOL
Rate this:
Please Sign up or sign in to vote.
Utilize NLog.net in a Service-oriented architecture

Introduction

We have implemented NLog.net in our service oriented architecture. It can log different levels exception/message to your selected data storage.

Background

There are many articles about how to implement NLog.net but there is not a good article about how to implement ILogReceiverServer interface inside a SOA system. The tip will show you how to do that.

This demo has 7 parts.

  1. The external DLL which is NLog.dll, you can get it from Nuget and put in a solution folder to share it between different projects.
  2. Data storage, we will focus on using a SqlServer database as our log data storage.

    Here is the script to create the table:

    SET ANSI_PADDING ON
    GO
    
    CREATE TABLE [dbo].[EventLogs](
        [ID] [bigint] IDENTITY(1,1) NOT NULL,
        [ActivityID] [varchar](20) NOT NULL,
        [Source] [varchar](100) NOT NULL,
        [SubSource] [varchar](150) NOT NULL,
        [DateTimeStamp] [datetime] NOT NULL,
        [LogLevel] [varchar](20) NOT NULL,
        [MachineName] [varchar](50) NOT NULL,
        [WindowsID] [varchar](50) NOT NULL,
        [StackTrace] [varchar](max) NOT NULL,
        [Logger] [varchar](100) NOT NULL,
        [Exception] [varchar](max) NOT NULL,
        [LogMessage] [varchar](max) NOT NULL,
     CONSTRAINT [PK_EventLogs] PRIMARY KEY CLUSTERED 
    (
        [ID] 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
  3. DataAccess layer

    We use the following code to insert logs.

    It will take NLog's LogEventInfo as parameter and parse out the properties to insert.

    public void InsertLog(LogEventInfo ev)
    {
      try
                {
                    using (SqlConnection connection = new SqlConnection(DBConn))
                    {
                        SqlCommand command = new SqlCommand(CommandText, connection);
    
                        foreach (DBParameter p in DBParameters)
                        {
                            command.Parameters.AddWithValue(p.Name, ev.Properties[p.Layout]);
                        }
    
                        try
                        {
                            connection.Open();
                            Int32 rowsAffected = command.ExecuteNonQuery();
                            Console.WriteLine("RowsAffected: {0}", rowsAffected);
                        }
                        catch (Exception ex)
                        {
                            logger.Error(ex);
                        }
                    }
                }
                catch (Exception ex)
                {
                    logger.Error(ex);
                }
            }

    We will build the DBParameters by reading the NLog.config file.

    protected List<DBParameter> DBParameters { get; set; }
    
            public void ReadNLogConfigure()
            {
                try
                {
                    string myString = "";
    
                    using (System.IO.StreamReader myFile = new System.IO.StreamReader(AppDomain.CurrentDomain.BaseDirectory + "NLog.config"))
                    {
                        myString = myFile.ReadToEnd();
                    }
                    myString = myString.Replace("xmlns=\"http://www.nlog-project.org/schemas/NLog.xsd\"", "");
                    myString = myString.Replace("xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"", "");
                    myString = myString.Replace("xsi:", "");
    
                    XmlDocument xDoc = new XmlDocument();
                    xDoc.LoadXml(myString);
    
                    //XmlNamespaceManager nsmgr = new XmlNamespaceManager(xDoc.NameTable);
                    //nsmgr.AddNamespace(string.Empty, "http://www.nlog-project.org/schemas/NLog.xsd");
                    //nsmgr.AddNamespace("xsi", "http://www.w3.org/2001/XMLSchema-instance");
    
                    XmlNode xn = xDoc.SelectSingleNode("//target[@type=\"Database\"]");//,nsmgr);
    
                    DBParameters = new List<DBParameter>();
                    if (xn != null)
                    {
                        DBConn = xn.Attributes["connectionString"].Value;
                        CommandText = xn.Attributes["commandText"].Value;
    
                        foreach (XmlNode xp in xn.SelectNodes("parameter"))
                        {
                            DBParameter dp = new DBParameter();
                            dp.Name = xp.Attributes["name"].Value;
                            //dp.Layout = xp.Attributes["layout"].Value.Replace("${", "").Replace("}", "");
                            dp.Layout = xp.Attributes["name"].Value.Replace("@", "");
                            DBParameters.Add(dp);
                        }
                    }
                }
                catch (Exception ex)
                {
                    logger.Error(ex);
                }
            }
  4. NLogService WCF service.

    We have two services.

    LogReceiverServer: This will accept the log request from client.

    public class LogReceiverServer : ILogReceiverServer
        {
    
            public void ProcessLogMessages(NLogEvents nevents)
            {
                var events = nevents.ToEventInfo("Client.");
                Console.WriteLine("in: {0} {1}", nevents.Events.Length, events.Count);
    
                LogDataBaseAccess logToDB = new LogDataBaseAccess();
    
                foreach (var ev in events)
                {
                    var logger = LogManager.GetLogger(ev.LoggerName);
    
                    //logger.Log(ev);
                    logToDB.InsertLog(ev);
                }
            }
        }

    NLogConfigService: This will let you config log level from server to client.

    public class NLogConfigService : INLogConfigService
        {
            public string GetLogLevel(string userID)
            {
                if (userID == "Grant")
                    return "Error";
                else
                    return "Trace";
            }
        }

    So we can control which level we want the client to be.

  5. NLogReceiverServiceHost

    This is the WCF host for our service by a Windows Form application.

    private void F_Main_Load(object sender, EventArgs e)
            {
                try
                {
                    StringBuilder sb = new StringBuilder();
                    //host the service here
                    ServiceHost host = new ServiceHost(typeof(NLogService.LogReceiverServer));
                    host.Open();
                    sb.Append("LogReceiverServer is running"+Environment.NewLine);
    
                    host = new ServiceHost(typeof(NLogService.NLogConfigService));
                    host.Open();
                    sb.Append("NLogConfigService is running" + Environment.NewLine);
    
                    lbServiceStatus.Text = sb.ToString();
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message);
                }
            }
  6. NLogDemo

    This is the client side Windows Form application.

    private void cmdLogAll_Click(object sender, EventArgs e)
            {
                logger.Trace("This is a Trace message");
                logger.Debug("This is a Debug message");
                logger.Info("This is an Info message");
    
                logger.Warn("This is a Warn message");
                logger.Error("This is an Error message");
                logger.Fatal("This is a Fatal error message");
            }
    
            private void cmdLogException_Click(object sender, EventArgs e)
            {
                try
                {
                    int i = 10;
                    int j = 0;
                    int k = i / j;
                }
                catch (Exception ex)
                {
                    logger.ErrorException("This is an Error message", ex);
                }
            }
  7. Utility

    This module provides a function to let you reconfig client's log level.

        public static void Reconfigure(LogLevel logLevel)
            {
                foreach (var rule in LogManager.Configuration.LoggingRules)
                {
                    rule.DisableLoggingForLevel(LogLevel.Trace);
                    rule.DisableLoggingForLevel(LogLevel.Debug);
                    rule.DisableLoggingForLevel(LogLevel.Info);
                    rule.DisableLoggingForLevel(LogLevel.Warn);
                    rule.DisableLoggingForLevel(LogLevel.Error);
                    rule.DisableLoggingForLevel(LogLevel.Fatal);
    
                    EnableHigherLevel(rule, logLevel);                
                }
    
                //Call to update existing Loggers created with GetLogger() or 
                //GetCurrentClassLogger()
                LogManager.ReconfigExistingLoggers();
            }
    
            public static void EnableHigherLevel(LoggingRule rule, LogLevel logLevel)
            {
                //Trace - Very detailed log messages, potentially of a high frequency and volume
                //Debug -Less detailed and/or less frequent debugging messages
                //Info - Informational messages
                //Warn - Warnings which don't appear to the user of the application
                //Error - Error messages
                //Fatal - Fatal error messages. After a fatal error, the application usually terminates. 
    
                switch (logLevel.ToString())
                {
                    case "Trace":
                        rule.EnableLoggingForLevel(LogLevel.Trace);
                        rule.EnableLoggingForLevel(LogLevel.Debug);
                        rule.EnableLoggingForLevel(LogLevel.Info);
                        rule.EnableLoggingForLevel(LogLevel.Warn);
                        rule.EnableLoggingForLevel(LogLevel.Error);
                        rule.EnableLoggingForLevel(LogLevel.Fatal);
    
                        break;
                    case "Debug":                    
                        rule.EnableLoggingForLevel(LogLevel.Debug);
                        rule.EnableLoggingForLevel(LogLevel.Info);
                        rule.EnableLoggingForLevel(LogLevel.Warn);
                        rule.EnableLoggingForLevel(LogLevel.Error);
                        rule.EnableLoggingForLevel(LogLevel.Fatal);
    
                        break;
                    case "Info":                    
                        rule.EnableLoggingForLevel(LogLevel.Info);
                        rule.EnableLoggingForLevel(LogLevel.Warn);
                        rule.EnableLoggingForLevel(LogLevel.Error);
                        rule.EnableLoggingForLevel(LogLevel.Fatal);
    
                        break;
                    case "Warn":                    
                        rule.EnableLoggingForLevel(LogLevel.Warn);
                        rule.EnableLoggingForLevel(LogLevel.Error);
                        rule.EnableLoggingForLevel(LogLevel.Fatal);
    
                        break;
                    case "Error":                    
                        rule.EnableLoggingForLevel(LogLevel.Error);
                        rule.EnableLoggingForLevel(LogLevel.Fatal);
    
                        break;
                    case "Fatal":                
                        rule.EnableLoggingForLevel(LogLevel.Fatal);
                        break;
                    default:
                        break;
                }
            }     

Points of Interest

Use NLog in SOA system.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

grantliu

United States United States
No Biography provided

Comments and Discussions

 
Generalcould be 5 if .. PinmemberSouthmountain25-Apr-14 5:43 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web02 | 2.8.141022.2 | Last Updated 25 Apr 2014
Article Copyright 2014 by grantliu
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid