Esempio n. 1
0
        internal HealthCheckRuleResult createHealthCheckRuleResult(
            JobTarget jobTarget,
            string entityType,
            string entityName,
            long entityID,
            HealthCheckRuleDescription hcrd)
        {
            HealthCheckRuleResult healthCheckRuleResult = new HealthCheckRuleResult();

            healthCheckRuleResult.Controller    = jobTarget.Controller;
            healthCheckRuleResult.Application   = jobTarget.Application;
            healthCheckRuleResult.ApplicationID = jobTarget.ApplicationID;

            healthCheckRuleResult.EntityType = entityType;
            healthCheckRuleResult.EntityName = entityName;
            healthCheckRuleResult.EntityID   = entityID;

            healthCheckRuleResult.Category = hcrd.Category;
            healthCheckRuleResult.Code     = hcrd.Code;
            healthCheckRuleResult.Name     = hcrd.Name;

            healthCheckRuleResult.Grade = 0;

            healthCheckRuleResult.EvaluationTime = DateTime.Now;

            return(healthCheckRuleResult);
        }
        private HealthCheckRuleResult evaluate_Controller_Setting_Performance_Profile(
            HealthCheckRuleDescription hcrd,
            JobTarget jobTarget,
            Dictionary <string, HealthCheckSettingMapping> healthCheckSettingsDictionary,
            List <ControllerSetting> controllerSettingsList)
        {
            logger.Trace("Evaluating {0}", hcrd);

            HealthCheckRuleResult healthCheckRuleResult = createHealthCheckRuleResult(jobTarget, "Controller", jobTarget.Controller, 0, hcrd);

            healthCheckRuleResult.Application = "[ALL APPS]";

            if (controllerSettingsList != null)
            {
                ControllerSetting controllerSettingProfile = controllerSettingsList.Where(s => s.Name == "performance.profile").FirstOrDefault();
                if (controllerSettingProfile == null)
                {
                    healthCheckRuleResult.Grade       = 1;
                    healthCheckRuleResult.Description = "Controller performance profile is unknown";
                }
                else
                {
                    healthCheckRuleResult.Description = String.Format("Controller performance profile is '{0}'", controllerSettingProfile.Value);

                    // Defined in Enterprise Console via various
                    // C:\AppDynamics\Platform\platform-admin\archives\controller\4.5.4.15417\playbooks\controller-<size>.groovy
                    switch (controllerSettingProfile.Value.ToLower())
                    {
                    case "internal":
                    case "dev":
                    case "demo":
                        healthCheckRuleResult.Grade = 1;
                        break;

                    case "small":
                        healthCheckRuleResult.Grade = 2;
                        break;

                    case "medium":
                        healthCheckRuleResult.Grade = 3;
                        break;

                    case "large":
                        healthCheckRuleResult.Grade = 4;
                        break;

                    case "extra-large":
                        healthCheckRuleResult.Grade = 5;
                        break;

                    default:
                        healthCheckRuleResult.Grade = 1;
                        break;
                    }
                }
            }

            return(healthCheckRuleResult);
        }
        /// <summary>
        /// Version of Controller should be reasonably latest
        /// </summary>
        /// <param name="jobTarget"></param>
        /// <param name="healthCheckSettingsDictionary"></param>
        /// <param name="controllerSummariesList"></param>
        /// <returns></returns>
        private HealthCheckRuleResult evaluate_Controller_Version(
            HealthCheckRuleDescription hcrd,
            JobTarget jobTarget,
            Dictionary <string, HealthCheckSettingMapping> healthCheckSettingsDictionary,
            List <ControllerSummary> controllerSummariesList)
        {
            logger.Trace("Evaluating {0}", hcrd);

            HealthCheckRuleResult healthCheckRuleResult = createHealthCheckRuleResult(jobTarget, "Controller", jobTarget.Controller, 0, hcrd);

            healthCheckRuleResult.Application = "[ALL APPS]";

            if (controllerSummariesList != null && controllerSummariesList.Count > 0)
            {
                ControllerSummary controllerSummary     = controllerSummariesList[0];
                Version           versionThisController = new Version(jobTarget.ControllerVersion);

                healthCheckRuleResult.Description = String.Format("The Controller version '{0}'", jobTarget.ControllerVersion, getVersionSetting(healthCheckSettingsDictionary, "ControllerVersionGrade5", "4.5"));

                if (versionThisController >= getVersionSetting(healthCheckSettingsDictionary, "ControllerVersionGrade5", "4.5"))
                {
                    healthCheckRuleResult.Grade = 5;
                }
                else if (versionThisController >= getVersionSetting(healthCheckSettingsDictionary, "ControllerVersionGrade4", "4.4"))
                {
                    healthCheckRuleResult.Grade = 4;
                }
                else if (versionThisController >= getVersionSetting(healthCheckSettingsDictionary, "ControllerVersionGrade3", "4.3"))
                {
                    healthCheckRuleResult.Grade = 3;
                }
                else if (versionThisController >= getVersionSetting(healthCheckSettingsDictionary, "ControllerVersionGrade2", "4.2"))
                {
                    healthCheckRuleResult.Grade = 2;
                }
                else
                {
                    healthCheckRuleResult.Grade = 1;
                }
            }
            else
            {
                healthCheckRuleResult.Grade       = 1;
                healthCheckRuleResult.Description = "No information about Controller version available";
            }

            return(healthCheckRuleResult);
        }
        /// <summary>
        /// We like SaaS controllers more than on premises
        /// </summary>
        /// <param name="jobTarget"></param>
        /// <param name="healthCheckSettingsDictionary"></param>
        /// <returns></returns>
        private HealthCheckRuleResult evaluate_Controller_SaaS_OnPrem(
            HealthCheckRuleDescription hcrd,
            JobTarget jobTarget,
            Dictionary <string, HealthCheckSettingMapping> healthCheckSettingsDictionary)
        {
            logger.Trace("Evaluating {0}", hcrd);

            HealthCheckRuleResult healthCheckRuleResult = createHealthCheckRuleResult(jobTarget, "Controller", jobTarget.Controller, 0, hcrd);

            healthCheckRuleResult.Application = "[ALL APPS]";

            if (jobTarget.Controller.ToLower().Contains("saas.appdynamics") == true)
            {
                healthCheckRuleResult.Grade       = 5;
                healthCheckRuleResult.Description = "Controller is running in AppDynamics SaaS cloud";
            }
            else
            {
                healthCheckRuleResult.Grade       = 3;
                healthCheckRuleResult.Description = "Controller is running in OnPremises configuration";
            }
            return(healthCheckRuleResult);
        }
Esempio n. 5
0
        public override bool Execute(ProgramOptions programOptions, JobConfiguration jobConfiguration)
        {
            Stopwatch stopWatch = new Stopwatch();

            stopWatch.Start();

            StepTiming stepTimingFunction = new StepTiming();

            stepTimingFunction.JobFileName = programOptions.OutputJobFilePath;
            stepTimingFunction.StepName    = jobConfiguration.Status.ToString();
            stepTimingFunction.StepID      = (int)jobConfiguration.Status;
            stepTimingFunction.StartTime   = DateTime.Now;
            stepTimingFunction.NumEntities = jobConfiguration.Target.Count;

            this.DisplayJobStepStartingStatus(jobConfiguration);

            FilePathMap = new FilePathMap(programOptions, jobConfiguration);

            if (this.ShouldExecute(programOptions, jobConfiguration) == false)
            {
                return(true);
            }

            try
            {
                loggerConsole.Info("Prepare APM Health Check Report File");

                #region Prepare the report package

                // Prepare package
                ExcelPackage excelReport = new ExcelPackage();
                excelReport.Workbook.Properties.Author  = String.Format("AppDynamics DEXTER {0}", Assembly.GetEntryAssembly().GetName().Version);
                excelReport.Workbook.Properties.Title   = "AppDynamics DEXTER APM Health Check Report";
                excelReport.Workbook.Properties.Subject = programOptions.JobName;

                excelReport.Workbook.Properties.Comments = String.Format("Targets={0}\nFrom={1:o}\nTo={2:o}", jobConfiguration.Target.Count, jobConfiguration.Input.TimeRange.From, jobConfiguration.Input.TimeRange.To);

                #endregion

                #region Parameters sheet

                // Parameters sheet
                ExcelWorksheet sheet = excelReport.Workbook.Worksheets.Add(SHEET_PARAMETERS);

                var hyperLinkStyle = sheet.Workbook.Styles.CreateNamedStyle("HyperLinkStyle");
                hyperLinkStyle.Style.Font.UnderLineType = ExcelUnderLineType.Single;
                hyperLinkStyle.Style.Font.Color.SetColor(colorBlueForHyperlinks);

                var timelineStyle = sheet.Workbook.Styles.CreateNamedStyle("TimelineStyle");
                timelineStyle.Style.Font.Name = "Consolas";
                timelineStyle.Style.Font.Size = 8;

                fillReportParametersSheet(sheet, jobConfiguration, "AppDynamics DEXTER APM Health Check Report");

                #endregion

                #region TOC sheet

                // Navigation sheet with link to other sheets
                sheet = excelReport.Workbook.Worksheets.Add(SHEET_TOC);

                #endregion

                #region Entity sheets and their associated pivot

                // Entity sheets
                sheet = excelReport.Workbook.Worksheets.Add(SHEET_CONTROLLERS_LIST);
                sheet.Cells[1, 1].Value     = "Table of Contents";
                sheet.Cells[1, 2].Formula   = String.Format(@"=HYPERLINK(""#'{0}'!A1"", ""<Go>"")", SHEET_TOC);
                sheet.Cells[1, 2].StyleName = "HyperLinkStyle";
                sheet.View.FreezePanes(LIST_SHEET_START_TABLE_AT + 1, 1);

                sheet = excelReport.Workbook.Worksheets.Add(SHEET_APPLICATIONS_ALL_LIST);
                sheet.Cells[1, 1].Value     = "Table of Contents";
                sheet.Cells[1, 2].Formula   = String.Format(@"=HYPERLINK(""#'{0}'!A1"", ""<Go>"")", SHEET_TOC);
                sheet.Cells[1, 2].StyleName = "HyperLinkStyle";
                sheet.View.FreezePanes(LIST_SHEET_START_TABLE_AT + 1, 1);

                sheet = excelReport.Workbook.Worksheets.Add(SHEET_HEALTH_CHECK_RULE_RESULTS);
                sheet.Cells[1, 1].Value     = "Table of Contents";
                sheet.Cells[1, 2].Formula   = String.Format(@"=HYPERLINK(""#'{0}'!A1"", ""<Go>"")", SHEET_TOC);
                sheet.Cells[1, 2].StyleName = "HyperLinkStyle";
                sheet.Cells[2, 1].Value     = "See Rating";
                sheet.Cells[2, 2].Formula   = String.Format(@"=HYPERLINK(""#'{0}'!A1"", ""<Go>"")", SHEET_HEALTH_CHECK_RULE_RESULTS_DISPLAY);
                sheet.Cells[2, 2].StyleName = "HyperLinkStyle";
                sheet.Cells[3, 1].Value     = "See Summary";
                sheet.Cells[3, 2].Formula   = String.Format(@"=HYPERLINK(""#'{0}'!A1"", ""<Go>"")", SHEET_HEALTH_CHECK_RULE_RESULTS_DISPLAY);
                sheet.Cells[3, 2].StyleName = "HyperLinkStyle";
                sheet.View.FreezePanes(LIST_SHEET_START_TABLE_AT + 1, 1);

                sheet = excelReport.Workbook.Worksheets.Add(SHEET_HEALTH_CHECK_RULE_RESULTS_DESCRIPTION_PIVOT);
                sheet.Cells[1, 1].Value     = "Table of Contents";
                sheet.Cells[1, 2].Formula   = String.Format(@"=HYPERLINK(""#'{0}'!A1"", ""<Go>"")", SHEET_TOC);
                sheet.Cells[1, 2].StyleName = "HyperLinkStyle";
                sheet.Cells[2, 1].Value     = "See Table";
                sheet.Cells[2, 2].Formula   = String.Format(@"=HYPERLINK(""#'{0}'!A1"", ""<Go>"")", SHEET_HEALTH_CHECK_RULE_RESULTS);
                sheet.Cells[2, 2].StyleName = "HyperLinkStyle";
                sheet.View.FreezePanes(PIVOT_SHEET_START_PIVOT_AT - 4 + 2, 1);

                sheet = excelReport.Workbook.Worksheets.Add(SHEET_HEALTH_CHECK_RULE_RESULTS_DISPLAY);
                sheet.Cells[1, 1].Value     = "Table of Contents";
                sheet.Cells[1, 2].Formula   = String.Format(@"=HYPERLINK(""#'{0}'!A1"", ""<Go>"")", SHEET_TOC);
                sheet.Cells[1, 2].StyleName = "HyperLinkStyle";
                sheet.Cells[2, 1].Value     = "See Table";
                sheet.Cells[2, 2].Formula   = String.Format(@"=HYPERLINK(""#'{0}'!A1"", ""<Go>"")", SHEET_HEALTH_CHECK_RULE_RESULTS);
                sheet.Cells[2, 2].StyleName = "HyperLinkStyle";
                sheet.View.FreezePanes(LIST_SHEET_START_TABLE_AT + 1, 1);

                #endregion

                #region Report file variables

                ExcelRangeBase range = null;
                ExcelTable     table = null;

                #endregion

                loggerConsole.Info("Fill APM Health Check Report File");

                #region Controllers

                loggerConsole.Info("List of Controllers");

                sheet = excelReport.Workbook.Worksheets[SHEET_CONTROLLERS_LIST];
                EPPlusCSVHelper.ReadCSVFileIntoExcelRange(FilePathMap.ControllerSummaryReportFilePath(), 0, typeof(ControllerSummary), sheet, LIST_SHEET_START_TABLE_AT, 1);

                #endregion

                #region Applications

                loggerConsole.Info("List of Applications - All");

                sheet = excelReport.Workbook.Worksheets[SHEET_APPLICATIONS_ALL_LIST];
                EPPlusCSVHelper.ReadCSVFileIntoExcelRange(FilePathMap.ControllerApplicationsReportFilePath(), 0, typeof(ControllerApplication), sheet, LIST_SHEET_START_TABLE_AT, 1);

                #endregion

                #region Health Check Results

                loggerConsole.Info("List of Health Check Results");

                sheet = excelReport.Workbook.Worksheets[SHEET_HEALTH_CHECK_RULE_RESULTS];
                EPPlusCSVHelper.ReadCSVFileIntoExcelRange(FilePathMap.APMHealthCheckRuleResultsReportFilePath(), 0, typeof(HealthCheckRuleResult), sheet, LIST_SHEET_START_TABLE_AT, 1);
                if (sheet.Dimension.Rows > LIST_SHEET_START_TABLE_AT)
                {
                    EPPlusCSVHelper.ReadCSVFileIntoExcelRange(FilePathMap.ControllerHealthCheckRuleResultsReportFilePath(), 1, typeof(HealthCheckRuleResult), sheet, sheet.Dimension.Rows + 1, 1);
                }
                else
                {
                    EPPlusCSVHelper.ReadCSVFileIntoExcelRange(FilePathMap.ControllerHealthCheckRuleResultsReportFilePath(), 0, typeof(HealthCheckRuleResult), sheet, LIST_SHEET_START_TABLE_AT, 1);
                }

                #endregion

                loggerConsole.Info("Finalize APM Health Check Report File");

                #region Controllers sheet

                // Make table
                sheet = excelReport.Workbook.Worksheets[SHEET_CONTROLLERS_LIST];
                logger.Info("{0} Sheet ({1} rows)", sheet.Name, sheet.Dimension.Rows);
                loggerConsole.Info("{0} Sheet ({1} rows)", sheet.Name, sheet.Dimension.Rows);
                if (sheet.Dimension.Rows > LIST_SHEET_START_TABLE_AT)
                {
                    range            = sheet.Cells[LIST_SHEET_START_TABLE_AT, 1, sheet.Dimension.Rows, sheet.Dimension.Columns];
                    table            = sheet.Tables.Add(range, TABLE_CONTROLLERS);
                    table.ShowHeader = true;
                    table.TableStyle = TableStyles.Medium2;
                    table.ShowFilter = true;
                    table.ShowTotal  = false;

                    sheet.Column(table.Columns["Controller"].Position + 1).Width = 25;
                    sheet.Column(table.Columns["Version"].Position + 1).Width    = 15;
                }

                #endregion

                #region Applications

                // Make table
                sheet = excelReport.Workbook.Worksheets[SHEET_APPLICATIONS_ALL_LIST];
                logger.Info("{0} Sheet ({1} rows)", sheet.Name, sheet.Dimension.Rows);
                loggerConsole.Info("{0} Sheet ({1} rows)", sheet.Name, sheet.Dimension.Rows);
                if (sheet.Dimension.Rows > LIST_SHEET_START_TABLE_AT)
                {
                    range            = sheet.Cells[LIST_SHEET_START_TABLE_AT, 1, sheet.Dimension.Rows, sheet.Dimension.Columns];
                    table            = sheet.Tables.Add(range, TABLE_APPLICATIONS_ALL);
                    table.ShowHeader = true;
                    table.TableStyle = TableStyles.Medium2;
                    table.ShowFilter = true;
                    table.ShowTotal  = false;

                    sheet.Column(table.Columns["Controller"].Position + 1).Width      = 15;
                    sheet.Column(table.Columns["ApplicationName"].Position + 1).Width = 20;
                    sheet.Column(table.Columns["Description"].Position + 1).Width     = 15;

                    sheet.Column(table.Columns["CreatedBy"].Position + 1).Width = 15;
                    sheet.Column(table.Columns["UpdatedBy"].Position + 1).Width = 15;

                    sheet.Column(table.Columns["CreatedOn"].Position + 1).Width    = 20;
                    sheet.Column(table.Columns["UpdatedOn"].Position + 1).Width    = 20;
                    sheet.Column(table.Columns["CreatedOnUtc"].Position + 1).Width = 20;
                    sheet.Column(table.Columns["UpdatedOnUtc"].Position + 1).Width = 20;
                }

                #endregion

                #region Health Check Results

                // Make table
                sheet = excelReport.Workbook.Worksheets[SHEET_HEALTH_CHECK_RULE_RESULTS];
                logger.Info("{0} Sheet ({1} rows)", sheet.Name, sheet.Dimension.Rows);
                loggerConsole.Info("{0} Sheet ({1} rows)", sheet.Name, sheet.Dimension.Rows);
                if (sheet.Dimension.Rows > LIST_SHEET_START_TABLE_AT)
                {
                    range            = sheet.Cells[LIST_SHEET_START_TABLE_AT, 1, sheet.Dimension.Rows, sheet.Dimension.Columns];
                    table            = sheet.Tables.Add(range, TABLE_HEALTH_CHECK_RULE_RESULTS);
                    table.ShowHeader = true;
                    table.TableStyle = TableStyles.Medium2;
                    table.ShowFilter = true;
                    table.ShowTotal  = false;

                    sheet.Column(table.Columns["Controller"].Position + 1).Width  = 15;
                    sheet.Column(table.Columns["Application"].Position + 1).Width = 20;
                    sheet.Column(table.Columns["EntityName"].Position + 1).Width  = 20;
                    sheet.Column(table.Columns["Category"].Position + 1).Width    = 30;
                    sheet.Column(table.Columns["Code"].Position + 1).Width        = 15;
                    sheet.Column(table.Columns["Name"].Position + 1).Width        = 50;
                    sheet.Column(table.Columns["Description"].Position + 1).Width = 40;

                    ExcelAddress cfAddressGrade = new ExcelAddress(LIST_SHEET_START_TABLE_AT + 1, table.Columns["Grade"].Position + 1, sheet.Dimension.Rows, table.Columns["Grade"].Position + 1);
                    var          cfGrade        = sheet.ConditionalFormatting.AddThreeColorScale(cfAddressGrade);
                    cfGrade.LowValue.Type     = eExcelConditionalFormattingValueObjectType.Num;
                    cfGrade.LowValue.Color    = colorRedFor3ColorScales;
                    cfGrade.LowValue.Value    = 1;
                    cfGrade.MiddleValue.Type  = eExcelConditionalFormattingValueObjectType.Num;
                    cfGrade.MiddleValue.Value = 3;
                    cfGrade.MiddleValue.Color = colorYellowFor3ColorScales;
                    cfGrade.HighValue.Type    = eExcelConditionalFormattingValueObjectType.Num;
                    cfGrade.HighValue.Color   = colorGreenFor3ColorScales;
                    cfGrade.HighValue.Value   = 5;

                    sheet = excelReport.Workbook.Worksheets[SHEET_HEALTH_CHECK_RULE_RESULTS_DESCRIPTION_PIVOT];
                    ExcelPivotTable pivot = sheet.PivotTables.Add(sheet.Cells[PIVOT_SHEET_START_PIVOT_AT - 4, 1], range, PIVOT_HEALTH_CHECK_RULE_RESULTS_DESCRIPTION_TYPE);
                    setDefaultPivotTableSettings(pivot);
                    addRowFieldToPivot(pivot, "Controller");
                    addRowFieldToPivot(pivot, "Application");
                    addRowFieldToPivot(pivot, "Category");
                    addRowFieldToPivot(pivot, "EntityType");
                    addRowFieldToPivot(pivot, "Name");
                    addRowFieldToPivot(pivot, "Description");
                    addColumnFieldToPivot(pivot, "Grade", eSortType.Ascending);
                    addDataFieldToPivot(pivot, "Name", DataFieldFunctions.Count, "Rating");

                    sheet.Column(1).Width = 20;
                    sheet.Column(2).Width = 20;
                    sheet.Column(3).Width = 20;
                    sheet.Column(4).Width = 20;
                    sheet.Column(5).Width = 30;
                    sheet.Column(6).Width = 30;
                }

                #endregion

                #region Health Check Results Display

                sheet = excelReport.Workbook.Worksheets[SHEET_HEALTH_CHECK_RULE_RESULTS_DISPLAY];

                List <HealthCheckRuleResult> healthCheckRuleResults = new List <HealthCheckRuleResult>();

                List <HealthCheckRuleResult> healthCheckRuleResultsController = FileIOHelper.ReadListFromCSVFile(FilePathMap.ControllerHealthCheckRuleResultsReportFilePath(), new HealthCheckRuleResultReportMap());
                if (healthCheckRuleResultsController != null)
                {
                    healthCheckRuleResults.AddRange(healthCheckRuleResultsController);
                }

                List <HealthCheckRuleResult> healthCheckRuleResultsAPM = FileIOHelper.ReadListFromCSVFile(FilePathMap.APMHealthCheckRuleResultsReportFilePath(), new HealthCheckRuleResultReportMap());
                if (healthCheckRuleResultsAPM != null)
                {
                    healthCheckRuleResults.AddRange(healthCheckRuleResultsAPM);
                }

                if (healthCheckRuleResults != null)
                {
                    #region Output summary of Applications by Category table

                    // Make this following table out of the list of health rule evaluations
                    // Controller | Application | Category1 | Category2 | Category 3
                    // -------------------------------------------------------------
                    // CntrVal    | AppName     | Avg(Grade)| Avg(Grade)| Avg(Grade)

                    // To do this, we measure number of rows (Controller/Application pairs) and Columns (Category values), and build a table
                    int numRows    = healthCheckRuleResults.Select(h => String.Format("{0}/{1}", h.Controller, h.Application)).Distinct().Count();
                    int numColumns = healthCheckRuleResults.Select(h => h.Category).Distinct().Count();

                    Dictionary <string, int> categoryTableRowsLookup    = new Dictionary <string, int>(numRows);
                    Dictionary <string, int> categoryTableColumnsLookup = new Dictionary <string, int>(numColumns);

                    List <HealthCheckRuleResult>[,] categoryTableValues = new List <HealthCheckRuleResult> [numRows, numColumns];

                    foreach (HealthCheckRuleResult healthCheckRuleResult in healthCheckRuleResults)
                    {
                        int rowIndex    = 0;
                        int columnIndex = 0;

                        string rowIndexValue    = String.Format("{0}/{1}", healthCheckRuleResult.Controller, healthCheckRuleResult.Application);
                        string columnIndexValue = healthCheckRuleResult.Category;

                        if (categoryTableRowsLookup.ContainsKey(rowIndexValue) == true)
                        {
                            rowIndex = categoryTableRowsLookup[rowIndexValue];
                        }
                        else
                        {
                            rowIndex = categoryTableRowsLookup.Count;
                            categoryTableRowsLookup.Add(rowIndexValue, rowIndex);
                        }

                        if (categoryTableColumnsLookup.ContainsKey(columnIndexValue) == true)
                        {
                            columnIndex = categoryTableColumnsLookup[columnIndexValue];
                        }
                        else
                        {
                            columnIndex = categoryTableColumnsLookup.Count;
                            categoryTableColumnsLookup.Add(columnIndexValue, columnIndex);
                        }

                        // Fill in the cell
                        List <HealthCheckRuleResult> healthCheckRuleResultsInCell = categoryTableValues[rowIndex, columnIndex];
                        if (healthCheckRuleResultsInCell == null)
                        {
                            healthCheckRuleResultsInCell = new List <HealthCheckRuleResult>();
                            categoryTableValues[rowIndex, columnIndex] = healthCheckRuleResultsInCell;
                        }
                        healthCheckRuleResultsInCell.Add(healthCheckRuleResult);
                    }

                    // Output headers
                    int rowTableStart    = 4;
                    int gradeColumnStart = 4;
                    int fromRow          = rowTableStart;
                    int fromColumn       = gradeColumnStart;
                    sheet.Cells[fromRow, 1].Value = "Controller";
                    sheet.Cells[fromRow, 2].Value = "Application";
                    sheet.Cells[fromRow, 3].Value = "ApplicationID";
                    foreach (KeyValuePair <string, int> categoriesKVP in categoryTableColumnsLookup)
                    {
                        sheet.Cells[fromRow, fromColumn].Value         = categoriesKVP.Key;
                        sheet.Cells[fromRow - 1, fromColumn].Formula   = String.Format(@"=HYPERLINK(""#'{0}'!A1"", ""<See Details>"")", String.Format(SHEET_HEALTH_CHECK_RULE_CATEGORY_RESULTS_DISPLAY, categoriesKVP.Key));
                        sheet.Cells[fromRow - 1, fromColumn].StyleName = "HyperLinkStyle";
                        fromColumn++;
                    }
                    fromRow++;

                    // Output table
                    for (int rowIndex = 0; rowIndex < numRows; rowIndex++)
                    {
                        for (int columnIndex = 0; columnIndex < numColumns; columnIndex++)
                        {
                            List <HealthCheckRuleResult> healthCheckRuleResultsInCell = categoryTableValues[rowIndex, columnIndex];
                            if (healthCheckRuleResultsInCell != null && healthCheckRuleResultsInCell.Count > 0)
                            {
                                double gradeAverage = Math.Round((double)healthCheckRuleResultsInCell.Sum(h => h.Grade) / healthCheckRuleResultsInCell.Count, 1);

                                sheet.Cells[fromRow + rowIndex, gradeColumnStart + columnIndex].Value = gradeAverage;

                                sheet.Cells[fromRow + rowIndex, 1].Value = healthCheckRuleResultsInCell[0].Controller;
                                sheet.Cells[fromRow + rowIndex, 2].Value = healthCheckRuleResultsInCell[0].Application;
                                sheet.Cells[fromRow + rowIndex, 3].Value = healthCheckRuleResultsInCell[0].ApplicationID;
                            }
                            else
                            {
                                sheet.Cells[fromRow + rowIndex, gradeColumnStart + columnIndex].Value = "-";
                            }
                        }
                    }
                    fromRow = fromRow + numRows;

                    // Insert the table
                    range            = sheet.Cells[4, 1, 4 + numRows, 3 + numColumns];
                    table            = sheet.Tables.Add(range, TABLE_HEALTH_CHECK_RULE_APPLICATIONS);
                    table.ShowHeader = true;
                    table.TableStyle = TableStyles.None;
                    table.TableStyle = TableStyles.Medium2;
                    table.ShowFilter = true;
                    table.ShowTotal  = false;

                    // Resize the columns
                    sheet.Column(table.Columns["Controller"].Position + 1).Width  = 20;
                    sheet.Column(table.Columns["Application"].Position + 1).Width = 25;
                    for (int columnIndex = 0; columnIndex < numColumns; columnIndex++)
                    {
                        sheet.Column(gradeColumnStart + columnIndex).Width = 15;
                        // Make the header column cells wrap text for Categories headings
                        sheet.Cells[rowTableStart, gradeColumnStart + columnIndex].Style.WrapText = true;
                    }

                    // Make header row taller
                    sheet.Row(rowTableStart).Height = 40;

                    if (sheet.Dimension.Rows > rowTableStart)
                    {
                        // Color code it
                        ExcelAddress cfGradeNum = new ExcelAddress(LIST_SHEET_START_TABLE_AT + 1, 4, sheet.Dimension.Rows, 4 + numColumns);
                        var          cfGrade    = sheet.ConditionalFormatting.AddThreeColorScale(cfGradeNum);
                        cfGrade.LowValue.Type     = eExcelConditionalFormattingValueObjectType.Num;
                        cfGrade.LowValue.Color    = colorRedFor3ColorScales;
                        cfGrade.LowValue.Value    = 1;
                        cfGrade.MiddleValue.Type  = eExcelConditionalFormattingValueObjectType.Num;
                        cfGrade.MiddleValue.Value = 3;
                        cfGrade.MiddleValue.Color = colorYellowFor3ColorScales;
                        cfGrade.HighValue.Type    = eExcelConditionalFormattingValueObjectType.Num;
                        cfGrade.HighValue.Color   = colorGreenFor3ColorScales;
                        cfGrade.HighValue.Value   = 5;
                    }

                    #endregion

                    #region Output individual categories on separate sheets

                    // Get list of categories for which we'll be making things
                    List <string> listOfCategories = healthCheckRuleResults.Select(h => h.Category).Distinct().ToList <string>();

                    foreach (string category in listOfCategories)
                    {
                        sheet = excelReport.Workbook.Worksheets.Add(String.Format(SHEET_HEALTH_CHECK_RULE_CATEGORY_RESULTS_DISPLAY, category));
                        sheet.Cells[1, 1].Value     = "Table of Contents";
                        sheet.Cells[1, 2].Formula   = String.Format(@"=HYPERLINK(""#'{0}'!A1"", ""<Go>"")", SHEET_TOC);
                        sheet.Cells[1, 2].StyleName = "HyperLinkStyle";
                        sheet.Cells[2, 1].Value     = "See Table";
                        sheet.Cells[2, 2].Formula   = String.Format(@"=HYPERLINK(""#'{0}'!A1"", ""<Go>"")", SHEET_HEALTH_CHECK_RULE_RESULTS);
                        sheet.Cells[2, 2].StyleName = "HyperLinkStyle";
                        sheet.Cells[3, 1].Value     = "See Display";
                        sheet.Cells[3, 2].Formula   = String.Format(@"=HYPERLINK(""#'{0}'!A1"", ""<Go>"")", SHEET_HEALTH_CHECK_RULE_RESULTS_DISPLAY);
                        sheet.Cells[3, 2].StyleName = "HyperLinkStyle";
                        sheet.View.FreezePanes(LIST_SHEET_START_TABLE_AT + 1, 1);


                        // Make this following table out of the list of health rule evaluations
                        // Controller | Application | EntityType | EntityName | Rule 1 | Rule 2 | Rule 3
                        // -----------------------------------------------------------------------------
                        // CntrVal    | AppName     | APMApp     | AppName    | Grade  | Grade  | Grade (with comment of value)

                        // To do this, we measure number of rows (Controller/Application/EntityType/EntityName quads) and Columns (Rules within Category), and build a table
                        numRows    = healthCheckRuleResults.Where(h => h.Category == category).Select(h => String.Format("{0}/{1}/{2}/{3}", h.Controller, h.Application, h.EntityType, h.EntityName)).Distinct().Count();
                        numColumns = healthCheckRuleResults.Where(h => h.Category == category).Select(h => h.Name).Distinct().Count();

                        Dictionary <string, int> nameTableRowsLookup    = new Dictionary <string, int>(numRows);
                        Dictionary <string, int> nameTableColumnsLookup = new Dictionary <string, int>(numColumns);

                        List <HealthCheckRuleResult>[,] nameTableValues = new List <HealthCheckRuleResult> [numRows, numColumns];

                        foreach (HealthCheckRuleResult healthCheckRuleResult in healthCheckRuleResults)
                        {
                            // Only process the rules with the desired category
                            if (healthCheckRuleResult.Category != category)
                            {
                                continue;
                            }

                            int rowIndex    = 0;
                            int columnIndex = 0;

                            string rowIndexValue    = String.Format("{0}/{1}/{2}/{3}", healthCheckRuleResult.Controller, healthCheckRuleResult.Application, healthCheckRuleResult.EntityType, healthCheckRuleResult.EntityName);
                            string columnIndexValue = healthCheckRuleResult.Name;

                            if (nameTableRowsLookup.ContainsKey(rowIndexValue) == true)
                            {
                                rowIndex = nameTableRowsLookup[rowIndexValue];
                            }
                            else
                            {
                                rowIndex = nameTableRowsLookup.Count;
                                nameTableRowsLookup.Add(rowIndexValue, rowIndex);
                            }

                            if (nameTableColumnsLookup.ContainsKey(columnIndexValue) == true)
                            {
                                columnIndex = nameTableColumnsLookup[columnIndexValue];
                            }
                            else
                            {
                                columnIndex = nameTableColumnsLookup.Count;
                                nameTableColumnsLookup.Add(columnIndexValue, columnIndex);
                            }

                            // Fill in the cell
                            List <HealthCheckRuleResult> healthCheckRuleResultsInCell = nameTableValues[rowIndex, columnIndex];
                            if (healthCheckRuleResultsInCell == null)
                            {
                                healthCheckRuleResultsInCell           = new List <HealthCheckRuleResult>();
                                nameTableValues[rowIndex, columnIndex] = healthCheckRuleResultsInCell;
                            }
                            healthCheckRuleResultsInCell.Add(healthCheckRuleResult);
                        }

                        // Output headers
                        rowTableStart    = 4;
                        gradeColumnStart = 6;
                        fromRow          = rowTableStart;
                        fromColumn       = gradeColumnStart;
                        sheet.Cells[fromRow, 1].Value = "Controller";
                        sheet.Cells[fromRow, 2].Value = "Application";
                        sheet.Cells[fromRow, 3].Value = "ApplicationID";
                        sheet.Cells[fromRow, 4].Value = "EntityType";
                        sheet.Cells[fromRow, 5].Value = "EntityName";
                        foreach (KeyValuePair <string, int> namesKVP in nameTableColumnsLookup)
                        {
                            sheet.Cells[fromRow, fromColumn].Value = namesKVP.Key;
                            fromColumn++;
                        }
                        fromRow++;

                        // Output table
                        for (int rowIndex = 0; rowIndex < numRows; rowIndex++)
                        {
                            for (int columnIndex = 0; columnIndex < numColumns; columnIndex++)
                            {
                                List <HealthCheckRuleResult> healthCheckRuleResultsInCell = nameTableValues[rowIndex, columnIndex];
                                if (healthCheckRuleResultsInCell != null && healthCheckRuleResultsInCell.Count > 0)
                                {
                                    double gradeAverage = Math.Round((double)healthCheckRuleResultsInCell.Sum(h => h.Grade) / healthCheckRuleResultsInCell.Count, 1);

                                    sheet.Cells[fromRow + rowIndex, gradeColumnStart + columnIndex].Value = gradeAverage;

                                    sheet.Cells[fromRow + rowIndex, 1].Value = healthCheckRuleResultsInCell[0].Controller;
                                    sheet.Cells[fromRow + rowIndex, 2].Value = healthCheckRuleResultsInCell[0].Application;
                                    sheet.Cells[fromRow + rowIndex, 3].Value = healthCheckRuleResultsInCell[0].ApplicationID;
                                    sheet.Cells[fromRow + rowIndex, 4].Value = healthCheckRuleResultsInCell[0].EntityType;
                                    sheet.Cells[fromRow + rowIndex, 5].Value = healthCheckRuleResultsInCell[0].EntityName;

                                    StringBuilder sb = new StringBuilder(healthCheckRuleResultsInCell.Count * 128);
                                    for (int k = 0; k < healthCheckRuleResultsInCell.Count; k++)
                                    {
                                        HealthCheckRuleResult healthCheckRuleResult = healthCheckRuleResultsInCell[k];
                                        sb.AppendFormat("{0}: {1}\n", k + 1, wordWrapString(healthCheckRuleResult.Description, 100));
                                    }

                                    // Limit the size of the comment generated to ~2K of text because I think the Excel barfs when the comments are too long.
                                    if (sb.Length > 2500)
                                    {
                                        sb.Length = 2547;
                                        sb.Append("...");
                                    }

                                    // Excessive comments in the workbook lead to poor use experience. Need to rethink and refactor this
                                    ExcelComment comment = sheet.Cells[fromRow + rowIndex, gradeColumnStart + columnIndex].AddComment(sb.ToString(), healthCheckRuleResultsInCell[0].Code);
                                    comment.AutoFit = true;
                                }
                                else
                                {
                                    sheet.Cells[fromRow + rowIndex, gradeColumnStart + columnIndex].Value = "-";
                                }
                            }
                        }
                        fromRow = fromRow + numRows;

                        // Insert the table
                        range            = sheet.Cells[4, 1, 4 + numRows, 5 + numColumns];
                        table            = sheet.Tables.Add(range, getExcelTableOrSheetSafeString(String.Format(TABLE_HEALTH_CHECK_RULE_CATEGORY_RESULTS, category)));
                        table.ShowHeader = true;
                        table.TableStyle = TableStyles.None;
                        table.TableStyle = TableStyles.Medium2;
                        table.ShowFilter = true;
                        table.ShowTotal  = false;

                        // Resize the columns
                        sheet.Column(table.Columns["Controller"].Position + 1).Width  = 20;
                        sheet.Column(table.Columns["Application"].Position + 1).Width = 25;
                        sheet.Column(table.Columns["EntityName"].Position + 1).Width  = 25;
                        sheet.Column(table.Columns["EntityType"].Position + 1).Width  = 25;
                        for (int columnIndex = 0; columnIndex < numColumns; columnIndex++)
                        {
                            sheet.Column(gradeColumnStart + columnIndex).Width = 15;
                            // Make the header column cells wrap text for Categories headings
                            sheet.Cells[rowTableStart, gradeColumnStart + columnIndex].Style.WrapText = true;
                        }

                        // Make header row taller
                        sheet.Row(rowTableStart).Height = 50;

                        if (sheet.Dimension.Rows > rowTableStart)
                        {
                            // Color code it
                            ExcelAddress cfGradeNum = new ExcelAddress(LIST_SHEET_START_TABLE_AT + 1, 5, sheet.Dimension.Rows, 5 + numColumns);
                            var          cfGrade    = sheet.ConditionalFormatting.AddThreeColorScale(cfGradeNum);
                            cfGrade.LowValue.Type     = eExcelConditionalFormattingValueObjectType.Num;
                            cfGrade.LowValue.Color    = colorRedFor3ColorScales;
                            cfGrade.LowValue.Value    = 1;
                            cfGrade.MiddleValue.Type  = eExcelConditionalFormattingValueObjectType.Num;
                            cfGrade.MiddleValue.Value = 3;
                            cfGrade.MiddleValue.Color = colorYellowFor3ColorScales;
                            cfGrade.HighValue.Type    = eExcelConditionalFormattingValueObjectType.Num;
                            cfGrade.HighValue.Color   = colorGreenFor3ColorScales;
                            cfGrade.HighValue.Value   = 5;
                        }
                    }

                    #endregion
                }

                #endregion

                #region TOC sheet

                // TOC sheet again
                sheet = excelReport.Workbook.Worksheets[SHEET_TOC];
                fillTableOfContentsSheet(sheet, excelReport);

                #endregion

                #region Save file

                FileIOHelper.CreateFolder(FilePathMap.ReportFolderPath());

                string reportFilePath = FilePathMap.HealthCheckResultsExcelReportFilePath(jobConfiguration.Input.TimeRange);
                logger.Info("Saving Excel report {0}", reportFilePath);
                loggerConsole.Info("Saving Excel report {0}", reportFilePath);

                try
                {
                    // Save full report Excel files
                    excelReport.SaveAs(new FileInfo(reportFilePath));
                }
                catch (InvalidOperationException ex)
                {
                    logger.Warn("Unable to save Excel file {0}", reportFilePath);
                    logger.Warn(ex);
                    loggerConsole.Warn("Unable to save Excel file {0}", reportFilePath);
                }

                #endregion

                return(true);
            }
            catch (Exception ex)
            {
                logger.Error(ex);
                loggerConsole.Error(ex);

                return(false);
            }
            finally
            {
                stopWatch.Stop();

                this.DisplayJobStepEndedStatus(jobConfiguration, stopWatch);

                stepTimingFunction.EndTime    = DateTime.Now;
                stepTimingFunction.Duration   = stopWatch.Elapsed;
                stepTimingFunction.DurationMS = stopWatch.ElapsedMilliseconds;

                List <StepTiming> stepTimings = new List <StepTiming>(1);
                stepTimings.Add(stepTimingFunction);
                FileIOHelper.WriteListToCSVFile(stepTimings, new StepTimingReportMap(), FilePathMap.StepTimingReportFilePath(), true);
            }
        }
        /// <summary>
        /// https://community.appdynamics.com/t5/Knowledge-Base/Controller-and-Agent-ADD-Limit-Notifications-Explanations/ta-p/23273#CONTROLLER_ASYNC_ADD_REG_LIMIT_REACHED
        /// </summary>
        /// <param name="hcrd"></param>
        /// <param name="jobTarget"></param>
        /// <param name="healthCheckSettingsDictionary"></param>
        /// <param name="controllerSettingsList"></param>
        /// <returns></returns>
        private List <HealthCheckRuleResult> evaluate_Controller_Setting_ADD_Limits(
            HealthCheckRuleDescription hcrd,
            JobTarget jobTarget,
            Dictionary <string, HealthCheckSettingMapping> healthCheckSettingsDictionary,
            List <ControllerSetting> controllerSettingsList)
        {
            logger.Trace("Evaluating {0}", hcrd);

            HealthCheckRuleResult healthCheckRuleResult = createHealthCheckRuleResult(jobTarget, "Controller", jobTarget.Controller, 0, hcrd);

            healthCheckRuleResult.Application = "[ALL APPS]";

            List <HealthCheckRuleResult> healthCheckRuleResults = new List <HealthCheckRuleResult>();

            if (controllerSettingsList != null)
            {
                // Defined in Enterprise Console via various
                // C:\AppDynamics\Platform\platform-admin\archives\controller\4.5.4.15417\playbooks\controller-<size>.groovy
                ControllerSetting controllerSettingProfile = controllerSettingsList.Where(s => s.Name == "performance.profile").FirstOrDefault();
                if (controllerSettingProfile != null)
                {
                    List <ControllerSetting> controllerSettingsLimits = controllerSettingsList.Where(s => s.Name.Contains(".registration.limit")).ToList();
                    if (controllerSettingsLimits != null)
                    {
                        foreach (ControllerSetting controllerSetting in controllerSettingsLimits)
                        {
                            string lookupSettingName = String.Format("ControllerSetting.{0}.{1}", controllerSettingProfile.Value, controllerSetting.Name);

                            int settingCurrentValue     = -1;
                            int settingDefaultValue     = -1;
                            int settingRecommendedValue = -1;
                            if (Int32.TryParse(controllerSetting.Value, out settingCurrentValue) == true)
                            {
                                HealthCheckRuleResult healthCheckRuleResult1 = healthCheckRuleResult.Clone();
                                healthCheckRuleResult1.Name  = String.Format("{0} ({1})", healthCheckRuleResult.Name, controllerSetting.Name);
                                healthCheckRuleResult1.Grade = -1;

                                // All settings are taken
                                // from C:\AppDynamics\Platform\platform-admin\archives\controller\4.5.4.15417\playbooks\controller-<size>.groovy in EC
                                // And from careful review of significant number of controllers
                                switch (controllerSetting.Name)
                                {
                                case "application.custom.metric.registration.limit":
                                case "application.metric.registration.limit":
                                case "async.thread.tracking.registration.limit":
                                case "metric.registration.limit":
                                case "sep.ADD.registration.limit":
                                case "stacktrace.ADD.registration.limit":
                                case "error.registration.limit":
                                    // maxStacktracePerAccountLimit = 4000
                                    // maxSepPerAccountLimit = 4000
                                    // maxErrorsPerAccountLimit = 4000
                                    settingRecommendedValue = getIntegerSetting(healthCheckSettingsDictionary, lookupSettingName, -1);
                                    if (settingRecommendedValue != -1)
                                    {
                                        if (settingCurrentValue == settingRecommendedValue)
                                        {
                                            healthCheckRuleResult1.Grade       = 5;
                                            healthCheckRuleResult1.Description = String.Format("Controller setting '{0}'='{1}', at recommended value", controllerSetting.Name, settingCurrentValue);
                                        }
                                        else if (settingCurrentValue < settingRecommendedValue)
                                        {
                                            healthCheckRuleResult1.Grade       = 3;
                                            healthCheckRuleResult1.Description = String.Format("Controller setting '{0}'='{1}', (<) less than recommended value '{2}'", controllerSetting.Name, settingCurrentValue, settingRecommendedValue);
                                        }
                                        else if (settingCurrentValue > settingRecommendedValue)
                                        {
                                            healthCheckRuleResult1.Grade       = 5;
                                            healthCheckRuleResult1.Description = String.Format("Controller setting '{0}'='{1}', (>) greater than recommended value '{2}'", controllerSetting.Name, settingCurrentValue, settingRecommendedValue);
                                        }
                                    }
                                    break;

                                case "collections.ADD.registration.limit":
                                    // maxCollectionsPerAccountLimit = 4000
                                    settingDefaultValue = getIntegerSetting(healthCheckSettingsDictionary, lookupSettingName, 4000);
                                    if (settingCurrentValue == settingDefaultValue)
                                    {
                                        healthCheckRuleResult1.Grade       = 3;
                                        healthCheckRuleResult1.Description = String.Format("Controller setting '{0}'='{1}', at default value", controllerSetting.Name, settingCurrentValue);
                                    }
                                    else if (settingCurrentValue < settingDefaultValue)
                                    {
                                        healthCheckRuleResult1.Grade       = 2;
                                        healthCheckRuleResult1.Description = String.Format("Controller setting '{0}'='{1}', (<) less than default value '{2}'", controllerSetting.Name, settingCurrentValue, settingDefaultValue);
                                    }
                                    else if (settingCurrentValue > settingDefaultValue)
                                    {
                                        healthCheckRuleResult1.Grade       = 5;
                                        healthCheckRuleResult1.Description = String.Format("Controller setting '{0}'='{1}', (>) greater than default value '{2}'", controllerSetting.Name, settingCurrentValue, settingDefaultValue);
                                    }
                                    break;

                                case "tracked.object.ADD.registration.limit":
                                    // maxTrackedObjectAccountLimit = 4000
                                    settingDefaultValue = getIntegerSetting(healthCheckSettingsDictionary, lookupSettingName, 4000);
                                    if (settingCurrentValue == settingDefaultValue)
                                    {
                                        healthCheckRuleResult1.Grade       = 3;
                                        healthCheckRuleResult1.Description = String.Format("Controller setting '{0}'='{1}', at default value", controllerSetting.Name, settingCurrentValue);
                                    }
                                    else if (settingCurrentValue < settingDefaultValue)
                                    {
                                        healthCheckRuleResult1.Grade       = 2;
                                        healthCheckRuleResult1.Description = String.Format("Controller setting '{0}'='{1}', (<) less than default value '{2}'", controllerSetting.Name, settingCurrentValue, settingDefaultValue);
                                    }
                                    else if (settingCurrentValue > settingDefaultValue)
                                    {
                                        healthCheckRuleResult1.Grade       = 5;
                                        healthCheckRuleResult1.Description = String.Format("Controller setting '{0}'='{1}', (>) greater than default value '{2}'", controllerSetting.Name, settingCurrentValue, settingDefaultValue);
                                    }
                                    break;

                                case "memory.ADD.registration.limit":
                                    // maxMemoryPointsPerAccountLimit = 4000
                                    settingDefaultValue = getIntegerSetting(healthCheckSettingsDictionary, lookupSettingName, 4000);
                                    if (settingCurrentValue == settingDefaultValue)
                                    {
                                        healthCheckRuleResult1.Grade       = 3;
                                        healthCheckRuleResult1.Description = String.Format("Controller setting '{0}'='{1}', at default value", controllerSetting.Name, settingCurrentValue);
                                    }
                                    else if (settingCurrentValue < settingDefaultValue)
                                    {
                                        healthCheckRuleResult1.Grade       = 2;
                                        healthCheckRuleResult1.Description = String.Format("Controller setting '{0}'='{1}', (<) less than default value '{2}'", controllerSetting.Name, settingCurrentValue, settingDefaultValue);
                                    }
                                    else if (settingCurrentValue > settingDefaultValue)
                                    {
                                        healthCheckRuleResult1.Grade       = 5;
                                        healthCheckRuleResult1.Description = String.Format("Controller setting '{0}'='{1}', (>) greater than default value '{2}'", controllerSetting.Name, settingCurrentValue, settingDefaultValue);
                                    }
                                    break;

                                case "backend.registration.limit":
                                    // maxBackendsPerAccountLimit = 100000
                                    settingDefaultValue = getIntegerSetting(healthCheckSettingsDictionary, lookupSettingName, 10000);
                                    if (settingCurrentValue == settingDefaultValue)
                                    {
                                        healthCheckRuleResult1.Grade       = 3;
                                        healthCheckRuleResult1.Description = String.Format("Controller setting '{0}'='{1}', at default value", controllerSetting.Name, settingCurrentValue);
                                    }
                                    else if (settingCurrentValue < settingDefaultValue)
                                    {
                                        healthCheckRuleResult1.Grade       = 2;
                                        healthCheckRuleResult1.Description = String.Format("Controller setting '{0}'='{1}', (<) less than default value '{2}'", controllerSetting.Name, settingCurrentValue, settingDefaultValue);
                                    }
                                    else if (settingCurrentValue > settingDefaultValue)
                                    {
                                        healthCheckRuleResult1.Grade       = 5;
                                        healthCheckRuleResult1.Description = String.Format("Controller setting '{0}'='{1}', (>) greater than default value '{2}'", controllerSetting.Name, settingCurrentValue, settingDefaultValue);
                                    }
                                    break;

                                case "controller.metric.registration.limit":
                                // Don't know what this one means
                                default:
                                    break;
                                }

                                if (healthCheckRuleResult1.Grade != -1)
                                {
                                    healthCheckRuleResults.Add(healthCheckRuleResult1);
                                }
                            }
                        }
                    }
                }
            }

            return(healthCheckRuleResults);
        }
        /// <summary>
        /// https://community.appdynamics.com/t5/Knowledge-Base/Why-am-I-receiving-the-error-quot-Controller-Metric-Data-Buffer/ta-p/14653
        /// https://community.appdynamics.com/t5/Knowledge-Base/Why-are-snapshots-missing-in-the-Controller/ta-p/19047
        /// </summary>
        /// <param name="hcrd"></param>
        /// <param name="jobTarget"></param>
        /// <param name="healthCheckSettingsDictionary"></param>
        /// <param name="controllerSettingsList"></param>
        /// <returns></returns>
        private List <HealthCheckRuleResult> evaluate_Controller_Setting_Buffer_Sizes(
            HealthCheckRuleDescription hcrd,
            JobTarget jobTarget,
            Dictionary <string, HealthCheckSettingMapping> healthCheckSettingsDictionary,
            List <ControllerSetting> controllerSettingsList)
        {
            logger.Trace("Evaluating {0}", hcrd);

            HealthCheckRuleResult healthCheckRuleResult = createHealthCheckRuleResult(jobTarget, "Controller", jobTarget.Controller, 0, hcrd);

            healthCheckRuleResult.Application = "[ALL APPS]";

            List <HealthCheckRuleResult> healthCheckRuleResults = new List <HealthCheckRuleResult>();

            if (controllerSettingsList != null)
            {
                // Defined in Enterprise Console via various
                // C:\AppDynamics\Platform\platform-admin\archives\controller\4.5.4.15417\playbooks\controller-<size>.groovy
                ControllerSetting controllerSettingProfile = controllerSettingsList.Where(s => s.Name == "performance.profile").FirstOrDefault();
                if (controllerSettingProfile != null)
                {
                    List <ControllerSetting> controllerSettingsBuffers = controllerSettingsList.Where(s => s.Name.Contains(".buffer.size")).ToList();
                    if (controllerSettingsBuffers != null)
                    {
                        foreach (ControllerSetting controllerSetting in controllerSettingsBuffers)
                        {
                            // Dealing with only these:
                            // events.buffer.size
                            // metrics.buffer.size
                            // process.snapshots.buffer.size
                            // snapshots.buffer.size

                            string lookupSettingName = String.Format("ControllerSetting.{0}.{1}", controllerSettingProfile.Value, controllerSetting.Name);

                            int settingCurrentValue = -1;
                            Int32.TryParse(controllerSetting.Value, out settingCurrentValue);

                            int settingDefaultValue = getIntegerSetting(healthCheckSettingsDictionary, lookupSettingName, -1);

                            if (settingDefaultValue != -1 && settingCurrentValue != -1)
                            {
                                HealthCheckRuleResult healthCheckRuleResult1 = healthCheckRuleResult.Clone();
                                healthCheckRuleResult1.Name = String.Format("{0} ({1})", healthCheckRuleResult.Name, controllerSetting.Name);

                                if (settingCurrentValue == settingDefaultValue)
                                {
                                    healthCheckRuleResult1.Grade       = 5;
                                    healthCheckRuleResult1.Description = String.Format("Controller performance profile is '{0}', setting '{1}'='{2}', at default value", controllerSettingProfile.Value, controllerSetting.Name, settingCurrentValue);
                                }
                                else if (settingCurrentValue < settingDefaultValue)
                                {
                                    healthCheckRuleResult1.Grade       = 3;
                                    healthCheckRuleResult1.Description = String.Format("Controller performance profile is '{0}', setting '{1}'='{2}', (<) less than default value '{3}'", controllerSettingProfile.Value, controllerSetting.Name, settingCurrentValue, settingDefaultValue);
                                }
                                else if (settingCurrentValue > settingDefaultValue)
                                {
                                    healthCheckRuleResult1.Grade       = 4;
                                    healthCheckRuleResult1.Description = String.Format("Controller performance profile is '{0}', setting '{1}'='{2}', (>) greater than default value '{3}'", controllerSettingProfile.Value, controllerSetting.Name, settingCurrentValue, settingDefaultValue);
                                }

                                healthCheckRuleResults.Add(healthCheckRuleResult1);
                            }
                        }
                    }
                }
            }

            return(healthCheckRuleResults);
        }