views:

526

answers:

2

Hello,

i'm trying to get log4net integration for Castle Windsor working. I wrote my class with an public property of type ILogger and took the configuration in my app.config like following.

<configuration>
  <configsections>
    <section name="castle" type="Castle.Windsor.Configuration.AppDomain.CastleSectionHandler, Castle.Windsor" />
    <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" />
  </configsections>

  <castle>
    <facilities>
      <facility id="logging" type="Castle.Facilities.Logging.LoggingFacility, Castle.Facilities.Logging" loggingApi="log4net" />
    </facilities>
    <components>
      <component id="form1" type="WinFormsActiveRecordSample.Form1, WinFormsActiveRecordSample" />
    </components>
  </castle>
  <log4net>
    <root>
      <level value="ALL" />
      <appender-ref ref="FileAppender" />
    </root>
    <appender name="FileAppender" type="log4net.Appender.FileAppender">
      <file value="main.log" />
      <appendToFile value="true" />
      <layout type="log4net.Layout.PatternLayout">
        <conversionPattern value="%date{dd.MM.yy HH:mm:ss} %-5level %logger - %message%newline" />
      </layout>
    </appender>
  </log4net>
</configuration>

In my eyes this should be working, but it doesnt. When i set loggingApi="console" it logs correctly. When i change it to log4net it does nothing. The log4net configuration was taken from another project where the block is working. What must i do that the logfile was used? Must there be a special log4netconfiguration?

Thanks for any hint

Boris

+3  A: 

Move your log4net configuration to a separate file log4net.config, then refer that file from the facility configuration:

<facility id="loggingfacility" configfile="log4net.config" loggingapi="log4net" type="Castle.Facilities.Logging.LoggingFacility, Castle.Facilities.Logging"/>

If you want to have your log4net configuration in a section of your app.config:

public class MyLog4NetFactory: AbstractLoggerFactory {
    public MyLog4NetFactory() {
        XmlConfigurator.Configure();
    }

    public override ILogger Create(String name) {
        ILog log = LogManager.GetLogger(name);
        return new Log4netLogger(log, this);
    }

    public override ILogger Create(String name, LoggerLevel level) {
        throw new NotSupportedException("Logger levels cannot be set at runtime. Please review your configuration file.");
    }
}

then register the facility as:

<facility 
  id="loggingfacility" 
  loggingapi="custom" 
  customLoggerFactory="[fully qualified type name of MyLog4NetFactory]" 
  type="Castle.Facilities.Logging.LoggingFacility, Castle.Facilities.Logging"/>
Mauricio Scheffer
That is the way i was thinking about but i like the idea of having the configuration all in a single place. Ithink i must look into the factory to get a way to load the configuration from the app.config... but when its only the logging configuration which is static most of the time...Thanks for your tip
Booser
curious, must `configfile="..."` *not* be the app config? @Boris what happens if you specify `[application.name].exe.config` instead?
johnny g
@johnnyG: won't work
Mauricio Scheffer
@Boris: see updated answer
Mauricio Scheffer
Thanks for the new sample. I was looking into the source to make something like this when i saw your answer.The only thing was when i added the class to my project i had to use a own copy of the Log4netLogger class.When i used the code from here and set the return for Create to return new Castle.Services.Logging.Log4netIntegration.Log4netLogger(log, this);I get 2 argument errorsfirst argument could not be converted from log4net.ILog to Log4net.Core.ILogger
Booser
Second argument could not be converted from "WinFormsActiveRecordSample.MyLog4netFactory" to "Castle.Services.Logging.Log4netIntegration.Log4netFactory" Sry for incorrect messages but i translated it freely from my german errors.The second argument could i satisfy when i change AbstractLoggerFactory to Log4netFactory. But the Ilog to Ilogger.... i dont know how to change the code to use the existing Logger implementation.
Booser
@Boris, double-check your namespaces, Log4netLogger implements ILogger, not ILog: http://api.castleproject.org/html/T_Castle_Services_Logging_Log4netIntegration_Log4netLogger.htm
Mauricio Scheffer
@Boris: did you specify loggingapi="custom"?
Mauricio Scheffer
After i copied the Log4netLogger to MyLog4netLogger and used this i could use the whole logging. The problem was not that the facility was misconfigured but the code did not compile.Ill try to get an ILogger instance to remove the copied implementation of the logger.
Booser
Found the solution in the factory class.I changed to inherit from Log4netFactory and changed the return from the Create method to usereturn new Log4netLogger(log.Logger, this);Now it works like a charm.
Booser
A: 

This is the entire configuration for the sample given here Home » MicroKernel/Windsor » Getting Started » Part 1 - The basics

<configuration>
  <configSections>
    <section
        name="castle"
        type="Castle.Windsor.Configuration.AppDomain.CastleSectionHandler, Castle.Windsor" />
  </configSections>


  <castle>
    <facilities>
    <facility
         id="logging"
         type="Castle.Facilities.Logging.LoggingFacility, Castle.Facilities.Logging"
         loggingApi="log4net"
         configFile="D:\\Backup-E\\My Work\\.NET\\CastleWindsorPOC\\CastleWindosorApp\\CastleWindosorApp\\Log4Net.xml" />
    </facilities>
    <components>
      <component
          id="httpservicewatcher"
          type="CastleWindosorApp.HttpServiceWatcher, CastleWindosorApp" >
        <parameters>
          <notifiers>
            <array>
              <item>${email.notifier}</item>
              <item>${alarm.notifier}</item>
            </array>
          </notifiers>
          <Url>test url</Url>
          <!--<Logger>${logger.component}</Logger>-->
        </parameters>
      </component>

      <component
          id="email.notifier"
          service="CastleWindosorApp.IFailureNotifier, CastleWindosorApp"
          type="CastleWindosorApp.EmailFailureNotifier, CastleWindosorApp" />

      <component
          id="alarm.notifier"
          service="CastleWindosorApp.IFailureNotifier, CastleWindosorApp"
          type="CastleWindosorApp.AlarmFailureNotifier, CastleWindosorApp" />
     <!--<component
          id="logger.component"
          service="Castle.Core.Logging.ILogger, Castle.Core"
          type="Castle.Services.Logging.Log4netIntegration.Log4netLogger, Castle.Services.Logging.Log4netIntegration" />-->
      <component
          id="form.component"
          type="CastleWindosorApp.Form1, CastleWindosorApp" />


    </components>

  </castle>

The mistake i did was (as you can see the sections commented in the config file), tried to assign the Logger property once again in my class by registering the component in castle. this is not required as Castel does this automatically for you.

Cheers Badal

Badal Kotecha