Archive for SharePoint

SharePoint – Configuring log4net in a SharePoint Application

Cross-posted from my Clarity blog

Configuring log4net in a SharePoint or ASP.NET application is pretty straightforward, but no matter how many times I do it, I always forget something small and waste time troubleshooting why logging isn’t working.

Here’s a guide to configuring logging using log4net in a SharePoint application. This post will cover:

  • Creating and deploying a log4net configuration file
  • Making the necessary web.config changes to support logging
log4net deployment is documented extensively so I’ll keep this at a high level.

Creating and Deploying a log4net Configuration File

It’s always best to put your log4net configuration in a dedicated config file, this way you get to keep your SharePoint web.config file clean and not have to deal with the SPWebConfigModification class.

The part I always forget is that when you have the log4net configuration in a separate file, you need to tell your assembly the name of the log4net configuration file. You do that by adding the following attribute to the AssemblyInfo class of the SharePoint project or class library where you have your logger.

According to the documentation from Apache, this attribute is read and processed after the first time you invoke log4net. Your logger will call LogManager.GetLogger and look for this attribute and then read the configuration information.

[assembly: log4net.Config.XmlConfigurator(
 ConfigFile = "log4Net.config", Watch = true)]

You can examine properties of the logger such as isDebugEnabled and isErrorEnabled to check if everything is working properly.

You can then use a SharePoint Timer job to deploy the log4net.config file to the root of your SharePoint web application.

In a Web Application scoped feature, you can run a SharePoint Timer job in the FeactureActivated handler:

var log4NetDeployJob = new log4NetConfigDeploymentJob(
    _jobName, webApplication);
var schedule = new SPOneTimeSchedule(DateTime.Now);
log4NetDeployJob.Schedule = schedule;

The Execute method of the Timer Job extracts the log4net.config file from where it was deployed with your feature and copies it to the virtual directory:

public override void Execute(Guid targetInstanceId)
    var webApp = this.Parent as SPWebApplication;
    foreach (KeyValuePair<SPUrlZone, SPIisSettings> setting in webApp.IisSettings)
        var deployTo = setting.Value.Path.FullName + @"\log4Net.config";
        var filePath = SPUtility.GetGenericSetupPath(
        File.Copy(filePath, deployTo, true);


SPUtility.GetGenericSetupPath returns the full path to the 14 hive, and “TEMPLATE\FEATURES\log4Net\Configuration\log4Net.config” is the path to the log4Net.config file inside the feature.

Web.config Modifications

You now need to make some changes to the web application’s web.config file.

Add log4Net configuration section in configuration/configSections:

<section name="log4net"
  type="log4net.Config.Log4NetConfigurationSectionHandler, Log4net"/>

Add the following before the end of the configuration section:

<log4net configSource="log4Net.config" />

That’s it! Assuming you created a logger class in your application, you can start logging away. Check out the documentation from Apache for information about how to write a logger.

SharePoint – Timing of Master Page JavaScript

Our base SharePoint 2010 Publishing master page calls a JavaScript function that does things such as:

  • Initialize jQuery plugins
  • Configure some top-navigation tweaks
  • Miscellaneous items such as setting the date in the copyright footer
  • Initialize Google Analytics

We call this function right before the end of the head section of the master page. The contents of the JavaScript function are enclosed in a jQuery $(document).ready block, meaning that the function will run after the DOM is ready.

A drawback to this approach is that JavaScript that manipulate elements on the screen only executes after the DOM is ready. This isn’t a great user experience because the user can see the “jumpiness” on screen as the script executes.

I ran this by our resident web ninja Jacob Gable and he suggested breaking up the JavaScript function into smaller chunks and calling those chunks directly after the HTML content that they affect; for example:

<div id="footer">
    <span id="footer-year"></span>&nbsp;All rights reserved.
    <script type="text/javascript">

where SetCopyrightDate uses jQuery to set the date to the current year:

function SetCopyrightDate() 
    var today = new Date();
    var yr = today.getFullYear();
    $("#footer-year").text("© " + yr);

This is pretty obvious in retrospect; your JavaScript can be sprinkled throughout the page as needed. People are scared away by this, wanting to have a super-clean master page.

However, in this case, pulling out some JavaScript functionality into separate functions and calling them from the master page does the trick.

The remaining JavaScript can stay in a global function and run in a $(document).ready block; for us, all this does now is initialize jQuery plugins we’re using throughout the site.