Can I inherit TextFormatter to create a custom provider?

Topics: Building and extending application blocks, Logging Application Block
Feb 1, 2012 at 8:47 AM
Edited Feb 8, 2012 at 12:06 AM

 I want to inherit TextFormatter instead of  ILogFormatter to create a custom provider,  and I want to use Full Design-time Integration.

I tried many times and failed. Anyone help me? Thanks!

--MyTextFormatter.cs

namespace GAIA.Tool.MyLogging
{

[ConfigurationElementType(typeof(MyTextFormatterData))]
    public class MyTextFormatter : TextFormatter
    {
        new internal const string DefaultTextFormat = "\"{machine}\",\"{timestamp}\",\"{severity}\",\"{namaspace}\",\"{className}\",\"{methodSignature}\",\"{message}\",\"{user}\",\"{ipAddress}\",\"{userAgent}\",\"{url}\",\"{referrer}\"";

        private static readonly IDictionary<string, TokenHandler<LogEntry>> _extraTokenHandlers = GetExtraTokenHandlers();

        private NameValueCollection _attributes = null;

        public MyTextFormatter(NameValueCollection attributes)
        {
            this._attributes = attributes;            
        }

        public MyTextFormatter()
            : this(DefaultTextFormat)
        {
        }

        public MyTextFormatter(string template)
            : base(template, _extraTokenHandlers)
        {
        }

        private static IDictionary<string, TokenHandler<LogEntry>> GetExtraTokenHandlers()
        {
            IDictionary<string, TokenHandler<LogEntry>> extraHandlers = new Dictionary<string, TokenHandler<LogEntry>>();

            // Web Application parameters
            extraHandlers["namaspace"] = GenericTextFormatter<LogEntry>.CreateSimpleTokenHandler(le => ((WeblogEntry)le).NamespaceName);
            extraHandlers["className"] = GenericTextFormatter<LogEntry>.CreateSimpleTokenHandler(le => ((WeblogEntry)le).ClassName);
            extraHandlers["methodSignature"] = GenericTextFormatter<LogEntry>.CreateSimpleTokenHandler(le => ((WeblogEntry)le).MethodSignature);
            extraHandlers["user"] = GenericTextFormatter<LogEntry>.CreateSimpleTokenHandler(le => ((WeblogEntry)le).CurrentUserName);
            extraHandlers["ipAddress"] = GenericTextFormatter<LogEntry>.CreateSimpleTokenHandler(le => ((WeblogEntry)le).CurrentUserIPAddress);
            extraHandlers["userAgent"] = GenericTextFormatter<LogEntry>.CreateSimpleTokenHandler(le => ((WeblogEntry)le).CurrentUserAgent);
            extraHandlers["url"] = GenericTextFormatter<LogEntry>.CreateSimpleTokenHandler(le => ((WeblogEntry)le).CurrentUrl);
            extraHandlers["referrer"] = GenericTextFormatter<LogEntry>.CreateSimpleTokenHandler(le => ((WeblogEntry)le).CurrentUrl);

            return extraHandlers;
        }
    }
}

 

---MyTextFormatterData.cs

namespace GAIA.Tool.MyLogging
{

public class MyTextFormatterData : TextFormatterData
    {
        public MyTextFormatterData()
        {
            Type = typeof(MyTextFormatter);
        }

        public MyTextFormatterData(string templateData)
            : base(templateData)
        {
        }

        public MyTextFormatterData(string name, string templateData)
            : base(name, templateData)
        {
        }

        public override IEnumerable<TypeRegistration> GetRegistrations()
        {
            yield return new TypeRegistration<ILogFormatter>(() =>
                new MyTextFormatter(this.Template))
                {
                    Name = this.Name,
                    Lifetime = TypeRegistrationLifetime.Transient
                };
        }
    }
Feb 3, 2012 at 2:41 AM

"I tried many times and failed."

Can you be more specific?  What did you try and what happened?

I think you should be able to inherit from those classes (Enterprise Library does it for TraceListenerData).  One thing that is sometimes missed is to deploy the assembly with the custom classes to the same folder as the configuration tool.

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

Feb 3, 2012 at 8:06 AM

 I config MyTextFormatter in web.config and run test code, it throws an exception.  Is that I cannot inherit TextFormatter to implement an custom formatter?

The reason I inherit TextFormatter is to add some my own TokenHandler, such as:

extraHandlers["namaspace"] = GenericTextFormatter<LogEntry>.CreateSimpleTokenHandler(le => ((WeblogEntry)le).NamespaceName);
extraHandlers["className"] = GenericTextFormatter<LogEntry>.CreateSimpleTokenHandler(le => ((WeblogEntry)le).ClassName);

I Studied Samples in Enterprise_Library_Extensibility_Hands-On_Labs, but there's no such sample. Thanks!

Config:

<configSections>
    <section name="loggingConfiguration" type="Microsoft.Practices.EnterpriseLibrary.Logging.Configuration.LoggingSettings, Microsoft.Practices.EnterpriseLibrary.Logging" />
  </configSections>
  <loggingConfiguration name="Logging Application Block" tracingEnabled="true"
    defaultCategory="General" logWarningsWhenNoCategoriesMatch="true">
    <listeners>
      <add name="FlatFile TraceListener" type="Microsoft.Practices.EnterpriseLibrary.Logging.TraceListeners.FlatFileTraceListener, Microsoft.Practices.EnterpriseLibrary.Logging"
        listenerDataType="Microsoft.Practices.EnterpriseLibrary.Logging.Configuration.FlatFileTraceListenerData, Microsoft.Practices.EnterpriseLibrary.Logging"
        fileName="Logs\test.log" header="----------------------------------------"
        footer="----------------------------------------" formatter="MyCustomFormatter"
        traceOutputOptions="None" filter="All" />
    </listeners>
    <formatters>
      <add type="GAIA.Tool.MyLogging.MyTextFormatter, GAIA.Tool.MyLogging"
        template="Timestamp: {timestamp}&#xD;&#xA;Message: {message}&#xD;&#xA;Category: {category}&#xD;&#xA;Priority: {priority}&#xD;&#xA;EventId: {eventid}&#xD;&#xA;Severity: {severity}&#xD;&#xA;Title:{title}&#xD;&#xA;Machine: {machine}&#xD;&#xA;Application Domain: {appDomain}&#xD;&#xA;Process Id: {processId}&#xD;&#xA;Process Name: {processName}&#xD;&#xA;Win32 Thread Id: {win32ThreadId}&#xD;&#xA;Thread Name: {threadName}&#xD;&#xA;Extended Properties: {dictionary({key} - {value}&#xD;&#xA;)}"
        name="MyCustomFormatter" />
    </formatters>
    <categorySources>
      <add switchValue="All" name="General">
        <listeners>
          <add name="FlatFile TraceListener" />
        </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="FlatFile TraceListener" />
        </listeners>
      </errors>
    </specialSources>
  </loggingConfiguration>

 

Test Code:

        protected void Page_Load(object sender, EventArgs e)
        {
            LogEntry log = new LogEntry();

            log.EventId = 2000;

            log.Priority = 2;
            log.Severity = System.Diagnostics.TraceEventType.Information;
            log.Title = "title";
            log.TimeStamp = DateTime.UtcNow;
            log.Message = "Test log";

            ICollection<string> coll = new List<string>();
            coll.Add("General");
            log.Categories = coll;

            Logger.Write(log);
        }

Exception:

The current type, Microsoft.Practices.EnterpriseLibrary.Logging.Formatters.ILogFormatter, is an interface and cannot be constructed. Are you missing a type mapping?

System.InvalidOperationException: The current type, Microsoft.Practices.EnterpriseLibrary.Logging.Formatters.ILogFormatter, is an interface and cannot be constructed. Are you missing a type mapping?

line 406:                                TryLogConfigurationFailure(configurationException);
line 407:
line 408:                                throw;
line 409:                            }
line 410:                        }

Source File: D:\EntLib50\EntLib50Src\Blocks\Logging\Src\Logging\Logger.cs    Line: 408

[InvalidOperationException: The current type, Microsoft.Practices.EnterpriseLibrary.Logging.Formatters.ILogFormatter, is an interface and cannot be constructed. Are you missing a type mapping?]
   Microsoft.Practices.ObjectBuilder2.DynamicMethodConstructorStrategy.ThrowForAttemptingToConstructInterface(IBuilderContext context) +212
   BuildUp_Microsoft.Practices.EnterpriseLibrary.Logging.Formatters.ILogFormatter(IBuilderContext ) +39
   Microsoft.Practices.ObjectBuilder2.DynamicMethodBuildPlan.BuildUp(IBuilderContext context) +12
   Microsoft.Practices.ObjectBuilder2.BuildPlanStrategy.PreBuildUp(IBuilderContext context) +195
   Microsoft.Practices.ObjectBuilder2.StrategyChain.ExecuteBuildUp(IBuilderContext context) +190
   Microsoft.Practices.ObjectBuilder2.BuilderContext.NewBuildUp(NamedTypeBuildKey newBuildKey) +113
   Microsoft.Practices.Unity.ObjectBuilder.NamedTypeDependencyResolverPolicy.Resolve(IBuilderContext context) +48
   BuildUp_Microsoft.Practices.EnterpriseLibrary.Logging.TraceListeners.FlatFileTraceListener(IBuilderContext ) +375
   Microsoft.Practices.ObjectBuilder2.DynamicMethodBuildPlan.BuildUp(IBuilderContext context) +12
   Microsoft.Practices.ObjectBuilder2.BuildPlanStrategy.PreBuildUp(IBuilderContext context) +195
   Microsoft.Practices.ObjectBuilder2.StrategyChain.ExecuteBuildUp(IBuilderContext context) +190
   Microsoft.Practices.ObjectBuilder2.BuilderContext.NewBuildUp(NamedTypeBuildKey newBuildKey) +113
   Microsoft.Practices.Unity.ObjectBuilder.NamedTypeDependencyResolverPolicy.Resolve(IBuilderContext context) +48
   BuildUp_Microsoft.Practices.EnterpriseLibrary.Logging.TraceListeners.ReconfigurableTraceListenerWrapper(IBuilderContext ) +116
   Microsoft.Practices.ObjectBuilder2.DynamicMethodBuildPlan.BuildUp(IBuilderContext context) +12
   Microsoft.Practices.ObjectBuilder2.BuildPlanStrategy.PreBuildUp(IBuilderContext context) +195
   Microsoft.Practices.ObjectBuilder2.StrategyChain.ExecuteBuildUp(IBuilderContext context) +190
   Microsoft.Practices.ObjectBuilder2.BuilderContext.NewBuildUp(NamedTypeBuildKey newBuildKey) +113
   Microsoft.Practices.Unity.ObjectBuilder.NamedTypeDependencyResolverPolicy.Resolve(IBuilderContext context) +48
   Microsoft.Practices.Unity.ResolvedArrayWithElementsResolverPolicy.DoResolve(IBuilderContext context, IDependencyResolverPolicy[] elementPolicies) +108
   Microsoft.Practices.Unity.ResolvedArrayWithElementsResolverPolicy.Resolve(IBuilderContext context) +23
   BuildUp_Microsoft.Practices.EnterpriseLibrary.Logging.LogSource(IBuilderContext ) +203
   Microsoft.Practices.ObjectBuilder2.DynamicMethodBuildPlan.BuildUp(IBuilderContext context) +12
   Microsoft.Practices.ObjectBuilder2.BuildPlanStrategy.PreBuildUp(IBuilderContext context) +195
   Microsoft.Practices.ObjectBuilder2.StrategyChain.ExecuteBuildUp(IBuilderContext context) +190
   Microsoft.Practices.ObjectBuilder2.BuilderContext.NewBuildUp(NamedTypeBuildKey newBuildKey) +113
   Microsoft.Practices.Unity.ObjectBuilder.NamedTypeDependencyResolverPolicy.Resolve(IBuilderContext context) +48
   Microsoft.Practices.Unity.ResolvedArrayWithElementsResolverPolicy.DoResolve(IBuilderContext context, IDependencyResolverPolicy[] elementPolicies) +108
   Microsoft.Practices.Unity.ResolvedArrayWithElementsResolverPolicy.Resolve(IBuilderContext context) +23
   BuildUp_Microsoft.Practices.EnterpriseLibrary.Logging.LogWriterStructureHolder(IBuilderContext ) +252
   Microsoft.Practices.ObjectBuilder2.DynamicMethodBuildPlan.BuildUp(IBuilderContext context) +12
   Microsoft.Practices.ObjectBuilder2.BuildPlanStrategy.PreBuildUp(IBuilderContext context) +195
   Microsoft.Practices.ObjectBuilder2.StrategyChain.ExecuteBuildUp(IBuilderContext context) +190
   Microsoft.Practices.ObjectBuilder2.BuilderContext.NewBuildUp(NamedTypeBuildKey newBuildKey) +113
   Microsoft.Practices.Unity.ObjectBuilder.NamedTypeDependencyResolverPolicy.Resolve(IBuilderContext context) +48
   BuildUp_Microsoft.Practices.EnterpriseLibrary.Logging.LogWriterImpl(IBuilderContext ) +118
   Microsoft.Practices.ObjectBuilder2.DynamicMethodBuildPlan.BuildUp(IBuilderContext context) +12
   Microsoft.Practices.ObjectBuilder2.BuildPlanStrategy.PreBuildUp(IBuilderContext context) +195
   Microsoft.Practices.ObjectBuilder2.StrategyChain.ExecuteBuildUp(IBuilderContext context) +190
   Microsoft.Practices.Unity.UnityContainer.DoBuildUp(Type t, Object existing, String name, IEnumerable`1 resolverOverrides) +163

[ResolutionFailedException: Resolution of the dependency failed, type = "Microsoft.Practices.EnterpriseLibrary.Logging.LogWriter", name = "(none)".
Exception occurred while: while resolving.
Exception is: InvalidOperationException - The current type, Microsoft.Practices.EnterpriseLibrary.Logging.Formatters.ILogFormatter, is an interface and cannot be constructed. Are you missing a type mapping?
-----------------------------------------------
At the time of the exception, the container was:

  Resolving Microsoft.Practices.EnterpriseLibrary.Logging.LogWriterImpl,LogWriter.__default__ (mapped from Microsoft.Practices.EnterpriseLibrary.Logging.LogWriter, (none))
  Resolving parameter "structureHolder" of constructor Microsoft.Practices.EnterpriseLibrary.Logging.LogWriterImpl(Microsoft.Practices.EnterpriseLibrary.Logging.LogWriterStructureHolder structureHolder, Microsoft.Practices.EnterpriseLibrary.Logging.Instrumentation.ILoggingInstrumentationProvider instrumentationProvider, Microsoft.Practices.EnterpriseLibrary.Logging.ILoggingUpdateCoordinator updateCoordinator)
    Resolving Microsoft.Practices.EnterpriseLibrary.Logging.LogWriterStructureHolder,LogWriterStructureHolder.__default__ (mapped from Microsoft.Practices.EnterpriseLibrary.Logging.LogWriterStructureHolder, (none))
    Resolving parameter "traceSources" of constructor Microsoft.Practices.EnterpriseLibrary.Logging.LogWriterStructureHolder(System.Collections.Generic.IEnumerable`1[[Microsoft.Practices.EnterpriseLibrary.Logging.Filters.ILogFilter, Microsoft.Practices.EnterpriseLibrary.Logging, Version=5.0.414.0, Culture=neutral, PublicKeyToken=null]] filters, System.Collections.Generic.IEnumerable`1[[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]] traceSourceNames, System.Collections.Generic.IEnumerable`1[[Microsoft.Practices.EnterpriseLibrary.Logging.LogSource, Microsoft.Practices.EnterpriseLibrary.Logging, Version=5.0.414.0, Culture=neutral, PublicKeyToken=null]] traceSources, Microsoft.Practices.EnterpriseLibrary.Logging.LogSource allEventsTraceSource, Microsoft.Practices.EnterpriseLibrary.Logging.LogSource notProcessedTraceSource, Microsoft.Practices.EnterpriseLibrary.Logging.LogSource errorsTraceSource, System.String defaultCategory, System.Boolean tracingEnabled, System.Boolean logWarningsWhenNoCategoriesMatch, System.Boolean revertImpersonation)
      Resolving Microsoft.Practices.EnterpriseLibrary.Logging.LogSource,General
      Resolving parameter "traceListeners" of constructor Microsoft.Practices.EnterpriseLibrary.Logging.LogSource(System.String name, System.Collections.Generic.IEnumerable`1[[System.Diagnostics.TraceListener, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]] traceListeners, System.Diagnostics.SourceLevels level, System.Boolean autoFlush, Microsoft.Practices.EnterpriseLibrary.Logging.Instrumentation.ILoggingInstrumentationProvider instrumentationProvider)
        Resolving Microsoft.Practices.EnterpriseLibrary.Logging.TraceListeners.ReconfigurableTraceListenerWrapper,FlatFile TraceListener (mapped from System.Diagnostics.TraceListener, FlatFile TraceListener)
        Resolving parameter "wrappedTraceListener" of constructor Microsoft.Practices.EnterpriseLibrary.Logging.TraceListeners.ReconfigurableTraceListenerWrapper(System.Diagnostics.TraceListener wrappedTraceListener, Microsoft.Practices.EnterpriseLibrary.Logging.ILoggingUpdateCoordinator coordinator)
          Resolving Microsoft.Practices.EnterpriseLibrary.Logging.TraceListeners.FlatFileTraceListener,FlatFile TraceListener‌implementation (mapped from System.Diagnostics.TraceListener, FlatFile TraceListener‌implementation)
          Resolving parameter "formatter" of constructor Microsoft.Practices.EnterpriseLibrary.Logging.TraceListeners.FlatFileTraceListener(System.String fileName, System.String header, System.String footer, Microsoft.Practices.EnterpriseLibrary.Logging.Formatters.ILogFormatter formatter)
            Resolving Microsoft.Practices.EnterpriseLibrary.Logging.Formatters.ILogFormatter,Text Formatter
]
   Microsoft.Practices.Unity.UnityContainer.DoBuildUp(Type t, Object existing, String name, IEnumerable`1 resolverOverrides) +327
   Microsoft.Practices.Unity.UnityContainer.Resolve(Type t, String name, ResolverOverride[] resolverOverrides) +15
   Microsoft.Practices.Unity.UnityServiceLocator.DoGetInstance(Type serviceType, String key) +43
   Microsoft.Practices.ServiceLocation.ServiceLocatorImplBase.GetInstance(Type serviceType, String key) +50

[ActivationException: Activation error occured while trying to get instance of type LogWriter, key ""]
   Microsoft.Practices.ServiceLocation.ServiceLocatorImplBase.GetInstance(Type serviceType, String key) +110
   Microsoft.Practices.ServiceLocation.ServiceLocatorImplBase.GetInstance() +65
   Microsoft.Practices.EnterpriseLibrary.Logging.Logger.get_Writer() in D:\EntLib50\EntLib50Src\Blocks\Logging\Src\Logging\Logger.cs:408
   Microsoft.Practices.EnterpriseLibrary.Logging.Logger.Write(LogEntry log) in D:\EntLib50\EntLib50Src\Blocks\Logging\Src\Logging\Logger.cs:303
   testWeb.test.Page_Load(Object sender, EventArgs e) in D:\GAIA PlatForm\testWeb\test.aspx.cs:32
   System.Web.Util.CalliHelper.EventArgFunctionCaller(IntPtr fp, Object o, Object t, EventArgs e) +14
   System.Web.Util.CalliEventHandlerDelegateProxy.Callback(Object sender, EventArgs e) +35
   System.Web.UI.Control.OnLoad(EventArgs e) +91
   System.Web.UI.Control.LoadRecursive() +74
   System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +2207


Feb 8, 2012 at 12:08 AM

No Ans.

Feb 8, 2012 at 12:56 AM

The exception you are seeing is usually thrown when Enterprise Library is not configured properly.  However,  based on the code you've posted my sample project runs fine.  Perhaps you can post a sample project that demonstrates the issue?

Also, beware of downcasting in your token handler because if a LogEntry is passed in (which is perfectly legal since that is what the Enterprise Library interface specifies) instead of a WeblogEntry then an exception will be thrown and the message not logged.  

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

Feb 10, 2012 at 12:11 AM

Thank you, I've got it. Maybe I did not configure properly. And thanks for your suggesting on the using of WeblogEntry.