Database logging using Enterprise Library 5

Topics: Logging Application Block
Jan 2, 2014 at 1:27 PM
Hi
I have been following the ExtendedPropertyDatabaseListenerWithExceptionLogging sample and have tried to implement my own custom trace listeners.

My question is what do I need to do to be able to send my own custom ServerLogEntry object to the logger.Write method so that eventually in the FormattedDatabaseTraceListener the methods ExecuteWriteLogStoredProcedure which have the correct ServerLogEntry object, whereas at the moment its still using the default LogEntry object.

I have used to call trace and found that the TraceData method in FormattedDatabaseTraceListener has an object called data which contains data from the LogEntry class, eg

Timestamp: 02/01/2014 13:12:16
Message: 01/01/2014 13:11:11 31/12/2013 13:11:11 Logging .... True template name 10.10.21.98
Category: General
Priority: -1
EventId: 1
Severity: Information
Title:
Machine: BP-L48-LAP
App Domain: TestHarnessUI.vshost.exe
ProcessId: 10036
Process Name: C:\Users\cdev\documents\visual studio 2012\Projects\TestHarnessUI\bin\Debug\TestHarnessUI.vshost.exe
Thread Name:
Win32 ThreadId:4144
Extended Properties:


How do I get the object data to be passed in as my custom ServerLogEntry object?
   [ConfigurationElementType(typeof(FormattedDatabaseTraceListenerData))]
    public class ServerFormattedDatabaseTraceListener : FormattedTraceListenerBase
    {
        string writeLogStoredProcName = String.Empty;
        Microsoft.Practices.EnterpriseLibrary.Data.Database database;

        public ServerFormattedDatabaseTraceListener(Microsoft.Practices.EnterpriseLibrary.Data.Database database, string writeLogStoredProcName, ILogFormatter formatter) : base(formatter)
        {
            this.writeLogStoredProcName = writeLogStoredProcName;
            this.database = database;
        }

        public override void Write(string message)
        {
            ExecuteWriteLogStoredProcedure(DateTime.Now, DateTime.Now, message, true, string.Empty, string.Empty, database);
        }

        public override void WriteLine(string message)
        {
            Write(message);
        }

        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 ServerPrintServerLogEntry)
                {
                    var logEntry = data as ServerPrintServerLogEntry;
                    if (ValidateParameters(logEntry))
                        ExecuteStoredProcedure(logEntry);
                }
                else if (data is string) Write(data as string);
                else base.TraceData(eventCache, source, eventType, id, data);
            }
        }


        protected override string[] GetSupportedAttributes()
        {
            return new string[4] { "formatter", "writeLogStoredProcName", "addCategoryStoredProcName", "databaseInstanceName" };
        }


        private bool ValidateParameters(ServerPrintServerLogEntry logEntry)
        {
            bool valid = true;
            if (writeLogStoredProcName == null || writeLogStoredProcName.Length == 0) return false;

            return valid;
        }


        private void ExecuteStoredProcedure(ServerPrintServerLogEntry logEntry)
        {
            using (var connection = database.CreateConnection())
            {
                connection.Open();
                try
                {
                    using (var transaction = connection.BeginTransaction())
                    {
                        try
                        {
                            ExecuteWriteLogStoredProcedure(logEntry, database, transaction);
                            transaction.Commit();
                        }
                        catch
                        {
                            transaction.Rollback();
                            throw;
                        }
                    }
                }
                finally { connection.Close(); }
            }
        }

        private int ExecuteWriteLogStoredProcedure(DateTime printedOn, DateTime requestedOn, string status_ErrorMessage, bool status_Success, string templateName, string printerName, Microsoft.Practices.EnterpriseLibrary.Data.Database db)
        {
            var cmd = db.GetStoredProcCommand(writeLogStoredProcName);
            db.AddInParameter(cmd, "PrintedOn", DbType.DateTime, printedOn);
            db.AddInParameter(cmd, "RequestedOn", DbType.DateTime, requestedOn);
            db.AddParameter(cmd, "Status_ErrorMessage", DbType.String, 512, ParameterDirection.Input, false, 0, 0, null, DataRowVersion.Default, status_ErrorMessage);
            db.AddInParameter(cmd, "Status_Success", DbType.Boolean, status_Success);
            db.AddParameter(cmd, "TemplateName", DbType.String, 512, ParameterDirection.Input, false, 0, 0, null, DataRowVersion.Default, templateName);
            db.AddParameter(cmd, "PrinterName", DbType.String, 512, ParameterDirection.Input, false, 0, 0, null, DataRowVersion.Default, printerName);
            db.ExecuteNonQuery(cmd);
            return 1;
        }

        private int ExecuteWriteLogStoredProcedure(ServerPrintServerLogEntry logEntry, Microsoft.Practices.EnterpriseLibrary.Data.Database db, DbTransaction transaction)
        {
            var cmd = db.GetStoredProcCommand(writeLogStoredProcName);
            db.AddInParameter(cmd, "PrintedOn", DbType.DateTime, logEntry.PrintedOn);
            db.AddInParameter(cmd, "RequestedOn", DbType.DateTime, logEntry.RequestedOn);
            db.AddParameter(cmd, "Status_ErrorMessage", DbType.String, 512, ParameterDirection.Input, false, 0, 0, null, DataRowVersion.Default, logEntry.Status_ErrorMessage);
            db.AddInParameter(cmd, "Status_Success", DbType.Boolean, logEntry.Status_Success);
            db.AddParameter(cmd, "TemplateName", DbType.String, 512, ParameterDirection.Input, false, 0, 0, null, DataRowVersion.Default, logEntry.TemplateName);
            db.AddParameter(cmd, "PrinterName", DbType.String, 512, ParameterDirection.Input, false, 0, 0, null, DataRowVersion.Default, logEntry.PrinterName);
            db.ExecuteNonQuery(cmd, transaction);
            return 1;
        }
    }
Jan 2, 2014 at 1:28 PM
    [AddSateliteProviderCommand("connectionStrings", typeof(DatabaseSettings), "DefaultDatabase", "DatabaseInstanceName")]
    public class ServerFormattedDatabaseTraceListenerData : TraceListenerData
    {
        private const string addCategoryStoredProcNameProperty = "addCategoryStoredProcName";
        private const string databaseInstanceNameProperty = "databaseInstanceName";
        private const string formatterNameProperty = "formatter";
        private const string writeLogStoredProcNameProperty = "writeLogStoredProcName";

        /// <summary>
        /// 
        /// </summary>
        public ServerFormattedDatabaseTraceListenerData(): base(typeof(ServerFormattedDatabaseTraceListener))
        {
            this.ListenerDataType = typeof(ServerFormattedDatabaseTraceListenerData);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="name"></param>
        /// <param name="writeLogStoredProcName"></param>
        /// <param name="addCategoryStoredProcName"></param>
        /// <param name="databaseInstanceName"></param>
        /// <param name="formatterName"></param>
       
        public ServerFormattedDatabaseTraceListenerData(string name,
                                                  string writeLogStoredProcName,
                                                  string addCategoryStoredProcName,
                                                  string databaseInstanceName,
                                                  string formatterName)
            : this(
                name,
                writeLogStoredProcName,
                addCategoryStoredProcName,
                databaseInstanceName,
                formatterName,
                TraceOptions.None,
                SourceLevels.All)
        {
        }

        /// <summary>
        /// Initializes a named instance of <see cref="FormattedDatabaseTraceListenerData"/> with 
        /// name, stored procedure name, databse instance name, and formatter name.
        /// </summary>
        /// <param name="name">The name.</param>
        /// <param name="writeLogStoredProcName">The stored procedure name for writing the log.</param>
        /// <param name="addCategoryStoredProcName">The stored procedure name for adding a category for this log.</param>
        /// <param name="databaseInstanceName">The database instance name.</param>
        /// <param name="formatterName">The formatter name.</param>
        /// <param name="traceOutputOptions">The trace options.</param>
        /// <param name="filter">The filter to be applied</param>
        public ServerFormattedDatabaseTraceListenerData(string name,
                                                  string writeLogStoredProcName,
                                                  string addCategoryStoredProcName,
                                                  string databaseInstanceName,
                                                  string formatterName,
                                                  TraceOptions traceOutputOptions,
                                                  SourceLevels filter)
            : base(name, typeof(ServerFormattedDatabaseTraceListener), traceOutputOptions, filter)
        {
            DatabaseInstanceName = databaseInstanceName;
            WriteLogStoredProcName = writeLogStoredProcName;
            AddCategoryStoredProcName = addCategoryStoredProcName;
            Formatter = formatterName;
        }

        /// <summary>
        /// Gets and sets the database instance name.
        /// </summary>
        [ConfigurationProperty(databaseInstanceNameProperty, IsRequired = true)]
        [Reference(typeof(ConnectionStringSettingsCollection), typeof(ConnectionStringSettings))]
        public string DatabaseInstanceName
        {
            get { return (string)base[databaseInstanceNameProperty]; }
            set { base[databaseInstanceNameProperty] = value; }
        }

        /// <summary>
        /// Gets and sets the stored procedure name for writing the log.
        /// </summary>
        [ConfigurationProperty(writeLogStoredProcNameProperty, IsRequired = true, DefaultValue = "WriteLog")]
        public string WriteLogStoredProcName
        {
            get { return (string)base[writeLogStoredProcNameProperty]; }
            set { base[writeLogStoredProcNameProperty] = value; }
        }

        /// <summary>
        /// Gets and sets the stored procedure name for adding a category for this log.
        /// </summary>
        [ConfigurationProperty(addCategoryStoredProcNameProperty, IsRequired = true, DefaultValue = "AddCategory")]
        public string AddCategoryStoredProcName
        {
            get { return (string)base[addCategoryStoredProcNameProperty]; }
            set { base[addCategoryStoredProcNameProperty] = value; }
        }

        /// <summary>
        /// Gets and sets the formatter name.
        /// </summary>
        [ConfigurationProperty(formatterNameProperty, IsRequired = false)]
        [Reference(typeof(NameTypeConfigurationElementCollection<FormatterData, CustomFormatterData>), typeof(FormatterData))]
        public string Formatter
        {
            get { return (string)base[formatterNameProperty]; }
            set { base[formatterNameProperty] = value; }
        }

        /// <summary>
        /// Returns a lambda expression that represents the creation of the trace listener described by this
        /// configuration object.
        /// </summary>
        /// <returns>A lambda expression to create a trace listener.</returns>
        protected override Expression<Func<TraceListener>> GetCreationExpression()
        {
            return () =>
                   new ServerFormattedDatabaseTraceListener(
                       Container.Resolved<Microsoft.Practices.EnterpriseLibrary.Data.Database>(DatabaseInstanceName),
                       WriteLogStoredProcName,
                       Container.ResolvedIfNotNull<ILogFormatter>(Formatter));
        }
    }
Jan 2, 2014 at 1:29 PM
   public class ServerPrintServerLogEntry : ICloneable
    {
        private DateTime _printedOn;
        private DateTime _requestedOn;
        private string _status_ErrorMessage;
        private bool _status_Success;
        private string _templateName;
        private string _printerName;

        public ServerPrintServerLogEntry()
        {
        }

        public ServerPrintServerLogEntry(DateTime printedOn, DateTime requestedOn, string status_ErrorMessage, bool status_Success, string templateName, string printerName)
        {
            _printedOn = printedOn;
            _requestedOn = requestedOn;
            _status_ErrorMessage = status_ErrorMessage;
            _status_Success = status_Success;
            _templateName = templateName;
            _printerName = printerName;
        }


        public DateTime PrintedOn
        {
            get { return this._printedOn; }
            set { this._printedOn = value; }
        }

        public DateTime RequestedOn
        {
            get { return this._requestedOn; }
            set { this._requestedOn = value; }
        }

        public string Status_ErrorMessage
        {
            get { return this._status_ErrorMessage; }
            set { this._status_ErrorMessage = value; }
        }

        public bool Status_Success
        {
            get { return this._status_Success; }
            set { this._status_Success = value; }
        }

        public string TemplateName
        {
            get { return this._templateName; }
            set { this._templateName = value; }
        }

        public string PrinterName
        {
            get { return this._printerName; }
            set { this._printerName = value; }
        }

        public object Clone()
        {
            var result = new ServerPrintServerLogEntry
            {
                PrintedOn = this.PrintedOn,
                RequestedOn = this.RequestedOn,
                Status_ErrorMessage = this.Status_ErrorMessage,
                Status_Success = this.Status_Success,
                TemplateName = this.TemplateName,
                PrinterName = this.PrinterName
            };

            return result;
        }

        public override string ToString()
        {
            return string.Format("{0} {1} {2} {3} {4} {5}", PrintedOn, RequestedOn, Status_ErrorMessage, Status_Success, TemplateName, PrinterName);
        }
Jan 2, 2014 at 2:08 PM
My question is what do I need to do to be able to send my own custom ServerLogEntry object to the logger.Write method so that eventually in the FormattedDatabaseTraceListener the methods ExecuteWriteLogStoredProcedure which have the correct ServerLogEntry object, whereas at the moment its still using the default LogEntry object.

Take a look at the Custom Database Trace Listener Sample. That example creates a CustomLogEntry, passes it to Logger.Write(), extracts the custom info and writes to a custom database column.

In the trace listener the base LogEntry is downcast:
            // Add custom data
            CustomLogEntry customLogEntry = logEntry as CustomLogEntry;

            if (customLogEntry != null)
            {
                customData = customLogEntry.CustomData;
            }
~~
Randy Levy
entlib.support@live.com
Enterprise Library support engineer
Support How-to