Condividi tramite


Set IIS Log Fields with C#

This post shows how to set the log fields for IIS web sites programmatically.  Code is attached at the end of the post.

Background

I have a customer that has many web applications, and we need to set the IIS log fields to do some investigation.  James Blackwell posted a great sample of how to do this using VBScript (https://blogs.msdn.com/b/jb/archive/2008/02/03/script-for-enabling-full-iis-logging.aspx).  I had a need to do this via C#, and most of the work was simply converting James’ sample to use the System.DirectoryServices.DirectoryEntry class to manipulate the sites.  The reason I chose to use this instead of IIS7’s new Microsoft.Web.Administration namespace is because I am working with an IIS6 web server, however the code below works with both IIS6 and IIS7.

The Value of IIS Logs

I see a lot of customers who have IIS logging enabled but don’t do anything with the data.  The IIS logs can be invaluable to tell you what’s going on with your server at a particular time.  For instance, the operations team gets a call that their web site is slow.  We look, and don’t see anything wrong with the site.  We look at the IIS logs and see that the particular page in question is rendering very quickly.  We compare this against Fiddler and see that the customer introduced a ton of JavaScript that is slowing down the rendering of the page in the browser.  SharePoint is doing its job just fine.  Using IIS logs can considerably reduce the amount of time spent finding the needle that is poking the haystack.

A fantastic resource for measuring your site’s performance is the whitepaper, “Analyzing Microsoft SharePoint Products and Technologies Usage”.  It covers how to use tools like LogParser to get a better understanding of how your servers are performing.  Of course, to process the data means that your server needs to log the data in the first place.

The Implementation

We will create a .NET 2.0 console application and reference the System.DirectoryServices assembly.  You can query more than just Active Directory using the DirectoryEntry class, as we will see in this post.  We need to set the LogExtFiles property for a web site, which expects a DWORD, which is a 32-bit integer.  To set the flags, we first need to determine what the values are by looking them up in the LogExtFileFlags documentation.  That is where I got the values for the LogExt* constants below.

The rest is simple, just choose which fields you want to set and add them together to form the value.  For instance, if you only want to set LogExtFileDate and LogExtFileTime, the value is 1 + 2 = 3.  In my example below, I set all values except LogExtFileCookie because this field can cause your log files to grow considerably.

 using System;
using System.Collections.Generic;
using System.Text;
using System.DirectoryServices;

namespace SetWebSiteLoggingFields
{
    class Program
    {
        const int LogExtFileDate            = 1;        
        const int LogExtFileTime            = 2;
        const int LogExtFileClientIp        = 4;     
        const int LogExtFileUserName        = 8;    
        const int LogExtFileSiteName        = 16;
        const int LogExtFileComputerName    = 32;
        const int LogExtFileServerIp        = 64;
        const int LogExtFileMethod          = 128;
        const int LogExtFileUriStem         = 256;
        const int LogExtFileUriQuery        = 512;
        const int LogExtFileHttpStatus      = 1024;
        const int LogExtFileWin32Status     = 2048;
        const int LogExtFileBytesSent       = 4096;
        const int LogExtFileBytesRecv       = 8192;
        const int LogExtFileTimeTaken       = 16384;
        const int LogExtFileServerPort      = 32768;        
        const int LogExtFileUserAgent       = 65536;
        const int LogExtFileCookie          = 131072;
        const int LogExtFileReferer         = 262144;        
        const int LogExtFileProtocolVersion = 524288;
        const int LogExtFileHost            = 1048576;
        const int LogExtFileHttpSubStatus   = 2097152;  


        static void Main(string[] args)
        {
            try
            {
                string serverName = args[0];
                SetLogFields(serverName);
            }
            catch(Exception oops)
            {
                Console.WriteLine(oops.Message);
                Console.WriteLine();
                DisplayUsage();
            }
        }

        static void DisplayUsage()
        {
            Console.WriteLine("Enables all logging fields on all web sites.");
            Console.WriteLine("Usage:");
            Console.WriteLine("\tSetWebSiteLoggingFields <serverName>");
            Console.WriteLine();
            Console.WriteLine("Example:");
            Console.WriteLine("\tSetWebSiteLoggingFields WFE1");
            Console.WriteLine();

        }

        
        static void SetLogFields(string serverName)
        {            
            DirectoryEntry w3svc = new DirectoryEntry(
                                string.Format("IIS://{0}/w3svc", serverName));

            foreach (DirectoryEntry site in w3svc.Children)
            {
                Console.WriteLine("Site ID: " + site.Name);

                if (null != site.Properties["LogExtFileFlags"].Value)
                {
                    Console.WriteLine("Setting log fields for Site ID: " + site.Name);

                    site.Properties["LogExtFileFlags"][0] =
                        LogExtFileDate +
                        LogExtFileTime +
                        LogExtFileClientIp +
                        LogExtFileUserName +
                        LogExtFileSiteName +
                        LogExtFileComputerName +
                        LogExtFileServerIp +
                        LogExtFileMethod +
                        LogExtFileUriStem +
                        LogExtFileUriQuery +
                        LogExtFileHttpStatus +
                        LogExtFileWin32Status +
                        LogExtFileBytesSent +
                        LogExtFileBytesRecv +
                        LogExtFileTimeTaken +
                        LogExtFileServerPort +
                        LogExtFileUserAgent +
                        LogExtFileReferer +
                        LogExtFileProtocolVersion +
                        LogExtFileHost +
                        LogExtFileHttpSubStatus;
                    site.CommitChanges();

                }
            }  
        } 
    }
}

 

For More Information

Script for enabling full IIS logging

How to Use Microsoft.Web.Administration

LogExtFileFlags

Analyzing Microsoft SharePoint Products and Technologies Usage

SetWebSiteLoggingFields.zip

Comments

  • Anonymous
    November 17, 2011
    Here is a way to do with AppCMD $AppCMDPath = $env:windir + "system32inetsrv" Push-Location $AppCMDPath .appcmd.exe set config /section:system.applicationHost/sites /siteDefaults.logFile.logExtFileFlags:"Date, Time, ClientIP, UserName, SiteName, ComputerName, ServerIP, Method, UriStem, UriQuery, HttpStatus, Win32Status, BytesSent, BytesRecv, TimeTaken, ServerPort, UserAgent, Referer, ProtocolVersion, Host, HttpSubStatus"  /commit:apphost Pop-Location

  • Anonymous
    November 17, 2011
    That's why I've always been a fan of yours, Steve!  That's awesome, thanks for posting.  Any way to do this with Server 2003 R2 (doesn't have AppCMD that I know of).