Detailed Package Installer

Not too long ago I was deploying changes through the various environments that our client has. We did not have a tool like TDS or Razl to help with this, so we used Sitecore packages. Due to multiple languages and extensive changes to templates and content these packages were very large with thousands of items. Installing packages of this size can take a very long time, and the only way to know what is happening is to read the log files. I’ve seen solutions that use a separate PowerShell window to ‘tail’ the log file, but I wanted something that was integrated into the Installation Wizard dialog. At first I looked into modifying the installation Job to provide information about itself, but as I dug deeper it became apparent that this would require extensive customization to the Sitecore code. So, I began writing code to monitor the log file. In order to accomplish this, I need a few things:

  • INFO logging enabled
  • The current log path
  • Total items in the package

Sitecore uses log4net as its default logger. This will indicate whether INFO logging is enabled:

((Hierarchy) LogManager.GetLoggerRepository()).Root.IsEnabledFor(Level.INFO);

If INFO logging is not enabled, it is possible to programmatically change it:

var heirarchy = ((Hierarchy) LogManager.GetLoggerRepository());
InitialLoggingLevel = heirarchy.Root.Level.ToString();
heirarchy.Root.Level = Level.INFO;

And to set it back:

if (string.IsNullOrEmpty(InitialLoggingLevel))
{
    return;
}

var heirarchy = ((Hierarchy)LogManager.GetLoggerRepository());
var levelValue = heirarchy.LevelMap[InitialLoggingLevel];
heirarchy.Root.Level = levelValue;

Sitecore does a lot of logging, and the path can change. Fortunately it is possible to get the current log path:

var rootAppender = ((Hierarchy)LogManager.GetLoggerRepository())
                                            .Root.Appenders.OfType()
                                            .FirstOrDefault();

var path = rootAppender != null ? rootAppender.File : string.Empty;

Sitecore packages follow a specific pattern, so it is possible to open them to read their contents and determine the number of items in the package:

int itemCount;
var filename = Installer.GetFilename(PackageFile.Value);

using (var archive = ZipFile.OpenRead(filename))
{
    var packageEntry = archive.Entries.FirstOrDefault(e => e.FullName == InnerPackageFileName);
    if (packageEntry == null)
    {
        return;
    }

    using (var packageStream = packageEntry.Open())
    {
        using (var package = new ZipArchive(packageStream, ZipArchiveMode.Read))
        {
            itemCount = package.Entries.Count(e => e.FullName.StartsWith(PackageEntryItemPrefix));
        }
    }
}

Now that we’re set up, we can monitor the log and use the wealth of information it provides to present the status of the job to the client. Logging follows a pattern, so I created some constants that are used to filter the log entries and determine how they should be interpreted.

A client-side timer allows us to post requests back to the server so we can monitor the log at a specific interval. The current log path and cursor position are saved in the view to allow us to read the log delta each time the timer fires and update the status information.

Each log delta is split into a list of lines, which can then be interrogated to determine what they tell us. We basically care about three things:

  • What is the installer currently doing
  • How many items out of the total have been installed
  • Have any warning or errors occurred during the process.

A log line will be one of a handful of things:

  • Starting / Ending a section of work
  • Installing Item
  • Warning or Error

The Installer will do its work in three groups: Install Items, Install Security, Update Index. The view has three boxes that are used to indicate when one of the jobs is working: when a ‘Starting’ line is read, its corresponding box is turned to green. When an ‘Ending’ line is read, its corresponding box is turned gray.

Item installation progress is indicated by a visual progress bar and a text message. Each ‘Installing Item’ line will increment a counter, which is then used along with the total count (from reading the package) to indicate the progress.

A text box contains the log entries that have happened since the install started. Only INFO logs pertaining to the install will be shown, but all WARN and ERROR logs are shown because they might have an impact on the installation process. The lines will also be color coded: INFO = green; WARN = yellow; ERROR = red.

The full module can be found here: https://marketplace.sitecore.net/en/Modules/Detailed_Package_Installer.aspx

I hope the information in this article helps you, and I appreciate your taking the time to read it.

2 thoughts on “Detailed Package Installer

Add yours

  1. A bug exists in the initial release of this component: If the user chooses merge options for individual items, the SheerResponse.Timer will lose it’s context and the log monitor will stop running.
    A new version (1.1) has been uploaded to the marketplace that resolves this issue by moving all of the timing to the client via javascript.

    I added the following to the hi.InstallPackage namespace in InstallPackage.js:
    ip.SetTimer = function () {
    window.setTimeout(ip.CheckStatus, 500);
    };

    ip.CheckStatus = function () {
    if (scForm === undefined) {
    return;
    }
    var monitor = document.getElementById(‘MonitorLogEdit’);
    if (monitor.value === ‘true’) {
    scForm.invoke(“installer:CheckLogProgress”);
    ip.SetTimer();
    }
    };

    This allows all of the timing to occur on the client. If the merge-option modal stays open, this timer will continue to fire.

    I added [HandleMessage(“installer:CheckLogProgress”)] to the CheckLogProgress function, so I can post to it from the client.

    When the process starts, I call:
    Context.ClientPage.ClientResponse.Eval(“window.HI.InstallPackage.CheckStatus()”);
    To initialize the timer.

    Thanks for the feedback.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Blog at WordPress.com.

Up ↑

%d bloggers like this: