Extending the Logging Block by changing the datatype of log table column

Topics: Building and extending application blocks, Logging Application Block
Mar 22, 2012 at 6:08 AM

Hello Friends,

I have a very little experience in DotNet and now I have to implement logging block as per requirements.

I want to add a new column to the "Log" table and also I want to change the datatype of a particular column in the Log table.
I thought of doing this by changing the input values in front end application and changing the tables in database end.  But, the problem is....front end and database are linked through Ent. Lib. Dll's.  Now, I want to do something to make the link happened between.  I am not understanding what to do in this situation.  
Please help me out with this with a clear explanation.
Thanks
Pavan


Mar 22, 2012 at 2:12 PM
Edited Mar 22, 2012 at 2:15 PM

From a high level you will have to:

  1. Extract the new information you wish to log from your application.
  2. Determine how you want to store this data in the LogEntry class (which is what Enterprise Library uses for logging).  You could extend LogEntry and create your own custom type and then downcast later on to extract your data or you could use the ExtendedProperties IDictionary to store the data.
  3. Create a custom trace listener which will perform the new logic you want (add new DB parameter and change parameter data type).  Download the Hands on Labs and look at Logging Lab 2 to see how to create a custom trace listener.  You can also look at the Extensibility Hands on labs for another custom trace listener tutorial. It sounds like your trace listener will be very similar to the existing FormattedDatabaseTraceListener so look at the source code to get you most of the way there.  Also, you will have to configure Enterprise Library to use the new trace listener.
  4. Modify the stored procedure which inserts into the database to add the new parameter and change the data type for the other parameter.
  5. Add your new column to the database and modify the datatype of the existing column in the database.

--
Randy Levy
Enterprise Library support engineer
entlib.support@live.com 

Mar 23, 2012 at 3:39 AM

Thank you for the information.  But....how can I extend the logEntry and how to create the custom tracelistener?  I just wanted to add a single column to the existing tracelistener.  In the lab...they mentioned like creating a custom tracelistener and adding it in the config file and all.  They didn't show anything how to add an extra column or anything.

I am trying to understand this whole thing.....but I am not able to do that.  I am just a guy with a little experience.  That was the real issue.  Please explain with some kind of example.  Help will be appreciated.

 

Thanks

pavan

Mar 23, 2012 at 5:31 AM
Edited Mar 23, 2012 at 2:06 PM

> how can I extend the logEntry

You can create your own class that inherits from LogEntry:

    public class MyLogEntry : Microsoft.Practices.EnterpriseLibrary.Logging.LogEntry
    {
        public string MyNewColumnProperty
        {
            get;
            set;
        }
    }

>  how to create the custom tracelistener?

See the links I posted for the tutorials.

>They didn't show anything how to add an extra column or anything.

If you download the Enterprise Library source code and look at the FormattedDatabaseTraceListener you will see the logic for adding the stored procedure parameters.  You could use this code and modify it to add a column (modifications that might apply for your scenario are in bold):

private int ExecuteWriteLogStoredProcedure(LogEntry logEntry, Data.Database db, DbTransaction transaction)
{
    DbCommand cmd = db.GetStoredProcCommand(writeLogStoredProcName);


    db.AddInParameter(cmd, "eventID", DbType.Int32, logEntry.EventId);
    db.AddInParameter(cmd, "priority", DbType.Int32, logEntry.Priority);
    db.AddParameter(cmd, "severity", DbType.String, 32, ParameterDirection.Input, false, 0, 0, null, DataRowVersion.Default, logEntry.Severity.ToString());
    db.AddParameter(cmd, "title", DbType.String, 256, ParameterDirection.Input, false, 0, 0, null, DataRowVersion.Default, logEntry.Title);
    db.AddInParameter(cmd, "timestamp", DbType.DateTime, logEntry.TimeStamp);
    db.AddParameter(cmd, "machineName", DbType.String, 32, ParameterDirection.Input, false, 0, 0, null, DataRowVersion.Default, logEntry.MachineName);
    db.AddParameter(cmd, "AppDomainName", DbType.String, 512, ParameterDirection.Input, false, 0, 0, null, DataRowVersion.Default, logEntry.AppDomainName);
    db.AddParameter(cmd, "ProcessID", DbType.String, 256, ParameterDirection.Input, false, 0, 0, null, DataRowVersion.Default, logEntry.ProcessId);
    db.AddParameter(cmd, "ProcessName", DbType.String, 512, ParameterDirection.Input, false, 0, 0, null, DataRowVersion.Default, logEntry.ProcessName);
    db.AddParameter(cmd, "ThreadName", DbType.String, 512, ParameterDirection.Input, false, 0, 0, null, DataRowVersion.Default, logEntry.ManagedThreadName);
    db.AddParameter(cmd, "Win32ThreadId", DbType.String, 128, ParameterDirection.Input, false, 0, 0, null, DataRowVersion.Default, logEntry.Win32ThreadId);
    db.AddParameter(cmd, "message", DbType.String, 1500, ParameterDirection.Input, false, 0, 0, null, DataRowVersion.Default, logEntry.Message);

    if (Formatter != null)
        db.AddInParameter(cmd, "formattedmessage", DbType.String, Formatter.Format(logEntry));
    else
        db.AddInParameter(cmd, "formattedmessage", DbType.String, logEntry.Message);

    string myNewColumnProperty = null;

    // Downcast...check because it could fail
    MyLogEntry myLogEntry = logEntry as MyLogEntry;

    if (myLogEntry != null)
    {
        myNewColumnProperty = myLogEntry.MyNewColumnProperty;
    }

    db.AddParameter(cmd, "MyNewColumnName", DbType.String, 512, ParameterDirection.Input, true, 0, 0, null, DataRowVersion.Default, myNewColumnProperty); 

    db.AddOutParameter(cmd, "LogId", DbType.Int32, 4);

    db.ExecuteNonQuery(cmd, transaction);
    int logId = Convert.ToInt32(cmd.Parameters[cmd.Parameters.Count - 1].Value, CultureInfo.InvariantCulture);
    return logId;
}

 

--
Randy Levy
Enterprise Library support engineer
entlib.support@live.com 

Mar 23, 2012 at 6:14 PM

Wonderful Randy.

But the this is, we don't want to change the existing dll.  I want to override the datatabasetracelistener.  Below is the situation I am in

 

This is my service page where I am starting the logging process

 

namespace RatabaseLogging
{
    // NOTE: You can use the "Rename" command on the "Refactor" menu to change the class name "Service" in both code and config file together.
    public class Service : IService
    {
        #region Core Logic for Logging
        /// <summary>
        /// Logging will be done automatically with the help of Enterprise Library method
        /// </summary>
        /// <param name="PriorityValue"></param>
        /// <param name="CategoryValue"></param>
        /// <param name="TitleValue"></param>
        /// <param name="MessageValue"></param>

        public void Log(string CategoryValue, string TitleValue, string MessageValue)
        {
            CustomLogEntry lEntry = new CustomLogEntry();

            lEntry.Categories.Add(CategoryValue);
            lEntry.Title = TitleValue;
            lEntry.Message = MessageValue;

            String strGUID = Guid.NewGuid().ToString();

            lEntry.LogEntryID = strGUID;

            Task.Factory.StartNew(() => LogMessageAsync(lEntry));
        }

        #endregion

        #region Asynchronous Logging

        /// <summary>
        /// Asynchronous logging will be done through the inbuilt Enterprise Library method
        /// </summary>
        /// <param name="lEntry"></param>

        static public void LogMessageAsync(LogEntry lEntry)
        {
            LogWriter myLogWriter = EnterpriseLibraryContainer.Current.GetInstance<LogWriter>();
            myLogWriter.Write(lEntry);
        }

        #endregion

 

}

This is my CustomLogEntry page

 

namespace RatabaseLogging
{
    class CustomLogEntry : Microsoft.Practices.EnterpriseLibrary.Logging.LogEntry
    {

        private string logentryID;
       
        /// <summary>
        /// The Win32 process ID for the current running process.
        /// </summary>
        public string LogEntryID
        {
            get { return this.logentryID; }
            set { this.logentryID = value; }
        }

       
    }
}

This is my custom Trace Listener

namespace RatabaseLogging
{
    [ConfigurationElementType(typeof(CustomTraceListenerData))]
    public class LoggingTraceListener : CustomTraceListener
    {
        public LoggingTraceListener() : base() { }

        public override void Write(string message) 
        {
            Console.Write(message); 
        }
        
        public override void WriteLine(string message) 
        { 
            //// Delimit each message 
            //Console.WriteLine((string)this.Attributes["delimiter"]); 

            // Write formatted message 
            Console.WriteLine(message); 
        }

        public override void TraceData(TraceEventCache eventCache, string source, TraceEventType eventType, int id, object data) 
        { 
            if (data is LogEntry && this.Formatter != null) 
            { 
                this.WriteLine(this.Formatter.Format(data as LogEntry)); 
            } 
            else 
            { 
                this.WriteLine(data.ToString()); 
            } 
        }


    }
}

Now, where should I write the executestored procedure?  I dont want to change anything in the existing dll.

Thanks
Pavan



 

 

 

 

Mar 23, 2012 at 7:25 PM
Edited Mar 26, 2012 at 7:02 AM

Yes, you should create "a custom trace listener which will perform the new logic you want"; I wouldn't recommend changing Enterprise Library source.

You can override the FormattedDatabaseTraceListener but all of the logic is contained in private methods so you would still have to re-implement all of the actual logic (a portion of which I posted above). 

The actual code is less than 300 lines which is why I recommend moving a portion of that code into your trace listener.  You would add that logic to the TraceData method. 

--
Randy Levy
Enterprise Library support engineer
entlib.support@live.com 

Mar 26, 2012 at 4:25 AM

 

Hi,

I trie to do in the above procedure.

1)  I created a custom tracelistener as discussed in the lab tutorial.  But, the output is in console application.  My major concentration is logging into database.  I added a custom tracelistener in the web.config also.  And I changed the categories part also.  Removed databasetracelistener on category and added this customtracelistener.  But, nowhere I mentioned to give the database connection string.  What should be done?

2)  I created a custom logentry also.  I inherited LogEntry from logging and added the new column into it.  Now, from my application I am trying to create an object to the new custom logenty and passing the values including the new one.  In the "LogAsyncMessage" method, I am calling LogWriter.write(LogEntry xxx).  Do I need to change or override the LogWriter class also?

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Microsoft.Practices.EnterpriseLibrary.Logging;
using Microsoft.Practices.EnterpriseLibrary.Common.Configuration;
using System.Threading.Tasks;
using System.Reflection;

namespace RatabaseLogging
{
    class CustomLogEntry : Microsoft.Practices.EnterpriseLibrary.Logging.LogEntry
    {

        private string logentryID;
       
        /// <summary>
        /// The Win32 process ID for the current running process.
        /// </summary>
        public string LogEntryID
        {
            get { return this.logentryID; }
            set { this.logentryID = value; }
        }

       
    }
}








using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.Data;

using Microsoft.Practices.EnterpriseLibrary.Logging;
using Microsoft.Practices.EnterpriseLibrary.Common.Configuration;
using Microsoft.Practices.EnterpriseLibrary.Logging.Configuration;
using Microsoft.Practices.EnterpriseLibrary.Logging.Formatters;
using Microsoft.Practices.EnterpriseLibrary.Logging.TraceListeners;

using Microsoft.Practices.EnterpriseLibrary.Data;
using Microsoft.Practices.EnterpriseLibrary.Common;
using System.Diagnostics;
using System.Configuration;
using System.Data.Common;



namespace RatabaseLogging
{
    [ConfigurationElementType(typeof(CustomTraceListenerData))]
    public class LoggingTraceListener : CustomTraceListener
    {
        #region  Previous

        //public LoggingTraceListener() : base() { }

        //public override void Write(string message) 
        //{
        //    Console.Write(message); 
        //}
        
        //public override void WriteLine(string message) 
        //{ 
        //    //// Delimit each message 
        //    //Console.WriteLine((string)this.Attributes["delimiter"]); 

        //    // Write formatted message 
        //    Console.WriteLine(message); 
        //}

        //public override void TraceData(TraceEventCache eventCache, string source, TraceEventType eventType, int id, object data) 
        //{ 
        //    if (data is LogEntry && this.Formatter != null) 
        //    { 
        //        this.WriteLine(this.Formatter.Format(data as LogEntry)); 
        //    } 
        //    else 
        //    { 
        //        this.WriteLine(data.ToString()); 
        //    } 
        //}

        #endregion

        string writeLogStoredProcName = String.Empty;
        string addCategoryStoredProcName = String.Empty;
        //Data.Database database;

        public LoggingTraceListener() : base() { }

        /// <summary>
        /// The Write method 
        /// </summary>
        /// <param name="message">The message to log</param>
        public override void Write(string message)
        {
            ExecuteWriteLogStoredProcedure(0, 5, TraceEventType.Information, string.Empty, DateTime.Now, string.Empty,
                                            string.Empty, string.Empty, string.Empty, null, null, message, database);
        }

        /// <summary>
        /// The WriteLine method.
        /// </summary>
        /// <param name="message">The message to log</param>
        public override void WriteLine(string message)
        {
            Write(message);
        }


        /// <summary>
        /// Delivers the trace data to the underlying database.
        /// </summary>
        /// <param name="eventCache">The context information provided by <see cref="System.Diagnostics"/>.</param>
        /// <param name="source">The name of the trace source that delivered the trace data.</param>
        /// <param name="eventType">The type of event.</param>
        /// <param name="id">The id of the event.</param>
        /// <param name="data">The data to trace.</param>
        public override void TraceData(TraceEventCache eventCache, string source, TraceEventType eventType, int id, object data)
        {
            if ((this.Filter == null) || this.Filter.ShouldTrace(eventCache, source, eventType, id, null, null, data, null))
            {
                if (data is LogEntry)
                {
                    LogEntry logEntry = data as LogEntry;
                    if (ValidateParameters(logEntry))
                        ExecuteStoredProcedure(logEntry);
                }
                else if (data is string)
                {
                    Write(data as string);
                }
                else
                {
                    base.TraceData(eventCache, source, eventType, id, data);
                }
            }
        }

        /// <summary>
        /// Validates that enough information exists to attempt executing the stored procedures
        /// </summary>
        /// <param name="logEntry">The LogEntry to validate.</param>
        /// <returns>A Boolean indicating whether the parameters for the LogEntry configuration are valid.</returns>
        private bool ValidateParameters(LogEntry logEntry)
        {
            bool valid = true;

            if (writeLogStoredProcName == null ||
                writeLogStoredProcName.Length == 0)
            {
                return false;
            }

            if (addCategoryStoredProcName == null ||
                addCategoryStoredProcName.Length == 0)
            {
                return false;
            }

            return valid;
        }

        /// <summary>
        /// Executes the stored procedures
        /// </summary>
        /// <param name="logEntry">The LogEntry to store in the database</param>
        private void ExecuteStoredProcedure(LogEntry logEntry)
        {
            using (DbConnection connection = database.CreateConnection())
            {
                connection.Open();
                try
                {
                    using (DbTransaction transaction = connection.BeginTransaction())
                    {
                        try
                        {
                            int logID = Convert.ToInt32(ExecuteWriteLogStoredProcedure(logEntry, database, transaction));
                            ExecuteAddCategoryStoredProcedure(logEntry, logID, database, transaction);
                            transaction.Commit();
                        }
                        catch
                        {
                            transaction.Rollback();
                            throw;
                        }

                    }
                }
                finally
                {
                    connection.Close();
                }
            }
        }

        /// <summary>
        /// Executes the WriteLog stored procedure
        /// </summary>
        /// <param name="eventId">The event id for this LogEntry.</param>
        /// <param name="priority">The priority for this LogEntry.</param>
        /// <param name="severity">The severity for this LogEntry.</param>
        /// <param name="title">The title for this LogEntry.</param>
        /// <param name="timeStamp">The timestamp for this LogEntry.</param>
        /// <param name="machineName">The machine name for this LogEntry.</param>
        /// <param name="appDomainName">The appDomainName for this LogEntry.</param>
        /// <param name="processId">The process id for this LogEntry.</param>
        /// <param name="processName">The processName for this LogEntry.</param>
        /// <param name="managedThreadName">The managedthreadName for this LogEntry.</param>
        /// <param name="win32ThreadId">The win32threadID for this LogEntry.</param>
        /// <param name="message">The message for this LogEntry.</param>
        /// <param name="db">An instance of the database class to use for storing the LogEntry</param>
        /// <returns>An integer for the LogEntry Id</returns>
        private int ExecuteWriteLogStoredProcedure(int eventId, int priority, TraceEventType severity, string title, DateTime timeStamp,
                                                    string machineName, string appDomainName, string processId, string processName,
                                                    string managedThreadName, string win32ThreadId, int message, Data.Database db)
        {
            DbCommand cmd = db.GetStoredProcCommand(writeLogStoredProcName);

            db.AddInParameter(cmd, "eventID", DbType.Int32, eventId);
            db.AddInParameter(cmd, "priority", DbType.Int32, priority);
            db.AddParameter(cmd, "severity", DbType.String, 32, ParameterDirection.Input, false, 0, 0, null, DataRowVersion.Default, severity.ToString());
            db.AddParameter(cmd, "title", DbType.String, 256, ParameterDirection.Input, false, 0, 0, null, DataRowVersion.Default, title);
            db.AddInParameter(cmd, "timestamp", DbType.DateTime, timeStamp);
            db.AddParameter(cmd, "machineName", DbType.String, 32, ParameterDirection.Input, false, 0, 0, null, DataRowVersion.Default, machineName);
            db.AddParameter(cmd, "AppDomainName", DbType.String, 512, ParameterDirection.Input, false, 0, 0, null, DataRowVersion.Default, appDomainName);
            db.AddParameter(cmd, "ProcessID", DbType.String, 256, ParameterDirection.Input, false, 0, 0, null, DataRowVersion.Default, processId);
            db.AddParameter(cmd, "ProcessName", DbType.String, 512, ParameterDirection.Input, false, 0, 0, null, DataRowVersion.Default, processName);
            db.AddParameter(cmd, "ThreadName", DbType.String, 512, ParameterDirection.Input, false, 0, 0, null, DataRowVersion.Default, managedThreadName);
            db.AddParameter(cmd, "Win32ThreadId", DbType.String, 128, ParameterDirection.Input, false, 0, 0, null, DataRowVersion.Default, win32ThreadId);
            db.AddParameter(cmd, "message", DbType.Int32, message, ParameterDirection.Input, false, 0, 0, null, DataRowVersion.Default, message);
            db.AddInParameter(cmd, "formattedmessage", DbType.String, message);

            db.AddOutParameter(cmd, "LogId", DbType.Int32, 4);

            db.ExecuteNonQuery(cmd);
            int logId = Convert.ToInt32(cmd.Parameters[cmd.Parameters.Count - 1].Value, CultureInfo.InvariantCulture);
            return logId;
        }

        /// <summary>
        /// Executes the WriteLog stored procedure
        /// </summary>
        /// <param name="logEntry">The LogEntry to store in the database.</param>
        /// <param name="db">An instance of the database class to use for storing the LogEntry</param>
        /// <param name="transaction">The transaction that wraps around the execution calls for storing the LogEntry</param>
        /// <returns>An integer for the LogEntry Id</returns>
        private int ExecuteWriteLogStoredProcedure(LogEntry logEntry, Data.Database db, DbTransaction transaction)
        {
            DbCommand cmd = db.GetStoredProcCommand(writeLogStoredProcName);


            db.AddInParameter(cmd, "eventID", DbType.Int32, logEntry.EventId);
            db.AddInParameter(cmd, "priority", DbType.Int32, logEntry.Priority);
            db.AddParameter(cmd, "severity", DbType.String, 32, ParameterDirection.Input, false, 0, 0, null, DataRowVersion.Default, logEntry.Severity.ToString());
            db.AddParameter(cmd, "title", DbType.String, 256, ParameterDirection.Input, false, 0, 0, null, DataRowVersion.Default, logEntry.Title);
            db.AddInParameter(cmd, "timestamp", DbType.DateTime, logEntry.TimeStamp);
            db.AddParameter(cmd, "machineName", DbType.String, 32, ParameterDirection.Input, false, 0, 0, null, DataRowVersion.Default, logEntry.MachineName);
            db.AddParameter(cmd, "AppDomainName", DbType.String, 512, ParameterDirection.Input, false, 0, 0, null, DataRowVersion.Default, logEntry.AppDomainName);
            db.AddParameter(cmd, "ProcessID", DbType.String, 256, ParameterDirection.Input, false, 0, 0, null, DataRowVersion.Default, logEntry.ProcessId);
            db.AddParameter(cmd, "ProcessName", DbType.String, 512, ParameterDirection.Input, false, 0, 0, null, DataRowVersion.Default, logEntry.ProcessName);
            db.AddParameter(cmd, "ThreadName", DbType.String, 512, ParameterDirection.Input, false, 0, 0, null, DataRowVersion.Default, logEntry.ManagedThreadName);
            db.AddParameter(cmd, "Win32ThreadId", DbType.String, 128, ParameterDirection.Input, false, 0, 0, null, DataRowVersion.Default, logEntry.Win32ThreadId);
            db.AddParameter(cmd, "message", DbType.Int32, logEntry.Message, ParameterDirection.Input, false, 0, 0, null, DataRowVersion.Default, logEntry.Message);

            //db.AddParameter(cmd, "message", SqlDbType.VarBinary, int.MaxValue, ParameterDirection.Input, false, 0, 0, null, DataRowVersion.Default, logEntry.Message);

            if (Formatter != null)
                db.AddInParameter(cmd, "formattedmessage", DbType.String, Formatter.Format(logEntry));
            else
                db.AddInParameter(cmd, "formattedmessage", DbType.String, logEntry.Message);


            db.AddParameter(cmd, "logentryID", DbType.String, 512, ParameterDirection.Input, true, 0, 0, null, DataRowVersion.Default, logEntry.logentryID); 


            db.AddOutParameter(cmd, "LogId", DbType.Int32, 4);

            db.ExecuteNonQuery(cmd, transaction);
            int logId = Convert.ToInt32(cmd.Parameters[cmd.Parameters.Count - 1].Value, CultureInfo.InvariantCulture);
            return logId;
        }

        /// <summary>
        /// Executes the AddCategory stored procedure
        /// </summary>
        /// <param name="logEntry">The LogEntry to store in the database.</param>
        /// <param name="logID">The unique identifer for the LogEntry as obtained from the WriteLog Stored procedure.</param>
        /// <param name="db">An instance of the database class to use for storing the LogEntry</param>
        /// <param name="transaction">The transaction that wraps around the execution calls for storing the LogEntry</param>
        private void ExecuteAddCategoryStoredProcedure(LogEntry logEntry, int logID, Data.Database db, DbTransaction transaction)
        {
            foreach (string category in logEntry.Categories)
            {
                DbCommand cmd = db.GetStoredProcCommand(addCategoryStoredProcName);
                db.AddInParameter(cmd, "categoryName", DbType.String, category);
                db.AddInParameter(cmd, "logID", DbType.Int32, logID);
                db.ExecuteNonQuery(cmd, transaction);
            }
        }



    }
}








using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace RatabaseLogging
{
    class CustomLogWriter : Microsoft.Practices.EnterpriseLibrary.Logging.LogWriter
    {
        public abstract void Write(CustomLogEntry lEntry);


    }
}








// Copyright (c) CGI, 2012
// All Rights Reserved.  Unpublished rights under the copyright laws of
// the United States.
//
// The software contained on this media is proprietary to and embodies
// the confidential technology of CGI.  Possession, use, duplication or
// dissemination of the software and media is authorized only pursuant
// to a valid written license from CGI.
//
// RESTRICTED RIGHTS LEGEND   Use, duplication, or disclosure by the U.S.
// Government is subject to restrictions as set forth in Subparagraph
// (c)(1)(ii) of DFARS 252.227-7013, or in FAR 52.227-19, as applicable.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;

using Microsoft.Practices.EnterpriseLibrary.Logging;
using Microsoft.Practices.EnterpriseLibrary.Common.Configuration;
using System.Threading.Tasks;
using System.Reflection;

namespace RatabaseLogging
{
    // NOTE: You can use the "Rename" command on the "Refactor" menu to change the class name "Service" in both code and config file together.
    public class Service : IService
    {
        #region Core Logic for Logging
        /// <summary>
        /// Logging will be done automatically with the help of Enterprise Library method
        /// </summary>
        /// <param name="PriorityValue"></param>
        /// <param name="CategoryValue"></param>
        /// <param name="TitleValue"></param>
        /// <param name="MessageValue"></param>

        public void Log(string CategoryValue, string TitleValue, string MessageValue)
        {
            CustomLogEntry lEntry = new CustomLogEntry();

            lEntry.Categories.Add(CategoryValue);
            lEntry.Title = TitleValue;
            lEntry.Message = MessageValue;

            String strGUID = Guid.NewGuid().ToString();

            lEntry.LogEntryID = strGUID;

            LogMessageAsync(lEntry);

            //Task.Factory.StartNew(() => LogMessageAsync(lEntry));
        }

        #endregion

        #region Asynchronous Logging

        /// <summary>
        /// Asynchronous logging will be done through the inbuilt Enterprise Library method
        /// </summary>
        /// <param name="lEntry"></param>

        static public void LogMessageAsync(CustomLogEntry lEntry)
        {
            CustomLogWriter myLogWriter = new CustomLogWriter();
            myLogWriter.Write(lEntry);
        }

        #endregion

        #region To get Assembly Name

        static public String GetAssemblyFullName()
        {
            return Assembly.GetExecutingAssembly().FullName;
        }


        #endregion
    }
}


<?xml version="1.0" encoding="utf-8" ?>
<configuration>

  <configSections>
    <section name="loggingConfiguration" type="Microsoft.Practices.EnterpriseLibrary.Logging.Configuration.LoggingSettings, Microsoft.Practices.EnterpriseLibrary.Logging, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" requirePermission="true" />
  </configSections>
  <loggingConfiguration name="" tracingEnabled="true" defaultCategory="General">
    <listeners>
      <add name="Event Log Listener" type="Microsoft.Practices.EnterpriseLibrary.Logging.TraceListeners.FormattedEventLogTraceListener, Microsoft.Practices.EnterpriseLibrary.Logging, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
        listenerDataType="Microsoft.Practices.EnterpriseLibrary.Logging.Configuration.FormattedEventLogTraceListenerData, Microsoft.Practices.EnterpriseLibrary.Logging, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
        source="Enterprise Library Logging" formatter="Text Formatter"
        log="" machineName="." traceOutputOptions="None" />
      <add name="Database Trace Listener" type="Microsoft.Practices.EnterpriseLibrary.Logging.Database.FormattedDatabaseTraceListener, Microsoft.Practices.EnterpriseLibrary.Logging.Database, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
        listenerDataType="Microsoft.Practices.EnterpriseLibrary.Logging.Database.Configuration.FormattedDatabaseTraceListenerData, Microsoft.Practices.EnterpriseLibrary.Logging.Database, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
        databaseInstanceName="SQL" writeLogStoredProcName="WriteLog"
        addCategoryStoredProcName="AddCategory" formatter="Text Formatter" />
      <add name="Flat File Trace Listener" type="Microsoft.Practices.EnterpriseLibrary.Logging.TraceListeners.FlatFileTraceListener, Microsoft.Practices.EnterpriseLibrary.Logging, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
        listenerDataType="Microsoft.Practices.EnterpriseLibrary.Logging.Configuration.FlatFileTraceListenerData, Microsoft.Practices.EnterpriseLibrary.Logging, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
        fileName="trace.log" formatter="Text Formatter" />
      <add listenerDataType="Microsoft.Practices.EnterpriseLibrary.Logging.Configuration.CustomTraceListenerData, Microsoft.Practices.EnterpriseLibrary.Logging, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
        delimiter="--------------------" type="RatabaseLogging.LoggingTraceListener, RatabaseLogging, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"
        name="Custom Trace Listener" formatter="Text Formatter" />
    </listeners>
    <formatters>
      <add type="Microsoft.Practices.EnterpriseLibrary.Logging.Formatters.TextFormatter, Microsoft.Practices.EnterpriseLibrary.Logging, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
        template="Timestamp: {timestamp}{newline}&#xA;Message: {message}{newline}&#xA;Category: {category}{newline}&#xA;Priority: {priority}{newline}&#xA;EventId: {eventid}{newline}&#xA;Severity: {severity}{newline}&#xA;Title:{title}{newline}&#xA;Machine: {localMachine}{newline}&#xA;App Domain: {localAppDomain}{newline}&#xA;ProcessId: {localProcessId}{newline}&#xA;Process Name: {localProcessName}{newline}&#xA;Thread Name: {threadName}{newline}&#xA;Win32 ThreadId:{win32ThreadId}{newline}&#xA;Extended Properties: {dictionary({key} - {value}{newline})}"
        name="Text Formatter" />
    </formatters>
    <logFilters>
      <add type="Microsoft.Practices.EnterpriseLibrary.Logging.Filters.LogEnabledFilter, Microsoft.Practices.EnterpriseLibrary.Logging, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
        enabled="true" name="Logging Enabled Filter" />
    </logFilters>
    <categorySources>
      <add switchValue="All" name="General">
        <listeners>
          <add name="Event Log Listener" />
          <add name="Flat File Trace Listener" />
          <add name="Custom Trace Listener" />
        </listeners>
      </add>
    </categorySources>
    <specialSources>
      <allEvents switchValue="All" name="All Events" />
      <notProcessed switchValue="All" name="Unprocessed Category" />
      <errors switchValue="All" name="Logging Errors &amp; Warnings">
        <listeners>
          <add name="Event Log Listener" />
        </listeners>
      </errors>
    </specialSources>
  </loggingConfiguration>
  <connectionStrings>
    <add name="SQL" connectionString="data source=IPAVAN-D20961;database=logging;uid=TestID06;pwd=TestID06"
      providerName="System.Data.SqlClient" />
  </connectionStrings>
  <system.web>
    <compilation debug="true" />
  </system.web>
  <!-- When deploying the service library project, the content of the config file must be added to the host's 
  app.config file. System.Configuration does not support config files for libraries. -->
  <system.serviceModel>
    <services>
      <service name="RatabaseLogging.Service">
        <endpoint address="" binding="wsHttpBinding" contract="RatabaseLogging.IService">
          <identity>
            <dns value="localhost" />
          </identity>
        </endpoint>
        <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
        <host>
          <baseAddresses>
            <add baseAddress="http://localhost:8732/Design_Time_Addresses/RatabaseLogging/Service/" />
          </baseAddresses>
        </host>
      </service>
    </services>
    <behaviors>
      <serviceBehaviors>
        <behavior>
          <!-- To avoid disclosing metadata information, 
          set the value below to false and remove the metadata endpoint above before deployment -->
          <serviceMetadata httpGetEnabled="True"/>
          <!-- To receive exception details in faults for debugging purposes, 
          set the value below to true.  Set to false before deployment 
          to avoid disclosing exception information -->
          <serviceDebug includeExceptionDetailInFaults="False" />
        </behavior>
      </serviceBehaviors>
    </behaviors>
  </system.serviceModel>

</configuration>


This is the total code related to my application.  I dont know where and all i need to make changes to add a new column to my database
table.  Please suggest me clearly.

Thanks
pavan


Mar 26, 2012 at 11:54 PM

>   But, the output is in console application.

You can move your code (trace listener) into a Class Library if you don't want it in a console application (although you can also add a reference to the console application and use the classes in that assembly but in this case it doesn't make much sense).

> But, nowhere I mentioned to give the database connection string.  What should be done?

You need to configure the CustomTraceListener with any information your trace listener needs.  Since your implementation is using the Database object you would probably pass in the name of the database, the writelog procedure and the add to category procedure.  Basically anything you want to be able to change at runtime for your trace listener.

Your configuration would look something like this:

<add listenerDataType="Microsoft.Practices.EnterpriseLibrary.Logging.Configuration.CustomTraceListenerData, Microsoft.Practices.EnterpriseLibrary.Logging, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"        
delimiter="--------------------"
type="RatabaseLogging.LoggingTraceListener, RatabaseLogging, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"
name="Custom Trace Listener"
formatter="Text Formatter" databaseInstanceName="LocalSqlServer" writeLogStoredProcName="WriteLog2"
addCategoryStoredProcName="AddCategory2" />

Inside the your tracelistener you can get access to the custom configuration items via the Attributes property.

E.g. 

string dbName = Attributes["databaseInstanceName"];
string writeLogProc= Attributes["writeLogStoredProcName"];
string addCategoryProc = Attributes["addCategoryStoredProcName"];

> Do I need to change or override the LogWriter class also?

No.  Your trace listener will be called by the internal LogWriter implementation class to perform the actual logging of the message.

As I mentioned, the logging interface takes a LogEntry only so you will have to downcast inside your trace listener to extract the custom information you've added:

    string logEntryId = null;

    // Downcast...check because it could fail    
    CustomLogEntry customLogEntry = logEntry as CustomLogEntry;

    if (customLogEntry != null)    
    {
        logEntryId = customLogEntry.LogEntryID;    
    }

    db.AddParameter(cmd, "LogEntryID", DbType.String, 36, ParameterDirection.Input, true, 0, 0, null, DataRowVersion.Default, logEntryId); 

--
Randy Levy
Enterprise Library support engineer
entlib.support@live.com 

Sep 11, 2012 at 1:30 AM
Edited Sep 11, 2012 at 1:31 AM

I am using enterprise library 5 for logging. i have to log the errors in to the custom table in oracle and not in to the sql server logging table provided by enterprise library. can anyone help me in how to create the custom trace listener

Sep 11, 2012 at 1:42 AM

See: http://entlib.codeplex.com/workitem/28946.  There are links that can help along with a sample download provided by the poster. 

--
Randy Levy
Enterprise Library support engineer
entlib.support@live.com 

Sep 11, 2012 at 2:33 AM

Thanks for the post. i am looking for the example where we can log errors in our own custom table of oracle and not in to the enterprise table structure.

Sep 11, 2012 at 2:52 AM
swaroop2502 wrote:

Thanks for the post. i am looking for the example where we can log errors in our own custom table of oracle and not in to the enterprise table structure.

Just modify the create script to add any columns you want and add the new parameters to the stored procedure and when you create the custom trace listener add the additional database parameters.  

This thread outlines how to do that (especially my first 2 posts) and the link to the workitem show how to create a custom database trace listener for Oracle.  Grab the LoggingAppBlock.Oracle.rar download and get the FormattedOracleTraceListener working (modify and run the SQL script first and change the configuration).  Once that's working then modify to add the custom columns/data. 

You can also take a look at the Enterprise Library 5.0 - Extensibility Labs for an introduction to extending Enterprise Library in general.

--
Randy Levy
Enterprise Library support engineer
entlib.support@live.com 

Sep 11, 2012 at 7:31 PM
Edited Sep 11, 2012 at 7:32 PM

randy,

 

i have modified the code and added the configuration in my application. i am getting the below error can you please let me know how to resolve it:

error:

Invalid TraceListenerData type in configuration 'listenerDataType="LoggingAppBlock.Oracle.FormattedOracleTraceListenerData, LoggingAppBlock.Oracle"'.

 

below is my app.config:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <configSections>
        <section name="dataConfiguration" type="Microsoft.Practices.EnterpriseLibrary.Data.Configuration.DatabaseSettings, Microsoft.Practices.EnterpriseLibrary.Data, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" requirePermission="true" />
        <section name="oracleConnectionSettings" type="Microsoft.Practices.EnterpriseLibrary.Data.Oracle.Configuration.OracleConnectionSettings, Microsoft.Practices.EnterpriseLibrary.Data, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" requirePermission="true" />
        <section name="loggingConfiguration" type="Microsoft.Practices.EnterpriseLibrary.Logging.Configuration.LoggingSettings, Microsoft.Practices.EnterpriseLibrary.Logging, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" requirePermission="false" />
    </configSections>
    <oracleConnectionSettings>
        <add name="Oracle">
            <packages>
                <add prefix="LOGS" name="PKG_LOGGER" />
            </packages>
        </add>
    </oracleConnectionSettings>
    <connectionStrings>
        <add name="Oracle" connectionString="User ID=petroapp;password=petroapp;Data Source=XE;Max Pool Size=200;Pooling=true"
            providerName="System.Data.OracleClient" />
    </connectionStrings>
    <loggingConfiguration name="" tracingEnabled="true" defaultCategory="General">
        <listeners>
            <add name="Flat File Trace Listener" type="Microsoft.Practices.EnterpriseLibrary.Logging.TraceListeners.FlatFileTraceListener, Microsoft.Practices.EnterpriseLibrary.Logging, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
                listenerDataType="Microsoft.Practices.EnterpriseLibrary.Logging.Configuration.FlatFileTraceListenerData, Microsoft.Practices.EnterpriseLibrary.Logging, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
                fileName="C:\TestCode\PlatformLibrary\LogFile\Errorlog.log"
                formatter="Text Formatter" traceOutputOptions="DateTime, ProcessId, ThreadId" />
            <add name="Message Queuing Trace Listener" type="Microsoft.Practices.EnterpriseLibrary.Logging.TraceListeners.MsmqTraceListener, Microsoft.Practices.EnterpriseLibrary.Logging, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
                listenerDataType="Microsoft.Practices.EnterpriseLibrary.Logging.Configuration.MsmqTraceListenerData, Microsoft.Practices.EnterpriseLibrary.Logging, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
                queuePath=".\Private$\PlatformLibraryQ" formatter="Binary Log Message Formatter"
                useDeadLetterQueue="true" traceOutputOptions="DateTime, ProcessId, ThreadId" />
            <add name="Event Log Trace Listener" type="Microsoft.Practices.EnterpriseLibrary.Logging.TraceListeners.FormattedEventLogTraceListener, Microsoft.Practices.EnterpriseLibrary.Logging, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
                listenerDataType="Microsoft.Practices.EnterpriseLibrary.Logging.Configuration.FormattedEventLogTraceListenerData, Microsoft.Practices.EnterpriseLibrary.Logging, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
                source="PetroDexServices" formatter="Text Formatter" traceOutputOptions="LogicalOperationStack, DateTime" />
          <add name="Custom Oracle Trace Listener"
           type="LoggingAppBlock.Oracle.FormattedOracleTraceListener, LoggingAppBlock.Oracle"
           listenerDataType="LoggingAppBlock.Oracle.FormattedOracleTraceListenerData, LoggingAppBlock.Oracle"
           writeLogStoredProcName="PKG_LOGGER.WRITELOG" databaseInstanceName="Oracle"
           addCategoryStoredProcName="PKG_LOGGER.ADDCATEGORY" formatter="Text Formatter"
           filter="All" />
        </listeners>
        <formatters>
            <add type="Microsoft.Practices.EnterpriseLibrary.Logging.Formatters.TextFormatter, Microsoft.Practices.EnterpriseLibrary.Logging, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
                template="Timestamp: {timestamp}{newline}&#xA;Message: {message}{newline}&#xA;Category: {category}{newline}&#xA;Priority: {priority}{newline}&#xA;EventId: {eventid}{newline}&#xA;Severity: {severity}{newline}&#xA;Title:{title}{newline}&#xA;Machine: {localMachine}{newline}&#xA;App Domain: {localAppDomain}{newline}&#xA;ProcessId: {localProcessId}{newline}&#xA;Process Name: {localProcessName}{newline}&#xA;Thread Name: {threadName}{newline}&#xA;Win32 ThreadId:{win32ThreadId}{newline}&#xA;Extended Properties: {dictionary({key} - {value}{newline})}"
                name="Text Formatter" />
            <add type="Microsoft.Practices.EnterpriseLibrary.Logging.Formatters.BinaryLogFormatter, Microsoft.Practices.EnterpriseLibrary.Logging, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
                name="Binary Log Message Formatter" />
        </formatters>
        <categorySources>
            <add switchValue="All" name="General">
                <listeners>
                    <add name="Flat File Trace Listener" />
                    <add name="Message Queuing Trace Listener" />
                    <add name="Event Log Trace Listener" />
                  <add name="Custom Oracle Trace Listener" />
                </listeners>
            </add>
            <add switchValue="All" name="MSMQLogging">
                <listeners>
                    <add name="Message Queuing Trace Listener" />
                </listeners>
            </add>
            <add switchValue="All" name="FlatFileLogging">
                <listeners>
                    <add name="Flat File Trace Listener" />
                </listeners>
            </add>
          <add switchValue="All" name="DataBaseLogging">
            <listeners>
              <add name="Custom Oracle Trace Listener" />
            </listeners>
          </add>
          
        </categorySources>
        <specialSources>
            <allEvents switchValue="All" name="All Events" />
            <notProcessed switchValue="All" name="Unprocessed Category" />
            <errors switchValue="All" name="Logging Errors &amp; Warnings">
                <listeners>
                    <add name="Flat File Trace Listener" />
                    <add name="Message Queuing Trace Listener" />
                    <add name="Event Log Trace Listener" />
                  <add name="Custom Oracle Trace Listener" />
                </listeners>
            </errors>
        </specialSources>
    </loggingConfiguration>
</configuration>

i would really appreciate your help

Sep 12, 2012 at 12:35 AM

Ensure that the assembly that you created,  LoggingAppBlock.Oracle.dll, is deployed to the output directory (bin or bin/debug|release).  Since the reference to the assembly is only in configuration Visual Studio doesn't know to copy it to the output directory.

--
Randy Levy
Enterprise Library support engineer
entlib.support@live.com