Using Log4Net in ArcMap COM Extensions/Commands etc

I was building an edit task for ArcMap today, and got to a point where I had the geometry operations solid (using Test-Driven-Development for them) but when I got to iterating over sets of real data, I though it would be really handy to use a logger to kick out more detailed debug information. We use log4net in our web applications, so I thought I’d try dropping it in.

Turns out it took all of 5 minutes to get it working, so here’s the how-to (there’s some sample code at the end)

Get log4net

Get log4net from http://logging.apache.org/log4net/download.html – simple.

Add the Reference

Now that you have the log4net zip archive, copy the log4net.dll from the log4net-1.2.10binnet2.0release folder in the zip file into your lib folder. I always have a lib folder for external assemblies that are used in a project. This is preferable to storing these in a central location because the lib folder get’s stored in source control along with everything else that your project required. So – if you don’t have a lib folder, make one!

Now that it’s in the create a reference to log4net from your project in Visual Studio.

Media_httpblogdavebou_cajfl

Configure It

The easiest way to use log4net is with the standard log file appender which just writes to a text file. In order to configure this, we need to edit the ArcMap.exe.config file (located in ArcGISbin). Of course you can store the log in other places (databases etc) – just Google for the details.

By default, this configuration file is almost empty, so you’ll need to add in the configSections as well as the log4net section.

<configSections>
  <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net"
requirePermission="false" />
</configSections>

 

…lower down in the file…

<log4net>
  <appender name="LogFileAppender" type="log4net.Appender.FileAppender">
    <file value=".Logs_log.txt" />
    <appendToFile value="true" />
    <lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
    <layout type="log4net.Layout.PatternLayout">
      <conversionPattern value="%date [%thread] %-5level %logger [%property{NDC}] - %message%newline%exception" />
    </layout>
  </appender>
  <root>
    <level value="ALL" />
    <appender-ref ref="LogFileAppender" />
  </root>
</log4net>

Now we have to wire log4net into our code. In order to be useful, we’ll want to have access to the “logger” throughout our class, so we’ll make it a private member. Ideally we’d pass in the logger from a dependency injection framework, but we’ll keep things simple for this example (sometimes DI *is* overkill). Thus, we’ll setup the logger in the constructor of our class.

private log4net.ILog _logger;

 

/// <summary>
///
Constructor.
/// </summary>
publicLRSEditTask()
{
log4net.Config.XmlConfigurator.Configure();

_logger = log4net.LogManager.GetLogger(typeof(LRSEditTask));
}

Logging

Would not be very much help if I did not show how to actually write to the log! Now that we have _logger, we can just pump data to it. There are a number of levels you use to send out data, depending on the severity. During development, I’ll use the Debug(<info>) method to see what’s going on inside the code, but you’ll also want to use the Warn, Error and Fatal methods when your code experiences errors. Using the different methods allows you to control what’s output to the log file via the configuration section. This way you can leave all that debug stuff in the code, but not have log files piling up on production systems.

In the sample code, I’m just pumping out examples of each type of log.

public void Activate(IEditor Editor, IEditTask oldTask)
{
    _logger.Info("Task Activated.");
}

public void Deactivate()
{
    _logger.Warn("Task Deactivated.");
}

public string Name
{
    get { return "Log4Net Example Task"; }
}

public void OnDeleteSketch()
{
    _logger.Fatal("On Delete Sketch Called");
}

public void OnFinishSketch()
{
    _logger.Error("On Finish Sketch Called");
}

 

In the log file you’ll see something like this…

2009-10-15 15:32:25,631 [1] INFO  Log4NetDemoTask.LogEditTask [(null)] – Task Activated.
2009-10-15 15:32:29,205 [1] ERROR Log4NetDemoTask.LogEditTask [(null)] – On Finish Sketch Called
2009-10-15 15:32:33,003 [1] FATAL Log4NetDemoTask.LogEditTask [(null)] – On Delete Sketch Called
2009-10-15 15:32:38,182 [1] WARN  Log4NetDemoTask.LogEditTask [(null)] – Task Deactivated.

Post Build Tasks

This is a subtle thing, but as far as I can tell, if you want your code to be able to “see” the ArcMap.exe.config file, your dll must reside in the bin folder right beside ArcMap.exe. This is easily accomplished by adding a post-build event in Visual Studio

copy $(TargetDir)*.* “c:program filesArcGISbin”

Now, every time you build the project, it will copy your dll and any dependencies (log4net in our case) into the bin folder.

A final note – when you start using logging, you’ll want to be able to look at the log without re-opening the file all the time. Thanks to Vish I’ve been using BareTail for quite some time now – this app will let you watch the file as lines are added to it.

Here’s a simple sample editing task, (sorry – misplaced the file!) along with an ArcMap.exe.config file. Have fun!

4 thoughts on “Using Log4Net in ArcMap COM Extensions/Commands etc

  1. bertsens

    step with copy to ArcGIS directoryis not needed if you do XmlConfigurator.Configure(new FileInfo(Assembly.GetExecutingAssembly().Location + “.config”)); but there is a problem if you use this command in multiple extensions/tools.

    Reply
  2. kisutch

    @bertsens Where can I find out more information about this “problem” using with multiple extensions. I was hoping to use log4Net in several of my extensions.

    Reply
    1. Dave Bouwman Post author

      Sorry Dejan, but it looks like I misplaced the source code. Anyhow – this tool would not do you much good as this post is about how to add logging to your own tools ;-)

      Dave

      Reply

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>