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>