dynamics-crm-2011dynamics-crm

Strategy for logging in production for Dynamics CRM plugins


CRM 2011 on premise.

I have a plugin written in C#. It could throw exceptions or otherwise behave badly in production.

When this happens I want to capture information about the state and about recent code execution to help me analyse the problem.

Ideally I would like the following:

  1. If the code decides I should know about a problem then I want it to be able to tell me that there was a problem asap, without me looking to see if a problem has occurred.

  2. I want the information about the problem to be easily accessible to me. I don't want to have to RDP to another machine and search through files.

  3. I don't want logging to have much impact on performance.

I guess I'm looking for something like this:

I'm fairly new to CRM but I've developed systems like this before. Since CRM has been around for many years I'd expect this to be available for it.


Solution

  • To support your wish list, I'd create these Entities:

    PluginLog

    PluginException

    Now let's go through your wish list:

    Edit

    To help get you started, this is what I currently use to retrieve all the information from the plugin context, and convert it into text that gets inserted into an Exception:

        #region GetPluginInfo
    
        private Exception GetPluginExecutionInfoForLog(IServiceProvider serviceProvider, Exception ex)
        {
            if(ex.GetType() == typeof(InvalidPluginExecutionException)){ return ex; }
    
            try
            {
                var context = serviceProvider.GetContext();
    
                ex = new InvalidPluginExecutionException(
                    String.Format("Error During Plugin Execution: {0}**** Context Values ****{0}{1}", 
                        Environment.NewLine, GetPluginExecutionInfo(context)), ex);
            }
            catch (Exception childEx)
            {
                OnError(childEx);
            }
            return ex;
        }
    
        protected String GetPluginExecutionInfo(IPluginExecutionContext context)
        {
            var lines = new List<String>();
            var target = GetTarget<Entity>(context);
    
            lines.Add("MessageName: " + context.MessageName);
            lines.Add("PrimaryEntityName: " + context.PrimaryEntityName);
            lines.Add("PrimaryEntityId: " + context.PrimaryEntityId);
            lines.Add("BusinessUnitId: " + context.BusinessUnitId);
            lines.Add("CorrelationId: " + context.CorrelationId);
            lines.Add("Depth: " + context.Depth);
            lines.Add("Has Parent Context: " + (context.ParentContext != null));
            lines.Add("InitiatingUserId: " + context.InitiatingUserId);
            AddParameters(lines, context.InputParameters, "Input Parameters");
            lines.Add("IsInTransaction: " + context.IsInTransaction);
            lines.Add("IsolationMode: " + context.IsolationMode);
            lines.Add("Mode: " + context.Mode);
            lines.Add("OperationCreatedOn: " + context.OperationCreatedOn);
            lines.Add("OperationId: " + context.OperationId);
            lines.Add("Organization: " + context.OrganizationName + "(" + context.OrganizationId + ")");
            AddParameters(lines, context.OutputParameters, "Output Parameters");
            AddEntityReference(lines, context.OwningExtension, "OwningExtension");
            AddEntityImages(lines, context.PostEntityImages, "Post Entity Images");
            AddEntityImages(lines, context.PreEntityImages, "Pre Entity Images");
            lines.Add("SecondaryEntityName: " + context.SecondaryEntityName);
            AddParameters(lines, context.SharedVariables, "Shared Variables");
            lines.Add("Stage: " + context.Stage);
            lines.Add("UserId: " + context.UserId);
    
            if (target == null || target.Attributes.Count == 0)
            {
                lines.Add("Target: Empty ");
            }
            else
            {
                lines.Add("* Target " + target.ToEntityReference().GetNameId() + " *");
                foreach (var att in target.Attributes)
                {
                    lines.Add("    Entity[" + att.Key + "]: " + GetAttributeValue(att.Value));
                }
            }
    
            lines.Add("* App Config Values *");
            foreach (var key in ConfigurationManager.AppSettings.AllKeys)
            {
                lines.Add("    [" + key + "]: " + ConfigurationManager.AppSettings[key]);
            }
    
            return String.Join(Environment.NewLine, lines);
        }
    
        private static string GetAttributeValue(object value)
        {
            if(value == null){
                return "Null";
            }
            var type = value.GetType();
            if (type == typeof(OptionSetValue))
            {
                return ((OptionSetValue)value).Value.ToString();
            }
            else if (type == typeof(EntityReference))
            {
                return ((EntityReference)value).GetNameId();
            }
            else
            {
                return value.ToString();
            }
        }
    
        private static void AddEntityReference(List<string> nameValuePairs, EntityReference entity, string name)
        {
            if (entity != null)
            {
                nameValuePairs.Add(name + ": " + entity.GetNameId());
            }
        }
    
        private static void AddEntityImages(List<string> nameValuePairs, EntityImageCollection images, string name)
        {
            if (images != null && images.Count > 0)
            {
                nameValuePairs.Add("** " + name + " **");
                foreach (var image in images)
                {
                    if (image.Value == null || image.Value.Attributes.Count == 0)
                    {
                        nameValuePairs.Add("    Image[" + image.Key + "] " + image.Value.ToEntityReference().GetNameId() + ": Empty");
                    }
                    else
                    {
                        nameValuePairs.Add("*   Image[" + image.Key + "] " + image.Value.ToEntityReference().GetNameId() + "   *");
                        foreach (var att in image.Value.Attributes)
                        {
                            nameValuePairs.Add("        Entity[" + att.Key + "]: " + GetAttributeValue(att.Value));
                        }
                    }
                }
            }
            else
            {
                nameValuePairs.Add(name + ": Empty");
            }
        }
    
        private static void AddParameters(List<string> nameValuePairs, ParameterCollection parameters, string name)
        {
            if (parameters != null && parameters.Count > 0)
            {
                nameValuePairs.Add("* " + name + " *");
                foreach (var param in parameters)
                {
                    nameValuePairs.Add("    Param[" + param.Key + "]: " + param.Value);
                }
            }
            else
            {
                nameValuePairs.Add(name + ": Empty");
            }
        }
    
        #endregion // GetPluginInfo