6

I would like to capture more log info from Sitecore Logging. Changes such as what exactly was edited, what text changes were added or removed. Which images were added and so on.

Has anyone done anything like this already? I found an article http://info.exsquared.com/ex-squared-blog/logging-changes-in-sitecore-made-by-content-authors but it is not working properly. The AssemblyInfo.cs file is the problem I think.

any help would be much appreciated.

6

With this solution, it will create a new log file call audit.{date}.log and log any change the users make to the content. To achieve this, the pipeline subscribes the audit class to the item:creating, saving, deleting, copying, moving, renamed, sortorderchanged, templatechanged and itemProcessed events. Each time one of these events is triggered, a new log will be logged to the audit log describing the change. It details what field has changed, by who, and when.

The logs look like this

24320 00:40:07 INFO  (sitecore\admin): DELETE: master:/sitecore/content/Sites/Bonfire/Settings/Authors/test, language: en, version: 1, id: {25FBDA3C-1B2A-46C2-A1C6-0DE06F44CFE4}
2316 00:41:26 INFO  (sitecore\admin): SAVE: master:/sitecore/content/Sites/Bonfire/Settings/Authors/Chris Auer, language: en, version: 1, id: {F808FA41-3483-4334-8DF1-CB1AD1079F56}
2316 00:41:26 INFO  (sitecore\admin): ** [Author Image]
2316 00:41:26 INFO  (sitecore\admin):    -> New: <image mediaid="{C6888F94-FB48-493B-9399-83871CAF5446}" />
2316 00:41:26 INFO  (sitecore\admin):    -> Old: <image mediaid="{C1838093-8EFD-4204-A665-7A700EBBBA62}" /> 

This code was taken from the blog post http://info.exsquared.com/ex-squared-blog/logging-changes-in-sitecore-made-by-content-authors#audit_code. I changed it a little bit because I wanted to use config files for consistency and not the AssemblyInfo class.

The code

using System;
using System.Collections.Generic;
using System.Linq;
using Sitecore.Diagnostics;
using Sitecore.Data.Items;
using Sitecore.Events;
using Sitecore.Data.Events;
using Sitecore.Pipelines;
using Sitecore.SecurityModel;

namespace Custom.Diagnostics
{
    public class Audit : Sitecore.Mvc.Pipelines.Loader.InitializeRoutes
    {

        #region Configuration Entries
        // The master switch for allowing auditing; To disable Sitecore item auditing add the following to <settings> section within a patch config: <setting name="Audit.Enabled" value="false"/>
        private static readonly bool _auditingEnabled = Sitecore.Configuration.Settings.GetBoolSetting("Audit.Enabled", true);

        // Boolean indication if this is a content authoring server (CAS) - which uses the master database.  Content delivery servers use the web database...
        private static readonly bool _isCAS = Sitecore.Sites.SiteManager.GetSite("website").Properties["database"].ToLower() == "master";

        // To prevent duplicate item names via the shell editor (UI) add the following to <settings> section within a patch config: <setting name="PreventDuplicateItemNames" value="true"/>
        // Both auditing, and auditing created items must be enabled...
        private static readonly bool _preventDuplicateNames = Sitecore.Configuration.Settings.GetBoolSetting("PreventDuplicateItemNames", false);

        // To disable auditing item creations, add the following to <settings> section within a patch config: <setting name="Audit.ItemCreating" value="false"/>
        private static readonly bool _auditItemCreating = Sitecore.Configuration.Settings.GetBoolSetting("Audit.ItemCreating", true);

        // To disable auditing changes to items, add the following to <settings> section within a patch config: <setting name="Audit.ItemSaving" value="false"/>
        private static readonly bool _auditItemSaving = Sitecore.Configuration.Settings.GetBoolSetting("Audit.ItemSaving", true);

        // To disable auditing item deletions, add the following to <settings> section within a patch config: <setting name="Audit.ItemDeleting" value="false"/>
        private static readonly bool _auditItemDeleting = Sitecore.Configuration.Settings.GetBoolSetting("Audit.ItemDeleting", true);

        // To disable auditing copying items, add the following to <settings> section within a patch config: <setting name="Audit.ItemCopying" value="false"/>
        private static readonly bool _auditItemCopying = Sitecore.Configuration.Settings.GetBoolSetting("Audit.ItemCopying", true);

        // To disable auditing item moves, add the following to <settings> section within a patch config: <setting name="Audit.ItemMoving" value="false"/>
        private static readonly bool _auditItemMoving = Sitecore.Configuration.Settings.GetBoolSetting("Audit.ItemMoving", true);

        // To disable auditing renaming of items, add the following to <settings> section within a patch config: <setting name="Audit.ItemRenamed" value="false"/>
        private static readonly bool _auditItemRenamed = Sitecore.Configuration.Settings.GetBoolSetting("Audit.ItemRenamed", true);

        // To enable auditing item sort order changes, add the following to <settings> section within a patch config: <setting name="Audit.ItemSortOrderChanged" value="true"/>
        private static readonly bool _auditItemSortOrderChanged = Sitecore.Configuration.Settings.GetBoolSetting("Audit.ItemSortOrderChanged", false);

        // To disable auditing item template changes, add the following to <settings> section within a patch config: <setting name="Audit.ItemTemplateChanged" value="false"/>
        private static readonly bool _auditItemTemplateChanged = Sitecore.Configuration.Settings.GetBoolSetting("Audit.ItemTemplateChanged", true);

        // To enable auditing item publish processed events, add the following to <settings> section within a patch config: <setting name="Audit.ItemPublished" value="true"/>
        private static readonly bool _auditItemPublished = Sitecore.Configuration.Settings.GetBoolSetting("Audit.ItemPublished", false);

        #endregion


        private static log4net.ILog _log = Sitecore.Diagnostics.LoggerFactory.GetLogger("Sitecore.Diagnostics.Auditing");

        public override void Process(PipelineArgs args)
        {
            OnStart();
        }

        public void Log(string message)
        {
            if (_log == null)
                Sitecore.Diagnostics.Log.Audit(message, this);
            else
            {
                string user = (Sitecore.Context.User == null) ? "extranet\\Anonymous" : Sitecore.Context.User.Name;
                _log.Info(string.Format("({0}): {1}", user, message));
            }
        }


        public static void OnStart()
        {
               //if (_isCAS && _auditingEnabled)
               //{
                var handler = new Audit();
                if (_auditItemCreating) Sitecore.Events.Event.Subscribe("item:creating", new EventHandler(handler.OnItemCreating));
                if (_auditItemSaving) Sitecore.Events.Event.Subscribe("item:saving", new EventHandler(handler.OnItemSaving));
                if (_auditItemDeleting) Sitecore.Events.Event.Subscribe("item:deleting", new EventHandler(handler.OnItemDeleting));

                if (_auditItemCopying) Sitecore.Events.Event.Subscribe("item:copying", new EventHandler(handler.OnItemCopying));
                if (_auditItemMoving) Sitecore.Events.Event.Subscribe("item:moving", new EventHandler(handler.OnItemMoving));
                if (_auditItemRenamed) Sitecore.Events.Event.Subscribe("item:renamed", new EventHandler(handler.OnItemRenamed));
                if (_auditItemSortOrderChanged) Sitecore.Events.Event.Subscribe("item:sortorderchanged", new EventHandler(handler.OnItemSortOrderChanged));
                if (_auditItemTemplateChanged) Sitecore.Events.Event.Subscribe("item:templateChanged", new EventHandler(handler.OnItemTemplateChanged));

                if (_auditItemPublished) Sitecore.Events.Event.Subscribe("publish:itemProcessed", new EventHandler(handler.OnItemPublished));

               //}

        }

        protected void OnItemPublished(object sender, EventArgs args)
        {
            Assert.IsTrue(args != null, "args != null");
            if (args != null && args is Sitecore.Publishing.Pipelines.PublishItem.ItemProcessedEventArgs && _auditItemPublished)
            {
                using (new SecurityDisabler())
                {
                    Sitecore.Publishing.Pipelines.PublishItem.PublishItemContext context = (args as Sitecore.Publishing.Pipelines.PublishItem.ItemProcessedEventArgs).Context;

                    if (context.Result.Operation == Sitecore.Publishing.PublishOperation.Skipped)
                    {
                        try
                        {
                            // If we skipped publishing this item, we only care about logging why if we deliberately tried to republish this item...
                            if (!context.PublishOptions.CompareRevisions && context.PublishOptions.RootItem.ID == context.ItemId)
                            {
                                if (context.PublishHelper.SourceItemExists(context.ItemId))
                                {
                                    Item sourceItem = context.PublishHelper.GetSourceItem(context.ItemId);
                                    Log(string.Format("PUBLISH [{0}]: {1}", context.Result.Operation, AuditFormatter.FormatItem(sourceItem)));
                                }
                                else
                                {
                                    Log(string.Format("PUBLISH [{0}]: {1}", context.Result.Operation, context.ItemId.ToString()));
                                }
                                Log(string.Format("** {0}", context.Result.Explanation));
                            }
                        }
                        catch (Exception)
                        {
                            // We don't need to log - we were skipping this item from getting published anyway
                        }
                    }
                    else
                    {
                        if (context.PublishHelper.SourceItemExists(context.ItemId))
                        {
                            Item sourceItem = context.PublishHelper.GetSourceItem(context.ItemId);
                            Log(string.Format("PUBLISH [{0}]: {1}", context.Result.Operation, AuditFormatter.FormatItem(sourceItem)));
                        }
                        else
                        {
                            Log(string.Format("PUBLISH [{0}]: {1}, msg: {2}", context.Result.Operation, context.ItemId.ToString(), context.Result.Explanation));
                        }
                    }

                }
            }
        }

        /// <summary>
        /// Responds to Sitecore new item creation, cloning an item, and duplicating an item (either via the UI or API)
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="args">Param index 0 contains the ItemCreatingEventArgs: Contains item ID, name, master and template IDs, parent item</param>
        protected void OnItemCreating(object sender, EventArgs args)
        {
            Assert.IsTrue(args != null, "args != null");
            if (args != null && _auditItemCreating)
            {
                using (new SecurityDisabler())
                {
                    ItemCreatingEventArgs arg = Event.ExtractParameter(args, 0) as ItemCreatingEventArgs;
                    Assert.IsTrue(arg != null, "arg != null");

                    if ((arg != null) && (Sitecore.Context.Site.Name == "shell") && (_preventDuplicateNames))
                    {
                        foreach (Item currentItem in arg.Parent.GetChildren())
                        {
                            if ((arg.ItemName.Replace(' ', '-').ToLower() == currentItem.Name.ToLower()) && (arg.ItemId != currentItem.ID))
                            {
                                arg.Cancel = true;
                                Sitecore.Context.ClientPage.ClientResponse.Alert("Name \"" + currentItem.Name + "\" is already in use. Please use another name for the item.");
                                return;
                            }
                        }
                    }

                    if (arg != null && ShouldAudit(arg.Parent))
                    {
                        Item t = arg.Parent.Database.Items[arg.TemplateId];
                        string templateName = t != null ? t.Name : arg.TemplateId.ToString();

                        Log(string.Format("CREATE: {0}:{1}/{2}, id: {3}, template: {4}", arg.Parent.Database.Name, arg.Parent.Paths.Path, arg.ItemName, arg.ItemId.ToString(), templateName));
                    }
                }
            }
        }

        /// <summary>
        /// Responds to Sitecore item deletions
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="args">Param index 0 contains the Item being deleted</param>
        protected void OnItemDeleting(object sender, EventArgs args)
        {
            Assert.IsTrue(args != null, "args != null");
            if (args != null && _auditItemDeleting)
            {
                using (new SecurityDisabler())
                {
                    Item item = Event.ExtractParameter(args, 0) as Item;
                    Assert.IsTrue(item != null, "item != null");

                    if (item != null && ShouldAudit(item))
                    {
                        Log(string.Format("DELETE: {0}", AuditFormatter.FormatItem(item)));
                    }
                }
            }
        }

        /// <summary>
        /// Responds to Sitecore item updates
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="args">Param index 0 contains the Item being saved</param>
        protected void OnItemSaving(object sender, EventArgs args)
        {
            Assert.IsTrue(args != null, "args != null");
            if (args != null && _auditItemSaving)
            {
                using (new SecurityDisabler())
                {
                    Item item = Event.ExtractParameter(args, 0) as Item;
                    Assert.IsTrue(item != null, "item != null");

                    if (item != null && ShouldAudit(item))
                    {
                        Item originalItem = item.Database.GetItem(item.ID, item.Language, item.Version);

                        var differences = FindDifferences(item, originalItem);

                        if (differences.Any())
                        {
                            TimeSpan createdTS = item.Statistics.Updated - item.Statistics.Created;
                            TimeSpan sinceLastSave = item.Statistics.Updated - originalItem.Statistics.Updated;

                            if (createdTS.TotalSeconds > 2 && sinceLastSave.TotalSeconds > 2)
                                Log(string.Format("SAVE: {0}", AuditFormatter.FormatItem(item)));

                            foreach (string f in differences)
                            {
                                if (string.IsNullOrWhiteSpace(originalItem[f]))
                                    Log(string.Format("** [{0}]: {1}", item.Fields[f].DisplayName, item[f]));
                                else if (originalItem[f].Length <= 40 && item[f].Length <= 40)
                                    Log(string.Format("** [{0}]: {1}, old: {2}", item.Fields[f].DisplayName, item[f], originalItem[f]));
                                else
                                {
                                    Log(string.Format("** [{0}]", item.Fields[f].DisplayName));
                                    Log(string.Format("   -> New: {0}", item[f]));
                                    Log(string.Format("   -> Old: {0}", originalItem[f]));
                                }
                            }
                        }
                    }
                }
            }
        }

        /// <summary>
        /// Find non-system fields that have changed
        /// </summary>
        /// <param name="newItem"></param>
        /// <param name="originalItem"></param>
        /// <returns></returns>
        private static List<string> FindDifferences(Item newItem, Item originalItem)
        {
            newItem.Fields.ReadAll();

            IEnumerable<string> fieldNames = newItem.Fields.Select(f => f.Name).Where(name => !name.StartsWith("__"));

            return fieldNames
              .Where(fieldName => newItem[fieldName] != originalItem[fieldName] && originalItem.Fields[fieldName] != null && newItem.Fields[fieldName].ID == originalItem.Fields[fieldName].ID)
              .ToList();
        }

        /// <summary>
        /// Retrieve the current workflow state for the Sitecore item
        /// </summary>
        /// <param name="item"></param>
        /// <returns></returns>
        private static string GetWorkflowState(Item item)
        {
            Sitecore.Workflows.WorkflowInfo info = item.Database.DataManager.GetWorkflowInfo(item);
            return (info != null) ? info.StateID : String.Empty;
        }

        private static bool ShouldAudit(Item item)
        {
            return item.Database.Name.ToLower() == "master";
        }

        /// <summary>
        /// Responds to Sitecore item copying
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="args">
        /// Param index 0 contains the Item being copied,
        /// Param index 1 contains the Item Copy destination,
        /// Param index 2 contains the Result item name,
        /// Param index 3 contains the Result item ID,
        /// Param index 4 contains the boolean indication whether it is a recursive copy (including children) or not
        /// </param>
        protected void OnItemCopying(object sender, EventArgs args)
        {
            Assert.IsTrue(args != null, "args != null");
            if (args != null && _auditItemCopying)
            {
                using (new SecurityDisabler())
                {
                    Item item = Event.ExtractParameter(args, 0) as Item;
                    Assert.IsTrue(item != null, "item != null");

                    if (item != null && ShouldAudit(item))
                    {
                        Item destination = Event.ExtractParameter(args, 1) as Item;
                        string itemName = Event.ExtractParameter(args, 2) as string;
                        Sitecore.Data.ID itemID = Event.ExtractParameter(args, 3) as Sitecore.Data.ID;
                        bool recursive = (bool)Event.ExtractParameter(args, 4);

                        if (item.Parent.Paths.Path == destination.Paths.Path && item.Name != itemName)
                            Log(string.Format("DUPLICATE: {0}:{1}, destination: {2}/{3}, id: {4}{5}", item.Database.Name, item.Paths.Path, destination.Paths.Path, itemName, itemID.ToString(), item.Children.Count == 0 ? string.Empty : string.Format(" recursive: {0}", recursive.ToString())));
                        else
                            Log(string.Format("COPY: {0}:{1}, destination: {2}/{3}, id: {4}{5}", item.Database.Name, item.Paths.Path, destination.Paths.Path, itemName, itemID.ToString(), item.Children.Count == 0 ? string.Empty : string.Format(" recursive: {0}", recursive.ToString())));
                    }
                }
            }
        }

        /// <summary>
        /// Responds to Sitecore item moving
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="args">
        /// Param index 0 contains the Item being moved,
        /// Param index 1 contains the ID of the old parent,
        /// Param index 2 contains the ID of the new parent
        /// </param>
        protected void OnItemMoving(object sender, EventArgs args)
        {
            Assert.IsTrue(args != null, "args != null");
            if (args != null && _auditItemMoving)
            {
                using (new SecurityDisabler())
                {
                    Item item = Event.ExtractParameter(args, 0) as Item;
                    Assert.IsTrue(item != null, "item != null");

                    if (ShouldAudit(item))
                    {
                        Sitecore.Data.ID oldParentID = Event.ExtractParameter(args, 1) as Sitecore.Data.ID;
                        Sitecore.Data.ID newParentID = Event.ExtractParameter(args, 2) as Sitecore.Data.ID;
                        Item oldParent = item.Database.Items[oldParentID];
                        Item newParent = item.Database.Items[newParentID];

                        if (item != null && oldParent != null && newParent != null && oldParent.ID != newParent.ID)
                        {
                            Log(string.Format("MOVE: [{0}] from: {1}:{2} to: {3}:{4}", item.Name, oldParent.Database.Name, oldParent.Paths.Path, newParent.Database.Name, newParent.Paths.Path));
                        }
                    }
                }
            }
        }

        /// <summary>
        /// Responds to Sitecore item rename
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="args">
        /// Param index 0 contains the result Item,
        /// Param index 1 contains the Item name prior to being renamed
        /// </param>
        protected void OnItemRenamed(object sender, EventArgs args)
        {
            Assert.IsTrue(args != null, "args != null");
            if (args != null && _auditItemRenamed)
            {
                using (new SecurityDisabler())
                {
                    Item item = Event.ExtractParameter(args, 0) as Item;
                    string itemNameBeforeRename = Event.ExtractParameter(args, 1) as string;

                    Assert.IsTrue(item != null, "item != null");

                    if (item != null && itemNameBeforeRename != item.Name && ShouldAudit(item))
                    {
                        Log(string.Format("RENAME: {0}:{1}/{2}, as: {3}", item.Database.Name, item.Parent.Paths.Path, itemNameBeforeRename, item.Name));
                    }
                }
            }
        }

        /// <summary>
        /// Responds to Sitecore item sort order changed
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="args">
        /// Param index 0 contains the sorted Item,
        /// Param index 1 contains the Old sortorder value (string)
        /// </param>
        protected void OnItemSortOrderChanged(object sender, EventArgs args)
        {
            Assert.IsTrue(args != null, "args != null");
            if (args != null && _auditItemSortOrderChanged)
            {
                using (new SecurityDisabler())
                {
                    Item item = Event.ExtractParameter(args, 0) as Item;
                    string oldSortOrder = Event.ExtractParameter(args, 1) as string;

                    Assert.IsTrue(item != null, "item != null");

                    if (item != null && ShouldAudit(item))
                    {
                        Log(string.Format("SORT: {0}:{1}, new: {2}, old: {3}", item.Database.Name, item.Paths.Path, item.Appearance.Sortorder, oldSortOrder));
                    }
                }
            }
        }

        /// <summary>
        /// Responds to Sitecore item template changed
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="args">
        /// Param index 0 contains the ID of the item being changed,
        /// Param index 1 contains the Instance of the datamanager class handling the template
        /// </param>
        protected void OnItemTemplateChanged(object sender, EventArgs args)
        {
            Assert.IsTrue(args != null, "args != null");
            if (args != null && _auditItemDeleting)
            {
                using (new SecurityDisabler())
                {
                    Item item = Event.ExtractParameter(args, 0) as Item;
                    Sitecore.Data.Templates.TemplateChangeList change = Event.ExtractParameter(args, 1) as Sitecore.Data.Templates.TemplateChangeList;

                    Assert.IsTrue(item != null, "item != null");

                    if (item != null && ShouldAudit(item) && change.Target.ID != change.Source.ID)
                    {
                        Log(string.Format("TEMPLATE CHANGE: {0}:{1}, target: {2}, source: {3}", item.Database.Name, item.Paths.Path, change.Target.Name, change.Source.Name));
                        foreach (Sitecore.Data.Templates.TemplateChangeList.TemplateChange c in change.Changes)
                        {
                            if (c.Action == Sitecore.Data.Templates.TemplateChangeAction.DeleteField)
                                Log(string.Format("** {0}: {1}", c.Action, c.SourceField.Name));
                        }
                    }
                }
            }
        }
    }
}

The config

  <sitecore>
    <pipelines>
      <initialize>
        <processor type="Custom.Diagnostics.Audit, Sitecore.Foundation.Logging" />
      </initialize>
    </pipelines>
  </sitecore>

Sitecore.config change

This change needs to be applied to the section of the sitecore.config file.

<appender name="AuditLogFileAppender" type="log4net.Appender.SitecoreLogFileAppender, Sitecore.Logging">
  <file value="$(dataFolder)/logs/audit.log.{date}.txt" />
  <appendToFile value="true" />
  <layout type="log4net.Layout.PatternLayout">
    <conversionPattern value="%4t %d{ABSOLUTE} %-5p %m%n" />
  </layout>
  <encoding value="utf-8" />
</appender>
<logger name="Sitecore.Diagnostics.Auditing" additivity="false">
  <level value="INFO" />
  <appender-ref ref="AuditLogFileAppender" />
</logger>
  • Thank you for you help. I have one more question the section that you have "The config" where should that code be placed at? – Tony Nov 30 '16 at 15:41
  • 1
    In a config file of your choosing. It must exist under /App_Config/Include/ folder to be picked up by Sitecore. I usually use /App_Config/Include/z_ClientName/ to keep everything together nicely. – Chris Auer Nov 30 '16 at 15:43
  • I am getting an error message after I add a processor. shrib.com/2UfuFWcvdMUED0F – Tony Nov 30 '16 at 17:01
  • 1
    Change Sitecore.Foundation.Logging to your assembly name for the project you put the Custom.Diagnostics.Audit code into. – Chris Auer Nov 30 '16 at 17:31
  • 1
    You don't need AssemblyInfo.cs, using the config fixed that. Using configs keeps Sitecore consistent. What is the name of you project project/custom/diagnostics/audit.cs lives in? If I have a web.app/library project called MyCompany.Logging and in that project is where the audit cs lives, the config would be. <processor type="Custom.Diagnostics.Audit, MyCompany.Logging" /> – Chris Auer Nov 30 '16 at 18:41
7

Sounds like you need Sitecore Sidekick Audit Logger - its a package you can install and provides much more detailed audit logging than the standard log files.

You can search the log:

Search the audit log

Search by item:

enter image description here

and in the results you can see the details of the changes:

Edit changes

Should give you most of what you need.

EDIT: Installation Instructions Added

The easiest way to install without the Sitecore package from the market place, would be to add the NuGet Package to your project. When you deploy your project all the Sidekick binaries and content would be deployed also.

Install-Package SitecoreSidekickCore

The first time that your application starts after Sidekick is installed, Sidekick will create all the Desktop icons it needs for you to run the application.

Doing it this way also means that you can customize the configuration. You may want to change some of the default options listed here:

<scsRegister>
    <processor type="ScsAuditLog.AuditLogHandler, ScsAuditLog">
        <!-- 0 for indefinately -1 for no backup-->
        <param name="keepBackups">5</param>
        <!-- 0 for indefinately-->
        <param name="keepRecords">3</param>
        <!-- leave blank for any role, seperate multiple roles by | character -->
        <param name="roles"></param>
        <!-- set to "true" to only allow admins-->
        <param name="isAdmin">true</param>
        <!-- leave blank for any users, seperate multiple users by | character -->
        <param name="users"></param>
        <events hint="raw:AddEventProcessor">
            <onSaved type="ScsAuditLog.Pipelines.OnSave, ScsAuditLog" color="blue" id="0" label="Item was saved" event="item:saved" />
            <onSaved type="ScsAuditLog.Pipelines.OnMoved, ScsAuditLog" color="brown" id="1" label="Item was moved" event="item:moved" />
            <onSaved type="ScsAuditLog.Pipelines.OnDeleted, ScsAuditLog" color="red" id="2" label="Item was deleted" event="item:deleting" />
            <onSaved type="ScsAuditLog.Pipelines.OnRename, ScsAuditLog" color="orange" id="3" label="Item was renamed" event="item:renamed" />
            <onSaved type="ScsAuditLog.Pipelines.OnCreated, ScsAuditLog" color="green" id="4" label="Item was created" event="item:created" />
            <onSaved type="ScsAuditLog.Pipelines.GeneralEvent, ScsAuditLog" color="#dd33ff" id="7" label="Item was unlocked" event="item:unlocked" />
            <onSaved type="ScsAuditLog.Pipelines.GeneralEvent, ScsAuditLog" color="#aaaaff" id="8" label="Item was locked" event="item:locked" />
        </events>
        <customEvents hint="raw:RegisterCustomEventType">
            <publish color="purple" id="5" label="Publish Initiated" />
            <!--<publish color="#eee" id="6" label="Item Published" />-->
        </customEvents>
    </processor>
</scsRegister>
  • Is there any step by step instructions for this? Because on the web site it does not explain how to integrate it and implement it. – Tony Nov 30 '16 at 20:24
  • There should be a package to install on the market place but it looks like its missing. I'll add some installation instructions. – Richard Seal Nov 30 '16 at 20:51
  • Can you post it here, once you add them. – Tony Nov 30 '16 at 21:45
  • I have added the instructions to my answer. The blog post is not mine. – Richard Seal Nov 30 '16 at 21:46
  • Followed your instructions, nothing changed on the Desktop, nothing was added. – Tony Nov 30 '16 at 22:09

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.