fluent interface for configuring custom data base trace listener

Topics: Logging Application Block
Sep 17, 2012 at 4:48 PM

I am using fluent interface for configuring the enterprise library logging. i want to know how to configure custom data base listener for logging in to db. i have created a custom trace listener"FormattedOracleTraceListener" which logs data in to the custom table. i want to configure the listener to use the connecton string. kindly any on ehelp me with this?

 

 

 

swaroop

Sep 17, 2012 at 9:05 PM

i am getting the below error when i am trying to configure:

Error 1 The type 'LoggingAppBlock.Oracle.FormattedOracleTraceListener' cannot be used as type parameter 'TCustomListenerType' in the generic type or method 'Microsoft.Practices.EnterpriseLibrary.Common.Configuration.SendToCustomTraceListenerExtensions.Custom<TCustomListenerType>(Microsoft.Practices.EnterpriseLibrary.Common.Configuration.Fluent.ILoggingConfigurationSendTo, string)'. There is no implicit reference conversion from 'LoggingAppBlock.Oracle.FormattedOracleTraceListener' to 'Microsoft.Practices.EnterpriseLibrary.Logging.TraceListeners.CustomTraceListener'. C:\TestCode\Platform.Logging\Platform.Logging\Platform.Logging\LogAdapters\DatabaseLoggerWrapper.cs 35 17 Platform.Logging

 

  builder.ConfigureLogging()
                .WithOptions
                .DoNotRevertImpersonation()
                .LogToCategoryNamed("Database Logging")
                .WithOptions.ToSourceLevels(minimumSourceLevel)
                .SendTo.Custom<FormattedOracleTraceListener>("Oracle Database Trace Listener")

my customer listener is inherited from FormattedTraceListenerBase. 
public class FormattedOracleTraceListener : FormattedTraceListenerBase
     {

           //implementation

            }

can anyone help me with configuration of custom data base trace listener, which accepts connection string to log in to db.

 

thanks

swaroop

Sep 18, 2012 at 12:38 AM

A CustomTraceListener has partial integration, in that the configuration is done via key/value pairs.

The database trace listener that you have created uses full integration.  In order to get full integration with the configuration tool/system you had to create a FormattedOracleTraceListenerData class.  Similarly to a achieve full integration with the fluent interface then some custom work needs to be created to integrate with the fluent interface.

I have updated the CustomDatabaseTraceListener project on the sample page to have a full fluent interface.

The code looks like this:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Practices.EnterpriseLibrary.Common.Configuration.Fluent;
using Microsoft.Practices.EnterpriseLibrary.Common;
using System.Diagnostics;

namespace CustomDatabaseTraceListener.Configuration.Fluent
{
    /// <summary>
    /// Fluent interface used to configure a <see cref="CustomDatabaseTraceListener"/> instance.
    /// </summary>
    /// <seealso cref="CustomDatabaseTraceListener"/>
    /// <seealso cref="CustomDatabaseTraceListenerData"/>
    public interface ILoggingConfigurationSendToCustomDatabaseTraceListener : ILoggingConfigurationContd, ILoggingConfigurationCategoryContd, IFluentInterface
    {

        /// <summary>
        /// Specifies the formatter used to format database log messages send by this <see cref="CustomDatabaseTraceListener"/>.<br/>
        /// </summary>
        /// <param name="formatBuilder">The <see cref="FormatterBuilder"/> used to create an <see cref="LogFormatter"/> .</param>
        /// <returns>Fluent interface that can be used to further configure the current <see cref="CustomDatabaseTraceListener"/> instance. </returns>
        /// <seealso cref="CustomDatabaseTraceListener"/>
        /// <seealso cref="CustomDatabaseTraceListenerData"/>
        ILoggingConfigurationSendToCustomDatabaseTraceListener FormatWith(IFormatterBuilder formatBuilder);


        /// <summary>
        /// Specifies the formatter used to format log messages send by this <see cref="CustomDatabaseTraceListener"/>.<br/>
        /// </summary>
        /// <returns>Fluent interface that can be used to further configure the current <see cref="CustomDatabaseTraceListener"/> instance. </returns>
        /// <seealso cref="CustomDatabaseTraceListener"/>
        /// <seealso cref="CustomDatabaseTraceListenerData"/>
        ILoggingConfigurationSendToCustomDatabaseTraceListener FormatWithSharedFormatter(string formatterName);

        /// <summary>
        /// Specifies which options, or elements, should be included in messages send by this <see cref="CustomDatabaseTraceListener"/>.<br/>
        /// </summary>
        /// <returns>Fluent interface that can be used to further configure the current <see cref="CustomDatabaseTraceListener"/> instance. </returns>
        /// <seealso cref="CustomDatabaseTraceListener"/>
        /// <seealso cref="CustomDatabaseTraceListenerData"/>
        /// <seealso cref="TraceOptions"/>
        ILoggingConfigurationSendToCustomDatabaseTraceListener WithTraceOptions(TraceOptions traceOptions);

        /// <summary>
        /// Specifies the <see cref="SourceLevels"/> that should be used to filter trace output by this <see cref="CustomDatabaseTraceListener"/>.
        /// </summary>
        /// <returns>Fluent interface that can be used to further configure the current <see cref="CustomDatabaseTraceListener"/> instance. </returns>
        /// <seealso cref="CustomDatabaseTraceListener"/>
        /// <seealso cref="CustomDatabaseTraceListenerData"/>
        /// <seealso cref="SourceLevels"/>
        ILoggingConfigurationSendToCustomDatabaseTraceListener Filter(SourceLevels sourceLevel);

        /// <summary>
        /// Specifies the name of the stored procedure that should be used to add a new log category.
        /// </summary>
        /// <param name="addCategoryStoredProcedureName">The name of the stored procedure that should be used to add a new log category.</param>
        /// <returns>Fluent interface that can be used to further configure the current <see cref="CustomDatabaseTraceListener"/> instance. </returns>
        /// <seealso cref="CustomDatabaseTraceListener"/>
        /// <seealso cref="CustomDatabaseTraceListenerData"/>
        ILoggingConfigurationSendToCustomDatabaseTraceListener WithAddCategoryStoredProcedure(string addCategoryStoredProcedureName);


        /// <summary>
        /// Specifies the name of the stored procedure that should be used when writing a log entry.
        /// </summary>
        /// <param name="writeLogStoredProcedureName">The name of the stored procedure that should be used when writing a log entry.</param>
        /// <returns>Fluent interface that can be used to further configure the current <see cref="CustomDatabaseTraceListener"/> instance. </returns>
        /// <seealso cref="CustomDatabaseTraceListener"/>
        /// <seealso cref="CustomDatabaseTraceListenerData"/>
        ILoggingConfigurationSendToCustomDatabaseTraceListener WithWriteLogStoredProcedure(string writeLogStoredProcedureName);

        /// <summary>
        /// Specifies which database instance, or connection string, should be used to send log messages to.
        /// </summary>
        /// <param name="databaseInstanceName">The name of the database instance, or connection string, should be used to send log messages to.</param>
        /// <returns>Fluent interface that can be used to further configure the current <see cref="CustomDatabaseTraceListener"/> instance. </returns>
        /// <seealso cref="CustomDatabaseTraceListener"/>
        /// <seealso cref="CustomDatabaseTraceListenerData"/>
        ILoggingConfigurationSendToCustomDatabaseTraceListener UseDatabase(string databaseInstanceName);
    }

}

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Practices.EnterpriseLibrary.Common.Configuration.Fluent;
using Microsoft.Practices.EnterpriseLibrary.Logging.Database.Configuration;
using Microsoft.Practices.EnterpriseLibrary.Logging.Configuration;
using System.Diagnostics;
using Microsoft.Practices.EnterpriseLibrary.Common.Properties;

namespace CustomDatabaseTraceListener.Configuration.Fluent
{
    /// <summary>
    /// Extension methods to support configuration of <see cref="CustomDatabaseTraceListener"/>.
    /// </summary>
    /// <seealso cref="CustomDatabaseTraceListener"/>
    /// <seealso cref="CustomDatabaseTraceListenerData"/>
    public static class SendToCustomDatabaseTraceListenerExtension
    {
        /// <summary>
        /// Adds a new <see cref="CustomDatabaseTraceListener"/> to the logging settings and creates
        /// a reference to this Trace Listener for the current category source.
        /// </summary>
        /// <param name="context">Fluent interface extension point.</param>
        /// <param name="listenerName">The name of the <see cref="CustomDatabaseTraceListener"/>.</param>
        /// <returns>Fluent interface that can be used to further configure the created <see cref="CustomDatabaseTraceListenerData"/>. </returns>
        /// <seealso cref="CustomDatabaseTraceListener"/>
        /// <seealso cref="CustomDatabaseTraceListenerData"/>
        public static ILoggingConfigurationSendToCustomDatabaseTraceListener CustomDatabase(this ILoggingConfigurationSendTo context, string listenerName)
        {
            if (string.IsNullOrEmpty(listenerName))
                throw new ArgumentException(Resources.ExceptionStringNullOrEmpty, "listenerName");

            return new SendToCustomDatabaseTraceListenerBuilder(context, listenerName);
        }

        private class SendToCustomDatabaseTraceListenerBuilder : SendToTraceListenerExtension, ILoggingConfigurationSendToCustomDatabaseTraceListener
        {
            CustomDatabaseTraceListenerData databaseTraceListener;
            public SendToCustomDatabaseTraceListenerBuilder(ILoggingConfigurationSendTo context, string listenerName)
                : base(context)
            {
                databaseTraceListener = new CustomDatabaseTraceListenerData
                {
                    Name = listenerName
                };

                base.AddTraceListenerToSettingsAndCategory(databaseTraceListener);
            }


            public ILoggingConfigurationSendToCustomDatabaseTraceListener FormatWith(IFormatterBuilder formatBuilder)
            {
                if (formatBuilder == null) throw new ArgumentNullException("formatBuilder");

                FormatterData formatter = formatBuilder.GetFormatterData();
                databaseTraceListener.Formatter = formatter.Name;
                LoggingSettings.Formatters.Add(formatter);

                return this;
            }

            public ILoggingConfigurationSendToCustomDatabaseTraceListener FormatWithSharedFormatter(string formatterName)
            {
                databaseTraceListener.Formatter = formatterName;

                return this;
            }

            public ILoggingConfigurationSendToCustomDatabaseTraceListener WithTraceOptions(TraceOptions traceOptions)
            {
                databaseTraceListener.TraceOutputOptions = traceOptions;

                return this;
            }

            public ILoggingConfigurationSendToCustomDatabaseTraceListener Filter(SourceLevels sourceLevel)
            {
                databaseTraceListener.Filter = sourceLevel;

                return this;
            }

            public ILoggingConfigurationSendToCustomDatabaseTraceListener WithAddCategoryStoredProcedure(string addCategoryStoredProcedureName)
            {
                if (string.IsNullOrEmpty(addCategoryStoredProcedureName))
                    throw new ArgumentException(Resources.ExceptionStringNullOrEmpty, "addCategoryStoredProcedureName");

                databaseTraceListener.AddCategoryStoredProcName = addCategoryStoredProcedureName;

                return this;
            }

            public ILoggingConfigurationSendToCustomDatabaseTraceListener WithWriteLogStoredProcedure(string writeLogStoredProcedureName)
            {
                if (string.IsNullOrEmpty(writeLogStoredProcedureName))
                    throw new ArgumentException(Resources.ExceptionStringNullOrEmpty, "writeLogStoredProcedureName");

                databaseTraceListener.WriteLogStoredProcName = writeLogStoredProcedureName;

                return this;
            }

            public ILoggingConfigurationSendToCustomDatabaseTraceListener UseDatabase(string databaseInstanceName)
            {
                databaseTraceListener.DatabaseInstanceName = databaseInstanceName;

                return this;
            }
        }
    }
}

It's probably easier to read in the sample solution.

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

Sep 18, 2012 at 3:51 PM
Edited Sep 18, 2012 at 4:11 PM

randy,

thank you for the code. i have configured the trace listener but i am getting the below error when trying to log:

Exception Type: System.Data.OracleClient.OracleExceptionCode: 6550ErrorCode: -2146232008Message: ORA-06550: line 1, column 7:PLS-00201: identifier 'WRITELOG' must be declaredORA-06550: line 1, column 7:PL/SQL: Statement ignored

i have sent the code zip to ur mail id. can you please let me know the issue as i am fighting against the deadline working on db logging

swaroop

Sep 19, 2012 at 12:30 AM

You are getting an oracle compilation error when trying to execute the trace listener logic.  I would verify that you can invoke the WriteLog stored procedure from PL/SQL.  If that works but you are still getting an error I would debug the trace listener to ensure that it is functioning as you would expect.  If the trace listener is still not working after that I would start with a small sample ADO.NET app that works and build it up to find the cause of the error.

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

Sep 25, 2012 at 10:26 PM

randy,

the package is being executed on oracle db. but i am getting the same error when called from .net. my question is do i have to add the package name while configuring the tracelistener?

 

below is the code.

  var minimumSourceLevel = MinimumSourceLevel();
            builder.ConfigureData()
                .ForDatabaseNamed("Oracle")
                    .ThatIs.AnOracleDatabase()
                    .WithConnectionString(connectionString)
                .AsDefault();
 
            builder.ConfigureLogging()
                    .WithOptions
                    .DoNotRevertImpersonation()
                    .LogToCategoryNamed("Errors")
                        .WithOptions.SetAsDefaultCategory()
                        .SendTo.CustomDatabase("Custom Database Trace Listener")
                        .UseDatabase("Oracle")
                        .WithWriteLogStoredProcedure("PKG_LOGGER.Write_Log")
                        .Filter(minimumSourceLevel)
                    .SpecialSources.LoggingErrorsAndWarningsCategory
                        .SendTo.EventLog("Event Log Listener")
                        .FormatWith(new FormatterBuilder()
                             .TextFormatterNamed("Text Formatter")
                               .UsingTemplate(@"Timestamp: {timestamp}{newline}
                             Message: {message}{newline}
                             Category: {category}{newline}
                             Priority: {priority}{newline}
                             EventId: {eventid}{newline}
                             Severity: {severity}{newline}
                             Title:{title}{newline}
                             Machine: {localMachine}{newline}
                             App Domain: {localAppDomain}{newline}
                             ProcessId: {localProcessId}{newline}
                             Process Name: {localProcessName}{newline}
                             Thread Name: {threadName}{newline}
                             Win32 ThreadId:{win32ThreadId}{newline}
                             Extended Properties: {dictionary({key} - {value}{newline})}"))
                            .ToLog("PetroDex Services")
                            .ToMachine(".")
                            .UsingEventLogSource("PETRODEX_EL_LOG")
                            .Filter(SourceLevels.All)
                            ; 
Sep 26, 2012 at 3:04 AM

Yes, you should have the package name.  This Q&A, http://stackoverflow.com/questions/657787/running-oracle-stored-procs-from-c-sharp, seems to indicate that the problem could be caused by the user not having the proper permissions.

If that doesn't help, I would recommend trying a more general purpose forum to track down the cause of the Oracle error.

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