Monday, March 16, 2009

Setting up Timer Job to Cleanup Audit Log

I had a requirement to cleanup the SharePoint audit log after a certain amount of time (in our case a year). This is a simple operation using the SPAudit class and the DeleteEntries() method.

The timer job definition:

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

 

using Microsoft.SharePoint;

using Microsoft.SharePoint.Administration;

using Microsoft.SharePoint.Utilities;

 

using MaskedSharePointer.Logging;

 

namespace MaskedSharePointer.TimerJobs

{

    public class AuditLogManagerJobDefinition : SPJobDefinition

    {

        private const string siteIdPropertyName = "SiteCollectionId";

        private const string daysToRetainPropertyName = "DaysToRetain";

 

        private const string dateFormat = "dd/MM/yyyy HH:mm:ss";

 

        public AuditLogManagerJobDefinition()

        {

        }

 

        public AuditLogManagerJobDefinition(string jobName, SPWebApplication webApp, Guid siteId, int daysToRetain): base(jobName, webApp, null, SPJobLockType.ContentDatabase)

        {

            this.Title = jobName;

            this.Properties.Add(siteIdPropertyName, siteId);

            this.Properties.Add(daysToRetainPropertyName, daysToRetain);

        }

 

        public override void Execute(Guid targetInstanceId)

        {

            try

            {

                Guid siteId = (Guid)this.Properties[siteIdPropertyName];

                int daysToRetain = (int)this.Properties[daysToRetainPropertyName];

 

                DateTime deleteEndDate = DateTime.Now.AddDays(-daysToRetain);

 

                using (SPSite site = new SPSite(siteId))

                {

                    SPAudit audit = site.Audit;                   

                    int recordsDeleted = audit.DeleteEntries(deleteEndDate);

 

                    Logger.LogInformation(string.Format("{3} Timer Job completed at {0}.  It removed all records created before {1} ({2} audit log records were deleted).", DateTime.Now.ToString(dateFormat), deleteEndDate.ToString(dateFormat), recordsDeleted, Title));

                }

            }

            catch (Exception ex)

            {

                Logger.LogException(ex);

            }

        }

    }

}



The feature to activate the timer job:

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

 

using Microsoft.SharePoint;

using Microsoft.SharePoint.Administration;

 

using MaskedSharePointer.TimerJobs;

 

namespace MaskedSharePointer.Receivers

{

    public class AuditLogManager : SPFeatureReceiver

    {

        private readonly string _scheduleKey = "Schedule";

        private readonly string _daysToRetainKey = "DaysToRetain";

 

        private const int _defaultDaysToRetain = 365;

 

        public override void FeatureActivated(SPFeatureReceiverProperties properties)

        {

            string jobName = properties.Definition.DisplayName;

 

            SPSite site = properties.Feature.Parent as SPSite;

 

            RemoveExistingTimerJob(site, jobName);

 

            int daysToRetain = GetDaysToRetain(properties);

 

            AuditLogManagerJobDefinition auditLogManagerJobDefinition = new AuditLogManagerJobDefinition(jobName, site.WebApplication, site.ID, daysToRetain);

            auditLogManagerJobDefinition.Schedule = GetSchedule(properties);

            auditLogManagerJobDefinition.Update();

        }

 

 

        public override void FeatureDeactivating(SPFeatureReceiverProperties properties)

        {

            string jobName = properties.Definition.DisplayName;

 

            SPSite site = properties.Feature.Parent as SPSite;

            RemoveExistingTimerJob(site, jobName);

        }

 

        public override void FeatureInstalled(SPFeatureReceiverProperties properties)

        {

        }

 

        public override void FeatureUninstalling(SPFeatureReceiverProperties properties)

        {

        }

 

        private static void RemoveExistingTimerJob(SPSite site, string jobName)

        {

            foreach (SPJobDefinition job in site.WebApplication.JobDefinitions)

            {

                if (job.Name == jobName)

                {

                    job.Delete();

                    break;

                }

            }

        }

 

        private SPSchedule GetSchedule(SPFeatureReceiverProperties properties)

        {

            try

            {

                if (properties.Feature.Properties[_scheduleKey] != null)

                    return SPSchedule.FromString(properties.Feature.Properties[_scheduleKey].Value);

                else

                    return new SPWeeklySchedule();

            }

            catch

            {

                return new SPWeeklySchedule();

            }

        }

 

        private int GetDaysToRetain(SPFeatureReceiverProperties properties)

        {

            try

            {

                if (properties.Feature.Properties[_daysToRetainKey] != null)

                    return Convert.ToInt32(properties.Feature.Properties[_daysToRetainKey].Value);

                else

                    return _defaultDaysToRetain;

            }

            catch

            {

                return _defaultDaysToRetain;

            }

        }

    }

}



And the xml of the feature to setup how often to run the timer job. I run it daily as the call to DeleteEntries() does a simple SQL delete directly on the content database:

<?xml version="1.0" encoding="utf-8" ?>

<Feature

    Id="{GUID}"

    Title="Audit Log Manager Timer Job"

    Description="Timer job that clears the audit log after a certain amount of time."

    Scope="Site"

    Version="1.0.0.0"

    Hidden="FALSE"

    xmlns="http://schemas.microsoft.com/sharepoint/"

    ReceiverAssembly="MaskedSharePointer.Demo, Version=1.0.0.0, Culture=neutral, PublicKeyToken=xxxxxxxxxxxxxxxx"

    ReceiverClass="MaskedSharePointer.Receivers.AuditLogManager ">

    <Properties>

        <Property Key="DaysToRetain" Value="365" />

 

        <!-- Choose one of the following and modify as necassary -->

        <Property Key="Schedule" Value="every 20 minutes"/>

        <Property Key="Schedule" Value="hourly between 8 and 18"/>

        <Property Key="Schedule" Value="daily at 09:00:00"/>

        <Property Key="Schedule" Value="weekly at mon 09:00:00"/>

        <Property Key="Schedule" Value="monthly at 1 09:00:00"/>

        <Property Key="Schedule" Value="yearly at jan 1 09:00:00"/>

    </Properties>

</Feature>

No comments: