Sitecore Analytics Tracker Common Issues and How to Resolve Them

Blog Series: Unlocking xDB – Vol: #5  
Referenced Sitecore Version: Sitecore 8.0 – 8.2

In this Weekend Edition of Unlocking xDB, I’m hoping to provide relief to those suffering from common issues regarding Sitecore’s Analytic’s Tracker.  The Tracker is a special context object that Sitecore uses to gather information about the Contact and the Interaction occurring during a web visit.  This Tracker also comes with a few special considerations that are often missed in the first pass of a Sitecore environment’s configuration.

Here are some examples of common issues and logging errors that result from improper configuration of a Sitecore Environment.

ERROR Cannot create tracker.
    Exception: System.InvalidOperationException
    Message: session is not initialized
    Source: Sitecore.Analytics
       at Sitecore.Analytics.Data.HttpSessionContextManager.GetSession()
       at Sitecore.Analytics.Pipelines.EnsureSessionContext.EnsureContext.Process(InitializeTrackerArgs args)
       at (Object , Object[] )
       at Sitecore.Pipelines.CorePipeline.Run(PipelineArgs args)
       at Sitecore.Analytics.Pipelines.EnsureSessionContext.EnsureSessionContextPipeline.Run(InitializeTrackerArgs args)
       at Sitecore.Analytics.DefaultTracker.EnsureSessionContext()
       at Sitecore.Analytics.Pipelines.CreateTracker.GetTracker.Process(CreateTrackerArgs args)
       at (Object , Object[] )
       at Sitecore.Pipelines.CorePipeline.Run(PipelineArgs args)
       at Sitecore.Analytics.Tracker.Initialize()
3608 07:08:13 ERROR Media request analytics failed
Exception: System.InvalidOperationException
Message: Tracker.Current is not initialized
Source: Sitecore.Analytics
   at Sitecore.Analytics.Pipelines.StartAnalytics.StartTracking.Process(PipelineArgs args)
   at (Object , Object[] )
   at Sitecore.Pipelines.CorePipeline.Run(PipelineArgs args)
   at Sitecore.Analytics.Pipelines.StartAnalytics.StartAnalyticsPipeline.Run()
   at Sitecore.Analytics.Media.MediaRequestEventHandler.StartTracking()
   at Sitecore.Analytics.Media.MediaRequestEventHandler.OnMediaRequest(Object sender, EventArgs args)
Exception: System.InvalidOperationException
Message: Tracker.Current is not initialized
Source: Sitecore.Analytics
at Sitecore.Analytics.Pipelines.StartAnalytics.StartTracking.Process(PipelineArgs args)
at (Object , Object[] )
at Sitecore.Pipelines.CorePipeline.Run(PipelineArgs args)
at Sitecore.Analytics.Pipelines.HttpRequest.StartAnalytics.Process(RenderLayoutArgs args)

As you can see, there are a fair number of similar looking error messages that Sitecore will complain about regarding the Analytic’s Tracker.

Common Reasons and Way to Fix

In almost every scenario that I have faced myself, as well as helping others, I have come to the utmost conclusion, that every single time this issue comes up is because of the following reasons:

Reason 1: Analytics.ClusterName is configured incorrectly.

The Analytics.ClusterName which is set in the Sitecore.Analytics.Tracking.config needs to be a legitimate, resolvable hostname. The default “default-cd-cluster” is not enough to promote a working solution. This value has to be a DNS name that all Sitecore Servers can reach (e.g. cd.cluster.domain.com for example).

  • Ensure that each server, at a minimum has the configured Analytics.ClusterName in the windows host file and configured to point to an IP address of a Content Delivery server.
    • If on a content delivery server, set this host file IP equal to localhost, which is 127.0.0.1.
    • If on a content management or other server, set the host file IP equal to the IP of ONE of your CD servers. Do not set it to the load balancer IP (unless that can be reached by your network).

Reason 2: Analytics.Hostname is Incorrect

It has been my experience that sets a value for Analytics.Hostname, located in the Sitecore.Analytics.Tracking.config file does more harm than good. I have found leaving this value BLANK, makes everything work as it should.

Reason 3: Sitecore.Context.Page is not available.

Sitecore’s Analytic Tracker requires that the Sitecore.Context.Page object be available in order for Tracker to be initialized. In certain cases where this object is not available, and Tracker tries to be started, it will throw this error.

Tracker cannot be utilized on ASHX’s, internal pipelines or thread processes where Page is not set.

Reason 4: HttpContext.Current.Session is not available

Tracker has to be able to obtain a session in order to successfully process the interaction. In cases where the session is occuring on a server that is NOT a Content Delivery server, Sitecore will Transfer the session to a Content Delivery server via the Analytics.ClusterName setting.

Utilization of Tracker on Content Management Servers.

Pure (role configured) Content Management servers do not utilize session state management, and therefore can not run Tracker natively. Instead, they rely on the Analytics.ClusterName to resolve in order to communicate a session back to the Content Delivery servers. In cases where on the Content Management server, you receive these types of errors, it is because of Analytics.ClusterName is not correctly setup and reachable.

This also applies to Processing Servers, EXM Dispatch Servers, and Secondary Content Management Servers.

A Look Under the Covers

So what is actually happening when Tracker attempts to start? A look behind the scenes reveals the following process.  We’ll start with the creation of the DefaultTracker object which occurs at the time of an HTTP request.

Creating The Tracker

This class has a constructor method that does two things:

  1. Sets Sampling to a new  TrackerSampling().
  2. Ensure Session Context. – This is the single most common point of failure for Tracker Related issues.

Ensuring Session Context

Ensuring Session Context fires off the pipeline ensureSessionContext which validates whether or not an HTTP Session is available. One of the processors of this pipeline is called ClusterCheck which does a lookup of the Analytics.ClusterName variable (located and set in the Sitecore.Analytics.Tracking.config) and validates itself as an IP address and if it is reachable.

namespace Sitecore.Analytics.Pipelines.EnsureSessionContext
{
public class ClusterCheck : InitializeTrackerProcessor
{
private string hostRequested;

public override void Process(InitializeTrackerArgs args)
{
Assert.ArgumentNotNull((object) args, "args");
Assert.IsNotNull((object) args.Session, "args.Session");
Assert.IsNotNull((object) args.ContactId, "args.ContactId");
Assert.IsNotNull((object) args.Session.Device, "args.Session.Device");
Uri uri = Assert.ResultNotNull<Uri>(Assert.ResultNotNull<HttpContextBase>(args.HttpContext, "The HTTP Context for the InitializeTracker pipeline is not set.").Request.Url, "The request in the HTTP Context does not have the URL set.");
this.hostRequested = ClusterCheck.ExtractRequestedHost(args.HttpContext).ToLowerInvariant();
string targetHost = (string) null;
if (this.ThisRequestShouldNeverBeRedirected(uri))
return;
if (args.RedirectToCluster != (LeaseOwner) null && !this.hostRequested.Equals(args.RedirectToCluster.Identifier))
targetHost = args.RedirectToCluster.Identifier;
else if (args.Session.Settings.IsFirstRequest)
{
string lowerInvariant = AnalyticsSettings.HostName.ToLowerInvariant();
if (!string.IsNullOrEmpty(lowerInvariant) && !this.hostRequested.Equals(lowerInvariant))
targetHost = lowerInvariant;
}
if (string.IsNullOrEmpty(targetHost))
return;
TransferSessionPipeline.Run(new TransferSessionArgs(new Guid?(args.Session.Contact.ContactId), args.Session, targetHost, uri));
}

private bool ThisRequestShouldNeverBeRedirected(Uri uri)
{
bool flag = false;
if (!string.IsNullOrEmpty(this.hostRequested))
uri = ClusterCheck.ReplaceHost(uri, this.hostRequested);
return flag | (uri.IsLoopback | ClusterCheck.IsIpAdrress(uri));
}

private static string ExtractRequestedHost(HttpContextBase context)
{
Assert.IsNotNull((object) context.Request.Url, "The URL of the specified HTTP Context object is not set.");
Uri url = context.Request.Url;
string uri = context.Request.Headers["host"];
string host;
if (string.IsNullOrEmpty(uri))
{
host = url.Host;
}
else
{
string str = url.Scheme + "://";
if (!uri.StartsWith(str))
uri = str + uri;
host = new UriBuilder(uri).Host;
}
return host;
}

private static bool IsIpAdrress(Uri uri)
{
IPAddress address;
return IPAddress.TryParse(uri.Host, out address);
}

private static Uri ReplaceHost(Uri uri, string host)
{
return new UriBuilder(uri) { Host = host }.Uri;
}
}
}

As shown here, the TransferSession Pipeline is the process that occurs on a NON-Content Delivery Servers. This is why it’s important that Content Management Servers are able to resolve the Analytics.ClusterName.

If both of these checks pass and the session can be obtained, then the ability to at least attempt to START the tracker can succeed.

Starting The Tracker

Step 1: Is Tracker Already Active

During this check, Tracker Looks at Tracker.IsActive to determine is it was already activated. Upon a successful activation of Tracker, Sitecore populates Context.Items[“SC_TRACKER_ACTIVE”].

Step 2: Tracker Checks to the Sampling (as they call it) is possible.

In reality, this is really doing three sub-steps:

  1. Is HttpContext.Current null
  2. Is HttpContext.Current.Session null
  3. Is HttpContext.Current.Session[“SC_ANALYTICS_SAMPLING”] null

If anyone of these is null, Sitecore won’t start the Tracker.

Step 3: Check Site Configuration

If the Sitecore.Context.Site is null or Site.Tracking().EnabledTracking is false, Sitecore will throw a Debug Log of “Cannot start tracking, analytics is not enabled for site”

Step 4: Check Request Exclusion Lists

This step runs the ExcludeRobots pipeline, which checks to see if the UserAgent or IP address have been excluded from Analytics which is set in the Sitecore.Analytics.ExcludRobots.config.

In cases where this occurs, if Log level is set to Debug, Sitecore will log “The request was excluded because the Agent or IP is determined as a robot, see Exclude robots configuration file”

Step 5: Check to ensure that the Current Item’s Tracking Field hasn’t been set to Ignore

On any Sitecore item, the Tracking field allows a content author to setup rules about how Sitecore Analytics should treat the tracking of an item. One of these rules is the ability to ignore the item from Analytics.

Step 6: Start Tracking Analytics

This is really a save point step. If all previous 5 steps pass their respective tests, then Sitecore Analytics begins the process of starting the Analytics Tracker. This and of itself is a procedural workflow with multiple steps.

  1. Set IsActive equal to True
  2. Create StartTracking Pipeline Arguments. This requires that HttpContext.Current is available, which is passed into the StartTracking pipeline.
  3. Execute The StartTracking pipeline.
    1. This Pipeline serves two purposes:
      1. To Initialize the Tracker (See Step 7)
      2. Process GeoIP data and Analytics Query String Params

Step 7: Initialize the Tracker

This step is actually the second processor in the StartTracking pipeline called InitializeTracker. This processor requires the following Context objects to be active in order to even begin, thanks to Sitecore’s Assert.IsNotNull methods.

  1. Tracker.Current
  2. Tracker.Current.Session
  3. Tracker.Current.Session.Contact.

If any of these are null, This will error out with the elusive “Cannot start analytics Tracker”

If these are not null, then the StartTracking processor invokes the InitializeTracker pipeline, which brings us to Step 8.

Step 8: Run InitializeTracker pipeline

This part contains the majority of where most of our issues exist. This pipeline has the following steps/processors:

  1. IsMediaRequest
    1. This specifically calls the MediaManager.IsMediaUrl(args.HttpContext.Request.RawUrl) method.
  2. CreateVisit
    1. The very first part of this process checks to see if Session is null. If so, it errors out with “The session is not set” and aborts the pipeline, which also throws “Cannot start analytics Tracker”
    2. The second part of this processor
  3. CreatePage
    1. If HttpContext is null, it will abort the pipeline.
    2. Otherwise, it tries and attempts to create the Page Context. In doing so, Sitecore.Context.Page must be available. If it is not, then Tracker will error.
  4. EnsureNextPageData
    1. This processor is really a housekeeping processor that adds page events to the current Interaction, registers page data, triggers campaigns, and sets up the NextPage events. This processor sets Session.Interaction.CurrentPage.
    2. If Tracker.Current.Session.Interaction is null, processor aborts and throws “Cannot start analytics Tracker”
  5. Robots
    1. Classifies whether or not the incoming request is a Robot.
    2. There a lot of things that, if null, will blow up this processor, all of which have been mentioned previously except for Tracker.Current.Session.Interaction.CurrentPage.
  6. EnsureContactClassification
    1. Honestly, by this point, if Tracker hasn’t already bombed out, then it’s probably safe to say that Tracker is going to initialize just fine.
    2. This processor sets up the current Contact’s Classification and identification as a Robot or Human, among other things.
  7. RunRules
    1. Last but not least, this runs any rules on the Parent Item of the Current Item.

If this pipeline is allowed to succeed, then Tracker is officially started. Any error that causes this pipeline to blow up though, will induce the dreaded “Cannot start analytics Tracker“, which further down the chain will cause the “Tracker.Current is not initialized” error.

Summary

I hope that this blog post is helpful to you. I have used this advice while helping others on the Sitecore Community Slack server, as well as on the Sitecore Stack Exchange site.

If you are in need of additional help or want a second pair of eyes to look at your error, please do not hesitate to reach me.

 

Leave a Reply

Please log in using one of these methods to post your comment:

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