diff --git a/AppDynamics.Dexter.Core.csproj b/AppDynamics.Dexter.Core.csproj index e944b62..2bb9c76 100644 --- a/AppDynamics.Dexter.Core.csproj +++ b/AppDynamics.Dexter.Core.csproj @@ -59,6 +59,9 @@ Always + + Always + Always diff --git a/AppDynamics.Dexter.csproj b/AppDynamics.Dexter.csproj index 04c29ff..38b9b23 100644 --- a/AppDynamics.Dexter.csproj +++ b/AppDynamics.Dexter.csproj @@ -159,12 +159,19 @@ + + + + + + + @@ -226,6 +233,9 @@ Always + + Always + Designer diff --git a/DataObjects/JobConfiguration/JobStatus.cs b/DataObjects/JobConfiguration/JobStatus.cs index 0c20d25..b3db94f 100644 --- a/DataObjects/JobConfiguration/JobStatus.cs +++ b/DataObjects/JobConfiguration/JobStatus.cs @@ -24,8 +24,9 @@ public enum JobStatus ReportApplicationAndEntityMetricGraphs = 24, ReportEventsAndHealthRuleViolations = 25, ReportSnapshots = 26, - ReportIndividualApplicationAndEntityDetails = 27, - ReportFlameGraphs = 28, + ReportSnapshotsMethodCallLines = 27, + ReportIndividualApplicationAndEntityDetails = 28, + ReportFlameGraphs = 29, Done = 30, diff --git a/DataObjects/ProgramOptions/ProgramOptions.cs b/DataObjects/ProgramOptions/ProgramOptions.cs index 42c7f58..b3f135e 100644 --- a/DataObjects/ProgramOptions/ProgramOptions.cs +++ b/DataObjects/ProgramOptions/ProgramOptions.cs @@ -22,6 +22,8 @@ class ProgramOptions public string OutputJobFilePath { get; set; } + public string ProgramLocationFolderPath { get; set; } + public string JobName { get; set; } [ParserState] @@ -36,7 +38,7 @@ public string GetUsage() public override string ToString() { - return String.Format("ProgramOptions:\r\nInputJobFilePath='{0}'\r\nRestartJobFromBeginning='{1}'\r\nOutputFolderPath='{2}'\r\nOutputJobFolderPath='{3}'\r\nOutputJobFilePath='{4}'\r\nProcessSequentially='{5}'", this.InputJobFilePath, this.RestartJobFromBeginning, this.OutputFolderPath, this.OutputJobFolderPath, this.OutputJobFilePath, this.ProcessSequentially); + return String.Format("ProgramOptions:\r\nInputJobFilePath='{0}'\r\nRestartJobFromBeginning='{1}'\r\nOutputFolderPath='{2}'\r\nOutputJobFolderPath='{3}'\r\nOutputJobFilePath='{4}'\r\nProcessSequentially='{5}'\r\nProgramLocationFolderPath='{6}'", this.InputJobFilePath, this.RestartJobFromBeginning, this.OutputFolderPath, this.OutputJobFolderPath, this.OutputJobFilePath, this.ProcessSequentially, this.ProgramLocationFolderPath); } } } diff --git a/MethodNamespaceTypeMapping.csv b/MethodNamespaceTypeMapping.csv new file mode 100644 index 0000000..8c1e440 --- /dev/null +++ b/MethodNamespaceTypeMapping.csv @@ -0,0 +1,137 @@ +ClassPrefix,FrameworkType +ActivityFeeds,Microsoft Dynamics CRM +antrl,ANTLR Parser +ASP,.NET ASP.NET +Asynchronous,.NET ASP.NET +ch.qos.logback,Logback +com.amazonaws,Amazon Core +com.amazonaws.AmazonWebServiceClient,Amazon Web Service Client +com.amazonaws.auth,Amazon Auth +com.amazonaws.http,Amazon Http +com.amazonaws.services.sns,Amazon SNS +com.amazonaws.services.sqs,Amazon SQS +com.appdynamics,AppDynamics +com.appdynamicspilot,AppDynamics +com.arjuna.ats,JBoss Arjuna +com.aspose,Aspose Components +com.atomikos,Atomicos Transactions +com.bea,BEA Core +com.blazesoft,FICO BlazeAdvisor +com.blazesoft.engines,FICO BlazeAdvisor Rules Engine +com.crossview.commerce,IBM WebSphere Commerce +com.ctc.wstx,Sun Woodstox +com.cybersource,CyberSource ECommerce +com.entrust,Entrust ECommerce +com.fasterxml.jackson,Jackson Core +com.fasterxml.jackson.annotation,Jackson Annotation +com.fasterxml.jackson.core,Jackson Core +com.fasterxml.jackson.databind,Jackson DataBind +com.google,Google Core +com.ibm,IBM Core +com.informix,Informix +com.mchange.v2.c3p0,c3p0 JDBC Connection Pooling +com.microsoft,Microsoft +com.microsoft.sqlserver,Microsoft SQL Server Driver +com.mysql,MySQL Driver +com.nimbusds,NimbusDS +com.opensymphony,OpenSymphony J2EE +com.oracle,Oracle Core +com.paypal,PayPal +com.pointbase,Pointbase Driver +com.rsa,RSA Security +com.singularity,AppDynamics +com.softwareag,Software AG +com.sun,JDK Core +com.sun.jersey,Jersey REST Framework +com.sun.xml.ws,Sun Web Services +com.sybase.jdbc2,Sybase JDBC2 +com.sybase.jdbc3,Sybase JDBC3 +com.sybase.jdbc4,Sybase JDBC3 +com.terracotta,Terracota DB +com.terracottatech,Terracota DB +com.thoughtworks,ThoughWorks +com.weblogic,WebLogic Core +com.webmethods,Software AG webMethods +Corillian,Corillian/Voyager Banking +Fiserv,FiServ Financial +freemarker,Apache FreeMarker +io.undertow,JBoss Undertow +java,Java Core +java.io,Java IO +java.lang.reflect,Java Reflection +javax,Java Extension +jersey,Jersey REST Framework +jrockit,JRockit JVM +log4net,Log4Net Logging +Microsoft,Microsoft +Microsoft.Azure.KeyVault,Microsoft Azure KeyVault +Microsoft.Crm,Microsoft Dynamics CRM +Microsoft.CSharp,.NET C# +Microsoft.Dynamics,Microsoft Dynamics CRM +Microsoft.OData,Microsoft OData +Microsoft.Owin,Microsoft Owin +Microsoft.Practices,Microsoft Patterns and Practices +Microsoft.ServiceBus,Microsoft Service Bus +Microsoft.ServiceFabric,Microsoft Service Fabric +Microsoft.SharePoint,Microsoft SharePoint +Microsoft.SqlServer,Microsoft SQL Server +Microsoft.VisualBasic,.NET VB.NET +Microsoft.WindowsAzure.Storage,Microsoft Azure Storage +Microsoft.Xrm,Microsoft Dynamics CRM +MobileMoney.Voyager,Corillian/Voyager Banking +MS.Internal.Xaml,.NET XAML +MS.Internal.Xml,.NET XML +MySQL,MySQL Driver +net.sf,SourceForge +netscape,Netscape +Newtonsoft.Json,Newtonsoft JSON +Novell,Novell +NLog,NLog Framework +ognl,Apache OGNL +oracle,Oracle Core +org.acegisecurity,Acegi Security +org.apache,Apache +org.apache.camel.components.seda,Apache Camel Seda +org.apache.camel.example,Apache Camel Example +org.apache.cassandra,Apache Cassandra +org.apache.kafka,Apache Kafka +org.apache.openejb,Apache OpenEJB +org.apache.ws,Apache Web Services +org.apache.xmlbeans,Apache XML Beans +Org.BouncyCastle,Bouncy Castle Encryption +org.eclipse.jetty,Eclipse Jetty +org.glassfish,GlassFish +org.jboss,JBoss +org.jboss.soa.esb.client,JBoss ESB +org.mule.processor,Mule ESB +org.springframework,Spring +org.springframework.integration,Spring Integration +org.springframework.jms,Spring JMS +persistence.antlr,TopLink JPA +redis,Redis Cache +redis.clients,Redis Cache Client +SNINativeMethodWrapper,.NET ADO.NET +StackExchange.Redis,Redis StackExchange +StructureMap,StructureMap IoC/DI +sun,JDK Core +sun.reflect,Java Reflection +System,.NET System +System.Activities,.NET WF +System.Collections,.NET Collections +System.Data,.NET Data +System.Data.Linq,.NET Data Linq +System.Diagnostics,.NET Diagnostics +System.IO,.NET IO +System.Linq,.NET Linq +System.Net,.NET Network +System.Reflection,.NET Reflection +System.Runtime,.NET Runtime +System.Security,.NET Security +System.ServiceModel,.NET WCF +System.Text,.NET Text +System.Threading,.NET Threading +System.Web,.NET ASP.NET +System.Web.Mvc,.NET ASP.NET MVC +System.Xaml,.NET XAML +System.Xml,.NET XML +weblogic,WebLogic Core \ No newline at end of file diff --git a/ProcessJob.cs b/ProcessJob.cs index 636c839..8d1f274 100644 --- a/ProcessJob.cs +++ b/ProcessJob.cs @@ -319,6 +319,8 @@ public class ProcessJob private const string CONVERT_SNAPSHOTS_SEGMENTS_SERVICE_ENDPOINTS_CALLS_FILE_NAME = "snapshots.serviceendpoints.csv"; private const string CONVERT_SNAPSHOTS_SEGMENTS_DETECTED_ERRORS_FILE_NAME = "snapshots.errors.csv"; private const string CONVERT_SNAPSHOTS_SEGMENTS_BUSINESS_DATA_FILE_NAME = "snapshots.businessdata.csv"; + private const string CONVERT_SNAPSHOTS_SEGMENTS_METHOD_CALL_LINES_FILE_NAME = "snapshots.methodcalllines.csv"; + private const string CONVERT_SNAPSHOTS_SEGMENTS_METHOD_CALL_LINES_OCCURRENCES_FILE_NAME = "snapshots.methodcalllinesoccurrences.csv"; private const string CONVERT_SNAPSHOT_FILE_NAME = "snapshot.csv"; private const string CONVERT_SNAPSHOT_SEGMENTS_FILE_NAME = "snapshot.segments.csv"; @@ -326,6 +328,8 @@ public class ProcessJob private const string CONVERT_SNAPSHOT_SEGMENTS_SERVICE_ENDPOINT_CALLS_FILE_NAME = "snapshot.serviceendpoints.csv"; private const string CONVERT_SNAPSHOT_SEGMENTS_DETECTED_ERRORS_FILE_NAME = "snapshot.errors.csv"; private const string CONVERT_SNAPSHOT_SEGMENTS_BUSINESS_DATA_FILE_NAME = "snapshot.businessdata.csv"; + private const string CONVERT_SNAPSHOT_SEGMENTS_METHOD_CALL_LINES_FILE_NAME = "snapshot.methodcalllines.csv"; + private const string CONVERT_SNAPSHOT_SEGMENTS_METHOD_CALL_LINES_OCCURRENCES_FILE_NAME = "snapshot.methodcalllinesoccurrences.csv"; // Settings report list private const string CONTROLLER_SETTINGS_FILE_NAME = "controller.settings.csv"; @@ -346,6 +350,9 @@ public class ProcessJob private const string APPLICATION_CONFIGURATION_AGENT_CALL_GRAPH_SETTINGS_FILE_NAME = "callgraphs.configuration.csv"; private const string APPLICATION_CONFIGURATION_HEALTH_RULES_FILE_NAME = "healthrules.csv"; + // Settings for method and call mapping + private const string METHOD_CALL_LINES_TO_FRAMEWORK_TYPE_MAPPING_FILE_NAME = "MethodNamespaceTypeMapping.csv"; + #endregion #region Constants for the folder and file names of data reports @@ -359,6 +366,7 @@ public class ProcessJob private const string REPORT_METRICS_ALL_ENTITIES_FILE_NAME = "EntityMetrics.{0}.{1:yyyyMMddHH}-{2:yyyyMMddHH}.xlsx"; private const string REPORT_DETECTED_EVENTS_FILE_NAME = "Events.{0}.{1:yyyyMMddHH}-{2:yyyyMMddHH}.xlsx"; private const string REPORT_SNAPSHOTS_FILE_NAME = "Snapshots.{0}.{1:yyyyMMddHH}-{2:yyyyMMddHH}.xlsx"; + private const string REPORT_SNAPSHOTS_METHOD_CALL_LINES_FILE_NAME = "Snapshots.MethodCallLines.{0}.{1:yyyyMMddHH}-{2:yyyyMMddHH}.xlsx"; private const string REPORT_CONFIGURATION_FILE_NAME = "Configuration.{0}.{1:yyyyMMddHH}-{2:yyyyMMddHH}.xlsx"; // Per entity report names @@ -462,6 +470,7 @@ public class ProcessJob private const string REPORT_METRICS_ALL_ENTITIES_TABLE_TOC = "t_TOC"; private const string REPORT_METRICS_ALL_ENTITIES_TABLE_PARAMETERS_TARGETS = "t_InputTargets"; + private const string REPORT_METRICS_ALL_ENTITIES_TABLE_CONTROLLERS = "t_Controllers"; private const string REPORT_METRICS_ALL_ENTITIES_TABLE_APPLICATIONS_FULL = "t_Applications_Full"; private const string REPORT_METRICS_ALL_ENTITIES_TABLE_APPLICATIONS_HOURLY = "t_Applications_Hourly"; @@ -504,6 +513,10 @@ public class ProcessJob private const string REPORT_METRICS_GRAPHS_SHEET_INFORMATION_POINTS_METRICS = "11.Information Points.Metrics"; private const string REPORT_METRICS_GRAPHS_SHEET_INFORMATION_POINTS_GRAPHS = "11.Information Points.Graphs"; + private const string REPORT_METRICS_GRAPHS_TABLE_TOC = "t_TOC"; + private const string REPORT_METRICS_GRAPHS_TABLE_PARAMETERS_TARGETS = "t_InputTargets"; + private const string REPORT_METRICS_GRAPHS_TABLE_CONTROLLERS = "t_Controllers"; + // Description tables from metric.summary.csv private const string REPORT_METRICS_GRAPHS_METRIC_TABLE_METRIC_DESCRIPTION = "t_Metric_Description_{0}_{1}_{2}"; // Metric data tables from metric.values.csv @@ -530,6 +543,9 @@ public class ProcessJob private const string REPORT_DETECTED_EVENTS_TABLE_CONTROLLERS = "t_Controllers"; private const string REPORT_DETECTED_EVENTS_TABLE_APPLICATIONS = "t_Applications"; + private const string REPORT_DETECTED_EVENTS_TABLE_TOC = "t_TOC"; + private const string REPORT_DETECTED_EVENTS_TABLE_PARAMETERS_TARGETS = "t_InputTargets"; + private const string REPORT_DETECTED_EVENTS_TABLE_EVENTS = "t_Events"; private const string REPORT_DETECTED_EVENTS_TABLE_HEALTH_RULE_VIOLATION_EVENTS = "t_HealthRuleViolationEvents"; @@ -644,6 +660,17 @@ public class ProcessJob private const string REPORT_SNAPSHOTS_SHEET_BUSINESS_DATA = "10.Business Data"; private const string REPORT_SNAPSHOTS_SHEET_BUSINESS_DATA_PIVOT = "10.Business Data.Type"; + private const string REPORT_SNAPSHOTS_SHEET_METHOD_CALL_LINES = "11.Method Calls"; + private const string REPORT_SNAPSHOTS_SHEET_METHOD_CALL_LINES_TYPE_PIVOT = "11.Method Calls.Type"; + private const string REPORT_SNAPSHOTS_SHEET_METHOD_CALL_LINES_LOCATION_PIVOT = "11.Method Calls.Location"; + + private const string REPORT_SNAPSHOTS_SHEET_METHOD_CALL_LINES_OCCURRENCES = "12.Method Occurrences"; + private const string REPORT_SNAPSHOTS_SHEET_METHOD_CALL_LINES_OCCURRENCES_TYPE_PIVOT = "12.Method Occurrences.Type"; + private const string REPORT_SNAPSHOTS_SHEET_METHOD_CALL_LINES_OCCURRENCES_LOCATION_PIVOT = "12.Method Occurrences.Location"; + + private const string REPORT_SNAPSHOTS_TABLE_TOC = "t_TOC"; + private const string REPORT_SNAPSHOTS_TABLE_PARAMETERS_TARGETS = "t_InputTargets"; + private const string REPORT_SNAPSHOTS_TABLE_CONTROLLERS = "t_Controllers"; private const string REPORT_SNAPSHOTS_TABLE_APPLICATIONS = "t_Applications"; @@ -653,6 +680,8 @@ public class ProcessJob private const string REPORT_SNAPSHOTS_TABLE_SERVICE_ENDPOINT_CALLS = "t_ServiceEndpointCalls"; private const string REPORT_SNAPSHOTS_TABLE_DETECTED_ERRORS = "t_DetectedErrors"; private const string REPORT_SNAPSHOTS_TABLE_BUSINESS_DATA = "t_BusinessData"; + private const string REPORT_SNAPSHOTS_TABLE_METHOD_CALL_LINES = "t_MethodCallLines"; + private const string REPORT_SNAPSHOTS_TABLE_METHOD_CALL_LINES_OCCURRENCES = "t_MethodCallLinesOccurrences"; private const string REPORT_SNAPSHOTS_PIVOT_SNAPSHOTS = "p_Snapshots"; private const string REPORT_SNAPSHOTS_PIVOT_SEGMENTS = "p_Segments"; @@ -660,6 +689,10 @@ public class ProcessJob private const string REPORT_SNAPSHOTS_PIVOT_EXIT_CALLS_DETAILS_DURATION = "p_ExitCallsDetailsDuration"; private const string REPORT_SNAPSHOTS_PIVOT_DETECTED_ERRORS = "p_DetectedErrors"; private const string REPORT_SNAPSHOTS_PIVOT_BUSINESS_DATA = "p_BusinessData"; + private const string REPORT_SNAPSHOTS_PIVOT_METHOD_CALL_LINES_TYPE = "p_MethodCallLinesType"; + private const string REPORT_SNAPSHOTS_PIVOT_METHOD_CALL_LINES_LOCATION = "p_MethodCallLinesDuration"; + private const string REPORT_SNAPSHOTS_PIVOT_METHOD_CALL_LINES_OCCURRENCES_TYPE = "p_MethodCallLinesOccurrencesType"; + private const string REPORT_SNAPSHOTS_PIVOT_METHOD_CALL_LINES_OCCURRENCES_LOCATION = "p_MethodCallLinesOccurrencesLocation"; private const string REPORT_SNAPSHOTS_PIVOT_SNAPSHOTS_GRAPH = "g_Snapshots"; private const string REPORT_SNAPSHOTS_PIVOT_SEGMENTS_GRAPH = "g_Segments"; @@ -667,6 +700,10 @@ public class ProcessJob private const string REPORT_SNAPSHOTS_PIVOT_EXIT_CALLS_DETAILS_DURATION_GRAPH = "g_ExitCallsDetailsDuration"; private const string REPORT_SNAPSHOTS_PIVOT_DETECTED_ERRORS_GRAPH = "g_DetectedErrors"; private const string REPORT_SNAPSHOTS_PIVOT_BUSINESS_DATA_GRAPH = "g_BusinessData"; + private const string REPORT_SNAPSHOTS_PIVOT_METHOD_CALL_LINES_GRAPH_TYPE = "g_MethodCallLinesType"; + private const string REPORT_SNAPSHOTS_PIVOT_METHOD_CALL_LINES_GRAPH_LOCATION = "g_MethodCallLinesLocation"; + private const string REPORT_SNAPSHOTS_PIVOT_METHOD_CALL_LINES_OCCURRENCES_GRAPH_TYPE = "g_MethodCallLinesOccurrencesType"; + private const string REPORT_SNAPSHOTS_PIVOT_METHOD_CALL_LINES_OCCURRENCES_GRAPH_LOCATION = "g_MethodCallLinesOccurrencesLocation"; private const int REPORT_SNAPSHOTS_LIST_SHEET_START_TABLE_AT = 4; private const int REPORT_SNAPSHOTS_PIVOT_SHEET_START_PIVOT_AT = 8; @@ -705,6 +742,7 @@ public class ProcessJob private const string REPORT_CONFIGURATION_SHEET_AGENT_CALL_GRAPH_SETTINGS = "19.Call Graph Settings"; private const string REPORT_CONFIGURATION_DETAILS_TABLE_TOC = "t_TOC"; + private const string REPORT_CONFIGURATION_TABLE_PARAMETERS_TARGETS = "t_InputTargets"; private const string REPORT_CONFIGURATION_DETAILS_TABLE_CONTROLLERS = "t_Controllers"; // Full and hourly metric data @@ -876,6 +914,7 @@ internal static void startOrContinueJob(ProgramOptions programOptions) JobStatus.ReportApplicationAndEntityMetricGraphs, JobStatus.ReportEventsAndHealthRuleViolations, JobStatus.ReportSnapshots, + JobStatus.ReportSnapshotsMethodCallLines, JobStatus.ReportIndividualApplicationAndEntityDetails, //JobStatus.ReportFlameGraphs, @@ -1247,6 +1286,26 @@ internal static void startOrContinueJob(ProgramOptions programOptions) } break; + case JobStatus.ReportSnapshotsMethodCallLines: + if (jobConfiguration.Input.Snapshots == true && jobConfiguration.Output.Snapshots == true) + { + if (stepReportSnapshotsMethodCallLines(programOptions, jobConfiguration, jobConfiguration.Status) == true) + { + jobConfiguration.Status = jobStepsLinked.Find(jobConfiguration.Status).Next.Value; + } + else + { + jobConfiguration.Status = JobStatus.Error; + } + } + else + { + jobConfiguration.Status = jobStepsLinked.Find(jobConfiguration.Status).Next.Value; + + loggerConsole.Debug("Skipping report of snapshots"); + } + break; + case JobStatus.ReportIndividualApplicationAndEntityDetails: if ((jobConfiguration.Input.Metrics == true || jobConfiguration.Input.Events == true || @@ -3425,7 +3484,7 @@ private static bool stepIndexControllersApplicationsAndEntities(ProgramOptions p List informationPointsRESTList = FileIOHelper.loadListOfObjectsFromFile(informationPointsFilePath); List informationPointsList = null; - if (serviceEndpointsRESTList != null) + if (informationPointsRESTList != null) { loggerConsole.Info("Index List of Information points ({0} entities)", informationPointsRESTList.Count); @@ -6449,6 +6508,7 @@ private static bool stepIndexSnapshots(ProgramOptions programOptions, JobConfigu string snapshotsFolderPath = Path.Combine(applicationFolderPath, SNAPSHOTS_FOLDER_NAME); string reportFolderPath = Path.Combine(programOptions.OutputJobFolderPath, REPORTS_FOLDER_NAME); string snapshotsAllFolderPath = Path.Combine(reportFolderPath, SNAPSHOTS_FOLDER_NAME); + string configFolderPath = Path.Combine(applicationFolderPath, CONFIGURATION_FOLDER_NAME); // Previosly rendered report files string applicationReportFilePath = Path.Combine(applicationFolderPath, CONVERT_ENTITY_APPLICATION_FILE_NAME); @@ -6456,6 +6516,8 @@ private static bool stepIndexSnapshots(ProgramOptions programOptions, JobConfigu string backendsReportFilePath = Path.Combine(entitiesFolderPath, CONVERT_ENTITY_BACKENDS_FILE_NAME); string serviceEndpointsReportFilePath = Path.Combine(entitiesFolderPath, CONVERT_ENTITY_SERVICE_ENDPOINTS_FILE_NAME); string errorsReportFilePath = Path.Combine(entitiesFolderPath, CONVERT_ENTITY_ERRORS_FILE_NAME); + string methodInvocationDataCollectorsReportFilePath = Path.Combine(configFolderPath, APPLICATION_CONFIGURATION_METHOD_INVOCATION_DATA_COLLECTORS_FILE_NAME); + string methodCallLinesToFrameworkTypeMappingFilePath = Path.Combine(programOptions.ProgramLocationFolderPath, METHOD_CALL_LINES_TO_FRAMEWORK_TYPE_MAPPING_FILE_NAME); // Report files string snapshotsReportFilePath = Path.Combine(snapshotsFolderPath, CONVERT_SNAPSHOTS_FILE_NAME); @@ -6464,6 +6526,8 @@ private static bool stepIndexSnapshots(ProgramOptions programOptions, JobConfigu string serviceEndpointCallsReportFilePath = Path.Combine(snapshotsFolderPath, CONVERT_SNAPSHOTS_SEGMENTS_SERVICE_ENDPOINTS_CALLS_FILE_NAME); string detectedErrorsReportFilePath = Path.Combine(snapshotsFolderPath, CONVERT_SNAPSHOTS_SEGMENTS_DETECTED_ERRORS_FILE_NAME); string businessDataReportFilePath = Path.Combine(snapshotsFolderPath, CONVERT_SNAPSHOTS_SEGMENTS_BUSINESS_DATA_FILE_NAME); + string methodCallLinesReportFilePath = Path.Combine(snapshotsFolderPath, CONVERT_SNAPSHOTS_SEGMENTS_METHOD_CALL_LINES_FILE_NAME); + string methodCallLinesOccurrencesReportFilePath = Path.Combine(snapshotsFolderPath, CONVERT_SNAPSHOTS_SEGMENTS_METHOD_CALL_LINES_OCCURRENCES_FILE_NAME); string applicationSnapshotsSummaryReportFilePath = Path.Combine(snapshotsFolderPath, CONVERT_APPLICATION_SNAPSHOTS_FILE_NAME); // Report files for All @@ -6473,6 +6537,8 @@ private static bool stepIndexSnapshots(ProgramOptions programOptions, JobConfigu string serviceEndpointCallsAllReporFilePath = Path.Combine(snapshotsAllFolderPath, CONVERT_SNAPSHOTS_SEGMENTS_SERVICE_ENDPOINTS_CALLS_FILE_NAME); string detectedErrorsAllReporFilePath = Path.Combine(snapshotsAllFolderPath, CONVERT_SNAPSHOTS_SEGMENTS_DETECTED_ERRORS_FILE_NAME); string businessDataAllReportFilePath = Path.Combine(snapshotsAllFolderPath, CONVERT_SNAPSHOTS_SEGMENTS_BUSINESS_DATA_FILE_NAME); + string methodCallLinesAllReportFilePath = Path.Combine(snapshotsAllFolderPath, CONVERT_SNAPSHOTS_SEGMENTS_METHOD_CALL_LINES_FILE_NAME); + string methodCallLinesOccurrencesAllReportFilePath = Path.Combine(snapshotsAllFolderPath, CONVERT_SNAPSHOTS_SEGMENTS_METHOD_CALL_LINES_OCCURRENCES_FILE_NAME); string applicationSnapshotsSummaryAllReportFilePath = Path.Combine(snapshotsAllFolderPath, CONVERT_APPLICATION_SNAPSHOTS_FILE_NAME); #endregion @@ -6486,6 +6552,38 @@ private static bool stepIndexSnapshots(ProgramOptions programOptions, JobConfigu List backendsList = FileIOHelper.readListFromCSVFile(backendsReportFilePath, new BackendEntityReportMap()); List serviceEndpointsList = FileIOHelper.readListFromCSVFile(serviceEndpointsReportFilePath, new ServiceEndpointEntityReportMap()); List errorsList = FileIOHelper.readListFromCSVFile(errorsReportFilePath, new ErrorEntityReportMap()); + List methodInvocationDataCollectorsList = FileIOHelper.readListFromCSVFile(methodInvocationDataCollectorsReportFilePath, new MethodInvocationDataCollectorReportMap()); + + // Load and bucketize the framework mappings + List methodCallLineClassToFrameworkTypeMappingList = FileIOHelper.readListFromCSVFile(methodCallLinesToFrameworkTypeMappingFilePath, new MethodCallLineClassTypeMappingReportMap()); + methodCallLineClassToFrameworkTypeMappingList = methodCallLineClassToFrameworkTypeMappingList.OrderByDescending(m => m.ClassPrefix).ToList(); + Dictionary> methodCallLineClassToFrameworkTypeMappingDictionary = new Dictionary>(26); + methodCallLineClassToFrameworkTypeMappingDictionary.Add("a", methodCallLineClassToFrameworkTypeMappingList.Where(m => m.ClassPrefix.Substring(0, 1).ToLower() == "a").ToList()); + methodCallLineClassToFrameworkTypeMappingDictionary.Add("b", methodCallLineClassToFrameworkTypeMappingList.Where(m => m.ClassPrefix.Substring(0, 1).ToLower() == "b").ToList()); + methodCallLineClassToFrameworkTypeMappingDictionary.Add("c", methodCallLineClassToFrameworkTypeMappingList.Where(m => m.ClassPrefix.Substring(0, 1).ToLower() == "c").ToList()); + methodCallLineClassToFrameworkTypeMappingDictionary.Add("d", methodCallLineClassToFrameworkTypeMappingList.Where(m => m.ClassPrefix.Substring(0, 1).ToLower() == "d").ToList()); + methodCallLineClassToFrameworkTypeMappingDictionary.Add("e", methodCallLineClassToFrameworkTypeMappingList.Where(m => m.ClassPrefix.Substring(0, 1).ToLower() == "e").ToList()); + methodCallLineClassToFrameworkTypeMappingDictionary.Add("f", methodCallLineClassToFrameworkTypeMappingList.Where(m => m.ClassPrefix.Substring(0, 1).ToLower() == "f").ToList()); + methodCallLineClassToFrameworkTypeMappingDictionary.Add("g", methodCallLineClassToFrameworkTypeMappingList.Where(m => m.ClassPrefix.Substring(0, 1).ToLower() == "g").ToList()); + methodCallLineClassToFrameworkTypeMappingDictionary.Add("h", methodCallLineClassToFrameworkTypeMappingList.Where(m => m.ClassPrefix.Substring(0, 1).ToLower() == "h").ToList()); + methodCallLineClassToFrameworkTypeMappingDictionary.Add("i", methodCallLineClassToFrameworkTypeMappingList.Where(m => m.ClassPrefix.Substring(0, 1).ToLower() == "i").ToList()); + methodCallLineClassToFrameworkTypeMappingDictionary.Add("j", methodCallLineClassToFrameworkTypeMappingList.Where(m => m.ClassPrefix.Substring(0, 1).ToLower() == "j").ToList()); + methodCallLineClassToFrameworkTypeMappingDictionary.Add("k", methodCallLineClassToFrameworkTypeMappingList.Where(m => m.ClassPrefix.Substring(0, 1).ToLower() == "k").ToList()); + methodCallLineClassToFrameworkTypeMappingDictionary.Add("l", methodCallLineClassToFrameworkTypeMappingList.Where(m => m.ClassPrefix.Substring(0, 1).ToLower() == "l").ToList()); + methodCallLineClassToFrameworkTypeMappingDictionary.Add("m", methodCallLineClassToFrameworkTypeMappingList.Where(m => m.ClassPrefix.Substring(0, 1).ToLower() == "m").ToList()); + methodCallLineClassToFrameworkTypeMappingDictionary.Add("n", methodCallLineClassToFrameworkTypeMappingList.Where(m => m.ClassPrefix.Substring(0, 1).ToLower() == "n").ToList()); + methodCallLineClassToFrameworkTypeMappingDictionary.Add("o", methodCallLineClassToFrameworkTypeMappingList.Where(m => m.ClassPrefix.Substring(0, 1).ToLower() == "o").ToList()); + methodCallLineClassToFrameworkTypeMappingDictionary.Add("p", methodCallLineClassToFrameworkTypeMappingList.Where(m => m.ClassPrefix.Substring(0, 1).ToLower() == "p").ToList()); + methodCallLineClassToFrameworkTypeMappingDictionary.Add("q", methodCallLineClassToFrameworkTypeMappingList.Where(m => m.ClassPrefix.Substring(0, 1).ToLower() == "q").ToList()); + methodCallLineClassToFrameworkTypeMappingDictionary.Add("r", methodCallLineClassToFrameworkTypeMappingList.Where(m => m.ClassPrefix.Substring(0, 1).ToLower() == "r").ToList()); + methodCallLineClassToFrameworkTypeMappingDictionary.Add("s", methodCallLineClassToFrameworkTypeMappingList.Where(m => m.ClassPrefix.Substring(0, 1).ToLower() == "s").ToList()); + methodCallLineClassToFrameworkTypeMappingDictionary.Add("t", methodCallLineClassToFrameworkTypeMappingList.Where(m => m.ClassPrefix.Substring(0, 1).ToLower() == "t").ToList()); + methodCallLineClassToFrameworkTypeMappingDictionary.Add("u", methodCallLineClassToFrameworkTypeMappingList.Where(m => m.ClassPrefix.Substring(0, 1).ToLower() == "u").ToList()); + methodCallLineClassToFrameworkTypeMappingDictionary.Add("v", methodCallLineClassToFrameworkTypeMappingList.Where(m => m.ClassPrefix.Substring(0, 1).ToLower() == "v").ToList()); + methodCallLineClassToFrameworkTypeMappingDictionary.Add("w", methodCallLineClassToFrameworkTypeMappingList.Where(m => m.ClassPrefix.Substring(0, 1).ToLower() == "w").ToList()); + methodCallLineClassToFrameworkTypeMappingDictionary.Add("x", methodCallLineClassToFrameworkTypeMappingList.Where(m => m.ClassPrefix.Substring(0, 1).ToLower() == "x").ToList()); + methodCallLineClassToFrameworkTypeMappingDictionary.Add("y", methodCallLineClassToFrameworkTypeMappingList.Where(m => m.ClassPrefix.Substring(0, 1).ToLower() == "y").ToList()); + methodCallLineClassToFrameworkTypeMappingDictionary.Add("z", methodCallLineClassToFrameworkTypeMappingList.Where(m => m.ClassPrefix.Substring(0, 1).ToLower() == "z").ToList()); int totalNumberOfSnapshots = 0; foreach (JobTimeRange jobTimeRange in jobConfiguration.Input.HourlyTimeRanges) @@ -6510,7 +6608,7 @@ private static bool stepIndexSnapshots(ProgramOptions programOptions, JobConfigu () => 0, (listOfSnapshotsInHourChunk, loop, subtotal) => { - subtotal += indexSnapshots(programOptions, jobConfiguration, jobTarget, jobTimeRange, listOfSnapshotsInHourChunk, tiersList, backendsList, serviceEndpointsList, errorsList, false); + subtotal += indexSnapshots(programOptions, jobConfiguration, jobTarget, jobTimeRange, listOfSnapshotsInHourChunk, tiersList, backendsList, serviceEndpointsList, errorsList, methodInvocationDataCollectorsList, methodCallLineClassToFrameworkTypeMappingDictionary, false); return subtotal; }, (finalResult) => @@ -6522,7 +6620,7 @@ private static bool stepIndexSnapshots(ProgramOptions programOptions, JobConfigu } else { - j = indexSnapshots(programOptions, jobConfiguration, jobTarget, jobTimeRange, listOfSnapshotsInHour.ToList(), tiersList, backendsList, serviceEndpointsList, errorsList, true); + j = indexSnapshots(programOptions, jobConfiguration, jobTarget, jobTimeRange, listOfSnapshotsInHour.ToList(), tiersList, backendsList, serviceEndpointsList, errorsList, methodInvocationDataCollectorsList, methodCallLineClassToFrameworkTypeMappingDictionary, true); } loggerConsole.Info("{0} snapshots", j); @@ -6544,6 +6642,8 @@ private static bool stepIndexSnapshots(ProgramOptions programOptions, JobConfigu FileIOHelper.deleteFile(serviceEndpointCallsReportFilePath); FileIOHelper.deleteFile(detectedErrorsReportFilePath); FileIOHelper.deleteFile(businessDataReportFilePath); + FileIOHelper.deleteFile(methodCallLinesReportFilePath); + FileIOHelper.deleteFile(methodCallLinesOccurrencesReportFilePath); FileIOHelper.deleteFile(applicationSnapshotsSummaryReportFilePath); List applicationList = FileIOHelper.readListFromCSVFile(applicationReportFilePath, new ApplicationEntityReportMap()); @@ -6584,75 +6684,85 @@ private static bool stepIndexSnapshots(ProgramOptions programOptions, JobConfigu { using (FileStream businessDataReportFileStream = File.Open(businessDataReportFilePath, FileMode.Append)) { - foreach (JToken snapshot in listOfSnapshotsInHour) + using (FileStream methodCallLinesReportFileStream = File.Open(methodCallLinesReportFilePath, FileMode.Append)) { - if (requestIDs.ContainsKey(snapshot["requestGUID"].ToString()) == true) + using (FileStream methodCallLinesOccurrencesReportFileStream = File.Open(methodCallLinesOccurrencesReportFilePath, FileMode.Append)) { - logger.Warn("Snapshot {0} is a duplicate, skipping", snapshot["requestGUID"]); - continue; - } - requestIDs.Add(snapshot["requestGUID"].ToString(), true); - - // Count the snapshot - if (applicationsRow != null) - { - applicationsRow.NumSnapshots++; - switch (snapshot["userExperience"].ToString()) + foreach (JToken snapshot in listOfSnapshotsInHour) { - case "NORMAL": - applicationsRow.NumSnapshotsNormal++; - break; - - case "SLOW": - applicationsRow.NumSnapshotsSlow++; - break; - - case "VERY_SLOW": - applicationsRow.NumSnapshotsVerySlow++; - break; - - case "STALL": - applicationsRow.NumSnapshotsStall++; - break; - - case "ERROR": - applicationsRow.NumSnapshotsError++; - break; - - default: - break; + if (requestIDs.ContainsKey(snapshot["requestGUID"].ToString()) == true) + { + logger.Warn("Snapshot {0} is a duplicate, skipping", snapshot["requestGUID"]); + continue; + } + requestIDs.Add(snapshot["requestGUID"].ToString(), true); + + // Count the snapshot + if (applicationsRow != null) + { + applicationsRow.NumSnapshots++; + switch (snapshot["userExperience"].ToString()) + { + case "NORMAL": + applicationsRow.NumSnapshotsNormal++; + break; + + case "SLOW": + applicationsRow.NumSnapshotsSlow++; + break; + + case "VERY_SLOW": + applicationsRow.NumSnapshotsVerySlow++; + break; + + case "STALL": + applicationsRow.NumSnapshotsStall++; + break; + + case "ERROR": + applicationsRow.NumSnapshotsError++; + break; + + default: + break; + } + } + + DateTime snapshotTime = convertFromUnixTimestamp((long)snapshot["serverStartTime"]); + + string snapshotFolderPath = Path.Combine( + snapshotsFolderPath, + getShortenedEntityNameForFileSystem(snapshot["applicationComponentName"].ToString(), (long)snapshot["applicationComponentId"]), + getShortenedEntityNameForFileSystem(snapshot["businessTransactionName"].ToString(), (long)snapshot["businessTransactionId"]), + String.Format("{0:yyyyMMddHH}", snapshotTime), + userExperienceFolderNameMapping[snapshot["userExperience"].ToString()], + String.Format(SNAPSHOT_FOLDER_NAME, snapshot["requestGUID"], snapshotTime)); + + string thisSnapshotSnapshotsFileName = Path.Combine(snapshotFolderPath, CONVERT_SNAPSHOT_FILE_NAME); + string thisSnapshotSegmentsFileName = Path.Combine(snapshotFolderPath, CONVERT_SNAPSHOT_SEGMENTS_FILE_NAME); + string thisSnapshotExitCallsFileName = Path.Combine(snapshotFolderPath, CONVERT_SNAPSHOT_SEGMENTS_EXIT_CALLS_FILE_NAME); + string thisSnapshotServiceEndpointCallsFileName = Path.Combine(snapshotFolderPath, CONVERT_SNAPSHOT_SEGMENTS_SERVICE_ENDPOINT_CALLS_FILE_NAME); + string thisSnapshotDetectedErrorsFileName = Path.Combine(snapshotFolderPath, CONVERT_SNAPSHOT_SEGMENTS_DETECTED_ERRORS_FILE_NAME); + string thisSnapshotBusinessDataFileName = Path.Combine(snapshotFolderPath, CONVERT_SNAPSHOT_SEGMENTS_BUSINESS_DATA_FILE_NAME); + string thisSnapshotMethodCallLinesFileName = Path.Combine(snapshotFolderPath, CONVERT_SNAPSHOT_SEGMENTS_METHOD_CALL_LINES_FILE_NAME); + string thisSnapshotMethodCallOccurrencesLinesFileName = Path.Combine(snapshotFolderPath, CONVERT_SNAPSHOT_SEGMENTS_METHOD_CALL_LINES_OCCURRENCES_FILE_NAME); + + FileIOHelper.appendTwoCSVFiles(snapshotsReportFileStream, thisSnapshotSnapshotsFileName); + FileIOHelper.appendTwoCSVFiles(segmentsReportFileStream, thisSnapshotSegmentsFileName); + FileIOHelper.appendTwoCSVFiles(callExitsReportFileStream, thisSnapshotExitCallsFileName); + FileIOHelper.appendTwoCSVFiles(serviceEndpointCallsReportFileStream, thisSnapshotServiceEndpointCallsFileName); + FileIOHelper.appendTwoCSVFiles(detectedErrorsReportFileStream, thisSnapshotDetectedErrorsFileName); + FileIOHelper.appendTwoCSVFiles(businessDataReportFileStream, thisSnapshotBusinessDataFileName); + FileIOHelper.appendTwoCSVFiles(methodCallLinesReportFileStream, thisSnapshotMethodCallLinesFileName); + FileIOHelper.appendTwoCSVFiles(methodCallLinesOccurrencesReportFileStream, thisSnapshotMethodCallOccurrencesLinesFileName); + + j++; + if (j % 200 == 0) + { + Console.Write("[{0}].", j); + } } } - - DateTime snapshotTime = convertFromUnixTimestamp((long)snapshot["serverStartTime"]); - - string snapshotFolderPath = Path.Combine( - snapshotsFolderPath, - getShortenedEntityNameForFileSystem(snapshot["applicationComponentName"].ToString(), (long)snapshot["applicationComponentId"]), - getShortenedEntityNameForFileSystem(snapshot["businessTransactionName"].ToString(), (long)snapshot["businessTransactionId"]), - String.Format("{0:yyyyMMddHH}", snapshotTime), - userExperienceFolderNameMapping[snapshot["userExperience"].ToString()], - String.Format(SNAPSHOT_FOLDER_NAME, snapshot["requestGUID"], snapshotTime)); - - string thisSnapshotSnapshotsFileName = Path.Combine(snapshotFolderPath, CONVERT_SNAPSHOT_FILE_NAME); - string thisSnapshotSegmentsFileName = Path.Combine(snapshotFolderPath, CONVERT_SNAPSHOT_SEGMENTS_FILE_NAME); - string thisSnapshotExitCallsFileName = Path.Combine(snapshotFolderPath, CONVERT_SNAPSHOT_SEGMENTS_EXIT_CALLS_FILE_NAME); - string thisSnapshotServiceEndpointCallsFileName = Path.Combine(snapshotFolderPath, CONVERT_SNAPSHOT_SEGMENTS_SERVICE_ENDPOINT_CALLS_FILE_NAME); - string thisSnapshotDetectedErrorsFileName = Path.Combine(snapshotFolderPath, CONVERT_SNAPSHOT_SEGMENTS_DETECTED_ERRORS_FILE_NAME); - string thisSnapshotBusinessDataFileName = Path.Combine(snapshotFolderPath, CONVERT_SNAPSHOT_SEGMENTS_BUSINESS_DATA_FILE_NAME); - - FileIOHelper.appendTwoCSVFiles(snapshotsReportFileStream, thisSnapshotSnapshotsFileName); - FileIOHelper.appendTwoCSVFiles(segmentsReportFileStream, thisSnapshotSegmentsFileName); - FileIOHelper.appendTwoCSVFiles(callExitsReportFileStream, thisSnapshotExitCallsFileName); - FileIOHelper.appendTwoCSVFiles(serviceEndpointCallsReportFileStream, thisSnapshotServiceEndpointCallsFileName); - FileIOHelper.appendTwoCSVFiles(detectedErrorsReportFileStream, thisSnapshotDetectedErrorsFileName); - FileIOHelper.appendTwoCSVFiles(businessDataReportFileStream, thisSnapshotBusinessDataFileName); - - j++; - if (j % 100 == 0) - { - Console.Write("[{0}].", j); - } } } } @@ -6694,6 +6804,8 @@ private static bool stepIndexSnapshots(ProgramOptions programOptions, JobConfigu FileIOHelper.appendTwoCSVFiles(serviceEndpointCallsAllReporFilePath, serviceEndpointCallsReportFilePath); FileIOHelper.appendTwoCSVFiles(detectedErrorsAllReporFilePath, detectedErrorsReportFilePath); FileIOHelper.appendTwoCSVFiles(businessDataAllReportFilePath, businessDataReportFilePath); + FileIOHelper.appendTwoCSVFiles(methodCallLinesAllReportFilePath, methodCallLinesReportFilePath); + FileIOHelper.appendTwoCSVFiles(methodCallLinesOccurrencesAllReportFilePath, methodCallLinesOccurrencesReportFilePath); FileIOHelper.appendTwoCSVFiles(applicationSnapshotsSummaryAllReportFilePath, applicationSnapshotsSummaryReportFilePath); #endregion @@ -7169,6 +7281,7 @@ private static bool stepReportControlerApplicationsAndEntities(ProgramOptions pr readCSVFileIntoExcelRange(informationPointsAllReportFilePath, 0, sheet, REPORT_DETECTED_ENTITIES_LIST_SHEET_START_TABLE_AT, 1); #endregion + loggerConsole.Info("Finalize Detected Entities Report File"); #region Controllers sheet @@ -7209,25 +7322,25 @@ private static bool stepReportControlerApplicationsAndEntities(ProgramOptions pr adjustColumnsOfEntityRowTableInEntitiesReport(APPLICATION_TYPE_SHORT, sheet, table); - ExcelAddress cfAddressNum = new ExcelAddress(REPORT_METRICS_ALL_ENTITIES_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumTiers"].Position + 1, sheet.Dimension.Rows, table.Columns["NumTiers"].Position + 1); + ExcelAddress cfAddressNum = new ExcelAddress(REPORT_DETECTED_ENTITIES_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumTiers"].Position + 1, sheet.Dimension.Rows, table.Columns["NumTiers"].Position + 1); var cfNum = sheet.ConditionalFormatting.AddDatabar(cfAddressNum, colorLightBlueForDatabars); - cfAddressNum = new ExcelAddress(REPORT_METRICS_ALL_ENTITIES_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumNodes"].Position + 1, sheet.Dimension.Rows, table.Columns["NumNodes"].Position + 1); + cfAddressNum = new ExcelAddress(REPORT_DETECTED_ENTITIES_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumNodes"].Position + 1, sheet.Dimension.Rows, table.Columns["NumNodes"].Position + 1); cfNum = sheet.ConditionalFormatting.AddDatabar(cfAddressNum, colorLightBlueForDatabars); - cfAddressNum = new ExcelAddress(REPORT_METRICS_ALL_ENTITIES_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumBackends"].Position + 1, sheet.Dimension.Rows, table.Columns["NumBackends"].Position + 1); + cfAddressNum = new ExcelAddress(REPORT_DETECTED_ENTITIES_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumBackends"].Position + 1, sheet.Dimension.Rows, table.Columns["NumBackends"].Position + 1); cfNum = sheet.ConditionalFormatting.AddDatabar(cfAddressNum, colorLightBlueForDatabars); - cfAddressNum = new ExcelAddress(REPORT_METRICS_ALL_ENTITIES_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumBTs"].Position + 1, sheet.Dimension.Rows, table.Columns["NumBTs"].Position + 1); + cfAddressNum = new ExcelAddress(REPORT_DETECTED_ENTITIES_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumBTs"].Position + 1, sheet.Dimension.Rows, table.Columns["NumBTs"].Position + 1); cfNum = sheet.ConditionalFormatting.AddDatabar(cfAddressNum, colorLightBlueForDatabars); - cfAddressNum = new ExcelAddress(REPORT_METRICS_ALL_ENTITIES_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumSEPs"].Position + 1, sheet.Dimension.Rows, table.Columns["NumSEPs"].Position + 1); + cfAddressNum = new ExcelAddress(REPORT_DETECTED_ENTITIES_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumSEPs"].Position + 1, sheet.Dimension.Rows, table.Columns["NumSEPs"].Position + 1); cfNum = sheet.ConditionalFormatting.AddDatabar(cfAddressNum, colorLightBlueForDatabars); - cfAddressNum = new ExcelAddress(REPORT_METRICS_ALL_ENTITIES_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumErrors"].Position + 1, sheet.Dimension.Rows, table.Columns["NumErrors"].Position + 1); + cfAddressNum = new ExcelAddress(REPORT_DETECTED_ENTITIES_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumErrors"].Position + 1, sheet.Dimension.Rows, table.Columns["NumErrors"].Position + 1); cfNum = sheet.ConditionalFormatting.AddDatabar(cfAddressNum, colorLightBlueForDatabars); - cfAddressNum = new ExcelAddress(REPORT_METRICS_ALL_ENTITIES_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumIPs"].Position + 1, sheet.Dimension.Rows, table.Columns["NumIPs"].Position + 1); + cfAddressNum = new ExcelAddress(REPORT_DETECTED_ENTITIES_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumIPs"].Position + 1, sheet.Dimension.Rows, table.Columns["NumIPs"].Position + 1); cfNum = sheet.ConditionalFormatting.AddDatabar(cfAddressNum, colorLightBlueForDatabars); } @@ -7250,16 +7363,16 @@ private static bool stepReportControlerApplicationsAndEntities(ProgramOptions pr adjustColumnsOfEntityRowTableInEntitiesReport(TIERS_TYPE_SHORT, sheet, table); - ExcelAddress cfAddressNum = new ExcelAddress(REPORT_METRICS_ALL_ENTITIES_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumNodes"].Position + 1, sheet.Dimension.Rows, table.Columns["NumNodes"].Position + 1); + ExcelAddress cfAddressNum = new ExcelAddress(REPORT_DETECTED_ENTITIES_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumNodes"].Position + 1, sheet.Dimension.Rows, table.Columns["NumNodes"].Position + 1); var cfNum = sheet.ConditionalFormatting.AddDatabar(cfAddressNum, colorLightBlueForDatabars); - cfAddressNum = new ExcelAddress(REPORT_METRICS_ALL_ENTITIES_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumBTs"].Position + 1, sheet.Dimension.Rows, table.Columns["NumBTs"].Position + 1); + cfAddressNum = new ExcelAddress(REPORT_DETECTED_ENTITIES_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumBTs"].Position + 1, sheet.Dimension.Rows, table.Columns["NumBTs"].Position + 1); cfNum = sheet.ConditionalFormatting.AddDatabar(cfAddressNum, colorLightBlueForDatabars); - cfAddressNum = new ExcelAddress(REPORT_METRICS_ALL_ENTITIES_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumSEPs"].Position + 1, sheet.Dimension.Rows, table.Columns["NumSEPs"].Position + 1); + cfAddressNum = new ExcelAddress(REPORT_DETECTED_ENTITIES_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumSEPs"].Position + 1, sheet.Dimension.Rows, table.Columns["NumSEPs"].Position + 1); cfNum = sheet.ConditionalFormatting.AddDatabar(cfAddressNum, colorLightBlueForDatabars); - cfAddressNum = new ExcelAddress(REPORT_METRICS_ALL_ENTITIES_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumErrors"].Position + 1, sheet.Dimension.Rows, table.Columns["NumErrors"].Position + 1); + cfAddressNum = new ExcelAddress(REPORT_DETECTED_ENTITIES_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumErrors"].Position + 1, sheet.Dimension.Rows, table.Columns["NumErrors"].Position + 1); cfNum = sheet.ConditionalFormatting.AddDatabar(cfAddressNum, colorLightBlueForDatabars); // Make pivot @@ -7855,7 +7968,7 @@ private static bool stepReportControllerAndApplicationConfiguration(ProgramOptio ApplicationID = jobTarget.ApplicationID, Status = jobTarget.Status.ToString() }, true); - ExcelTable table = sheet.Tables.Add(range, REPORT_DETECTED_ENTITIES_TABLE_PARAMETERS_TARGETS); + ExcelTable table = sheet.Tables.Add(range, REPORT_CONFIGURATION_TABLE_PARAMETERS_TARGETS); table.ShowHeader = true; table.TableStyle = TableStyles.Medium2; table.ShowFilter = true; @@ -7877,7 +7990,7 @@ private static bool stepReportControllerAndApplicationConfiguration(ProgramOptio #region Entity sheets and their associated pivots // Entity sheets - sheet = excelReport.Workbook.Worksheets.Add(REPORT_DETECTED_ENTITIES_SHEET_CONTROLLERS); + sheet = excelReport.Workbook.Worksheets.Add(REPORT_CONFIGURATION_SHEET_CONTROLLERS); sheet.Cells[1, 1].Value = "Table of Contents"; sheet.Cells[1, 2].Formula = String.Format(@"=HYPERLINK(""#'{0}'!A1"", """")", REPORT_SHEET_TOC); sheet.Cells[1, 2].StyleName = "HyperLinkStyle"; @@ -8118,8 +8231,8 @@ private static bool stepReportControllerAndApplicationConfiguration(ProgramOptio loggerConsole.Info("List of Controllers"); - sheet = excelReport.Workbook.Worksheets[REPORT_DETECTED_ENTITIES_SHEET_CONTROLLERS]; - readCSVFileIntoExcelRange(controllersAllReportFilePath, 0, sheet, REPORT_DETECTED_ENTITIES_LIST_SHEET_START_TABLE_AT, 1); + sheet = excelReport.Workbook.Worksheets[REPORT_CONFIGURATION_SHEET_CONTROLLERS]; + readCSVFileIntoExcelRange(controllersAllReportFilePath, 0, sheet, REPORT_CONFIGURATION_LIST_SHEET_START_TABLE_AT, 1); #endregion @@ -8128,7 +8241,7 @@ private static bool stepReportControllerAndApplicationConfiguration(ProgramOptio loggerConsole.Info("List of Controller Settings"); sheet = excelReport.Workbook.Worksheets[REPORT_CONFIGURATION_SHEET_CONTROLLER_SETTINGS]; - readCSVFileIntoExcelRange(controllerSettingsAllReportFilePath, 0, sheet, REPORT_DETECTED_ENTITIES_LIST_SHEET_START_TABLE_AT, 1); + readCSVFileIntoExcelRange(controllerSettingsAllReportFilePath, 0, sheet, REPORT_CONFIGURATION_LIST_SHEET_START_TABLE_AT, 1); #endregion @@ -8137,7 +8250,7 @@ private static bool stepReportControllerAndApplicationConfiguration(ProgramOptio loggerConsole.Info("List of Application Configuration"); sheet = excelReport.Workbook.Worksheets[REPORT_CONFIGURATION_SHEET_APPLICATION_CONFIGURATION]; - readCSVFileIntoExcelRange(applicationConfigurationAllReportFilePath, 0, sheet, REPORT_DETECTED_ENTITIES_LIST_SHEET_START_TABLE_AT, 1); + readCSVFileIntoExcelRange(applicationConfigurationAllReportFilePath, 0, sheet, REPORT_CONFIGURATION_LIST_SHEET_START_TABLE_AT, 1); #endregion @@ -8146,7 +8259,7 @@ private static bool stepReportControllerAndApplicationConfiguration(ProgramOptio loggerConsole.Info("List of Business Transaction Detection Rules"); sheet = excelReport.Workbook.Worksheets[REPORT_CONFIGURATION_SHEET_BUSINESS_TRANSACTION_DISCOVERY_RULES]; - readCSVFileIntoExcelRange(businessTransactionDiscoveryRulesAllReportFilePath, 0, sheet, REPORT_DETECTED_ENTITIES_LIST_SHEET_START_TABLE_AT, 1); + readCSVFileIntoExcelRange(businessTransactionDiscoveryRulesAllReportFilePath, 0, sheet, REPORT_CONFIGURATION_LIST_SHEET_START_TABLE_AT, 1); #endregion @@ -8155,7 +8268,7 @@ private static bool stepReportControllerAndApplicationConfiguration(ProgramOptio loggerConsole.Info("List of Business Transaction Entry Rules"); sheet = excelReport.Workbook.Worksheets[REPORT_CONFIGURATION_SHEET_BUSINESS_TRANSACTION_ENTRY_RULES]; - readCSVFileIntoExcelRange(businessTransactionEntryRulesAllReportFilePath, 0, sheet, REPORT_DETECTED_ENTITIES_LIST_SHEET_START_TABLE_AT, 1); + readCSVFileIntoExcelRange(businessTransactionEntryRulesAllReportFilePath, 0, sheet, REPORT_CONFIGURATION_LIST_SHEET_START_TABLE_AT, 1); #endregion @@ -8164,7 +8277,7 @@ private static bool stepReportControllerAndApplicationConfiguration(ProgramOptio loggerConsole.Info("List of Business Transaction Scopes"); sheet = excelReport.Workbook.Worksheets[REPORT_CONFIGURATION_SHEET_BUSINESS_TRANSACTION_SCOPES]; - readCSVFileIntoExcelRange(businessTransactionEntryScopesAllReportFilePath, 0, sheet, REPORT_DETECTED_ENTITIES_LIST_SHEET_START_TABLE_AT, 1); + readCSVFileIntoExcelRange(businessTransactionEntryScopesAllReportFilePath, 0, sheet, REPORT_CONFIGURATION_LIST_SHEET_START_TABLE_AT, 1); #endregion @@ -8173,7 +8286,7 @@ private static bool stepReportControllerAndApplicationConfiguration(ProgramOptio loggerConsole.Info("List of Business Transaction 2.0 Detection Rules"); sheet = excelReport.Workbook.Worksheets[REPORT_CONFIGURATION_SHEET_BUSINESS_TRANSACTION_DISCOVERY_RULES_20]; - readCSVFileIntoExcelRange(businessTransactionDiscoveryRules20AllReportFilePath, 0, sheet, REPORT_DETECTED_ENTITIES_LIST_SHEET_START_TABLE_AT, 1); + readCSVFileIntoExcelRange(businessTransactionDiscoveryRules20AllReportFilePath, 0, sheet, REPORT_CONFIGURATION_LIST_SHEET_START_TABLE_AT, 1); #endregion @@ -8182,7 +8295,7 @@ private static bool stepReportControllerAndApplicationConfiguration(ProgramOptio loggerConsole.Info("List of Business Transaction 2.0 Entry Rules"); sheet = excelReport.Workbook.Worksheets[REPORT_CONFIGURATION_SHEET_BUSINESS_TRANSACTION_ENTRY_RULES_20]; - readCSVFileIntoExcelRange(businessTransactionEntryRules20AllReportFilePath, 0, sheet, REPORT_DETECTED_ENTITIES_LIST_SHEET_START_TABLE_AT, 1); + readCSVFileIntoExcelRange(businessTransactionEntryRules20AllReportFilePath, 0, sheet, REPORT_CONFIGURATION_LIST_SHEET_START_TABLE_AT, 1); #endregion @@ -8191,7 +8304,7 @@ private static bool stepReportControllerAndApplicationConfiguration(ProgramOptio loggerConsole.Info("List of Backend Detection Rules"); sheet = excelReport.Workbook.Worksheets[REPORT_CONFIGURATION_SHEET_BACKEND_DISCOVERY_ENTRY_RULES]; - readCSVFileIntoExcelRange(backendDiscoveryRulesAllReportFilePath, 0, sheet, REPORT_DETECTED_ENTITIES_LIST_SHEET_START_TABLE_AT, 1); + readCSVFileIntoExcelRange(backendDiscoveryRulesAllReportFilePath, 0, sheet, REPORT_CONFIGURATION_LIST_SHEET_START_TABLE_AT, 1); #endregion @@ -8200,7 +8313,7 @@ private static bool stepReportControllerAndApplicationConfiguration(ProgramOptio loggerConsole.Info("List of Custom Exit Rules"); sheet = excelReport.Workbook.Worksheets[REPORT_CONFIGURATION_SHEET_CUSTOM_EXIT_RULES]; - readCSVFileIntoExcelRange(customExitRulesAllReportFilePath, 0, sheet, REPORT_DETECTED_ENTITIES_LIST_SHEET_START_TABLE_AT, 1); + readCSVFileIntoExcelRange(customExitRulesAllReportFilePath, 0, sheet, REPORT_CONFIGURATION_LIST_SHEET_START_TABLE_AT, 1); #endregion @@ -8209,7 +8322,7 @@ private static bool stepReportControllerAndApplicationConfiguration(ProgramOptio loggerConsole.Info("List of Information Point Rules"); sheet = excelReport.Workbook.Worksheets[REPORT_CONFIGURATION_SHEET_INFORMATION_POINT_RULES]; - readCSVFileIntoExcelRange(informationPointRulesAllReportFilePath, 0, sheet, REPORT_DETECTED_ENTITIES_LIST_SHEET_START_TABLE_AT, 1); + readCSVFileIntoExcelRange(informationPointRulesAllReportFilePath, 0, sheet, REPORT_CONFIGURATION_LIST_SHEET_START_TABLE_AT, 1); #endregion @@ -8218,7 +8331,7 @@ private static bool stepReportControllerAndApplicationConfiguration(ProgramOptio loggerConsole.Info("List of Agent Configuration Properties"); sheet = excelReport.Workbook.Worksheets[REPORT_CONFIGURATION_SHEET_AGENT_CONFIGURATION_PROPERTIES]; - readCSVFileIntoExcelRange(agentConfigurationPropertiesAllReportFilePath, 0, sheet, REPORT_DETECTED_ENTITIES_LIST_SHEET_START_TABLE_AT, 1); + readCSVFileIntoExcelRange(agentConfigurationPropertiesAllReportFilePath, 0, sheet, REPORT_CONFIGURATION_LIST_SHEET_START_TABLE_AT, 1); #endregion @@ -8227,12 +8340,12 @@ private static bool stepReportControllerAndApplicationConfiguration(ProgramOptio loggerConsole.Info("List of Method Invocation Data Collectors"); sheet = excelReport.Workbook.Worksheets[REPORT_CONFIGURATION_SHEET_METHOD_INVOCATION_DATA_COLLECTORS]; - readCSVFileIntoExcelRange(methodInvocationDataCollectorsAllReportFilePath, 0, sheet, REPORT_DETECTED_ENTITIES_LIST_SHEET_START_TABLE_AT, 1); + readCSVFileIntoExcelRange(methodInvocationDataCollectorsAllReportFilePath, 0, sheet, REPORT_CONFIGURATION_LIST_SHEET_START_TABLE_AT, 1); loggerConsole.Info("List of HTTP Data Collectors"); sheet = excelReport.Workbook.Worksheets[REPORT_CONFIGURATION_SHEET_HTTP_DATA_COLLECTORS]; - readCSVFileIntoExcelRange(httpDataCollectorsAllReportFilePath, 0, sheet, REPORT_DETECTED_ENTITIES_LIST_SHEET_START_TABLE_AT, 1); + readCSVFileIntoExcelRange(httpDataCollectorsAllReportFilePath, 0, sheet, REPORT_CONFIGURATION_LIST_SHEET_START_TABLE_AT, 1); #endregion @@ -8241,7 +8354,7 @@ private static bool stepReportControllerAndApplicationConfiguration(ProgramOptio loggerConsole.Info("List of Tier Settings"); sheet = excelReport.Workbook.Worksheets[REPORT_CONFIGURATION_SHEET_TIER_SETTINGS]; - readCSVFileIntoExcelRange(entityTierConfigurationsAllReportFilePath, 0, sheet, REPORT_DETECTED_ENTITIES_LIST_SHEET_START_TABLE_AT, 1); + readCSVFileIntoExcelRange(entityTierConfigurationsAllReportFilePath, 0, sheet, REPORT_CONFIGURATION_LIST_SHEET_START_TABLE_AT, 1); #endregion @@ -8250,7 +8363,7 @@ private static bool stepReportControllerAndApplicationConfiguration(ProgramOptio loggerConsole.Info("List of Detected Business Transaction and Assigned Data Collectors"); sheet = excelReport.Workbook.Worksheets[REPORT_CONFIGURATION_SHEET_BUSINESS_TRANSACTION_SETTINGS]; - readCSVFileIntoExcelRange(entityBusinessTransactionConfigurationsAllReportFilePath, 0, sheet, REPORT_DETECTED_ENTITIES_LIST_SHEET_START_TABLE_AT, 1); + readCSVFileIntoExcelRange(entityBusinessTransactionConfigurationsAllReportFilePath, 0, sheet, REPORT_CONFIGURATION_LIST_SHEET_START_TABLE_AT, 1); #endregion @@ -8259,7 +8372,7 @@ private static bool stepReportControllerAndApplicationConfiguration(ProgramOptio loggerConsole.Info("List of Agent Call Graph Settings"); sheet = excelReport.Workbook.Worksheets[REPORT_CONFIGURATION_SHEET_AGENT_CALL_GRAPH_SETTINGS]; - readCSVFileIntoExcelRange(agentCallGraphSettingsAllReportFilePath, 0, sheet, REPORT_DETECTED_ENTITIES_LIST_SHEET_START_TABLE_AT, 1); + readCSVFileIntoExcelRange(agentCallGraphSettingsAllReportFilePath, 0, sheet, REPORT_CONFIGURATION_LIST_SHEET_START_TABLE_AT, 1); #endregion @@ -8268,7 +8381,7 @@ private static bool stepReportControllerAndApplicationConfiguration(ProgramOptio loggerConsole.Info("List of Health Rules"); sheet = excelReport.Workbook.Worksheets[REPORT_CONFIGURATION_SHEET_HEALTH_RULES]; - readCSVFileIntoExcelRange(healthRulesAllReportFilePath, 0, sheet, REPORT_DETECTED_ENTITIES_LIST_SHEET_START_TABLE_AT, 1); + readCSVFileIntoExcelRange(healthRulesAllReportFilePath, 0, sheet, REPORT_CONFIGURATION_LIST_SHEET_START_TABLE_AT, 1); #endregion @@ -8277,7 +8390,7 @@ private static bool stepReportControllerAndApplicationConfiguration(ProgramOptio #region Controllers sheet // Make table - sheet = excelReport.Workbook.Worksheets[REPORT_DETECTED_ENTITIES_SHEET_CONTROLLERS]; + sheet = excelReport.Workbook.Worksheets[REPORT_CONFIGURATION_SHEET_CONTROLLERS]; logger.Info("Controllers Sheet ({0} rows)", sheet.Dimension.Rows); loggerConsole.Info("Controllers Sheet ({0} rows)", sheet.Dimension.Rows); if (sheet.Dimension.Rows > REPORT_CONFIGURATION_LIST_SHEET_START_TABLE_AT) @@ -8336,62 +8449,62 @@ private static bool stepReportControllerAndApplicationConfiguration(ProgramOptio sheet.Column(table.Columns["Controller"].Position + 1).Width = 20; sheet.Column(table.Columns["ApplicationName"].Position + 1).Width = 20; - ExcelAddress cfAddressNum = new ExcelAddress(REPORT_METRICS_ALL_ENTITIES_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumBTDiscoveryRules"].Position + 1, sheet.Dimension.Rows, table.Columns["NumBTDiscoveryRules"].Position + 1); + ExcelAddress cfAddressNum = new ExcelAddress(REPORT_CONFIGURATION_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumBTDiscoveryRules"].Position + 1, sheet.Dimension.Rows, table.Columns["NumBTDiscoveryRules"].Position + 1); var cfNum = sheet.ConditionalFormatting.AddDatabar(cfAddressNum, colorLightBlueForDatabars); - cfAddressNum = new ExcelAddress(REPORT_METRICS_ALL_ENTITIES_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumBTEntryRules"].Position + 1, sheet.Dimension.Rows, table.Columns["NumBTEntryRules"].Position + 1); + cfAddressNum = new ExcelAddress(REPORT_CONFIGURATION_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumBTEntryRules"].Position + 1, sheet.Dimension.Rows, table.Columns["NumBTEntryRules"].Position + 1); cfNum = sheet.ConditionalFormatting.AddDatabar(cfAddressNum, colorLightBlueForDatabars); - cfAddressNum = new ExcelAddress(REPORT_METRICS_ALL_ENTITIES_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumBTExcludeRules"].Position + 1, sheet.Dimension.Rows, table.Columns["NumBTExcludeRules"].Position + 1); + cfAddressNum = new ExcelAddress(REPORT_CONFIGURATION_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumBTExcludeRules"].Position + 1, sheet.Dimension.Rows, table.Columns["NumBTExcludeRules"].Position + 1); cfNum = sheet.ConditionalFormatting.AddDatabar(cfAddressNum, colorLightBlueForDatabars); - cfAddressNum = new ExcelAddress(REPORT_METRICS_ALL_ENTITIES_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumBT20Scopes"].Position + 1, sheet.Dimension.Rows, table.Columns["NumBT20Scopes"].Position + 1); + cfAddressNum = new ExcelAddress(REPORT_CONFIGURATION_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumBT20Scopes"].Position + 1, sheet.Dimension.Rows, table.Columns["NumBT20Scopes"].Position + 1); cfNum = sheet.ConditionalFormatting.AddDatabar(cfAddressNum, colorLightBlueForDatabars); - cfAddressNum = new ExcelAddress(REPORT_METRICS_ALL_ENTITIES_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumBT20DiscoveryRules"].Position + 1, sheet.Dimension.Rows, table.Columns["NumBT20DiscoveryRules"].Position + 1); + cfAddressNum = new ExcelAddress(REPORT_CONFIGURATION_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumBT20DiscoveryRules"].Position + 1, sheet.Dimension.Rows, table.Columns["NumBT20DiscoveryRules"].Position + 1); cfNum = sheet.ConditionalFormatting.AddDatabar(cfAddressNum, colorLightBlueForDatabars); - cfAddressNum = new ExcelAddress(REPORT_METRICS_ALL_ENTITIES_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumBT20EntryRules"].Position + 1, sheet.Dimension.Rows, table.Columns["NumBT20EntryRules"].Position + 1); + cfAddressNum = new ExcelAddress(REPORT_CONFIGURATION_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumBT20EntryRules"].Position + 1, sheet.Dimension.Rows, table.Columns["NumBT20EntryRules"].Position + 1); cfNum = sheet.ConditionalFormatting.AddDatabar(cfAddressNum, colorLightBlueForDatabars); - cfAddressNum = new ExcelAddress(REPORT_METRICS_ALL_ENTITIES_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumBT20ExcludeRules"].Position + 1, sheet.Dimension.Rows, table.Columns["NumBT20ExcludeRules"].Position + 1); + cfAddressNum = new ExcelAddress(REPORT_CONFIGURATION_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumBT20ExcludeRules"].Position + 1, sheet.Dimension.Rows, table.Columns["NumBT20ExcludeRules"].Position + 1); cfNum = sheet.ConditionalFormatting.AddDatabar(cfAddressNum, colorLightBlueForDatabars); - cfAddressNum = new ExcelAddress(REPORT_METRICS_ALL_ENTITIES_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumBackendRules"].Position + 1, sheet.Dimension.Rows, table.Columns["NumBackendRules"].Position + 1); + cfAddressNum = new ExcelAddress(REPORT_CONFIGURATION_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumBackendRules"].Position + 1, sheet.Dimension.Rows, table.Columns["NumBackendRules"].Position + 1); cfNum = sheet.ConditionalFormatting.AddDatabar(cfAddressNum, colorLightBlueForDatabars); - cfAddressNum = new ExcelAddress(REPORT_METRICS_ALL_ENTITIES_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumInfoPointRules"].Position + 1, sheet.Dimension.Rows, table.Columns["NumInfoPointRules"].Position + 1); + cfAddressNum = new ExcelAddress(REPORT_CONFIGURATION_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumInfoPointRules"].Position + 1, sheet.Dimension.Rows, table.Columns["NumInfoPointRules"].Position + 1); cfNum = sheet.ConditionalFormatting.AddDatabar(cfAddressNum, colorLightBlueForDatabars); - cfAddressNum = new ExcelAddress(REPORT_METRICS_ALL_ENTITIES_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumAgentProps"].Position + 1, sheet.Dimension.Rows, table.Columns["NumAgentProps"].Position + 1); + cfAddressNum = new ExcelAddress(REPORT_CONFIGURATION_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumAgentProps"].Position + 1, sheet.Dimension.Rows, table.Columns["NumAgentProps"].Position + 1); cfNum = sheet.ConditionalFormatting.AddDatabar(cfAddressNum, colorLightBlueForDatabars); - cfAddressNum = new ExcelAddress(REPORT_METRICS_ALL_ENTITIES_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumHealthRules"].Position + 1, sheet.Dimension.Rows, table.Columns["NumHealthRules"].Position + 1); + cfAddressNum = new ExcelAddress(REPORT_CONFIGURATION_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumHealthRules"].Position + 1, sheet.Dimension.Rows, table.Columns["NumHealthRules"].Position + 1); cfNum = sheet.ConditionalFormatting.AddDatabar(cfAddressNum, colorLightBlueForDatabars); - cfAddressNum = new ExcelAddress(REPORT_METRICS_ALL_ENTITIES_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumErrorRules"].Position + 1, sheet.Dimension.Rows, table.Columns["NumErrorRules"].Position + 1); + cfAddressNum = new ExcelAddress(REPORT_CONFIGURATION_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumErrorRules"].Position + 1, sheet.Dimension.Rows, table.Columns["NumErrorRules"].Position + 1); cfNum = sheet.ConditionalFormatting.AddDatabar(cfAddressNum, colorLightBlueForDatabars); - cfAddressNum = new ExcelAddress(REPORT_METRICS_ALL_ENTITIES_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumHTTPDCVariablesCollected"].Position + 1, sheet.Dimension.Rows, table.Columns["NumHTTPDCVariablesCollected"].Position + 1); + cfAddressNum = new ExcelAddress(REPORT_CONFIGURATION_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumHTTPDCVariablesCollected"].Position + 1, sheet.Dimension.Rows, table.Columns["NumHTTPDCVariablesCollected"].Position + 1); cfNum = sheet.ConditionalFormatting.AddDatabar(cfAddressNum, colorLightBlueForDatabars); - cfAddressNum = new ExcelAddress(REPORT_METRICS_ALL_ENTITIES_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumHTTPDCs"].Position + 1, sheet.Dimension.Rows, table.Columns["NumHTTPDCs"].Position + 1); + cfAddressNum = new ExcelAddress(REPORT_CONFIGURATION_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumHTTPDCs"].Position + 1, sheet.Dimension.Rows, table.Columns["NumHTTPDCs"].Position + 1); cfNum = sheet.ConditionalFormatting.AddDatabar(cfAddressNum, colorLightBlueForDatabars); - cfAddressNum = new ExcelAddress(REPORT_METRICS_ALL_ENTITIES_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumMIDCVariablesCollected"].Position + 1, sheet.Dimension.Rows, table.Columns["NumMIDCVariablesCollected"].Position + 1); + cfAddressNum = new ExcelAddress(REPORT_CONFIGURATION_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumMIDCVariablesCollected"].Position + 1, sheet.Dimension.Rows, table.Columns["NumMIDCVariablesCollected"].Position + 1); cfNum = sheet.ConditionalFormatting.AddDatabar(cfAddressNum, colorLightBlueForDatabars); - cfAddressNum = new ExcelAddress(REPORT_METRICS_ALL_ENTITIES_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumMIDCs"].Position + 1, sheet.Dimension.Rows, table.Columns["NumMIDCs"].Position + 1); + cfAddressNum = new ExcelAddress(REPORT_CONFIGURATION_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumMIDCs"].Position + 1, sheet.Dimension.Rows, table.Columns["NumMIDCs"].Position + 1); cfNum = sheet.ConditionalFormatting.AddDatabar(cfAddressNum, colorLightBlueForDatabars); - cfAddressNum = new ExcelAddress(REPORT_METRICS_ALL_ENTITIES_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumBaselines"].Position + 1, sheet.Dimension.Rows, table.Columns["NumBaselines"].Position + 1); + cfAddressNum = new ExcelAddress(REPORT_CONFIGURATION_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumBaselines"].Position + 1, sheet.Dimension.Rows, table.Columns["NumBaselines"].Position + 1); cfNum = sheet.ConditionalFormatting.AddDatabar(cfAddressNum, colorLightBlueForDatabars); - cfAddressNum = new ExcelAddress(REPORT_METRICS_ALL_ENTITIES_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumTiers"].Position + 1, sheet.Dimension.Rows, table.Columns["NumTiers"].Position + 1); + cfAddressNum = new ExcelAddress(REPORT_CONFIGURATION_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumTiers"].Position + 1, sheet.Dimension.Rows, table.Columns["NumTiers"].Position + 1); cfNum = sheet.ConditionalFormatting.AddDatabar(cfAddressNum, colorLightBlueForDatabars); - cfAddressNum = new ExcelAddress(REPORT_METRICS_ALL_ENTITIES_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumBTs"].Position + 1, sheet.Dimension.Rows, table.Columns["NumBTs"].Position + 1); + cfAddressNum = new ExcelAddress(REPORT_CONFIGURATION_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumBTs"].Position + 1, sheet.Dimension.Rows, table.Columns["NumBTs"].Position + 1); cfNum = sheet.ConditionalFormatting.AddDatabar(cfAddressNum, colorLightBlueForDatabars); } @@ -9348,8 +9461,8 @@ private static bool stepReportApplicationAndEntityMetrics(ProgramOptions program loggerConsole.Info("List of Controllers"); - sheet = excelReport.Workbook.Worksheets[REPORT_DETECTED_ENTITIES_SHEET_CONTROLLERS]; - readCSVFileIntoExcelRange(controllersAllReportFilePath, 0, sheet, REPORT_DETECTED_ENTITIES_LIST_SHEET_START_TABLE_AT, 1); + sheet = excelReport.Workbook.Worksheets[REPORT_METRICS_ALL_ENTITIES_SHEET_CONTROLLERS]; + readCSVFileIntoExcelRange(controllersAllReportFilePath, 0, sheet, REPORT_METRICS_ALL_ENTITIES_LIST_SHEET_START_TABLE_AT, 1); #endregion @@ -9358,12 +9471,12 @@ private static bool stepReportApplicationAndEntityMetrics(ProgramOptions program loggerConsole.Info("List of Applications (Full)"); sheet = excelReport.Workbook.Worksheets[REPORT_METRICS_ALL_ENTITIES_SHEET_APPLICATIONS_FULL]; - readCSVFileIntoExcelRange(applicationsAllFullReportFilePath, 0, sheet, REPORT_DETECTED_ENTITIES_LIST_SHEET_START_TABLE_AT, 1); + readCSVFileIntoExcelRange(applicationsAllFullReportFilePath, 0, sheet, REPORT_METRICS_ALL_ENTITIES_LIST_SHEET_START_TABLE_AT, 1); loggerConsole.Info("List of Applications (Hourly)"); sheet = excelReport.Workbook.Worksheets[REPORT_METRICS_ALL_ENTITIES_SHEET_APPLICATIONS_HOURLY]; - readCSVFileIntoExcelRange(applicationsAllHourlyReportFilePath, 0, sheet, REPORT_DETECTED_ENTITIES_LIST_SHEET_START_TABLE_AT, 1); + readCSVFileIntoExcelRange(applicationsAllHourlyReportFilePath, 0, sheet, REPORT_METRICS_ALL_ENTITIES_LIST_SHEET_START_TABLE_AT, 1); #endregion @@ -9372,12 +9485,12 @@ private static bool stepReportApplicationAndEntityMetrics(ProgramOptions program loggerConsole.Info("List of Tiers (Full)"); sheet = excelReport.Workbook.Worksheets[REPORT_METRICS_ALL_ENTITIES_SHEET_TIERS_FULL]; - readCSVFileIntoExcelRange(tiersAllFullReportFilePath, 0, sheet, REPORT_DETECTED_ENTITIES_LIST_SHEET_START_TABLE_AT, 1); + readCSVFileIntoExcelRange(tiersAllFullReportFilePath, 0, sheet, REPORT_METRICS_ALL_ENTITIES_LIST_SHEET_START_TABLE_AT, 1); loggerConsole.Info("List of Tiers (Hourly)"); sheet = excelReport.Workbook.Worksheets[REPORT_METRICS_ALL_ENTITIES_SHEET_TIERS_HOURLY]; - readCSVFileIntoExcelRange(tiersAllHourlyReportFilePath, 0, sheet, REPORT_DETECTED_ENTITIES_LIST_SHEET_START_TABLE_AT, 1); + readCSVFileIntoExcelRange(tiersAllHourlyReportFilePath, 0, sheet, REPORT_METRICS_ALL_ENTITIES_LIST_SHEET_START_TABLE_AT, 1); #endregion @@ -9386,12 +9499,12 @@ private static bool stepReportApplicationAndEntityMetrics(ProgramOptions program loggerConsole.Info("List of Nodes (Full)"); sheet = excelReport.Workbook.Worksheets[REPORT_METRICS_ALL_ENTITIES_SHEET_NODES_FULL]; - readCSVFileIntoExcelRange(nodesAllFullReportFilePath, 0, sheet, REPORT_DETECTED_ENTITIES_LIST_SHEET_START_TABLE_AT, 1); + readCSVFileIntoExcelRange(nodesAllFullReportFilePath, 0, sheet, REPORT_METRICS_ALL_ENTITIES_LIST_SHEET_START_TABLE_AT, 1); loggerConsole.Info("List of Nodes (Hourly)"); sheet = excelReport.Workbook.Worksheets[REPORT_METRICS_ALL_ENTITIES_SHEET_NODES_HOURLY]; - readCSVFileIntoExcelRange(nodesAllHourlyReportFilePath, 0, sheet, REPORT_DETECTED_ENTITIES_LIST_SHEET_START_TABLE_AT, 1); + readCSVFileIntoExcelRange(nodesAllHourlyReportFilePath, 0, sheet, REPORT_METRICS_ALL_ENTITIES_LIST_SHEET_START_TABLE_AT, 1); #endregion @@ -9400,12 +9513,12 @@ private static bool stepReportApplicationAndEntityMetrics(ProgramOptions program loggerConsole.Info("List of Backends (Full)"); sheet = excelReport.Workbook.Worksheets[REPORT_METRICS_ALL_ENTITIES_SHEET_BACKENDS_FULL]; - readCSVFileIntoExcelRange(backendsAllFullReportFilePath, 0, sheet, REPORT_DETECTED_ENTITIES_LIST_SHEET_START_TABLE_AT, 1); + readCSVFileIntoExcelRange(backendsAllFullReportFilePath, 0, sheet, REPORT_METRICS_ALL_ENTITIES_LIST_SHEET_START_TABLE_AT, 1); loggerConsole.Info("List of Backends (Hourly)"); sheet = excelReport.Workbook.Worksheets[REPORT_METRICS_ALL_ENTITIES_SHEET_BACKENDS_HOURLY]; - readCSVFileIntoExcelRange(backendsAllHourlyReportFilePath, 0, sheet, REPORT_DETECTED_ENTITIES_LIST_SHEET_START_TABLE_AT, 1); + readCSVFileIntoExcelRange(backendsAllHourlyReportFilePath, 0, sheet, REPORT_METRICS_ALL_ENTITIES_LIST_SHEET_START_TABLE_AT, 1); #endregion @@ -9414,12 +9527,12 @@ private static bool stepReportApplicationAndEntityMetrics(ProgramOptions program loggerConsole.Info("List of Business Transactions (Full)"); sheet = excelReport.Workbook.Worksheets[REPORT_METRICS_ALL_ENTITIES_SHEET_BUSINESS_TRANSACTIONS_FULL]; - readCSVFileIntoExcelRange(businessTransactionsAllFullReportFilePath, 0, sheet, REPORT_DETECTED_ENTITIES_LIST_SHEET_START_TABLE_AT, 1); + readCSVFileIntoExcelRange(businessTransactionsAllFullReportFilePath, 0, sheet, REPORT_METRICS_ALL_ENTITIES_LIST_SHEET_START_TABLE_AT, 1); loggerConsole.Info("List of Business Transactions (Hourly)"); sheet = excelReport.Workbook.Worksheets[REPORT_METRICS_ALL_ENTITIES_SHEET_BUSINESS_TRANSACTIONS_HOURLY]; - readCSVFileIntoExcelRange(businessTransactionsAllHourlyReportFilePath, 0, sheet, REPORT_DETECTED_ENTITIES_LIST_SHEET_START_TABLE_AT, 1); + readCSVFileIntoExcelRange(businessTransactionsAllHourlyReportFilePath, 0, sheet, REPORT_METRICS_ALL_ENTITIES_LIST_SHEET_START_TABLE_AT, 1); #endregion @@ -9428,12 +9541,12 @@ private static bool stepReportApplicationAndEntityMetrics(ProgramOptions program loggerConsole.Info("List of Service Endpoints (Full)"); sheet = excelReport.Workbook.Worksheets[REPORT_METRICS_ALL_ENTITIES_SHEET_SERVICE_ENDPOINTS_FULL]; - readCSVFileIntoExcelRange(serviceEndpointsAllFullReportFilePath, 0, sheet, REPORT_DETECTED_ENTITIES_LIST_SHEET_START_TABLE_AT, 1); + readCSVFileIntoExcelRange(serviceEndpointsAllFullReportFilePath, 0, sheet, REPORT_METRICS_ALL_ENTITIES_LIST_SHEET_START_TABLE_AT, 1); loggerConsole.Info("List of Service Endpoints (Hourly)"); sheet = excelReport.Workbook.Worksheets[REPORT_METRICS_ALL_ENTITIES_SHEET_SERVICE_ENDPOINTS_HOURLY]; - readCSVFileIntoExcelRange(serviceEndpointsAllHourlyReportFilePath, 0, sheet, REPORT_DETECTED_ENTITIES_LIST_SHEET_START_TABLE_AT, 1); + readCSVFileIntoExcelRange(serviceEndpointsAllHourlyReportFilePath, 0, sheet, REPORT_METRICS_ALL_ENTITIES_LIST_SHEET_START_TABLE_AT, 1); #endregion @@ -9442,12 +9555,12 @@ private static bool stepReportApplicationAndEntityMetrics(ProgramOptions program loggerConsole.Info("List of Errors (Full)"); sheet = excelReport.Workbook.Worksheets[REPORT_METRICS_ALL_ENTITIES_SHEET_ERRORS_FULL]; - readCSVFileIntoExcelRange(errorsAllFullReportFilePath, 0, sheet, REPORT_DETECTED_ENTITIES_LIST_SHEET_START_TABLE_AT, 1); + readCSVFileIntoExcelRange(errorsAllFullReportFilePath, 0, sheet, REPORT_METRICS_ALL_ENTITIES_LIST_SHEET_START_TABLE_AT, 1); loggerConsole.Info("List of Errors (Hourly)"); sheet = excelReport.Workbook.Worksheets[REPORT_METRICS_ALL_ENTITIES_SHEET_ERRORS_HOURLY]; - readCSVFileIntoExcelRange(errorsAllHourlyReportFilePath, 0, sheet, REPORT_DETECTED_ENTITIES_LIST_SHEET_START_TABLE_AT, 1); + readCSVFileIntoExcelRange(errorsAllHourlyReportFilePath, 0, sheet, REPORT_METRICS_ALL_ENTITIES_LIST_SHEET_START_TABLE_AT, 1); #endregion @@ -9456,12 +9569,12 @@ private static bool stepReportApplicationAndEntityMetrics(ProgramOptions program loggerConsole.Info("List of Information Points (Full)"); sheet = excelReport.Workbook.Worksheets[REPORT_METRICS_ALL_ENTITIES_SHEET_INFORMATION_POINTS_FULL]; - readCSVFileIntoExcelRange(informationPointsAllFullReportFilePath, 0, sheet, REPORT_DETECTED_ENTITIES_LIST_SHEET_START_TABLE_AT, 1); + readCSVFileIntoExcelRange(informationPointsAllFullReportFilePath, 0, sheet, REPORT_METRICS_ALL_ENTITIES_LIST_SHEET_START_TABLE_AT, 1); loggerConsole.Info("List of Information Points (Hourly)"); sheet = excelReport.Workbook.Worksheets[REPORT_METRICS_ALL_ENTITIES_SHEET_INFORMATION_POINTS_HOURLY]; - readCSVFileIntoExcelRange(informationPointsAllHourlyReportFilePath, 0, sheet, REPORT_DETECTED_ENTITIES_LIST_SHEET_START_TABLE_AT, 1); + readCSVFileIntoExcelRange(informationPointsAllHourlyReportFilePath, 0, sheet, REPORT_METRICS_ALL_ENTITIES_LIST_SHEET_START_TABLE_AT, 1); #endregion @@ -10387,7 +10500,7 @@ private static bool stepReportEventsAndHealthRuleViolations(ProgramOptions progr ApplicationID = jobTarget.ApplicationID, Status = jobTarget.Status.ToString() }, true); - ExcelTable table = sheet.Tables.Add(range, REPORT_DETECTED_ENTITIES_TABLE_PARAMETERS_TARGETS); + ExcelTable table = sheet.Tables.Add(range, REPORT_DETECTED_EVENTS_TABLE_PARAMETERS_TARGETS); table.ShowHeader = true; table.TableStyle = TableStyles.Medium2; table.ShowFilter = true; @@ -10413,7 +10526,7 @@ private static bool stepReportEventsAndHealthRuleViolations(ProgramOptions progr sheet.Cells[1, 1].Value = "Table of Contents"; sheet.Cells[1, 2].Formula = String.Format(@"=HYPERLINK(""#'{0}'!A1"", """")", REPORT_SHEET_TOC); sheet.Cells[1, 2].StyleName = "HyperLinkStyle"; - sheet.View.FreezePanes(REPORT_METRICS_ALL_ENTITIES_LIST_SHEET_START_TABLE_AT + 1, 1); + sheet.View.FreezePanes(REPORT_DETECTED_EVENTS_LIST_SHEET_START_TABLE_AT + 1, 1); sheet = excelReport.Workbook.Worksheets.Add(REPORT_DETECTED_EVENTS_SHEET_APPLICATIONS); sheet.Cells[1, 1].Value = "Table of Contents"; @@ -10480,8 +10593,8 @@ private static bool stepReportEventsAndHealthRuleViolations(ProgramOptions progr loggerConsole.Info("List of Controllers"); - sheet = excelReport.Workbook.Worksheets[REPORT_DETECTED_ENTITIES_SHEET_CONTROLLERS]; - readCSVFileIntoExcelRange(controllersAllReportFilePath, 0, sheet, REPORT_DETECTED_ENTITIES_LIST_SHEET_START_TABLE_AT, 1); + sheet = excelReport.Workbook.Worksheets[REPORT_DETECTED_EVENTS_SHEET_CONTROLLERS]; + readCSVFileIntoExcelRange(controllersAllReportFilePath, 0, sheet, REPORT_DETECTED_EVENTS_LIST_SHEET_START_TABLE_AT, 1); #endregion @@ -10490,7 +10603,7 @@ private static bool stepReportEventsAndHealthRuleViolations(ProgramOptions progr loggerConsole.Info("List of Applications"); sheet = excelReport.Workbook.Worksheets[REPORT_DETECTED_EVENTS_SHEET_APPLICATIONS]; - readCSVFileIntoExcelRange(applicationEventsSummaryAllReportFilePath, 0, sheet, REPORT_DETECTED_ENTITIES_LIST_SHEET_START_TABLE_AT, 1); + readCSVFileIntoExcelRange(applicationEventsSummaryAllReportFilePath, 0, sheet, REPORT_DETECTED_EVENTS_LIST_SHEET_START_TABLE_AT, 1); #endregion @@ -10499,7 +10612,7 @@ private static bool stepReportEventsAndHealthRuleViolations(ProgramOptions progr loggerConsole.Info("List of Events"); sheet = excelReport.Workbook.Worksheets[REPORT_DETECTED_EVENTS_SHEET_EVENTS]; - readCSVFileIntoExcelRange(eventsAllReportFilePath, 0, sheet, REPORT_DETECTED_ENTITIES_LIST_SHEET_START_TABLE_AT, 1); + readCSVFileIntoExcelRange(eventsAllReportFilePath, 0, sheet, REPORT_DETECTED_EVENTS_LIST_SHEET_START_TABLE_AT, 1); #endregion @@ -10508,7 +10621,7 @@ private static bool stepReportEventsAndHealthRuleViolations(ProgramOptions progr loggerConsole.Info("List of Health Rule Violation Events"); sheet = excelReport.Workbook.Worksheets[REPORT_DETECTED_EVENTS_SHEET_HEALTH_RULE_VIOLATIONS]; - readCSVFileIntoExcelRange(healthRuleViolationEventsAllReportFilePath, 0, sheet, REPORT_DETECTED_ENTITIES_LIST_SHEET_START_TABLE_AT, 1); + readCSVFileIntoExcelRange(healthRuleViolationEventsAllReportFilePath, 0, sheet, REPORT_DETECTED_EVENTS_LIST_SHEET_START_TABLE_AT, 1); #endregion @@ -10541,9 +10654,9 @@ private static bool stepReportEventsAndHealthRuleViolations(ProgramOptions progr sheet = excelReport.Workbook.Worksheets[REPORT_DETECTED_EVENTS_SHEET_APPLICATIONS]; logger.Info("Applications Sheet ({0} rows)", sheet.Dimension.Rows); loggerConsole.Info("Applications Sheet ({0} rows)", sheet.Dimension.Rows); - if (sheet.Dimension.Rows > REPORT_METRICS_ALL_ENTITIES_LIST_SHEET_START_TABLE_AT) + if (sheet.Dimension.Rows > REPORT_DETECTED_EVENTS_LIST_SHEET_START_TABLE_AT) { - range = sheet.Cells[REPORT_METRICS_ALL_ENTITIES_LIST_SHEET_START_TABLE_AT, 1, sheet.Dimension.Rows, sheet.Dimension.Columns]; + range = sheet.Cells[REPORT_DETECTED_EVENTS_LIST_SHEET_START_TABLE_AT, 1, sheet.Dimension.Rows, sheet.Dimension.Columns]; table = sheet.Tables.Add(range, REPORT_DETECTED_EVENTS_TABLE_APPLICATIONS); table.ShowHeader = true; table.TableStyle = TableStyles.Medium2; @@ -10552,25 +10665,25 @@ private static bool stepReportEventsAndHealthRuleViolations(ProgramOptions progr adjustColumnsOfEntityRowTableInMetricReport(APPLICATION_TYPE_SHORT, sheet, table); - ExcelAddress cfAddressNum = new ExcelAddress(REPORT_METRICS_ALL_ENTITIES_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumEvents"].Position + 1, sheet.Dimension.Rows, table.Columns["NumEvents"].Position + 1); + ExcelAddress cfAddressNum = new ExcelAddress(REPORT_DETECTED_EVENTS_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumEvents"].Position + 1, sheet.Dimension.Rows, table.Columns["NumEvents"].Position + 1); var cfNum = sheet.ConditionalFormatting.AddDatabar(cfAddressNum, colorLightBlueForDatabars); - cfAddressNum = new ExcelAddress(REPORT_METRICS_ALL_ENTITIES_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumEventsInfo"].Position + 1, sheet.Dimension.Rows, table.Columns["NumEventsInfo"].Position + 1); + cfAddressNum = new ExcelAddress(REPORT_DETECTED_EVENTS_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumEventsInfo"].Position + 1, sheet.Dimension.Rows, table.Columns["NumEventsInfo"].Position + 1); cfNum = sheet.ConditionalFormatting.AddDatabar(cfAddressNum, colorLightBlueForDatabars); - cfAddressNum = new ExcelAddress(REPORT_METRICS_ALL_ENTITIES_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumEventsWarning"].Position + 1, sheet.Dimension.Rows, table.Columns["NumEventsWarning"].Position + 1); + cfAddressNum = new ExcelAddress(REPORT_DETECTED_EVENTS_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumEventsWarning"].Position + 1, sheet.Dimension.Rows, table.Columns["NumEventsWarning"].Position + 1); cfNum = sheet.ConditionalFormatting.AddDatabar(cfAddressNum, colorLightBlueForDatabars); - cfAddressNum = new ExcelAddress(REPORT_METRICS_ALL_ENTITIES_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumEventsError"].Position + 1, sheet.Dimension.Rows, table.Columns["NumEventsError"].Position + 1); + cfAddressNum = new ExcelAddress(REPORT_DETECTED_EVENTS_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumEventsError"].Position + 1, sheet.Dimension.Rows, table.Columns["NumEventsError"].Position + 1); cfNum = sheet.ConditionalFormatting.AddDatabar(cfAddressNum, colorLightBlueForDatabars); - cfAddressNum = new ExcelAddress(REPORT_METRICS_ALL_ENTITIES_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumHRViolations"].Position + 1, sheet.Dimension.Rows, table.Columns["NumHRViolations"].Position + 1); + cfAddressNum = new ExcelAddress(REPORT_DETECTED_EVENTS_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumHRViolations"].Position + 1, sheet.Dimension.Rows, table.Columns["NumHRViolations"].Position + 1); cfNum = sheet.ConditionalFormatting.AddDatabar(cfAddressNum, colorLightBlueForDatabars); - cfAddressNum = new ExcelAddress(REPORT_METRICS_ALL_ENTITIES_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumHRViolationsWarning"].Position + 1, sheet.Dimension.Rows, table.Columns["NumHRViolationsWarning"].Position + 1); + cfAddressNum = new ExcelAddress(REPORT_DETECTED_EVENTS_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumHRViolationsWarning"].Position + 1, sheet.Dimension.Rows, table.Columns["NumHRViolationsWarning"].Position + 1); cfNum = sheet.ConditionalFormatting.AddDatabar(cfAddressNum, colorLightBlueForDatabars); - cfAddressNum = new ExcelAddress(REPORT_METRICS_ALL_ENTITIES_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumHRViolationsCritical"].Position + 1, sheet.Dimension.Rows, table.Columns["NumHRViolationsCritical"].Position + 1); + cfAddressNum = new ExcelAddress(REPORT_DETECTED_EVENTS_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumHRViolationsCritical"].Position + 1, sheet.Dimension.Rows, table.Columns["NumHRViolationsCritical"].Position + 1); cfNum = sheet.ConditionalFormatting.AddDatabar(cfAddressNum, colorLightBlueForDatabars); } @@ -10720,7 +10833,7 @@ private static bool stepReportEventsAndHealthRuleViolations(ProgramOptions progr } } range = sheet.Cells[1, 1, sheet.Dimension.Rows, sheet.Dimension.Columns]; - table = sheet.Tables.Add(range, REPORT_DETECTED_ENTITIES_TABLE_TOC); + table = sheet.Tables.Add(range, REPORT_DETECTED_EVENTS_TABLE_TOC); table.ShowHeader = true; table.TableStyle = TableStyles.Medium2; table.ShowFilter = true; @@ -10824,7 +10937,7 @@ private static bool stepReportSnapshots(ProgramOptions programOptions, JobConfig // Parameters sheet ExcelWorksheet sheet = excelReport.Workbook.Worksheets.Add(REPORT_SHEET_PARAMETERS); - + var hyperLinkStyle = sheet.Workbook.Styles.CreateNamedStyle("HyperLinkStyle"); hyperLinkStyle.Style.Font.UnderLineType = ExcelUnderLineType.Single; hyperLinkStyle.Style.Font.Color.SetColor(colorBlueForHyperlinks); @@ -10886,7 +10999,7 @@ private static bool stepReportSnapshots(ProgramOptions programOptions, JobConfig ApplicationID = jobTarget.ApplicationID, Status = jobTarget.Status.ToString() }, true); - ExcelTable table = sheet.Tables.Add(range, REPORT_DETECTED_ENTITIES_TABLE_PARAMETERS_TARGETS); + ExcelTable table = sheet.Tables.Add(range, REPORT_SNAPSHOTS_TABLE_PARAMETERS_TARGETS); table.ShowHeader = true; table.TableStyle = TableStyles.Medium2; table.ShowFilter = true; @@ -10981,13 +11094,13 @@ private static bool stepReportSnapshots(ProgramOptions programOptions, JobConfig sheet.Cells[2, 1].Value = "See Table"; sheet.Cells[2, 2].Formula = String.Format(@"=HYPERLINK(""#'{0}'!A1"", """")", REPORT_SNAPSHOTS_SHEET_EXIT_CALLS); sheet.Cells[2, 2].StyleName = "HyperLinkStyle"; + sheet.View.FreezePanes(REPORT_SNAPSHOTS_PIVOT_SHEET_START_PIVOT_AT + REPORT_SNAPSHOTS_PIVOT_SHEET_CHART_HEIGHT + 2, 1); sheet = excelReport.Workbook.Worksheets.Add(REPORT_SNAPSHOTS_SHEET_SERVICE_ENDPOINT_CALLS); sheet.Cells[1, 1].Value = "Table of Contents"; sheet.Cells[1, 2].Formula = String.Format(@"=HYPERLINK(""#'{0}'!A1"", """")", REPORT_SHEET_TOC); sheet.Cells[1, 2].StyleName = "HyperLinkStyle"; sheet.View.FreezePanes(REPORT_SNAPSHOTS_LIST_SHEET_START_TABLE_AT + 1, 1); - sheet.View.FreezePanes(REPORT_SNAPSHOTS_PIVOT_SHEET_START_PIVOT_AT + REPORT_SNAPSHOTS_PIVOT_SHEET_CHART_HEIGHT + 2, 1); sheet = excelReport.Workbook.Worksheets.Add(REPORT_SNAPSHOTS_SHEET_DETECTED_ERRORS); sheet.Cells[1, 1].Value = "Table of Contents"; @@ -11052,8 +11165,8 @@ private static bool stepReportSnapshots(ProgramOptions programOptions, JobConfig loggerConsole.Info("List of Controllers"); - sheet = excelReport.Workbook.Worksheets[REPORT_DETECTED_ENTITIES_SHEET_CONTROLLERS]; - readCSVFileIntoExcelRange(controllersAllReportFilePath, 0, sheet, REPORT_DETECTED_ENTITIES_LIST_SHEET_START_TABLE_AT, 1); + sheet = excelReport.Workbook.Worksheets[REPORT_DETECTED_EVENTS_SHEET_CONTROLLERS]; + readCSVFileIntoExcelRange(controllersAllReportFilePath, 0, sheet, REPORT_SNAPSHOTS_LIST_SHEET_START_TABLE_AT, 1); #endregion @@ -11062,7 +11175,7 @@ private static bool stepReportSnapshots(ProgramOptions programOptions, JobConfig loggerConsole.Info("List of Applications"); sheet = excelReport.Workbook.Worksheets[REPORT_DETECTED_EVENTS_SHEET_APPLICATIONS]; - readCSVFileIntoExcelRange(applicationSnapshotsSummaryAllReportFilePath, 0, sheet, REPORT_DETECTED_ENTITIES_LIST_SHEET_START_TABLE_AT, 1); + readCSVFileIntoExcelRange(applicationSnapshotsSummaryAllReportFilePath, 0, sheet, REPORT_SNAPSHOTS_LIST_SHEET_START_TABLE_AT, 1); #endregion @@ -11071,7 +11184,7 @@ private static bool stepReportSnapshots(ProgramOptions programOptions, JobConfig loggerConsole.Info("List of Snapshots"); sheet = excelReport.Workbook.Worksheets[REPORT_SNAPSHOTS_SHEET_SNAPSHOTS]; - readCSVFileIntoExcelRange(snapshotsAllReportFilePath, 0, sheet, REPORT_DETECTED_ENTITIES_LIST_SHEET_START_TABLE_AT, 1); + readCSVFileIntoExcelRange(snapshotsAllReportFilePath, 0, sheet, REPORT_SNAPSHOTS_LIST_SHEET_START_TABLE_AT, 1); #endregion @@ -11079,7 +11192,7 @@ private static bool stepReportSnapshots(ProgramOptions programOptions, JobConfig loggerConsole.Info("List of Segments"); sheet = excelReport.Workbook.Worksheets[REPORT_SNAPSHOTS_SHEET_SEGMENTS]; - readCSVFileIntoExcelRange(segmentsAllReportFilePath, 0, sheet, REPORT_DETECTED_ENTITIES_LIST_SHEET_START_TABLE_AT, 1); + readCSVFileIntoExcelRange(segmentsAllReportFilePath, 0, sheet, REPORT_SNAPSHOTS_LIST_SHEET_START_TABLE_AT, 1); #endregion @@ -11088,7 +11201,7 @@ private static bool stepReportSnapshots(ProgramOptions programOptions, JobConfig loggerConsole.Info("List of Exit Calls"); sheet = excelReport.Workbook.Worksheets[REPORT_SNAPSHOTS_SHEET_EXIT_CALLS]; - readCSVFileIntoExcelRange(callExitsAllReportFilePath, 0, sheet, REPORT_DETECTED_ENTITIES_LIST_SHEET_START_TABLE_AT, 1); + readCSVFileIntoExcelRange(callExitsAllReportFilePath, 0, sheet, REPORT_SNAPSHOTS_LIST_SHEET_START_TABLE_AT, 1); #endregion @@ -11097,7 +11210,7 @@ private static bool stepReportSnapshots(ProgramOptions programOptions, JobConfig loggerConsole.Info("List of Service Endpoint Calls"); sheet = excelReport.Workbook.Worksheets[REPORT_SNAPSHOTS_SHEET_SERVICE_ENDPOINT_CALLS]; - readCSVFileIntoExcelRange(serviceEndpointCallsAllReporFilePath, 0, sheet, REPORT_DETECTED_ENTITIES_LIST_SHEET_START_TABLE_AT, 1); + readCSVFileIntoExcelRange(serviceEndpointCallsAllReporFilePath, 0, sheet, REPORT_SNAPSHOTS_LIST_SHEET_START_TABLE_AT, 1); #endregion @@ -11106,7 +11219,7 @@ private static bool stepReportSnapshots(ProgramOptions programOptions, JobConfig loggerConsole.Info("List of Detected Errors"); sheet = excelReport.Workbook.Worksheets[REPORT_SNAPSHOTS_SHEET_DETECTED_ERRORS]; - readCSVFileIntoExcelRange(detectedErrorsAllReporFilePath, 0, sheet, REPORT_DETECTED_ENTITIES_LIST_SHEET_START_TABLE_AT, 1); + readCSVFileIntoExcelRange(detectedErrorsAllReporFilePath, 0, sheet, REPORT_SNAPSHOTS_LIST_SHEET_START_TABLE_AT, 1); #endregion @@ -11115,7 +11228,7 @@ private static bool stepReportSnapshots(ProgramOptions programOptions, JobConfig loggerConsole.Info("List of Business Data"); sheet = excelReport.Workbook.Worksheets[REPORT_SNAPSHOTS_SHEET_BUSINESS_DATA]; - readCSVFileIntoExcelRange(businessDataAllReportFilePath, 0, sheet, REPORT_DETECTED_ENTITIES_LIST_SHEET_START_TABLE_AT, 1); + readCSVFileIntoExcelRange(businessDataAllReportFilePath, 0, sheet, REPORT_SNAPSHOTS_LIST_SHEET_START_TABLE_AT, 1); #endregion @@ -11159,22 +11272,22 @@ private static bool stepReportSnapshots(ProgramOptions programOptions, JobConfig adjustColumnsOfEntityRowTableInMetricReport(APPLICATION_TYPE_SHORT, sheet, table); - ExcelAddress cfAddressNum = new ExcelAddress(REPORT_METRICS_ALL_ENTITIES_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumSnapshots"].Position + 1, sheet.Dimension.Rows, table.Columns["NumSnapshots"].Position + 1); + ExcelAddress cfAddressNum = new ExcelAddress(REPORT_SNAPSHOTS_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumSnapshots"].Position + 1, sheet.Dimension.Rows, table.Columns["NumSnapshots"].Position + 1); var cfNum = sheet.ConditionalFormatting.AddDatabar(cfAddressNum, colorLightBlueForDatabars); - cfAddressNum = new ExcelAddress(REPORT_METRICS_ALL_ENTITIES_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumSnapshotsNormal"].Position + 1, sheet.Dimension.Rows, table.Columns["NumSnapshotsNormal"].Position + 1); + cfAddressNum = new ExcelAddress(REPORT_SNAPSHOTS_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumSnapshotsNormal"].Position + 1, sheet.Dimension.Rows, table.Columns["NumSnapshotsNormal"].Position + 1); cfNum = sheet.ConditionalFormatting.AddDatabar(cfAddressNum, colorLightBlueForDatabars); - cfAddressNum = new ExcelAddress(REPORT_METRICS_ALL_ENTITIES_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumSnapshotsVerySlow"].Position + 1, sheet.Dimension.Rows, table.Columns["NumSnapshotsVerySlow"].Position + 1); + cfAddressNum = new ExcelAddress(REPORT_SNAPSHOTS_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumSnapshotsVerySlow"].Position + 1, sheet.Dimension.Rows, table.Columns["NumSnapshotsVerySlow"].Position + 1); cfNum = sheet.ConditionalFormatting.AddDatabar(cfAddressNum, colorLightBlueForDatabars); - cfAddressNum = new ExcelAddress(REPORT_METRICS_ALL_ENTITIES_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumSnapshotsStall"].Position + 1, sheet.Dimension.Rows, table.Columns["NumSnapshotsStall"].Position + 1); + cfAddressNum = new ExcelAddress(REPORT_SNAPSHOTS_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumSnapshotsStall"].Position + 1, sheet.Dimension.Rows, table.Columns["NumSnapshotsStall"].Position + 1); cfNum = sheet.ConditionalFormatting.AddDatabar(cfAddressNum, colorLightBlueForDatabars); - cfAddressNum = new ExcelAddress(REPORT_METRICS_ALL_ENTITIES_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumSnapshotsSlow"].Position + 1, sheet.Dimension.Rows, table.Columns["NumSnapshotsSlow"].Position + 1); + cfAddressNum = new ExcelAddress(REPORT_SNAPSHOTS_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumSnapshotsSlow"].Position + 1, sheet.Dimension.Rows, table.Columns["NumSnapshotsSlow"].Position + 1); cfNum = sheet.ConditionalFormatting.AddDatabar(cfAddressNum, colorLightBlueForDatabars); - cfAddressNum = new ExcelAddress(REPORT_METRICS_ALL_ENTITIES_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumSnapshotsError"].Position + 1, sheet.Dimension.Rows, table.Columns["NumSnapshotsError"].Position + 1); + cfAddressNum = new ExcelAddress(REPORT_SNAPSHOTS_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumSnapshotsError"].Position + 1, sheet.Dimension.Rows, table.Columns["NumSnapshotsError"].Position + 1); cfNum = sheet.ConditionalFormatting.AddDatabar(cfAddressNum, colorLightBlueForDatabars); } @@ -11206,7 +11319,7 @@ private static bool stepReportSnapshots(ProgramOptions programOptions, JobConfig sheet.Column(table.Columns["OccuredUtc"].Position + 1).Width = 20; sheet.Column(table.Columns["DetailLink"].Position + 1).Width = 25; - ExcelAddress cfAddressUserExperience = new ExcelAddress(REPORT_METRICS_ALL_ENTITIES_LIST_SHEET_START_TABLE_AT + 1, table.Columns["UserExperience"].Position + 1, sheet.Dimension.Rows, table.Columns["UserExperience"].Position + 1); + ExcelAddress cfAddressUserExperience = new ExcelAddress(REPORT_SNAPSHOTS_LIST_SHEET_START_TABLE_AT + 1, table.Columns["UserExperience"].Position + 1, sheet.Dimension.Rows, table.Columns["UserExperience"].Position + 1); var cfUserExperience = sheet.ConditionalFormatting.AddEqual(cfAddressUserExperience); cfUserExperience.Style.Font.Color.Color = Color.White; cfUserExperience.Style.Fill.BackgroundColor.Color = colorGreenForNormalSnapshots; @@ -11232,7 +11345,7 @@ private static bool stepReportSnapshots(ProgramOptions programOptions, JobConfig cfUserExperience.Style.Fill.BackgroundColor.Color = colorRedForErrorSnapshots; cfUserExperience.Formula = @"=""ERROR"""; - ExcelAddress cfAddressDuration = new ExcelAddress(REPORT_METRICS_ALL_ENTITIES_LIST_SHEET_START_TABLE_AT + 1, table.Columns["Duration"].Position + 1, sheet.Dimension.Rows, table.Columns["Duration"].Position + 1); + ExcelAddress cfAddressDuration = new ExcelAddress(REPORT_SNAPSHOTS_LIST_SHEET_START_TABLE_AT + 1, table.Columns["Duration"].Position + 1, sheet.Dimension.Rows, table.Columns["Duration"].Position + 1); var cfDuration = sheet.ConditionalFormatting.AddThreeColorScale(cfAddressDuration); cfDuration.LowValue.Color = colorGreenFor3ColorScales; cfDuration.MiddleValue.Type = eExcelConditionalFormattingValueObjectType.Percentile; @@ -11240,43 +11353,44 @@ private static bool stepReportSnapshots(ProgramOptions programOptions, JobConfig cfDuration.MiddleValue.Color = colorYellowFor3ColorScales; cfDuration.HighValue.Color = colorRedFor3ColorScales; - ExcelAddress cfAddressNum = new ExcelAddress(REPORT_METRICS_ALL_ENTITIES_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumErrors"].Position + 1, sheet.Dimension.Rows, table.Columns["NumErrors"].Position + 1); + ExcelAddress cfAddressNum = new ExcelAddress(REPORT_SNAPSHOTS_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumErrors"].Position + 1, sheet.Dimension.Rows, table.Columns["NumErrors"].Position + 1); var cfNum = sheet.ConditionalFormatting.AddDatabar(cfAddressNum, colorLightBlueForDatabars); - cfAddressNum = new ExcelAddress(REPORT_METRICS_ALL_ENTITIES_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumCallGraphs"].Position + 1, sheet.Dimension.Rows, table.Columns["NumCallGraphs"].Position + 1); + cfAddressNum = new ExcelAddress(REPORT_SNAPSHOTS_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumCallGraphs"].Position + 1, sheet.Dimension.Rows, table.Columns["NumCallGraphs"].Position + 1); cfNum = sheet.ConditionalFormatting.AddDatabar(cfAddressNum, colorLightBlueForDatabars); - cfAddressNum = new ExcelAddress(REPORT_METRICS_ALL_ENTITIES_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumCalledBackends"].Position + 1, sheet.Dimension.Rows, table.Columns["NumCalledBackends"].Position + 1); + cfAddressNum = new ExcelAddress(REPORT_SNAPSHOTS_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumCalledBackends"].Position + 1, sheet.Dimension.Rows, table.Columns["NumCalledBackends"].Position + 1); cfNum = sheet.ConditionalFormatting.AddDatabar(cfAddressNum, colorLightBlueForDatabars); - cfAddressNum = new ExcelAddress(REPORT_METRICS_ALL_ENTITIES_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumCalledTiers"].Position + 1, sheet.Dimension.Rows, table.Columns["NumCalledTiers"].Position + 1); + cfAddressNum = new ExcelAddress(REPORT_SNAPSHOTS_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumCalledTiers"].Position + 1, sheet.Dimension.Rows, table.Columns["NumCalledTiers"].Position + 1); cfNum = sheet.ConditionalFormatting.AddDatabar(cfAddressNum, colorLightBlueForDatabars); - cfAddressNum = new ExcelAddress(REPORT_METRICS_ALL_ENTITIES_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumCalledApplications"].Position + 1, sheet.Dimension.Rows, table.Columns["NumCalledApplications"].Position + 1); + cfAddressNum = new ExcelAddress(REPORT_SNAPSHOTS_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumCalledApplications"].Position + 1, sheet.Dimension.Rows, table.Columns["NumCalledApplications"].Position + 1); cfNum = sheet.ConditionalFormatting.AddDatabar(cfAddressNum, colorLightBlueForDatabars); - cfAddressNum = new ExcelAddress(REPORT_METRICS_ALL_ENTITIES_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumCallsToBackends"].Position + 1, sheet.Dimension.Rows, table.Columns["NumCallsToBackends"].Position + 1); + cfAddressNum = new ExcelAddress(REPORT_SNAPSHOTS_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumCallsToBackends"].Position + 1, sheet.Dimension.Rows, table.Columns["NumCallsToBackends"].Position + 1); cfNum = sheet.ConditionalFormatting.AddDatabar(cfAddressNum, colorLightBlueForDatabars); - cfAddressNum = new ExcelAddress(REPORT_METRICS_ALL_ENTITIES_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumCallsToTiers"].Position + 1, sheet.Dimension.Rows, table.Columns["NumCallsToTiers"].Position + 1); + cfAddressNum = new ExcelAddress(REPORT_SNAPSHOTS_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumCallsToTiers"].Position + 1, sheet.Dimension.Rows, table.Columns["NumCallsToTiers"].Position + 1); cfNum = sheet.ConditionalFormatting.AddDatabar(cfAddressNum, colorLightBlueForDatabars); - cfAddressNum = new ExcelAddress(REPORT_METRICS_ALL_ENTITIES_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumCallsToApplications"].Position + 1, sheet.Dimension.Rows, table.Columns["NumCallsToApplications"].Position + 1); + cfAddressNum = new ExcelAddress(REPORT_SNAPSHOTS_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumCallsToApplications"].Position + 1, sheet.Dimension.Rows, table.Columns["NumCallsToApplications"].Position + 1); cfNum = sheet.ConditionalFormatting.AddDatabar(cfAddressNum, colorLightBlueForDatabars); - cfAddressNum = new ExcelAddress(REPORT_METRICS_ALL_ENTITIES_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumSEPs"].Position + 1, sheet.Dimension.Rows, table.Columns["NumSEPs"].Position + 1); + cfAddressNum = new ExcelAddress(REPORT_SNAPSHOTS_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumSEPs"].Position + 1, sheet.Dimension.Rows, table.Columns["NumSEPs"].Position + 1); cfNum = sheet.ConditionalFormatting.AddDatabar(cfAddressNum, colorLightBlueForDatabars); - cfAddressNum = new ExcelAddress(REPORT_METRICS_ALL_ENTITIES_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumHTTPDCs"].Position + 1, sheet.Dimension.Rows, table.Columns["NumHTTPDCs"].Position + 1); + cfAddressNum = new ExcelAddress(REPORT_SNAPSHOTS_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumHTTPDCs"].Position + 1, sheet.Dimension.Rows, table.Columns["NumHTTPDCs"].Position + 1); cfNum = sheet.ConditionalFormatting.AddDatabar(cfAddressNum, colorLightBlueForDatabars); - cfAddressNum = new ExcelAddress(REPORT_METRICS_ALL_ENTITIES_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumMIDCs"].Position + 1, sheet.Dimension.Rows, table.Columns["NumMIDCs"].Position + 1); + cfAddressNum = new ExcelAddress(REPORT_SNAPSHOTS_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumMIDCs"].Position + 1, sheet.Dimension.Rows, table.Columns["NumMIDCs"].Position + 1); cfNum = sheet.ConditionalFormatting.AddDatabar(cfAddressNum, colorLightBlueForDatabars); sheet = excelReport.Workbook.Worksheets[REPORT_SNAPSHOTS_SHEET_SNAPSHOTS_PIVOT]; ExcelPivotTable pivot = sheet.PivotTables.Add(sheet.Cells[REPORT_SNAPSHOTS_PIVOT_SHEET_START_PIVOT_AT + REPORT_SNAPSHOTS_PIVOT_SHEET_CHART_HEIGHT, 1], range, REPORT_SNAPSHOTS_PIVOT_SNAPSHOTS); ExcelPivotTableField fieldF = pivot.PageFields.Add(pivot.Fields["HasErrors"]); fieldF = pivot.PageFields.Add(pivot.Fields["CallGraphType"]); + fieldF = pivot.PageFields.Add(pivot.Fields["DurationRange"]); ExcelPivotTableField fieldR = pivot.RowFields.Add(pivot.Fields["Controller"]); fieldR.Compact = false; fieldR.Outline = false; @@ -11324,13 +11438,13 @@ private static bool stepReportSnapshots(ProgramOptions programOptions, JobConfig sheet.Column(table.Columns["BTName"].Position + 1).Width = 20; sheet.Column(table.Columns["UserExperience"].Position + 1).Width = 10; sheet.Column(table.Columns["RequestID"].Position + 1).Width = 15; - sheet.Column(table.Columns["SegmentID"].Position + 1).Width = 15; - sheet.Column(table.Columns["ParentSegmentID"].Position + 1).Width = 15; - sheet.Column(table.Columns["ParentTierName"].Position + 1).Width = 20; + sheet.Column(table.Columns["SegmentID"].Position + 1).Width = 10; + sheet.Column(table.Columns["FromSegmentID"].Position + 1).Width = 15; + sheet.Column(table.Columns["FromTierName"].Position + 1).Width = 20; sheet.Column(table.Columns["Occured"].Position + 1).Width = 20; sheet.Column(table.Columns["OccuredUtc"].Position + 1).Width = 20; - ExcelAddress cfAddressUserExperience = new ExcelAddress(REPORT_METRICS_ALL_ENTITIES_LIST_SHEET_START_TABLE_AT + 1, table.Columns["UserExperience"].Position + 1, sheet.Dimension.Rows, table.Columns["UserExperience"].Position + 1); + ExcelAddress cfAddressUserExperience = new ExcelAddress(REPORT_SNAPSHOTS_LIST_SHEET_START_TABLE_AT + 1, table.Columns["UserExperience"].Position + 1, sheet.Dimension.Rows, table.Columns["UserExperience"].Position + 1); var cfUserExperience = sheet.ConditionalFormatting.AddEqual(cfAddressUserExperience); cfUserExperience.Style.Font.Color.Color = Color.White; cfUserExperience.Style.Fill.BackgroundColor.Color = colorGreenForNormalSnapshots; @@ -11356,7 +11470,7 @@ private static bool stepReportSnapshots(ProgramOptions programOptions, JobConfig cfUserExperience.Style.Fill.BackgroundColor.Color = colorRedForErrorSnapshots; cfUserExperience.Formula = @"=""ERROR"""; - ExcelAddress cfAddressDuration = new ExcelAddress(REPORT_METRICS_ALL_ENTITIES_LIST_SHEET_START_TABLE_AT + 1, table.Columns["Duration"].Position + 1, sheet.Dimension.Rows, table.Columns["Duration"].Position + 1); + ExcelAddress cfAddressDuration = new ExcelAddress(REPORT_SNAPSHOTS_LIST_SHEET_START_TABLE_AT + 1, table.Columns["Duration"].Position + 1, sheet.Dimension.Rows, table.Columns["Duration"].Position + 1); var cfDuration = sheet.ConditionalFormatting.AddThreeColorScale(cfAddressDuration); cfDuration.LowValue.Color = colorGreenFor3ColorScales; cfDuration.MiddleValue.Type = eExcelConditionalFormattingValueObjectType.Percentile; @@ -11364,40 +11478,41 @@ private static bool stepReportSnapshots(ProgramOptions programOptions, JobConfig cfDuration.MiddleValue.Color = colorYellowFor3ColorScales; cfDuration.HighValue.Color = colorRedFor3ColorScales; - ExcelAddress cfAddressNum = new ExcelAddress(REPORT_METRICS_ALL_ENTITIES_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumErrors"].Position + 1, sheet.Dimension.Rows, table.Columns["NumErrors"].Position + 1); + ExcelAddress cfAddressNum = new ExcelAddress(REPORT_SNAPSHOTS_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumErrors"].Position + 1, sheet.Dimension.Rows, table.Columns["NumErrors"].Position + 1); var cfNum = sheet.ConditionalFormatting.AddDatabar(cfAddressNum, colorLightBlueForDatabars); - cfAddressNum = new ExcelAddress(REPORT_METRICS_ALL_ENTITIES_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumCalledBackends"].Position + 1, sheet.Dimension.Rows, table.Columns["NumCalledBackends"].Position + 1); + cfAddressNum = new ExcelAddress(REPORT_SNAPSHOTS_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumCalledBackends"].Position + 1, sheet.Dimension.Rows, table.Columns["NumCalledBackends"].Position + 1); cfNum = sheet.ConditionalFormatting.AddDatabar(cfAddressNum, colorLightBlueForDatabars); - cfAddressNum = new ExcelAddress(REPORT_METRICS_ALL_ENTITIES_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumCalledTiers"].Position + 1, sheet.Dimension.Rows, table.Columns["NumCalledTiers"].Position + 1); + cfAddressNum = new ExcelAddress(REPORT_SNAPSHOTS_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumCalledTiers"].Position + 1, sheet.Dimension.Rows, table.Columns["NumCalledTiers"].Position + 1); cfNum = sheet.ConditionalFormatting.AddDatabar(cfAddressNum, colorLightBlueForDatabars); - cfAddressNum = new ExcelAddress(REPORT_METRICS_ALL_ENTITIES_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumCalledApplications"].Position + 1, sheet.Dimension.Rows, table.Columns["NumCalledApplications"].Position + 1); + cfAddressNum = new ExcelAddress(REPORT_SNAPSHOTS_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumCalledApplications"].Position + 1, sheet.Dimension.Rows, table.Columns["NumCalledApplications"].Position + 1); cfNum = sheet.ConditionalFormatting.AddDatabar(cfAddressNum, colorLightBlueForDatabars); - cfAddressNum = new ExcelAddress(REPORT_METRICS_ALL_ENTITIES_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumCallsToBackends"].Position + 1, sheet.Dimension.Rows, table.Columns["NumCallsToBackends"].Position + 1); + cfAddressNum = new ExcelAddress(REPORT_SNAPSHOTS_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumCallsToBackends"].Position + 1, sheet.Dimension.Rows, table.Columns["NumCallsToBackends"].Position + 1); cfNum = sheet.ConditionalFormatting.AddDatabar(cfAddressNum, colorLightBlueForDatabars); - cfAddressNum = new ExcelAddress(REPORT_METRICS_ALL_ENTITIES_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumCallsToTiers"].Position + 1, sheet.Dimension.Rows, table.Columns["NumCallsToTiers"].Position + 1); + cfAddressNum = new ExcelAddress(REPORT_SNAPSHOTS_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumCallsToTiers"].Position + 1, sheet.Dimension.Rows, table.Columns["NumCallsToTiers"].Position + 1); cfNum = sheet.ConditionalFormatting.AddDatabar(cfAddressNum, colorLightBlueForDatabars); - cfAddressNum = new ExcelAddress(REPORT_METRICS_ALL_ENTITIES_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumCallsToApplications"].Position + 1, sheet.Dimension.Rows, table.Columns["NumCallsToApplications"].Position + 1); + cfAddressNum = new ExcelAddress(REPORT_SNAPSHOTS_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumCallsToApplications"].Position + 1, sheet.Dimension.Rows, table.Columns["NumCallsToApplications"].Position + 1); cfNum = sheet.ConditionalFormatting.AddDatabar(cfAddressNum, colorLightBlueForDatabars); - cfAddressNum = new ExcelAddress(REPORT_METRICS_ALL_ENTITIES_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumSEPs"].Position + 1, sheet.Dimension.Rows, table.Columns["NumSEPs"].Position + 1); + cfAddressNum = new ExcelAddress(REPORT_SNAPSHOTS_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumSEPs"].Position + 1, sheet.Dimension.Rows, table.Columns["NumSEPs"].Position + 1); cfNum = sheet.ConditionalFormatting.AddDatabar(cfAddressNum, colorLightBlueForDatabars); - cfAddressNum = new ExcelAddress(REPORT_METRICS_ALL_ENTITIES_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumHTTPDCs"].Position + 1, sheet.Dimension.Rows, table.Columns["NumHTTPDCs"].Position + 1); + cfAddressNum = new ExcelAddress(REPORT_SNAPSHOTS_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumHTTPDCs"].Position + 1, sheet.Dimension.Rows, table.Columns["NumHTTPDCs"].Position + 1); cfNum = sheet.ConditionalFormatting.AddDatabar(cfAddressNum, colorLightBlueForDatabars); - cfAddressNum = new ExcelAddress(REPORT_METRICS_ALL_ENTITIES_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumMIDCs"].Position + 1, sheet.Dimension.Rows, table.Columns["NumMIDCs"].Position + 1); + cfAddressNum = new ExcelAddress(REPORT_SNAPSHOTS_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumMIDCs"].Position + 1, sheet.Dimension.Rows, table.Columns["NumMIDCs"].Position + 1); cfNum = sheet.ConditionalFormatting.AddDatabar(cfAddressNum, colorLightBlueForDatabars); sheet = excelReport.Workbook.Worksheets[REPORT_SNAPSHOTS_SHEET_SEGMENTS_PIVOT]; ExcelPivotTable pivot = sheet.PivotTables.Add(sheet.Cells[REPORT_SNAPSHOTS_PIVOT_SHEET_START_PIVOT_AT + REPORT_SNAPSHOTS_PIVOT_SHEET_CHART_HEIGHT, 1], range, REPORT_SNAPSHOTS_PIVOT_SEGMENTS); ExcelPivotTableField fieldF = pivot.PageFields.Add(pivot.Fields["HasErrors"]); fieldF = pivot.PageFields.Add(pivot.Fields["CallGraphType"]); + fieldF = pivot.PageFields.Add(pivot.Fields["DurationRange"]); ExcelPivotTableField fieldR = pivot.RowFields.Add(pivot.Fields["Controller"]); fieldR.Compact = false; fieldR.Outline = false; @@ -11444,15 +11559,16 @@ private static bool stepReportSnapshots(ProgramOptions programOptions, JobConfig sheet.Column(table.Columns["NodeName"].Position + 1).Width = 20; sheet.Column(table.Columns["BTName"].Position + 1).Width = 20; sheet.Column(table.Columns["RequestID"].Position + 1).Width = 15; - sheet.Column(table.Columns["SegmentID"].Position + 1).Width = 15; + sheet.Column(table.Columns["SegmentID"].Position + 1).Width = 10; sheet.Column(table.Columns["ToEntityName"].Position + 1).Width = 15; sheet.Column(table.Columns["ExitType"].Position + 1).Width = 10; sheet.Column(table.Columns["Detail"].Position + 1).Width = 20; sheet.Column(table.Columns["Method"].Position + 1).Width = 20; + sheet.Column(table.Columns["ToSegmentID"].Position + 1).Width = 15; sheet.Column(table.Columns["Occured"].Position + 1).Width = 20; sheet.Column(table.Columns["OccuredUtc"].Position + 1).Width = 20; - ExcelAddress cfAddressDuration = new ExcelAddress(REPORT_METRICS_ALL_ENTITIES_LIST_SHEET_START_TABLE_AT + 1, table.Columns["Duration"].Position + 1, sheet.Dimension.Rows, table.Columns["Duration"].Position + 1); + ExcelAddress cfAddressDuration = new ExcelAddress(REPORT_SNAPSHOTS_LIST_SHEET_START_TABLE_AT + 1, table.Columns["Duration"].Position + 1, sheet.Dimension.Rows, table.Columns["Duration"].Position + 1); var cfDuration = sheet.ConditionalFormatting.AddThreeColorScale(cfAddressDuration); cfDuration.LowValue.Color = colorGreenFor3ColorScales; cfDuration.MiddleValue.Type = eExcelConditionalFormattingValueObjectType.Percentile; @@ -11461,17 +11577,18 @@ private static bool stepReportSnapshots(ProgramOptions programOptions, JobConfig cfDuration.HighValue.Color = colorRedFor3ColorScales; sheet = excelReport.Workbook.Worksheets[REPORT_SNAPSHOTS_SHEET_EXIT_CALLS_PIVOT]; - ExcelPivotTable pivot = sheet.PivotTables.Add(sheet.Cells[REPORT_SNAPSHOTS_PIVOT_SHEET_START_PIVOT_AT + REPORT_SNAPSHOTS_PIVOT_SHEET_CHART_HEIGHT, 1], range, REPORT_SNAPSHOTS_PIVOT_EXIT_CALLS); + ExcelPivotTable pivot = sheet.PivotTables.Add(sheet.Cells[REPORT_SNAPSHOTS_PIVOT_SHEET_START_PIVOT_AT + REPORT_SNAPSHOTS_PIVOT_SHEET_CHART_HEIGHT + 1, 1], range, REPORT_SNAPSHOTS_PIVOT_EXIT_CALLS); ExcelPivotTableField fieldF = pivot.PageFields.Add(pivot.Fields["ToEntityType"]); fieldF = pivot.PageFields.Add(pivot.Fields["ToEntityName"]); fieldF = pivot.PageFields.Add(pivot.Fields["RequestID"]); - ExcelPivotTableField fieldR = pivot.RowFields.Add(pivot.Fields["Controller"]); + fieldF = pivot.PageFields.Add(pivot.Fields["DurationRange"]); + ExcelPivotTableField fieldR = pivot.RowFields.Add(pivot.Fields["ExitType"]); fieldR.Compact = false; fieldR.Outline = false; - fieldR = pivot.RowFields.Add(pivot.Fields["ExitType"]); + fieldR = pivot.RowFields.Add(pivot.Fields["Detail"]); fieldR.Compact = false; fieldR.Outline = false; - fieldR = pivot.RowFields.Add(pivot.Fields["Detail"]); + fieldR = pivot.RowFields.Add(pivot.Fields["Controller"]); fieldR.Compact = false; fieldR.Outline = false; fieldR = pivot.RowFields.Add(pivot.Fields["ApplicationName"]); @@ -11501,6 +11618,7 @@ private static bool stepReportSnapshots(ProgramOptions programOptions, JobConfig pivot = sheet.PivotTables.Add(sheet.Cells[REPORT_SNAPSHOTS_PIVOT_SHEET_START_PIVOT_AT + REPORT_SNAPSHOTS_PIVOT_SHEET_CHART_HEIGHT, 1], range, REPORT_SNAPSHOTS_PIVOT_EXIT_CALLS_DETAILS_DURATION); fieldF = pivot.PageFields.Add(pivot.Fields["ExitType"]); fieldF = pivot.PageFields.Add(pivot.Fields["Detail"]); + fieldF = pivot.PageFields.Add(pivot.Fields["DurationRange"]); fieldR = pivot.RowFields.Add(pivot.Fields["Occured"]); fieldR.AddDateGrouping(eDateGroupBy.Hours | eDateGroupBy.Minutes); fieldR.Compact = false; @@ -11537,7 +11655,7 @@ private static bool stepReportSnapshots(ProgramOptions programOptions, JobConfig sheet.Column(table.Columns["NodeName"].Position + 1).Width = 20; sheet.Column(table.Columns["BTName"].Position + 1).Width = 20; sheet.Column(table.Columns["RequestID"].Position + 1).Width = 15; - sheet.Column(table.Columns["SegmentID"].Position + 1).Width = 15; + sheet.Column(table.Columns["SegmentID"].Position + 1).Width = 10; sheet.Column(table.Columns["SepName"].Position + 1).Width = 20; } @@ -11564,7 +11682,7 @@ private static bool stepReportSnapshots(ProgramOptions programOptions, JobConfig sheet.Column(table.Columns["NodeName"].Position + 1).Width = 20; sheet.Column(table.Columns["BTName"].Position + 1).Width = 20; sheet.Column(table.Columns["RequestID"].Position + 1).Width = 15; - sheet.Column(table.Columns["SegmentID"].Position + 1).Width = 15; + sheet.Column(table.Columns["SegmentID"].Position + 1).Width = 10; sheet.Column(table.Columns["ErrorName"].Position + 1).Width = 20; sheet.Column(table.Columns["ErrorMessage"].Position + 1).Width = 20; sheet.Column(table.Columns["ErrorDetail"].Position + 1).Width = 20; @@ -11617,7 +11735,7 @@ private static bool stepReportSnapshots(ProgramOptions programOptions, JobConfig sheet.Column(table.Columns["NodeName"].Position + 1).Width = 20; sheet.Column(table.Columns["BTName"].Position + 1).Width = 20; sheet.Column(table.Columns["RequestID"].Position + 1).Width = 15; - sheet.Column(table.Columns["SegmentID"].Position + 1).Width = 15; + sheet.Column(table.Columns["SegmentID"].Position + 1).Width = 10; sheet.Column(table.Columns["DataName"].Position + 1).Width = 20; sheet.Column(table.Columns["DataValue"].Position + 1).Width = 20; sheet.Column(table.Columns["DataType"].Position + 1).Width = 10; @@ -11673,7 +11791,7 @@ private static bool stepReportSnapshots(ProgramOptions programOptions, JobConfig } } range = sheet.Cells[1, 1, sheet.Dimension.Rows, sheet.Dimension.Columns]; - table = sheet.Tables.Add(range, REPORT_DETECTED_ENTITIES_TABLE_TOC); + table = sheet.Tables.Add(range, REPORT_SNAPSHOTS_TABLE_TOC); table.ShowHeader = true; table.TableStyle = TableStyles.Medium2; table.ShowFilter = true; @@ -11743,7 +11861,7 @@ private static bool stepReportSnapshots(ProgramOptions programOptions, JobConfig } } - private static bool stepReportIndividualApplicationAndEntityDetails(ProgramOptions programOptions, JobConfiguration jobConfiguration, JobStatus jobStatus) + private static bool stepReportSnapshotsMethodCallLines(ProgramOptions programOptions, JobConfiguration jobConfiguration, JobStatus jobStatus) { Stopwatch stopWatch = new Stopwatch(); stopWatch.Start(); @@ -11759,584 +11877,565 @@ private static bool stepReportIndividualApplicationAndEntityDetails(ProgramOptio try { - // Process each target - for (int i = 0; i < jobConfiguration.Target.Count; i++) - { - Stopwatch stopWatchTarget = new Stopwatch(); - stopWatchTarget.Start(); + loggerConsole.Info("Prepare Snapshots Method Calls Report File"); - JobTarget jobTarget = jobConfiguration.Target[i]; + #region Prepare the report package - StepTiming stepTimingTarget = new StepTiming(); - stepTimingTarget.Controller = jobTarget.Controller; - stepTimingTarget.ApplicationName = jobTarget.Application; - stepTimingTarget.ApplicationID = jobTarget.ApplicationID; - stepTimingTarget.JobFileName = programOptions.OutputJobFilePath; - stepTimingTarget.StepName = jobStatus.ToString(); - stepTimingTarget.StepID = (int)jobStatus; - stepTimingTarget.StartTime = DateTime.Now; + // 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 Snapshots Method Call Lines Report"; + excelReport.Workbook.Properties.Subject = programOptions.JobName; - try - { - #region Output status + 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); - logger.Info("{0}({0:d}): [{1}/{2}], {3} {4}({5})", jobStatus, i + 1, jobConfiguration.Target.Count, jobTarget.Controller, jobTarget.Application, jobTarget.ApplicationID); - loggerConsole.Trace("{0}({0:d}): [{1}/{2}], {3} {4}({5})", jobStatus, i + 1, jobConfiguration.Target.Count, jobTarget.Controller, jobTarget.Application, jobTarget.ApplicationID); + #endregion - #endregion + #region Parameters sheet - #region Target state check + // Parameters sheet + ExcelWorksheet sheet = excelReport.Workbook.Worksheets.Add(REPORT_SHEET_PARAMETERS); - if (jobTarget.Status != JobTargetStatus.ConfigurationValid) - { - loggerConsole.Trace("Target in invalid state {0}, skipping", jobTarget.Status); + var hyperLinkStyle = sheet.Workbook.Styles.CreateNamedStyle("HyperLinkStyle"); + hyperLinkStyle.Style.Font.UnderLineType = ExcelUnderLineType.Single; + hyperLinkStyle.Style.Font.Color.SetColor(colorBlueForHyperlinks); - continue; - } + int l = 1; + sheet.Cells[l, 1].Value = "Table of Contents"; + sheet.Cells[l, 2].Formula = String.Format(@"=HYPERLINK(""#'{0}'!A1"", """")", REPORT_SHEET_TOC); + sheet.Cells[1, 2].StyleName = "HyperLinkStyle"; + l++; l++; + sheet.Cells[l, 1].Value = "AppDynamics DEXTER Snapshots Method Call Lines Report"; + l++; + sheet.Cells[l, 1].Value = "Version"; + sheet.Cells[l, 2].Value = Assembly.GetEntryAssembly().GetName().Version; + l++; l++; + sheet.Cells[l, 1].Value = "From"; + sheet.Cells[l, 2].Value = jobConfiguration.Input.TimeRange.From.ToString("G"); + l++; + sheet.Cells[l, 1].Value = "To"; + sheet.Cells[l, 2].Value = jobConfiguration.Input.TimeRange.To.ToString("G"); + l++; + sheet.Cells[l, 1].Value = "Expanded From (UTC)"; + sheet.Cells[l, 2].Value = jobConfiguration.Input.ExpandedTimeRange.From.ToString("G"); + l++; + sheet.Cells[l, 1].Value = "Expanded From (Local)"; + sheet.Cells[l, 2].Value = jobConfiguration.Input.ExpandedTimeRange.From.ToLocalTime().ToString("G"); + l++; + sheet.Cells[l, 1].Value = "Expanded To (UTC)"; + sheet.Cells[l, 2].Value = jobConfiguration.Input.ExpandedTimeRange.To.ToString("G"); + l++; + sheet.Cells[l, 1].Value = "Expanded To (Local)"; + sheet.Cells[l, 2].Value = jobConfiguration.Input.ExpandedTimeRange.To.ToLocalTime().ToString("G"); + l++; + sheet.Cells[l, 1].Value = "Number of Hours Intervals"; + sheet.Cells[l, 2].Value = jobConfiguration.Input.HourlyTimeRanges.Count; + l++; + sheet.Cells[l, 1].Value = "Export Metrics"; + sheet.Cells[l, 2].Value = jobConfiguration.Input.Metrics; + l++; + sheet.Cells[l, 1].Value = "Export Snapshots"; + sheet.Cells[l, 2].Value = jobConfiguration.Input.Snapshots; + l++; + sheet.Cells[l, 1].Value = "Export Flowmaps"; + sheet.Cells[l, 2].Value = jobConfiguration.Input.Flowmaps; + l++; + sheet.Cells[l, 1].Value = "Export Configuration"; + sheet.Cells[l, 2].Value = jobConfiguration.Input.Configuration; + l++; + sheet.Cells[l, 1].Value = "Export Events"; + sheet.Cells[l, 2].Value = jobConfiguration.Input.Events; + l++; + sheet.Cells[l, 1].Value = "Targets:"; + l++; l++; + ExcelRangeBase range = sheet.Cells[l, 1].LoadFromCollection(from jobTarget in jobConfiguration.Target + select new + { + Controller = jobTarget.Controller, + UserName = jobTarget.UserName, + Application = jobTarget.Application, + ApplicationID = jobTarget.ApplicationID, + Status = jobTarget.Status.ToString() + }, true); + ExcelTable table = sheet.Tables.Add(range, REPORT_SNAPSHOTS_TABLE_PARAMETERS_TARGETS); + table.ShowHeader = true; + table.TableStyle = TableStyles.Medium2; + table.ShowFilter = true; + table.ShowTotal = false; - #endregion + sheet.Column(1).Width = 25; + sheet.Column(2).Width = 25; + sheet.Column(3).Width = 25; - #region Target step variables + #endregion - // Various folders - string controllerFolderPath = Path.Combine(programOptions.OutputJobFolderPath, getFileSystemSafeString(new Uri(jobTarget.Controller).Host)); - string applicationFolderPath = Path.Combine(controllerFolderPath, getShortenedEntityNameForFileSystem(jobTarget.Application, jobTarget.ApplicationID)); - string metricsFolderPath = Path.Combine(applicationFolderPath, METRICS_FOLDER_NAME); - string entitiesFolderPath = Path.Combine(applicationFolderPath, ENTITIES_FOLDER_NAME); - string eventsFolderPath = Path.Combine(applicationFolderPath, EVENTS_FOLDER_NAME); - string snapshotsFolderPath = Path.Combine(applicationFolderPath, SNAPSHOTS_FOLDER_NAME); + #region TOC sheet - // Report files - string applicationReportFilePath = Path.Combine(applicationFolderPath, CONVERT_ENTITY_APPLICATION_FILE_NAME); - string tiersReportFilePath = Path.Combine(entitiesFolderPath, CONVERT_ENTITY_TIERS_FILE_NAME); - string nodesReportFilePath = Path.Combine(entitiesFolderPath, CONVERT_ENTITY_NODES_FILE_NAME); - string backendsReportFilePath = Path.Combine(entitiesFolderPath, CONVERT_ENTITY_BACKENDS_FILE_NAME); - string businessTransactionsReportFilePath = Path.Combine(entitiesFolderPath, CONVERT_ENTITY_BUSINESS_TRANSACTIONS_FILE_NAME); - string serviceEndpointsReportFilePath = Path.Combine(entitiesFolderPath, CONVERT_ENTITY_SERVICE_ENDPOINTS_FILE_NAME); - string errorsReportFilePath = Path.Combine(entitiesFolderPath, CONVERT_ENTITY_ERRORS_FILE_NAME); + // Navigation sheet with link to other sheets + sheet = excelReport.Workbook.Worksheets.Add(REPORT_SHEET_TOC); - string eventsFilePath = Path.Combine(eventsFolderPath, CONVERT_EVENTS_FILE_NAME); - string healthRuleViolationEventsFilePath = Path.Combine(eventsFolderPath, CONVERT_HEALTH_RULE_EVENTS_FILE_NAME); - string snapshotsFilePath = Path.Combine(snapshotsFolderPath, CONVERT_SNAPSHOTS_FILE_NAME); - string segmentsFilePath = Path.Combine(snapshotsFolderPath, CONVERT_SNAPSHOTS_SEGMENTS_FILE_NAME); - string exitCallsFilePath = Path.Combine(snapshotsFolderPath, CONVERT_SNAPSHOTS_SEGMENTS_EXIT_CALLS_FILE_NAME); - string serviceEndpointCallsFilePath = Path.Combine(snapshotsFolderPath, CONVERT_SNAPSHOTS_SEGMENTS_SERVICE_ENDPOINTS_CALLS_FILE_NAME); - string detectedErrorsFilePath = Path.Combine(snapshotsFolderPath, CONVERT_SNAPSHOTS_SEGMENTS_DETECTED_ERRORS_FILE_NAME); - string businessDataFilePath = Path.Combine(snapshotsFolderPath, CONVERT_SNAPSHOTS_SEGMENTS_BUSINESS_DATA_FILE_NAME); + #endregion - string metricsEntityFolderPath = String.Empty; - string entitiesFullRangeReportFilePath = String.Empty; + #region Entity sheets and their associated pivot - #endregion + // Entity sheets + sheet = excelReport.Workbook.Worksheets.Add(REPORT_SNAPSHOTS_SHEET_CONTROLLERS); + sheet.Cells[1, 1].Value = "Table of Contents"; + sheet.Cells[1, 2].Formula = String.Format(@"=HYPERLINK(""#'{0}'!A1"", """")", REPORT_SHEET_TOC); + sheet.Cells[1, 2].StyleName = "HyperLinkStyle"; + sheet.View.FreezePanes(REPORT_SNAPSHOTS_LIST_SHEET_START_TABLE_AT + 1, 1); - #region Preload all the reports that will be filtered by the subsequent entities + sheet = excelReport.Workbook.Worksheets.Add(REPORT_SNAPSHOTS_SHEET_APPLICATIONS); + sheet.Cells[1, 1].Value = "Table of Contents"; + sheet.Cells[1, 2].Formula = String.Format(@"=HYPERLINK(""#'{0}'!A1"", """")", REPORT_SHEET_TOC); + sheet.Cells[1, 2].StyleName = "HyperLinkStyle"; + sheet.View.FreezePanes(REPORT_SNAPSHOTS_LIST_SHEET_START_TABLE_AT + 1, 1); - loggerConsole.Info("Entity Details Data Preloading"); + sheet = excelReport.Workbook.Worksheets.Add(REPORT_SNAPSHOTS_SHEET_METHOD_CALL_LINES); + sheet.Cells[1, 1].Value = "Table of Contents"; + sheet.Cells[1, 2].Formula = String.Format(@"=HYPERLINK(""#'{0}'!A1"", """")", REPORT_SHEET_TOC); + sheet.Cells[1, 2].StyleName = "HyperLinkStyle"; + sheet.Cells[2, 1].Value = "See Pivot Type"; + sheet.Cells[2, 2].Formula = String.Format(@"=HYPERLINK(""#'{0}'!A1"", """")", REPORT_SNAPSHOTS_SHEET_METHOD_CALL_LINES_TYPE_PIVOT); + sheet.Cells[2, 2].StyleName = "HyperLinkStyle"; + sheet.Cells[3, 1].Value = "See Pivot Location"; + sheet.Cells[3, 2].Formula = String.Format(@"=HYPERLINK(""#'{0}'!A1"", """")", REPORT_SNAPSHOTS_SHEET_METHOD_CALL_LINES_LOCATION_PIVOT); + sheet.Cells[3, 2].StyleName = "HyperLinkStyle"; + sheet.View.FreezePanes(REPORT_SNAPSHOTS_LIST_SHEET_START_TABLE_AT + 1, 1); - List eventsAllList = FileIOHelper.readListFromCSVFile(eventsFilePath, new EventReportMap()); - List healthRuleViolationEventsAllList = FileIOHelper.readListFromCSVFile(healthRuleViolationEventsFilePath, new HealthRuleViolationEventReportMap()); - List snapshotsAllList = FileIOHelper.readListFromCSVFile(snapshotsFilePath, new SnapshotReportMap()); - List segmentsAllList = FileIOHelper.readListFromCSVFile(segmentsFilePath, new SegmentReportMap()); - List exitCallsAllList = FileIOHelper.readListFromCSVFile(exitCallsFilePath, new ExitCallReportMap()); - List serviceEndpointCallsAllList = FileIOHelper.readListFromCSVFile(serviceEndpointCallsFilePath, new ServiceEndpointCallReportMap()); - List detectedErrorsAllList = FileIOHelper.readListFromCSVFile(detectedErrorsFilePath, new DetectedErrorReportMap()); - List businessDataAllList = FileIOHelper.readListFromCSVFile(businessDataFilePath, new BusinessDataReportMap()); + sheet = excelReport.Workbook.Worksheets.Add(REPORT_SNAPSHOTS_SHEET_METHOD_CALL_LINES_TYPE_PIVOT); + sheet.Cells[1, 1].Value = "Table of Contents"; + sheet.Cells[1, 2].Formula = String.Format(@"=HYPERLINK(""#'{0}'!A1"", """")", REPORT_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"", """")", REPORT_SNAPSHOTS_SHEET_METHOD_CALL_LINES); + sheet.Cells[2, 2].StyleName = "HyperLinkStyle"; + sheet.View.FreezePanes(REPORT_SNAPSHOTS_PIVOT_SHEET_START_PIVOT_AT + REPORT_SNAPSHOTS_PIVOT_SHEET_CHART_HEIGHT + 5, 1); - #endregion + sheet = excelReport.Workbook.Worksheets.Add(REPORT_SNAPSHOTS_SHEET_METHOD_CALL_LINES_LOCATION_PIVOT); + sheet.Cells[1, 1].Value = "Table of Contents"; + sheet.Cells[1, 2].Formula = String.Format(@"=HYPERLINK(""#'{0}'!A1"", """")", REPORT_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"", """")", REPORT_SNAPSHOTS_SHEET_METHOD_CALL_LINES); + sheet.Cells[2, 2].StyleName = "HyperLinkStyle"; + sheet.View.FreezePanes(REPORT_SNAPSHOTS_PIVOT_SHEET_START_PIVOT_AT + REPORT_SNAPSHOTS_PIVOT_SHEET_CHART_HEIGHT + 3, 1); - #region Application + sheet = excelReport.Workbook.Worksheets.Add(REPORT_SNAPSHOTS_SHEET_METHOD_CALL_LINES_OCCURRENCES); + sheet.Cells[1, 1].Value = "Table of Contents"; + sheet.Cells[1, 2].Formula = String.Format(@"=HYPERLINK(""#'{0}'!A1"", """")", REPORT_SHEET_TOC); + sheet.Cells[1, 2].StyleName = "HyperLinkStyle"; + sheet.Cells[2, 1].Value = "See Pivot Type"; + sheet.Cells[2, 2].Formula = String.Format(@"=HYPERLINK(""#'{0}'!A1"", """")", REPORT_SNAPSHOTS_SHEET_METHOD_CALL_LINES_OCCURRENCES_TYPE_PIVOT); + sheet.Cells[2, 2].StyleName = "HyperLinkStyle"; + sheet.Cells[3, 1].Value = "See Pivot Location"; + sheet.Cells[3, 2].Formula = String.Format(@"=HYPERLINK(""#'{0}'!A1"", """")", REPORT_SNAPSHOTS_SHEET_METHOD_CALL_LINES_OCCURRENCES_LOCATION_PIVOT); + sheet.Cells[3, 2].StyleName = "HyperLinkStyle"; + sheet.View.FreezePanes(REPORT_SNAPSHOTS_LIST_SHEET_START_TABLE_AT + 1, 1); - List applicationList = FileIOHelper.readListFromCSVFile(applicationReportFilePath, new ApplicationEntityReportMap()); + sheet = excelReport.Workbook.Worksheets.Add(REPORT_SNAPSHOTS_SHEET_METHOD_CALL_LINES_OCCURRENCES_TYPE_PIVOT); + sheet.Cells[1, 1].Value = "Table of Contents"; + sheet.Cells[1, 2].Formula = String.Format(@"=HYPERLINK(""#'{0}'!A1"", """")", REPORT_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"", """")", REPORT_SNAPSHOTS_SHEET_METHOD_CALL_LINES_OCCURRENCES); + sheet.Cells[2, 2].StyleName = "HyperLinkStyle"; + sheet.View.FreezePanes(REPORT_SNAPSHOTS_PIVOT_SHEET_START_PIVOT_AT + REPORT_SNAPSHOTS_PIVOT_SHEET_CHART_HEIGHT + 5, 1); - metricsEntityFolderPath = Path.Combine(metricsFolderPath, APPLICATION_TYPE_SHORT); - entitiesFullRangeReportFilePath = Path.Combine(metricsEntityFolderPath, CONVERT_ENTITY_METRICS_FULLRANGE_FILE_NAME); - List applicationMetricsList = FileIOHelper.readListFromCSVFile(entitiesFullRangeReportFilePath, new ApplicationMetricReportMap()); + sheet = excelReport.Workbook.Worksheets.Add(REPORT_SNAPSHOTS_SHEET_METHOD_CALL_LINES_OCCURRENCES_LOCATION_PIVOT); + sheet.Cells[1, 1].Value = "Table of Contents"; + sheet.Cells[1, 2].Formula = String.Format(@"=HYPERLINK(""#'{0}'!A1"", """")", REPORT_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"", """")", REPORT_SNAPSHOTS_SHEET_METHOD_CALL_LINES_OCCURRENCES); + sheet.Cells[2, 2].StyleName = "HyperLinkStyle"; + sheet.View.FreezePanes(REPORT_SNAPSHOTS_PIVOT_SHEET_START_PIVOT_AT + REPORT_SNAPSHOTS_PIVOT_SHEET_CHART_HEIGHT + 4, 1); - if (applicationList != null && applicationList.Count > 0) - { - loggerConsole.Info("Entity Details for Application"); + #endregion - stepTimingTarget.NumEntities = stepTimingTarget.NumEntities + 1; + #region Report file variables - reportMetricDetailApplication( - programOptions, - jobConfiguration, - jobTarget, - applicationList[0], - (applicationMetricsList != null && applicationMetricsList.Count > 0) ? applicationMetricsList[0] : null, - eventsAllList, - healthRuleViolationEventsAllList, - snapshotsAllList, - segmentsAllList, - exitCallsAllList, - serviceEndpointCallsAllList, - detectedErrorsAllList, - businessDataAllList); - } + // Various folders + string reportFolderPath = Path.Combine(programOptions.OutputJobFolderPath, REPORTS_FOLDER_NAME); + string entitiesAllFolderPath = Path.Combine(reportFolderPath, ENTITIES_FOLDER_NAME); + string snapshotsAllFolderPath = Path.Combine(reportFolderPath, SNAPSHOTS_FOLDER_NAME); - #endregion + // Report files for All + string controllersAllReportFilePath = Path.Combine(entitiesAllFolderPath, CONVERT_ENTITY_CONTROLLERS_FILE_NAME); + string methodCallLinesAllReportFilePath = Path.Combine(snapshotsAllFolderPath, CONVERT_SNAPSHOTS_SEGMENTS_METHOD_CALL_LINES_FILE_NAME); + string methodCallLinesOccurrencesAllReportFilePath = Path.Combine(snapshotsAllFolderPath, CONVERT_SNAPSHOTS_SEGMENTS_METHOD_CALL_LINES_OCCURRENCES_FILE_NAME); + string applicationSnapshotsSummaryAllReportFilePath = Path.Combine(snapshotsAllFolderPath, CONVERT_APPLICATION_SNAPSHOTS_FILE_NAME); - #region Tier + #endregion - List tiersList = FileIOHelper.readListFromCSVFile(tiersReportFilePath, new TierEntityReportMap()); + loggerConsole.Info("Fill Snapshots Method Call Lines Report File"); - metricsEntityFolderPath = Path.Combine(metricsFolderPath, TIERS_TYPE_SHORT); - entitiesFullRangeReportFilePath = Path.Combine(metricsEntityFolderPath, CONVERT_ENTITIES_METRICS_FULLRANGE_FILE_NAME); - List tiersMetricsList = FileIOHelper.readListFromCSVFile(entitiesFullRangeReportFilePath, new TierMetricReportMap()); + #region Controllers - if (tiersList != null) - { - loggerConsole.Info("Entity Details for Tiers ({0} entities)", tiersList.Count); + loggerConsole.Info("List of Controllers"); - stepTimingTarget.NumEntities = stepTimingTarget.NumEntities + tiersList.Count; + sheet = excelReport.Workbook.Worksheets[REPORT_SNAPSHOTS_SHEET_CONTROLLERS]; + readCSVFileIntoExcelRange(controllersAllReportFilePath, 0, sheet, REPORT_SNAPSHOTS_LIST_SHEET_START_TABLE_AT, 1); - int j = 0; + #endregion - if (programOptions.ProcessSequentially == false) - { - var tiersListChunks = tiersList.BreakListIntoChunks(METRIC_DETAILS_REPORT_NUMBER_OF_ENTITIES_TO_PROCESS_PER_THREAD); + #region Applications - Parallel.ForEach, int>( - tiersListChunks, - () => 0, - (tiersListChunk, loop, subtotal) => - { - subtotal += reportMetricDetailTiers( - programOptions, - jobConfiguration, - jobTarget, - tiersListChunk, - tiersMetricsList, - eventsAllList, - healthRuleViolationEventsAllList, - snapshotsAllList, - segmentsAllList, - exitCallsAllList, - serviceEndpointCallsAllList, - detectedErrorsAllList, - businessDataAllList, - false); - return subtotal; - }, - (finalResult) => - { - j = Interlocked.Add(ref j, finalResult); - Console.Write("[{0}].", j); - } - ); - } - else - { - j = reportMetricDetailTiers( - programOptions, - jobConfiguration, - jobTarget, - tiersList, - tiersMetricsList, - eventsAllList, - healthRuleViolationEventsAllList, - snapshotsAllList, - segmentsAllList, - exitCallsAllList, - serviceEndpointCallsAllList, - detectedErrorsAllList, - businessDataAllList, - true); - } + loggerConsole.Info("List of Applications"); - loggerConsole.Info("{0} entities", j); - } + sheet = excelReport.Workbook.Worksheets[REPORT_SNAPSHOTS_SHEET_APPLICATIONS]; + readCSVFileIntoExcelRange(applicationSnapshotsSummaryAllReportFilePath, 0, sheet, REPORT_SNAPSHOTS_LIST_SHEET_START_TABLE_AT, 1); - #endregion + #endregion - #region Nodes + #region Method Call Lines - List nodesList = FileIOHelper.readListFromCSVFile(nodesReportFilePath, new NodeEntityReportMap()); + loggerConsole.Info("List of Method Call Lines"); - metricsEntityFolderPath = Path.Combine(metricsFolderPath, NODES_TYPE_SHORT); - entitiesFullRangeReportFilePath = Path.Combine(metricsEntityFolderPath, CONVERT_ENTITIES_METRICS_FULLRANGE_FILE_NAME); - List nodesMetricsList = FileIOHelper.readListFromCSVFile(entitiesFullRangeReportFilePath, new NodeMetricReportMap()); + sheet = excelReport.Workbook.Worksheets[REPORT_SNAPSHOTS_SHEET_METHOD_CALL_LINES]; + readCSVFileIntoExcelRange(methodCallLinesAllReportFilePath, 0, sheet, REPORT_SNAPSHOTS_LIST_SHEET_START_TABLE_AT, 1); - if (nodesList != null) - { - loggerConsole.Info("Entity Details for Nodes ({0} entities)", nodesList.Count); + #endregion - stepTimingTarget.NumEntities = stepTimingTarget.NumEntities + nodesList.Count; + #region Method Call Occurrences - int j = 0; + loggerConsole.Info("List of Method Call Occurrences"); - if (programOptions.ProcessSequentially == false) - { - var nodesListChunks = nodesList.BreakListIntoChunks(METRIC_DETAILS_REPORT_NUMBER_OF_ENTITIES_TO_PROCESS_PER_THREAD); + sheet = excelReport.Workbook.Worksheets[REPORT_SNAPSHOTS_SHEET_METHOD_CALL_LINES_OCCURRENCES]; + readCSVFileIntoExcelRange(methodCallLinesOccurrencesAllReportFilePath, 0, sheet, REPORT_SNAPSHOTS_LIST_SHEET_START_TABLE_AT, 1); - Parallel.ForEach, int>( - nodesListChunks, - () => 0, - (nodesListChunk, loop, subtotal) => - { - subtotal += reportMetricDetailNodes( - programOptions, - jobConfiguration, - jobTarget, - nodesListChunk, - nodesMetricsList, - eventsAllList, - healthRuleViolationEventsAllList, - snapshotsAllList, - segmentsAllList, - exitCallsAllList, - serviceEndpointCallsAllList, - detectedErrorsAllList, - businessDataAllList, - false); - return subtotal; - }, - (finalResult) => - { - j = Interlocked.Add(ref j, finalResult); - Console.Write("[{0}].", j); - } - ); - } - else - { - j = reportMetricDetailNodes( - programOptions, - jobConfiguration, - jobTarget, - nodesList, - nodesMetricsList, - eventsAllList, - healthRuleViolationEventsAllList, - snapshotsAllList, - segmentsAllList, - exitCallsAllList, - serviceEndpointCallsAllList, - detectedErrorsAllList, - businessDataAllList, - true); - } + #endregion - loggerConsole.Info("{0} entities", j); - } + loggerConsole.Info("Finalize Snapshots Method Call Lines Report File"); - #endregion + #region Controllers sheet - #region Backends + // Make table + sheet = excelReport.Workbook.Worksheets[REPORT_SNAPSHOTS_SHEET_CONTROLLERS]; + logger.Info("Controllers Sheet ({0} rows)", sheet.Dimension.Rows); + loggerConsole.Info("Controllers Sheet ({0} rows)", sheet.Dimension.Rows); + if (sheet.Dimension.Rows > REPORT_SNAPSHOTS_LIST_SHEET_START_TABLE_AT) + { + range = sheet.Cells[REPORT_SNAPSHOTS_LIST_SHEET_START_TABLE_AT, 1, sheet.Dimension.Rows, sheet.Dimension.Columns]; + table = sheet.Tables.Add(range, REPORT_SNAPSHOTS_TABLE_CONTROLLERS); + table.ShowHeader = true; + table.TableStyle = TableStyles.Medium2; + table.ShowFilter = true; + table.ShowTotal = false; - List backendsList = FileIOHelper.readListFromCSVFile(backendsReportFilePath, new BackendEntityReportMap()); + sheet.Column(table.Columns["Controller"].Position + 1).Width = 25; + sheet.Column(table.Columns["UserName"].Position + 1).Width = 25; + } - metricsEntityFolderPath = Path.Combine(metricsFolderPath, BACKENDS_TYPE_SHORT); - entitiesFullRangeReportFilePath = Path.Combine(metricsEntityFolderPath, CONVERT_ENTITIES_METRICS_FULLRANGE_FILE_NAME); - List backendsMetricsList = FileIOHelper.readListFromCSVFile(entitiesFullRangeReportFilePath, new BackendMetricReportMap()); + #endregion - if (backendsList != null) - { - loggerConsole.Info("Entity Details for Backends ({0} entities)", backendsList.Count); + #region Applications - stepTimingTarget.NumEntities = stepTimingTarget.NumEntities + backendsList.Count; + // Make table + sheet = excelReport.Workbook.Worksheets[REPORT_SNAPSHOTS_SHEET_APPLICATIONS]; + logger.Info("Applications Sheet ({0} rows)", sheet.Dimension.Rows); + loggerConsole.Info("Applications Sheet ({0} rows)", sheet.Dimension.Rows); + if (sheet.Dimension.Rows > REPORT_SNAPSHOTS_LIST_SHEET_START_TABLE_AT) + { + range = sheet.Cells[REPORT_SNAPSHOTS_LIST_SHEET_START_TABLE_AT, 1, sheet.Dimension.Rows, sheet.Dimension.Columns]; + table = sheet.Tables.Add(range, REPORT_SNAPSHOTS_TABLE_APPLICATIONS); + table.ShowHeader = true; + table.TableStyle = TableStyles.Medium2; + table.ShowFilter = true; + table.ShowTotal = false; - int j = 0; + adjustColumnsOfEntityRowTableInMetricReport(APPLICATION_TYPE_SHORT, sheet, table); - if (programOptions.ProcessSequentially == false) - { - var backendsListChunks = backendsList.BreakListIntoChunks(METRIC_DETAILS_REPORT_NUMBER_OF_ENTITIES_TO_PROCESS_PER_THREAD); + ExcelAddress cfAddressNum = new ExcelAddress(REPORT_SNAPSHOTS_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumSnapshots"].Position + 1, sheet.Dimension.Rows, table.Columns["NumSnapshots"].Position + 1); + var cfNum = sheet.ConditionalFormatting.AddDatabar(cfAddressNum, colorLightBlueForDatabars); - Parallel.ForEach, int>( - backendsListChunks, - () => 0, - (backendsListChunk, loop, subtotal) => - { - subtotal += reportMetricDetailBackends( - programOptions, - jobConfiguration, - jobTarget, - backendsListChunk, - backendsMetricsList, - eventsAllList, - healthRuleViolationEventsAllList, - snapshotsAllList, - segmentsAllList, - exitCallsAllList, - serviceEndpointCallsAllList, - detectedErrorsAllList, - businessDataAllList, - false); - return subtotal; - }, - (finalResult) => - { - j = Interlocked.Add(ref j, finalResult); - Console.Write("[{0}].", j); - } - ); - } - else - { - j = reportMetricDetailBackends( - programOptions, - jobConfiguration, - jobTarget, - backendsList, - backendsMetricsList, - eventsAllList, - healthRuleViolationEventsAllList, - snapshotsAllList, - segmentsAllList, - exitCallsAllList, - serviceEndpointCallsAllList, - detectedErrorsAllList, - businessDataAllList, - true); - } + cfAddressNum = new ExcelAddress(REPORT_SNAPSHOTS_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumSnapshotsNormal"].Position + 1, sheet.Dimension.Rows, table.Columns["NumSnapshotsNormal"].Position + 1); + cfNum = sheet.ConditionalFormatting.AddDatabar(cfAddressNum, colorLightBlueForDatabars); - loggerConsole.Info("{0} entities", j); - } + cfAddressNum = new ExcelAddress(REPORT_SNAPSHOTS_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumSnapshotsVerySlow"].Position + 1, sheet.Dimension.Rows, table.Columns["NumSnapshotsVerySlow"].Position + 1); + cfNum = sheet.ConditionalFormatting.AddDatabar(cfAddressNum, colorLightBlueForDatabars); - #endregion + cfAddressNum = new ExcelAddress(REPORT_SNAPSHOTS_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumSnapshotsStall"].Position + 1, sheet.Dimension.Rows, table.Columns["NumSnapshotsStall"].Position + 1); + cfNum = sheet.ConditionalFormatting.AddDatabar(cfAddressNum, colorLightBlueForDatabars); - #region Business Transactions + cfAddressNum = new ExcelAddress(REPORT_SNAPSHOTS_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumSnapshotsSlow"].Position + 1, sheet.Dimension.Rows, table.Columns["NumSnapshotsSlow"].Position + 1); + cfNum = sheet.ConditionalFormatting.AddDatabar(cfAddressNum, colorLightBlueForDatabars); - List businessTransactionsList = FileIOHelper.readListFromCSVFile(businessTransactionsReportFilePath, new BusinessTransactionEntityReportMap()); + cfAddressNum = new ExcelAddress(REPORT_SNAPSHOTS_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumSnapshotsError"].Position + 1, sheet.Dimension.Rows, table.Columns["NumSnapshotsError"].Position + 1); + cfNum = sheet.ConditionalFormatting.AddDatabar(cfAddressNum, colorLightBlueForDatabars); + } - metricsEntityFolderPath = Path.Combine(metricsFolderPath, BUSINESS_TRANSACTIONS_TYPE_SHORT); - entitiesFullRangeReportFilePath = Path.Combine(metricsEntityFolderPath, CONVERT_ENTITIES_METRICS_FULLRANGE_FILE_NAME); - List businessTransactionsMetricsList = FileIOHelper.readListFromCSVFile(entitiesFullRangeReportFilePath, new BusinessTransactionMetricReportMap()); + #endregion - if (businessTransactionsList != null) - { - loggerConsole.Info("Entity Details for Business Transactions ({0} entities)", businessTransactionsList.Count); + #region Method Call Lines - stepTimingTarget.NumEntities = stepTimingTarget.NumEntities + businessTransactionsList.Count; + // Make table + sheet = excelReport.Workbook.Worksheets[REPORT_SNAPSHOTS_SHEET_METHOD_CALL_LINES]; + logger.Info("Method Call Lines Sheet ({0} rows)", sheet.Dimension.Rows); + loggerConsole.Info("Method Call Lines Sheet ({0} rows)", sheet.Dimension.Rows); + if (sheet.Dimension.Rows > REPORT_SNAPSHOTS_LIST_SHEET_START_TABLE_AT) + { + range = sheet.Cells[REPORT_SNAPSHOTS_LIST_SHEET_START_TABLE_AT, 1, sheet.Dimension.Rows, sheet.Dimension.Columns]; + table = sheet.Tables.Add(range, REPORT_SNAPSHOTS_TABLE_METHOD_CALL_LINES); + table.ShowHeader = true; + table.TableStyle = TableStyles.Medium2; + table.ShowFilter = true; + table.ShowTotal = false; + + sheet.Column(table.Columns["Controller"].Position + 1).Width = 20; + sheet.Column(table.Columns["ApplicationName"].Position + 1).Width = 20; + sheet.Column(table.Columns["TierName"].Position + 1).Width = 20; + sheet.Column(table.Columns["NodeName"].Position + 1).Width = 20; + sheet.Column(table.Columns["BTName"].Position + 1).Width = 20; + sheet.Column(table.Columns["RequestID"].Position + 1).Width = 20; + sheet.Column(table.Columns["SegmentID"].Position + 1).Width = 10; + sheet.Column(table.Columns["Type"].Position + 1).Width = 15; + sheet.Column(table.Columns["Framework"].Position + 1).Width = 15; + sheet.Column(table.Columns["FullNameIndent"].Position + 1).Width = 45; + sheet.Column(table.Columns["ExitCalls"].Position + 1).Width = 15; + + sheet = excelReport.Workbook.Worksheets[REPORT_SNAPSHOTS_SHEET_METHOD_CALL_LINES_TYPE_PIVOT]; + ExcelPivotTable pivot = sheet.PivotTables.Add(sheet.Cells[REPORT_SNAPSHOTS_PIVOT_SHEET_START_PIVOT_AT + REPORT_SNAPSHOTS_PIVOT_SHEET_CHART_HEIGHT + 2, 1], range, REPORT_SNAPSHOTS_PIVOT_METHOD_CALL_LINES_TYPE); + ExcelPivotTableField fieldF = pivot.PageFields.Add(pivot.Fields["ElementType"]); + fieldF = pivot.PageFields.Add(pivot.Fields["NumChildren"]); + fieldF = pivot.PageFields.Add(pivot.Fields["NumExits"]); + fieldF = pivot.PageFields.Add(pivot.Fields["Depth"]); + fieldF = pivot.PageFields.Add(pivot.Fields["ExecRange"]); + ExcelPivotTableField fieldR = pivot.RowFields.Add(pivot.Fields["Controller"]); + fieldR.Compact = false; + fieldR.Outline = false; + fieldR = pivot.RowFields.Add(pivot.Fields["ApplicationName"]); + fieldR.Compact = false; + fieldR.Outline = false; + fieldR = pivot.RowFields.Add(pivot.Fields["TierName"]); + fieldR.Compact = false; + fieldR.Outline = false; + fieldR = pivot.RowFields.Add(pivot.Fields["BTName"]); + fieldR.Compact = false; + fieldR.Outline = false; + fieldR = pivot.RowFields.Add(pivot.Fields["FullName"]); + fieldR.Compact = false; + fieldR.Outline = false; + ExcelPivotTableField fieldC = pivot.ColumnFields.Add(pivot.Fields["Type"]); + fieldC.Compact = false; + fieldC.Outline = false; + fieldC = pivot.ColumnFields.Add(pivot.Fields["Framework"]); + fieldC.Compact = false; + fieldC.Outline = false; + ExcelPivotTableDataField fieldD = pivot.DataFields.Add(pivot.Fields["Exec"]); + fieldD.Function = DataFieldFunctions.Average; - int j = 0; + ExcelChart chart = sheet.Drawings.AddChart(REPORT_SNAPSHOTS_PIVOT_METHOD_CALL_LINES_GRAPH_TYPE, eChartType.ColumnClustered, pivot); + chart.SetPosition(2, 0, 0, 0); + chart.SetSize(800, 300); - if (programOptions.ProcessSequentially == false) - { - var businessTransactionsListChunks = businessTransactionsList.BreakListIntoChunks(METRIC_DETAILS_REPORT_NUMBER_OF_ENTITIES_TO_PROCESS_PER_THREAD); + sheet = excelReport.Workbook.Worksheets[REPORT_SNAPSHOTS_SHEET_METHOD_CALL_LINES_LOCATION_PIVOT]; + pivot = sheet.PivotTables.Add(sheet.Cells[REPORT_SNAPSHOTS_PIVOT_SHEET_START_PIVOT_AT + REPORT_SNAPSHOTS_PIVOT_SHEET_CHART_HEIGHT + 2, 1], range, REPORT_SNAPSHOTS_PIVOT_METHOD_CALL_LINES_LOCATION); + fieldF = pivot.PageFields.Add(pivot.Fields["ElementType"]); + fieldF = pivot.PageFields.Add(pivot.Fields["NumChildren"]); + fieldF = pivot.PageFields.Add(pivot.Fields["NumExits"]); + fieldF = pivot.PageFields.Add(pivot.Fields["Depth"]); + fieldF = pivot.PageFields.Add(pivot.Fields["ExecRange"]); + fieldR = pivot.RowFields.Add(pivot.Fields["Type"]); + fieldR.Compact = false; + fieldR.Outline = false; + fieldR = pivot.RowFields.Add(pivot.Fields["Framework"]); + fieldR.Compact = false; + fieldR.Outline = false; + fieldR = pivot.RowFields.Add(pivot.Fields["FullName"]); + fieldR.Compact = false; + fieldR.Outline = false; + fieldR = pivot.RowFields.Add(pivot.Fields["Controller"]); + fieldR.Compact = false; + fieldR.Outline = false; + fieldR = pivot.RowFields.Add(pivot.Fields["ApplicationName"]); + fieldR.Compact = false; + fieldR.Outline = false; + fieldR = pivot.RowFields.Add(pivot.Fields["TierName"]); + fieldR.Compact = false; + fieldR.Outline = false; + fieldR = pivot.RowFields.Add(pivot.Fields["BTName"]); + fieldR.Compact = false; + fieldR.Outline = false; + fieldD = pivot.DataFields.Add(pivot.Fields["Exec"]); + fieldD.Function = DataFieldFunctions.Count; + fieldD.Name = "Number of Items"; + fieldD = pivot.DataFields.Add(pivot.Fields["Exec"]); + fieldD.Function = DataFieldFunctions.Average; + fieldD.Name = "Average Duration"; + fieldD = pivot.DataFields.Add(pivot.Fields["Exec"]); + fieldD.Function = DataFieldFunctions.Sum; + fieldD.Name = "Total Duration"; - Parallel.ForEach, int>( - businessTransactionsListChunks, - () => 0, - (businessTransactionsListChunk, loop, subtotal) => - { - subtotal += reportMetricDetailBusinessTransactions( - programOptions, - jobConfiguration, - jobTarget, - businessTransactionsListChunk, - businessTransactionsMetricsList, - eventsAllList, - healthRuleViolationEventsAllList, - snapshotsAllList, - segmentsAllList, - exitCallsAllList, - serviceEndpointCallsAllList, - detectedErrorsAllList, - businessDataAllList, - false); - return subtotal; - }, - (finalResult) => - { - j = Interlocked.Add(ref j, finalResult); - Console.Write("[{0}].", j); - } - ); - } - else - { - j = reportMetricDetailBusinessTransactions( - programOptions, - jobConfiguration, - jobTarget, - businessTransactionsList, - businessTransactionsMetricsList, - eventsAllList, - healthRuleViolationEventsAllList, - snapshotsAllList, - segmentsAllList, - exitCallsAllList, - serviceEndpointCallsAllList, - detectedErrorsAllList, - businessDataAllList, - true); - } + chart = sheet.Drawings.AddChart(REPORT_SNAPSHOTS_PIVOT_METHOD_CALL_LINES_GRAPH_LOCATION, eChartType.ColumnClustered, pivot); + chart.SetPosition(2, 0, 0, 0); + chart.SetSize(800, 300); + } - loggerConsole.Info("{0} entities", j); - } + #endregion - #endregion + #region Method Call Occurrences - #region Service Endpoints + // Make table + sheet = excelReport.Workbook.Worksheets[REPORT_SNAPSHOTS_SHEET_METHOD_CALL_LINES_OCCURRENCES]; + logger.Info("Method Call Occurrences Sheet ({0} rows)", sheet.Dimension.Rows); + loggerConsole.Info("Method Call Occurrences Sheet ({0} rows)", sheet.Dimension.Rows); + if (sheet.Dimension.Rows > REPORT_SNAPSHOTS_LIST_SHEET_START_TABLE_AT) + { + range = sheet.Cells[REPORT_SNAPSHOTS_LIST_SHEET_START_TABLE_AT, 1, sheet.Dimension.Rows, sheet.Dimension.Columns]; + table = sheet.Tables.Add(range, REPORT_SNAPSHOTS_TABLE_METHOD_CALL_LINES_OCCURRENCES); + table.ShowHeader = true; + table.TableStyle = TableStyles.Medium2; + table.ShowFilter = true; + table.ShowTotal = false; - List serviceEndpointsList = FileIOHelper.readListFromCSVFile(serviceEndpointsReportFilePath, new ServiceEndpointEntityReportMap()); + sheet.Column(table.Columns["Controller"].Position + 1).Width = 20; + sheet.Column(table.Columns["ApplicationName"].Position + 1).Width = 20; + sheet.Column(table.Columns["TierName"].Position + 1).Width = 20; + sheet.Column(table.Columns["NodeName"].Position + 1).Width = 20; + sheet.Column(table.Columns["BTName"].Position + 1).Width = 20; + sheet.Column(table.Columns["RequestID"].Position + 1).Width = 20; + sheet.Column(table.Columns["SegmentID"].Position + 1).Width = 10; + sheet.Column(table.Columns["Type"].Position + 1).Width = 15; + sheet.Column(table.Columns["Framework"].Position + 1).Width = 15; + sheet.Column(table.Columns["FullName"].Position + 1).Width = 45; + + sheet = excelReport.Workbook.Worksheets[REPORT_SNAPSHOTS_SHEET_METHOD_CALL_LINES_OCCURRENCES_TYPE_PIVOT]; + ExcelPivotTable pivot = sheet.PivotTables.Add(sheet.Cells[REPORT_SNAPSHOTS_PIVOT_SHEET_START_PIVOT_AT + REPORT_SNAPSHOTS_PIVOT_SHEET_CHART_HEIGHT + 2, 1], range, REPORT_SNAPSHOTS_PIVOT_METHOD_CALL_LINES_OCCURRENCES_TYPE); + ExcelPivotTableField fieldF = pivot.PageFields.Add(pivot.Fields["NumChildren"]); + fieldF = pivot.PageFields.Add(pivot.Fields["NumExits"]); + fieldF = pivot.PageFields.Add(pivot.Fields["ExecRange"]); + ExcelPivotTableField fieldR = pivot.RowFields.Add(pivot.Fields["Controller"]); + fieldR.Compact = false; + fieldR.Outline = false; + fieldR = pivot.RowFields.Add(pivot.Fields["ApplicationName"]); + fieldR.Compact = false; + fieldR.Outline = false; + fieldR = pivot.RowFields.Add(pivot.Fields["TierName"]); + fieldR.Compact = false; + fieldR.Outline = false; + fieldR = pivot.RowFields.Add(pivot.Fields["BTName"]); + fieldR.Compact = false; + fieldR.Outline = false; + fieldR = pivot.RowFields.Add(pivot.Fields["FullName"]); + fieldR.Compact = false; + fieldR.Outline = false; + ExcelPivotTableField fieldC = pivot.ColumnFields.Add(pivot.Fields["Type"]); + fieldC.Compact = false; + fieldC.Outline = false; + fieldC = pivot.ColumnFields.Add(pivot.Fields["Framework"]); + fieldC.Compact = false; + fieldC.Outline = false; + ExcelPivotTableDataField fieldD = pivot.DataFields.Add(pivot.Fields["NumCalls"]); + fieldD.Function = DataFieldFunctions.Sum; - metricsEntityFolderPath = Path.Combine(metricsFolderPath, SERVICE_ENDPOINTS_TYPE_SHORT); - entitiesFullRangeReportFilePath = Path.Combine(metricsEntityFolderPath, CONVERT_ENTITIES_METRICS_FULLRANGE_FILE_NAME); - List serviceEndpointsMetricsList = FileIOHelper.readListFromCSVFile(entitiesFullRangeReportFilePath, new ServiceEndpointMetricReportMap()); + ExcelChart chart = sheet.Drawings.AddChart(REPORT_SNAPSHOTS_PIVOT_METHOD_CALL_LINES_GRAPH_TYPE, eChartType.ColumnClustered, pivot); + chart.SetPosition(2, 0, 0, 0); + chart.SetSize(800, 300); - if (serviceEndpointsList != null) - { - loggerConsole.Info("Entity Details for Service Endpoints ({0} entities)", serviceEndpointsList.Count); + sheet = excelReport.Workbook.Worksheets[REPORT_SNAPSHOTS_SHEET_METHOD_CALL_LINES_OCCURRENCES_LOCATION_PIVOT]; + pivot = sheet.PivotTables.Add(sheet.Cells[REPORT_SNAPSHOTS_PIVOT_SHEET_START_PIVOT_AT + REPORT_SNAPSHOTS_PIVOT_SHEET_CHART_HEIGHT + 2, 1], range, REPORT_SNAPSHOTS_PIVOT_METHOD_CALL_LINES_OCCURRENCES_LOCATION); + fieldF = pivot.PageFields.Add(pivot.Fields["NumChildren"]); + fieldF = pivot.PageFields.Add(pivot.Fields["NumExits"]); + fieldR = pivot.RowFields.Add(pivot.Fields["Type"]); + fieldR.Compact = false; + fieldR.Outline = false; + fieldR = pivot.RowFields.Add(pivot.Fields["Framework"]); + fieldR.Compact = false; + fieldR.Outline = false; + fieldR = pivot.RowFields.Add(pivot.Fields["FullName"]); + fieldR.Compact = false; + fieldR.Outline = false; + fieldR = pivot.RowFields.Add(pivot.Fields["Controller"]); + fieldR.Compact = false; + fieldR.Outline = false; + fieldR = pivot.RowFields.Add(pivot.Fields["ApplicationName"]); + fieldR.Compact = false; + fieldR.Outline = false; + fieldR = pivot.RowFields.Add(pivot.Fields["TierName"]); + fieldR.Compact = false; + fieldR.Outline = false; + fieldR = pivot.RowFields.Add(pivot.Fields["BTName"]); + fieldR.Compact = false; + fieldR.Outline = false; + fieldC = pivot.ColumnFields.Add(pivot.Fields["ExecRange"]); + fieldC.Compact = false; + fieldC.Outline = false; + fieldD = pivot.DataFields.Add(pivot.Fields["NumCalls"]); + fieldD.Function = DataFieldFunctions.Sum; - stepTimingTarget.NumEntities = stepTimingTarget.NumEntities + serviceEndpointsList.Count; + chart = sheet.Drawings.AddChart(REPORT_SNAPSHOTS_PIVOT_METHOD_CALL_LINES_OCCURRENCES_GRAPH_LOCATION, eChartType.ColumnClustered, pivot); + chart.SetPosition(2, 0, 0, 0); + chart.SetSize(800, 300); + } - int j = 0; + #endregion - if (programOptions.ProcessSequentially == false) - { - var serviceEndpointsListChunks = serviceEndpointsList.BreakListIntoChunks(METRIC_DETAILS_REPORT_NUMBER_OF_ENTITIES_TO_PROCESS_PER_THREAD); + #region TOC sheet - Parallel.ForEach, int>( - serviceEndpointsListChunks, - () => 0, - (serviceEndpointsListChunk, loop, subtotal) => - { - subtotal += reportMetricDetailServiceEndpoints( - programOptions, - jobConfiguration, - jobTarget, - serviceEndpointsListChunk, - serviceEndpointsMetricsList, - eventsAllList, - healthRuleViolationEventsAllList, - snapshotsAllList, - segmentsAllList, - exitCallsAllList, - serviceEndpointCallsAllList, - detectedErrorsAllList, - businessDataAllList, - false); - return subtotal; - }, - (finalResult) => - { - j = Interlocked.Add(ref j, finalResult); - Console.Write("[{0}].", j); - } - ); - } - else - { - j = reportMetricDetailServiceEndpoints( - programOptions, - jobConfiguration, - jobTarget, - serviceEndpointsList, - serviceEndpointsMetricsList, - eventsAllList, - healthRuleViolationEventsAllList, - snapshotsAllList, - segmentsAllList, - exitCallsAllList, - serviceEndpointCallsAllList, - detectedErrorsAllList, - businessDataAllList, - true); - } - - loggerConsole.Info("{0} entities", j); - } - - #endregion - - #region Errors - - List errorsList = FileIOHelper.readListFromCSVFile(errorsReportFilePath, new ErrorEntityReportMap()); - - metricsEntityFolderPath = Path.Combine(metricsFolderPath, ERRORS_TYPE_SHORT); - entitiesFullRangeReportFilePath = Path.Combine(metricsEntityFolderPath, CONVERT_ENTITIES_METRICS_FULLRANGE_FILE_NAME); - List errorsMetricsList = FileIOHelper.readListFromCSVFile(entitiesFullRangeReportFilePath, new ErrorMetricReportMap()); - - if (errorsList != null) - { - loggerConsole.Info("Entity Details for Errors ({0} entities)", errorsList.Count); - - stepTimingTarget.NumEntities = stepTimingTarget.NumEntities + errorsList.Count; - - int j = 0; - - if (programOptions.ProcessSequentially == false) - { - var errorsListChunks = errorsList.BreakListIntoChunks(METRIC_DETAILS_REPORT_NUMBER_OF_ENTITIES_TO_PROCESS_PER_THREAD); + // TOC sheet again + sheet = excelReport.Workbook.Worksheets[REPORT_SHEET_TOC]; + sheet.Cells[1, 1].Value = "Sheet Name"; + sheet.Cells[1, 2].Value = "# Entities"; + sheet.Cells[1, 3].Value = "Link"; + int rowNum = 1; + foreach (ExcelWorksheet s in excelReport.Workbook.Worksheets) + { + rowNum++; + sheet.Cells[rowNum, 1].Value = s.Name; + sheet.Cells[rowNum, 3].Formula = String.Format(@"=HYPERLINK(""#'{0}'!A1"", """")", s.Name); + sheet.Cells[rowNum, 3].StyleName = "HyperLinkStyle"; + if (s.Tables.Count > 0) + { + table = s.Tables[0]; + sheet.Cells[rowNum, 2].Value = table.Address.Rows - 1; + } + } + range = sheet.Cells[1, 1, sheet.Dimension.Rows, sheet.Dimension.Columns]; + table = sheet.Tables.Add(range, REPORT_SNAPSHOTS_TABLE_TOC); + table.ShowHeader = true; + table.TableStyle = TableStyles.Medium2; + table.ShowFilter = true; + table.ShowTotal = false; - Parallel.ForEach, int>( - errorsListChunks, - () => 0, - (errorsListChunk, loop, subtotal) => - { - subtotal += reportMetricDetailErrors( - programOptions, - jobConfiguration, - jobTarget, - errorsListChunk, - errorsMetricsList, - eventsAllList, - healthRuleViolationEventsAllList, - snapshotsAllList, - segmentsAllList, - exitCallsAllList, - serviceEndpointCallsAllList, - detectedErrorsAllList, - businessDataAllList, - false); - return subtotal; - }, - (finalResult) => - { - j = Interlocked.Add(ref j, finalResult); - Console.Write("[{0}].", j); - } - ); - } - else - { - j = reportMetricDetailErrors( - programOptions, - jobConfiguration, - jobTarget, - errorsList, - errorsMetricsList, - eventsAllList, - healthRuleViolationEventsAllList, - snapshotsAllList, - segmentsAllList, - exitCallsAllList, - serviceEndpointCallsAllList, - detectedErrorsAllList, - businessDataAllList, - true); - } + sheet.Column(table.Columns["Sheet Name"].Position + 1).Width = 25; + sheet.Column(table.Columns["# Entities"].Position + 1).Width = 25; - loggerConsole.Info("{0} entities", j); - } + #endregion - #endregion + #region Save file - } - catch (Exception ex) - { - logger.Warn(ex); - loggerConsole.Warn(ex); - } - finally - { - stopWatchTarget.Stop(); + // Report files + string reportFileName = String.Format( + REPORT_SNAPSHOTS_METHOD_CALL_LINES_FILE_NAME, + programOptions.JobName, + jobConfiguration.Input.ExpandedTimeRange.From, + jobConfiguration.Input.ExpandedTimeRange.To); + string reportFilePath = Path.Combine(programOptions.OutputJobFolderPath, REPORTS_FOLDER_NAME, reportFileName); - logger.Info("{0}({0:d}): [{1}/{2}], {3} {4} duration {5:c} ({6} ms)", jobStatus, i + 1, jobConfiguration.Target.Count, jobTarget.Controller, jobTarget.Application, stopWatchTarget.Elapsed, stopWatchTarget.ElapsedMilliseconds); - loggerConsole.Trace("{0}({0:d}): [{1}/{2}], {3} {4} duration {5:c} ({6} ms)", jobStatus, i + 1, jobConfiguration.Target.Count, jobTarget.Controller, jobTarget.Application, stopWatchTarget.Elapsed, stopWatchTarget.ElapsedMilliseconds); + string folderPath = Path.GetDirectoryName(reportFilePath); + if (Directory.Exists(folderPath) == false) + { + Directory.CreateDirectory(folderPath); + } - stepTimingTarget.EndTime = DateTime.Now; - stepTimingTarget.Duration = stopWatchTarget.Elapsed; - stepTimingTarget.DurationMS = stopWatchTarget.ElapsedMilliseconds; + logger.Info("Saving Excel report {0}", reportFilePath); + loggerConsole.Info("Saving Excel report {0}", reportFilePath); - List stepTimings = new List(1); - stepTimings.Add(stepTimingTarget); - FileIOHelper.writeListToCSVFile(stepTimings, new StepTimingReportMap(), stepTimingReportFilePath, true); - } + 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) @@ -12363,3303 +12462,3253 @@ private static bool stepReportIndividualApplicationAndEntityDetails(ProgramOptio } } - #endregion - - - #region Metric extraction functions - - private static void getMetricDataForMetricForAllRanges(ControllerApi controllerApi, JobTarget jobTarget, string metricPath, string metricName, JobConfiguration jobConfiguration, string metricsEntityFolderPath, bool progressToConsole) + private static bool stepReportIndividualApplicationAndEntityDetails(ProgramOptions programOptions, JobConfiguration jobConfiguration, JobStatus jobStatus) { - string metricEntitySubFolderName = metricNameToShortMetricNameMapping[metricName]; - - // Get the full range - JobTimeRange jobTimeRange = jobConfiguration.Input.ExpandedTimeRange; + Stopwatch stopWatch = new Stopwatch(); + stopWatch.Start(); - logger.Info("Retrieving metric for Application {0}({1}), Metric='{2}', From {3:o}, To {4:o}", jobTarget.Application, jobTarget.ApplicationID, metricPath, jobTimeRange.From, jobTimeRange.To); + StepTiming stepTimingFunction = new StepTiming(); + stepTimingFunction.JobFileName = programOptions.OutputJobFilePath; + stepTimingFunction.StepName = jobStatus.ToString(); + stepTimingFunction.StepID = (int)jobStatus; + stepTimingFunction.StartTime = DateTime.Now; + stepTimingFunction.NumEntities = jobConfiguration.Target.Count; - string metricsJson = String.Empty; + string stepTimingReportFilePath = Path.Combine(programOptions.OutputJobFolderPath, REPORTS_FOLDER_NAME, TIMING_REPORT_FILE_NAME); - string metricsDataFilePath = Path.Combine(metricsEntityFolderPath, metricEntitySubFolderName, String.Format(EXTRACT_METRIC_FULL_FILE_NAME, jobTimeRange.From, jobTimeRange.To)); - if (File.Exists(metricsDataFilePath) == false) + try { - if (progressToConsole == true) + // Process each target + for (int i = 0; i < jobConfiguration.Target.Count; i++) { - Console.Write("."); - } + Stopwatch stopWatchTarget = new Stopwatch(); + stopWatchTarget.Start(); - // First range is the whole thing - metricsJson = controllerApi.GetMetricData( - jobTarget.ApplicationID, - metricPath, - convertToUnixTimestamp(jobTimeRange.From), - convertToUnixTimestamp(jobTimeRange.To), - true); + JobTarget jobTarget = jobConfiguration.Target[i]; - if (metricsJson != String.Empty) FileIOHelper.saveFileToFolder(metricsJson, metricsDataFilePath); - } + StepTiming stepTimingTarget = new StepTiming(); + stepTimingTarget.Controller = jobTarget.Controller; + stepTimingTarget.ApplicationName = jobTarget.Application; + stepTimingTarget.ApplicationID = jobTarget.ApplicationID; + stepTimingTarget.JobFileName = programOptions.OutputJobFilePath; + stepTimingTarget.StepName = jobStatus.ToString(); + stepTimingTarget.StepID = (int)jobStatus; + stepTimingTarget.StartTime = DateTime.Now; - // Get the hourly time ranges - for (int j = 0; j < jobConfiguration.Input.HourlyTimeRanges.Count; j++) - { - if (progressToConsole == true) - { - Console.Write("."); - } + try + { + #region Output status - jobTimeRange = jobConfiguration.Input.HourlyTimeRanges[j]; + logger.Info("{0}({0:d}): [{1}/{2}], {3} {4}({5})", jobStatus, i + 1, jobConfiguration.Target.Count, jobTarget.Controller, jobTarget.Application, jobTarget.ApplicationID); + loggerConsole.Trace("{0}({0:d}): [{1}/{2}], {3} {4}({5})", jobStatus, i + 1, jobConfiguration.Target.Count, jobTarget.Controller, jobTarget.Application, jobTarget.ApplicationID); - logger.Info("Retrieving metric for Application {0}({1}), Metric='{2}', From {3:o}, To {4:o}", jobTarget.Application, jobTarget.ApplicationID, metricPath, jobTimeRange.From, jobTimeRange.To); + #endregion - metricsDataFilePath = Path.Combine(metricsEntityFolderPath, metricEntitySubFolderName, String.Format(EXTRACT_METRIC_HOUR_FILE_NAME, jobTimeRange.From, jobTimeRange.To)); + #region Target state check - if (File.Exists(metricsDataFilePath) == false) - { - // Subsequent ones are details - metricsJson = controllerApi.GetMetricData( - jobTarget.ApplicationID, - metricPath, - convertToUnixTimestamp(jobTimeRange.From), - convertToUnixTimestamp(jobTimeRange.To), - false); + if (jobTarget.Status != JobTargetStatus.ConfigurationValid) + { + loggerConsole.Trace("Target in invalid state {0}, skipping", jobTarget.Status); - if (metricsJson != String.Empty) FileIOHelper.saveFileToFolder(metricsJson, metricsDataFilePath); - } - } - } + continue; + } - #endregion + #endregion - #region Flowmap extraction functions + #region Target step variables - private static int extractFlowmapsApplication(JobConfiguration jobConfiguration, JobTarget jobTarget, ControllerApi controllerApi, string metricsFolderPath, long fromTimeUnix, long toTimeUnix, long differenceInMinutes) - { - logger.Info("Retrieving flowmap for Application {0}, From {1:o}, To {2:o}", jobTarget.Application, jobConfiguration.Input.ExpandedTimeRange.From, jobConfiguration.Input.ExpandedTimeRange.To); + // Various folders + string controllerFolderPath = Path.Combine(programOptions.OutputJobFolderPath, getFileSystemSafeString(new Uri(jobTarget.Controller).Host)); + string applicationFolderPath = Path.Combine(controllerFolderPath, getShortenedEntityNameForFileSystem(jobTarget.Application, jobTarget.ApplicationID)); + string metricsFolderPath = Path.Combine(applicationFolderPath, METRICS_FOLDER_NAME); + string entitiesFolderPath = Path.Combine(applicationFolderPath, ENTITIES_FOLDER_NAME); + string eventsFolderPath = Path.Combine(applicationFolderPath, EVENTS_FOLDER_NAME); + string snapshotsFolderPath = Path.Combine(applicationFolderPath, SNAPSHOTS_FOLDER_NAME); - string flowmapDataFilePath = Path.Combine( - metricsFolderPath, - APPLICATION_TYPE_SHORT, - String.Format(EXTRACT_ENTITY_FLOWMAP_FILE_NAME, jobConfiguration.Input.ExpandedTimeRange.From, jobConfiguration.Input.ExpandedTimeRange.To)); + // Report files + string applicationReportFilePath = Path.Combine(applicationFolderPath, CONVERT_ENTITY_APPLICATION_FILE_NAME); + string tiersReportFilePath = Path.Combine(entitiesFolderPath, CONVERT_ENTITY_TIERS_FILE_NAME); + string nodesReportFilePath = Path.Combine(entitiesFolderPath, CONVERT_ENTITY_NODES_FILE_NAME); + string backendsReportFilePath = Path.Combine(entitiesFolderPath, CONVERT_ENTITY_BACKENDS_FILE_NAME); + string businessTransactionsReportFilePath = Path.Combine(entitiesFolderPath, CONVERT_ENTITY_BUSINESS_TRANSACTIONS_FILE_NAME); + string serviceEndpointsReportFilePath = Path.Combine(entitiesFolderPath, CONVERT_ENTITY_SERVICE_ENDPOINTS_FILE_NAME); + string errorsReportFilePath = Path.Combine(entitiesFolderPath, CONVERT_ENTITY_ERRORS_FILE_NAME); - string flowmapJson = String.Empty; + string eventsFilePath = Path.Combine(eventsFolderPath, CONVERT_EVENTS_FILE_NAME); + string healthRuleViolationEventsFilePath = Path.Combine(eventsFolderPath, CONVERT_HEALTH_RULE_EVENTS_FILE_NAME); + string snapshotsFilePath = Path.Combine(snapshotsFolderPath, CONVERT_SNAPSHOTS_FILE_NAME); + string segmentsFilePath = Path.Combine(snapshotsFolderPath, CONVERT_SNAPSHOTS_SEGMENTS_FILE_NAME); + string exitCallsFilePath = Path.Combine(snapshotsFolderPath, CONVERT_SNAPSHOTS_SEGMENTS_EXIT_CALLS_FILE_NAME); + string serviceEndpointCallsFilePath = Path.Combine(snapshotsFolderPath, CONVERT_SNAPSHOTS_SEGMENTS_SERVICE_ENDPOINTS_CALLS_FILE_NAME); + string detectedErrorsFilePath = Path.Combine(snapshotsFolderPath, CONVERT_SNAPSHOTS_SEGMENTS_DETECTED_ERRORS_FILE_NAME); + string businessDataFilePath = Path.Combine(snapshotsFolderPath, CONVERT_SNAPSHOTS_SEGMENTS_BUSINESS_DATA_FILE_NAME); - if (File.Exists(flowmapDataFilePath) == false) - { - flowmapJson = controllerApi.GetFlowmapApplication(jobTarget.ApplicationID, fromTimeUnix, toTimeUnix, differenceInMinutes); - if (flowmapJson != String.Empty) FileIOHelper.saveFileToFolder(flowmapJson, flowmapDataFilePath); - } + string metricsEntityFolderPath = String.Empty; + string entitiesFullRangeReportFilePath = String.Empty; - return 1; - } + #endregion - private static int extractFlowmapsTiers(JobConfiguration jobConfiguration, JobTarget jobTarget, ControllerApi controllerApi, List entityList, string metricsFolderPath, long fromTimeUnix, long toTimeUnix, long differenceInMinutes, bool progressToConsole) - { - int j = 0; + #region Preload all the reports that will be filtered by the subsequent entities - foreach (AppDRESTTier tier in entityList) - { - logger.Info("Retrieving flowmap for Application {0}, Tier {1}, From {2:o}, To {3:o}", jobTarget.Application, tier.name, jobConfiguration.Input.ExpandedTimeRange.From, jobConfiguration.Input.ExpandedTimeRange.To); + loggerConsole.Info("Entity Details Data Preloading"); - string flowmapDataFilePath = Path.Combine( - metricsFolderPath, - TIERS_TYPE_SHORT, - getShortenedEntityNameForFileSystem(tier.name, tier.id), - String.Format(EXTRACT_ENTITY_FLOWMAP_FILE_NAME, jobConfiguration.Input.ExpandedTimeRange.From, jobConfiguration.Input.ExpandedTimeRange.To)); + List eventsAllList = FileIOHelper.readListFromCSVFile(eventsFilePath, new EventReportMap()); + List healthRuleViolationEventsAllList = FileIOHelper.readListFromCSVFile(healthRuleViolationEventsFilePath, new HealthRuleViolationEventReportMap()); + List snapshotsAllList = FileIOHelper.readListFromCSVFile(snapshotsFilePath, new SnapshotReportMap()); + List segmentsAllList = FileIOHelper.readListFromCSVFile(segmentsFilePath, new SegmentReportMap()); + List exitCallsAllList = FileIOHelper.readListFromCSVFile(exitCallsFilePath, new ExitCallReportMap()); + List serviceEndpointCallsAllList = FileIOHelper.readListFromCSVFile(serviceEndpointCallsFilePath, new ServiceEndpointCallReportMap()); + List detectedErrorsAllList = FileIOHelper.readListFromCSVFile(detectedErrorsFilePath, new DetectedErrorReportMap()); + List businessDataAllList = FileIOHelper.readListFromCSVFile(businessDataFilePath, new BusinessDataReportMap()); - if (File.Exists(flowmapDataFilePath) == false) - { - string flowmapJson = controllerApi.GetFlowmapTier(tier.id, fromTimeUnix, toTimeUnix, differenceInMinutes); - if (flowmapJson != String.Empty) FileIOHelper.saveFileToFolder(flowmapJson, flowmapDataFilePath); - } + #endregion - if (progressToConsole == true) - { - j++; - if (j % 10 == 0) - { - Console.Write("[{0}].", j); - } - } - } + #region Application - return entityList.Count; - } + List applicationList = FileIOHelper.readListFromCSVFile(applicationReportFilePath, new ApplicationEntityReportMap()); - private static int extractFlowmapsNodes(JobConfiguration jobConfiguration, JobTarget jobTarget, ControllerApi controllerApi, List entityList, string metricsFolderPath, long fromTimeUnix, long toTimeUnix, long differenceInMinutes, bool progressToConsole) - { - int j = 0; + metricsEntityFolderPath = Path.Combine(metricsFolderPath, APPLICATION_TYPE_SHORT); + entitiesFullRangeReportFilePath = Path.Combine(metricsEntityFolderPath, CONVERT_ENTITY_METRICS_FULLRANGE_FILE_NAME); + List applicationMetricsList = FileIOHelper.readListFromCSVFile(entitiesFullRangeReportFilePath, new ApplicationMetricReportMap()); - foreach (AppDRESTNode node in entityList) - { - logger.Info("Retrieving flowmap for Application {0}, Tier {1}, Node {2}, From {3:o}, To {4:o}", jobTarget.Application, node.tierName, node.name, jobConfiguration.Input.ExpandedTimeRange.From, jobConfiguration.Input.ExpandedTimeRange.To); + if (applicationList != null && applicationList.Count > 0) + { + loggerConsole.Info("Entity Details for Application"); - string flowmapDataFilePath = Path.Combine( - metricsFolderPath, - NODES_TYPE_SHORT, - getShortenedEntityNameForFileSystem(node.tierName, node.tierId), - getShortenedEntityNameForFileSystem(node.name, node.id), - String.Format(EXTRACT_ENTITY_FLOWMAP_FILE_NAME, jobConfiguration.Input.ExpandedTimeRange.From, jobConfiguration.Input.ExpandedTimeRange.To)); + stepTimingTarget.NumEntities = stepTimingTarget.NumEntities + 1; - if (File.Exists(flowmapDataFilePath) == false) - { - string flowmapJson = controllerApi.GetFlowmapNode(node.id, fromTimeUnix, toTimeUnix, differenceInMinutes); - if (flowmapJson != String.Empty) FileIOHelper.saveFileToFolder(flowmapJson, flowmapDataFilePath); - } + reportMetricDetailApplication( + programOptions, + jobConfiguration, + jobTarget, + applicationList[0], + (applicationMetricsList != null && applicationMetricsList.Count > 0) ? applicationMetricsList[0] : null, + eventsAllList, + healthRuleViolationEventsAllList, + snapshotsAllList, + segmentsAllList, + exitCallsAllList, + serviceEndpointCallsAllList, + detectedErrorsAllList, + businessDataAllList); + } - if (progressToConsole == true) - { - j++; - if (j % 10 == 0) - { - Console.Write("[{0}].", j); - } - } - } + #endregion - return entityList.Count; - } + #region Tier - private static int extractFlowmapsBackends(JobConfiguration jobConfiguration, JobTarget jobTarget, ControllerApi controllerApi, List entityList, string metricsFolderPath, long fromTimeUnix, long toTimeUnix, long differenceInMinutes, bool progressToConsole) - { - int j = 0; + List tiersList = FileIOHelper.readListFromCSVFile(tiersReportFilePath, new TierEntityReportMap()); - foreach (AppDRESTBackend backend in entityList) - { - logger.Info("Retrieving flowmap for Application {0}, Backend {1}, From {2:o}, To {3:o}", jobTarget.Application, backend.name, jobConfiguration.Input.ExpandedTimeRange.From, jobConfiguration.Input.ExpandedTimeRange.To); + metricsEntityFolderPath = Path.Combine(metricsFolderPath, TIERS_TYPE_SHORT); + entitiesFullRangeReportFilePath = Path.Combine(metricsEntityFolderPath, CONVERT_ENTITIES_METRICS_FULLRANGE_FILE_NAME); + List tiersMetricsList = FileIOHelper.readListFromCSVFile(entitiesFullRangeReportFilePath, new TierMetricReportMap()); - string flowmapDataFilePath = Path.Combine( - metricsFolderPath, - BACKENDS_TYPE_SHORT, - getShortenedEntityNameForFileSystem(backend.name, backend.id), - String.Format(EXTRACT_ENTITY_FLOWMAP_FILE_NAME, jobConfiguration.Input.ExpandedTimeRange.From, jobConfiguration.Input.ExpandedTimeRange.To)); + if (tiersList != null) + { + loggerConsole.Info("Entity Details for Tiers ({0} entities)", tiersList.Count); - if (File.Exists(flowmapDataFilePath) == false) - { - string flowmapJson = controllerApi.GetFlowmapBackend(backend.id, fromTimeUnix, toTimeUnix, differenceInMinutes); - if (flowmapJson != String.Empty) FileIOHelper.saveFileToFolder(flowmapJson, flowmapDataFilePath); - } + stepTimingTarget.NumEntities = stepTimingTarget.NumEntities + tiersList.Count; - if (progressToConsole == true) - { - j++; - if (j % 10 == 0) - { - Console.Write("[{0}].", j); - } - } - } + int j = 0; - return entityList.Count; - } + if (programOptions.ProcessSequentially == false) + { + var tiersListChunks = tiersList.BreakListIntoChunks(METRIC_DETAILS_REPORT_NUMBER_OF_ENTITIES_TO_PROCESS_PER_THREAD); - private static int extractFlowmapsBusinessTransactions(JobConfiguration jobConfiguration, JobTarget jobTarget, ControllerApi controllerApi, List entityList, string metricsFolderPath, long fromTimeUnix, long toTimeUnix, long differenceInMinutes, bool progressToConsole) - { - int j = 0; + Parallel.ForEach, int>( + tiersListChunks, + () => 0, + (tiersListChunk, loop, subtotal) => + { + subtotal += reportMetricDetailTiers( + programOptions, + jobConfiguration, + jobTarget, + tiersListChunk, + tiersMetricsList, + eventsAllList, + healthRuleViolationEventsAllList, + snapshotsAllList, + segmentsAllList, + exitCallsAllList, + serviceEndpointCallsAllList, + detectedErrorsAllList, + businessDataAllList, + false); + return subtotal; + }, + (finalResult) => + { + j = Interlocked.Add(ref j, finalResult); + Console.Write("[{0}].", j); + } + ); + } + else + { + j = reportMetricDetailTiers( + programOptions, + jobConfiguration, + jobTarget, + tiersList, + tiersMetricsList, + eventsAllList, + healthRuleViolationEventsAllList, + snapshotsAllList, + segmentsAllList, + exitCallsAllList, + serviceEndpointCallsAllList, + detectedErrorsAllList, + businessDataAllList, + true); + } - foreach (AppDRESTBusinessTransaction businessTransaction in entityList) - { - logger.Info("Retrieving flowmap for Application {0}, Tier {1}, Business Transaction {2}, From {3:o}, To {4:o}", jobTarget.Application, businessTransaction.tierName, businessTransaction.name, jobConfiguration.Input.ExpandedTimeRange.From, jobConfiguration.Input.ExpandedTimeRange.To); + loggerConsole.Info("{0} entities", j); + } - string flowmapDataFilePath = Path.Combine( - metricsFolderPath, - BUSINESS_TRANSACTIONS_TYPE_SHORT, - getShortenedEntityNameForFileSystem(businessTransaction.tierName, businessTransaction.tierId), - getShortenedEntityNameForFileSystem(businessTransaction.name, businessTransaction.id), - String.Format(EXTRACT_ENTITY_FLOWMAP_FILE_NAME, jobConfiguration.Input.ExpandedTimeRange.From, jobConfiguration.Input.ExpandedTimeRange.To)); + #endregion - if (File.Exists(flowmapDataFilePath) == false) - { - string flowmapJson = controllerApi.GetFlowmapBusinessTransaction(jobTarget.ApplicationID, businessTransaction.id, fromTimeUnix, toTimeUnix, differenceInMinutes); - if (flowmapJson != String.Empty) FileIOHelper.saveFileToFolder(flowmapJson, flowmapDataFilePath); - } + #region Nodes - if (progressToConsole == true) - { - j++; - if (j % 10 == 0) - { - Console.Write("[{0}].", j); - } - } - } + List nodesList = FileIOHelper.readListFromCSVFile(nodesReportFilePath, new NodeEntityReportMap()); - return entityList.Count; - } + metricsEntityFolderPath = Path.Combine(metricsFolderPath, NODES_TYPE_SHORT); + entitiesFullRangeReportFilePath = Path.Combine(metricsEntityFolderPath, CONVERT_ENTITIES_METRICS_FULLRANGE_FILE_NAME); + List nodesMetricsList = FileIOHelper.readListFromCSVFile(entitiesFullRangeReportFilePath, new NodeMetricReportMap()); - #endregion + if (nodesList != null) + { + loggerConsole.Info("Entity Details for Nodes ({0} entities)", nodesList.Count); - #region Event extraction functions - - private static int extractEvents(JobConfiguration jobConfiguration, JobTarget jobTarget, ControllerApi controllerApi, string eventsFolderPath, string eventType, bool progressToConsole) - { - if (progressToConsole == true) - { - loggerConsole.Info("Extract {0} events ({1} time ranges)", eventType, jobConfiguration.Input.HourlyTimeRanges.Count); - } - - JArray listOfEvents = new JArray(); - int totalEventsFound = 0; - foreach (JobTimeRange jobTimeRange in jobConfiguration.Input.HourlyTimeRanges) - { - long fromTimeUnix = convertToUnixTimestamp(jobTimeRange.From); - long toTimeUnix = convertToUnixTimestamp(jobTimeRange.To); - - string eventsJSON = controllerApi.GetEvents(jobTarget.ApplicationID, eventType, fromTimeUnix, toTimeUnix); - if (eventsJSON != String.Empty) - { - // Load events - JArray eventsInHour = JArray.Parse(eventsJSON); - foreach (JObject interestingEvent in eventsInHour) - { - listOfEvents.Add(interestingEvent); - } - totalEventsFound = totalEventsFound + eventsInHour.Count; - - if (progressToConsole == true) - { - Console.Write("+{0}", eventsInHour.Count); - } - } - } - - if (listOfEvents.Count > 0) - { - string eventsFilePath = Path.Combine( - eventsFolderPath, - String.Format(EVENTS_FILE_NAME, eventType, jobConfiguration.Input.ExpandedTimeRange.From, jobConfiguration.Input.ExpandedTimeRange.To)); - - FileIOHelper.writeJArrayToFile(listOfEvents, eventsFilePath); - - logger.Info("{0} events from {1:o} to {2:o}", listOfEvents.Count, jobConfiguration.Input.ExpandedTimeRange.From, jobConfiguration.Input.ExpandedTimeRange.To); - if (progressToConsole == true) - { - Console.Write("="); - loggerConsole.Info("{0} {1} events", listOfEvents.Count, eventType); - } - } - else - { - if (progressToConsole == true) - { - Console.WriteLine(); - } - } - - return listOfEvents.Count; - } - - #endregion + stepTimingTarget.NumEntities = stepTimingTarget.NumEntities + nodesList.Count; - #region Snapshot extraction functions + int j = 0; - private static int extractSnapshots(JobConfiguration jobConfiguration, JobTarget jobTarget, ControllerApi controllerApi, List entityList, string snapshotsFolderPath, bool progressToConsole) - { - int j = 0; + if (programOptions.ProcessSequentially == false) + { + var nodesListChunks = nodesList.BreakListIntoChunks(METRIC_DETAILS_REPORT_NUMBER_OF_ENTITIES_TO_PROCESS_PER_THREAD); - foreach (JToken snapshot in entityList) - { - // Only do first in chain - if ((bool)snapshot["firstInChain"] == true) - { - logger.Info("Retrieving snapshot for Application {0}, Tier {1}, Business Transaction {2}, RequestGUID {3}", jobTarget.Application, snapshot["applicationComponentName"], snapshot["businessTransactionName"], snapshot["requestGUID"]); + Parallel.ForEach, int>( + nodesListChunks, + () => 0, + (nodesListChunk, loop, subtotal) => + { + subtotal += reportMetricDetailNodes( + programOptions, + jobConfiguration, + jobTarget, + nodesListChunk, + nodesMetricsList, + eventsAllList, + healthRuleViolationEventsAllList, + snapshotsAllList, + segmentsAllList, + exitCallsAllList, + serviceEndpointCallsAllList, + detectedErrorsAllList, + businessDataAllList, + false); + return subtotal; + }, + (finalResult) => + { + j = Interlocked.Add(ref j, finalResult); + Console.Write("[{0}].", j); + } + ); + } + else + { + j = reportMetricDetailNodes( + programOptions, + jobConfiguration, + jobTarget, + nodesList, + nodesMetricsList, + eventsAllList, + healthRuleViolationEventsAllList, + snapshotsAllList, + segmentsAllList, + exitCallsAllList, + serviceEndpointCallsAllList, + detectedErrorsAllList, + businessDataAllList, + true); + } - #region Target step variables + loggerConsole.Info("{0} entities", j); + } - DateTime snapshotTime = convertFromUnixTimestamp((long)snapshot["serverStartTime"]); + #endregion - string snapshotFolderPath = Path.Combine( - snapshotsFolderPath, - getShortenedEntityNameForFileSystem(snapshot["applicationComponentName"].ToString(), (long)snapshot["applicationComponentId"]), - getShortenedEntityNameForFileSystem(snapshot["businessTransactionName"].ToString(), (long)snapshot["businessTransactionId"]), - String.Format("{0:yyyyMMddHH}", snapshotTime), - userExperienceFolderNameMapping[snapshot["userExperience"].ToString()], - String.Format(SNAPSHOT_FOLDER_NAME, snapshot["requestGUID"], snapshotTime)); + #region Backends - // Must strip out the milliseconds, because the segment list retrieval doesn't seem to like them in the datetimes - DateTime snapshotTimeFrom = snapshotTime.AddMinutes(-30).AddMilliseconds(snapshotTime.Millisecond * -1); - DateTime snapshotTimeTo = snapshotTime.AddMinutes(30).AddMilliseconds(snapshotTime.Millisecond * -1); + List backendsList = FileIOHelper.readListFromCSVFile(backendsReportFilePath, new BackendEntityReportMap()); - long fromTimeUnix = convertToUnixTimestamp(snapshotTimeFrom); - long toTimeUnix = convertToUnixTimestamp(snapshotTimeTo); - int differenceInMinutes = (int)(snapshotTimeTo - snapshotTimeFrom).TotalMinutes; + metricsEntityFolderPath = Path.Combine(metricsFolderPath, BACKENDS_TYPE_SHORT); + entitiesFullRangeReportFilePath = Path.Combine(metricsEntityFolderPath, CONVERT_ENTITIES_METRICS_FULLRANGE_FILE_NAME); + List backendsMetricsList = FileIOHelper.readListFromCSVFile(entitiesFullRangeReportFilePath, new BackendMetricReportMap()); - #endregion + if (backendsList != null) + { + loggerConsole.Info("Entity Details for Backends ({0} entities)", backendsList.Count); - #region Get Snapshot Flowmap + stepTimingTarget.NumEntities = stepTimingTarget.NumEntities + backendsList.Count; - // Get snapshot flow map - string snapshotFlowmapDataFilePath = Path.Combine(snapshotFolderPath, EXTRACT_SNAPSHOT_FLOWMAP_FILE_NAME); + int j = 0; - if (File.Exists(snapshotFlowmapDataFilePath) == false) - { - string snapshotFlowmapJson = controllerApi.GetFlowmapSnapshot(jobTarget.ApplicationID, (int)snapshot["businessTransactionId"], snapshot["requestGUID"].ToString(), fromTimeUnix, toTimeUnix, differenceInMinutes); - if (snapshotFlowmapJson != String.Empty) FileIOHelper.saveFileToFolder(snapshotFlowmapJson, snapshotFlowmapDataFilePath); - } + if (programOptions.ProcessSequentially == false) + { + var backendsListChunks = backendsList.BreakListIntoChunks(METRIC_DETAILS_REPORT_NUMBER_OF_ENTITIES_TO_PROCESS_PER_THREAD); - #endregion + Parallel.ForEach, int>( + backendsListChunks, + () => 0, + (backendsListChunk, loop, subtotal) => + { + subtotal += reportMetricDetailBackends( + programOptions, + jobConfiguration, + jobTarget, + backendsListChunk, + backendsMetricsList, + eventsAllList, + healthRuleViolationEventsAllList, + snapshotsAllList, + segmentsAllList, + exitCallsAllList, + serviceEndpointCallsAllList, + detectedErrorsAllList, + businessDataAllList, + false); + return subtotal; + }, + (finalResult) => + { + j = Interlocked.Add(ref j, finalResult); + Console.Write("[{0}].", j); + } + ); + } + else + { + j = reportMetricDetailBackends( + programOptions, + jobConfiguration, + jobTarget, + backendsList, + backendsMetricsList, + eventsAllList, + healthRuleViolationEventsAllList, + snapshotsAllList, + segmentsAllList, + exitCallsAllList, + serviceEndpointCallsAllList, + detectedErrorsAllList, + businessDataAllList, + true); + } - #region Get List of Segments + loggerConsole.Info("{0} entities", j); + } - // Get list of segments - string snapshotSegmentsDataFilePath = Path.Combine(snapshotFolderPath, EXTRACT_SNAPSHOT_SEGMENT_FILE_NAME); + #endregion - if (File.Exists(snapshotSegmentsDataFilePath) == false) - { - string snapshotSegmentsJson = controllerApi.GetSnapshotSegments(snapshot["requestGUID"].ToString(), snapshotTimeFrom, snapshotTimeTo, differenceInMinutes); - if (snapshotSegmentsJson != String.Empty) FileIOHelper.saveFileToFolder(snapshotSegmentsJson, snapshotSegmentsDataFilePath); - } + #region Business Transactions - #endregion + List businessTransactionsList = FileIOHelper.readListFromCSVFile(businessTransactionsReportFilePath, new BusinessTransactionEntityReportMap()); - #region Get Details for Each Segment + metricsEntityFolderPath = Path.Combine(metricsFolderPath, BUSINESS_TRANSACTIONS_TYPE_SHORT); + entitiesFullRangeReportFilePath = Path.Combine(metricsEntityFolderPath, CONVERT_ENTITIES_METRICS_FULLRANGE_FILE_NAME); + List businessTransactionsMetricsList = FileIOHelper.readListFromCSVFile(entitiesFullRangeReportFilePath, new BusinessTransactionMetricReportMap()); - JArray snapshotSegmentsList = FileIOHelper.loadJArrayFromFile(snapshotSegmentsDataFilePath); - if (snapshotSegmentsList != null) - { - // Get details for segment - foreach (JToken snapshotSegment in snapshotSegmentsList) + if (businessTransactionsList != null) { - string snapshotSegmentDataFilePath = Path.Combine(snapshotFolderPath, String.Format(EXTRACT_SNAPSHOT_SEGMENT_DATA_FILE_NAME, snapshotSegment["id"])); + loggerConsole.Info("Entity Details for Business Transactions ({0} entities)", businessTransactionsList.Count); - if (File.Exists(snapshotSegmentDataFilePath) == false) - { - string snapshotSegmentJson = controllerApi.GetSnapshotSegmentDetails((long)snapshotSegment["id"], fromTimeUnix, toTimeUnix, differenceInMinutes); - if (snapshotSegmentJson != String.Empty) FileIOHelper.saveFileToFolder(snapshotSegmentJson, snapshotSegmentDataFilePath); - } - } + stepTimingTarget.NumEntities = stepTimingTarget.NumEntities + businessTransactionsList.Count; - // Get errors for segment - foreach (JToken snapshotSegment in snapshotSegmentsList) - { - string snapshotSegmentErrorFilePath = Path.Combine(snapshotFolderPath, String.Format(EXTRACT_SNAPSHOT_SEGMENT_ERROR_FILE_NAME, snapshotSegment["id"])); + int j = 0; - if ((bool)snapshotSegment["errorOccurred"] == true && File.Exists(snapshotSegmentErrorFilePath) == false) + if (programOptions.ProcessSequentially == false) { - string snapshotSegmentJson = controllerApi.GetSnapshotSegmentErrors((long)snapshotSegment["id"], fromTimeUnix, toTimeUnix, differenceInMinutes); - if (snapshotSegmentJson != String.Empty) - { - // "[ ]" == empty data. Don't create the file - if (snapshotSegmentJson.Length > 3) + var businessTransactionsListChunks = businessTransactionsList.BreakListIntoChunks(METRIC_DETAILS_REPORT_NUMBER_OF_ENTITIES_TO_PROCESS_PER_THREAD); + + Parallel.ForEach, int>( + businessTransactionsListChunks, + () => 0, + (businessTransactionsListChunk, loop, subtotal) => { - FileIOHelper.saveFileToFolder(snapshotSegmentJson, snapshotSegmentErrorFilePath); + subtotal += reportMetricDetailBusinessTransactions( + programOptions, + jobConfiguration, + jobTarget, + businessTransactionsListChunk, + businessTransactionsMetricsList, + eventsAllList, + healthRuleViolationEventsAllList, + snapshotsAllList, + segmentsAllList, + exitCallsAllList, + serviceEndpointCallsAllList, + detectedErrorsAllList, + businessDataAllList, + false); + return subtotal; + }, + (finalResult) => + { + j = Interlocked.Add(ref j, finalResult); + Console.Write("[{0}].", j); } - } + ); + } + else + { + j = reportMetricDetailBusinessTransactions( + programOptions, + jobConfiguration, + jobTarget, + businessTransactionsList, + businessTransactionsMetricsList, + eventsAllList, + healthRuleViolationEventsAllList, + snapshotsAllList, + segmentsAllList, + exitCallsAllList, + serviceEndpointCallsAllList, + detectedErrorsAllList, + businessDataAllList, + true); } + + loggerConsole.Info("{0} entities", j); } - // Get call graphs for segment - foreach (JToken snapshotSegment in snapshotSegmentsList) + #endregion + + #region Service Endpoints + + List serviceEndpointsList = FileIOHelper.readListFromCSVFile(serviceEndpointsReportFilePath, new ServiceEndpointEntityReportMap()); + + metricsEntityFolderPath = Path.Combine(metricsFolderPath, SERVICE_ENDPOINTS_TYPE_SHORT); + entitiesFullRangeReportFilePath = Path.Combine(metricsEntityFolderPath, CONVERT_ENTITIES_METRICS_FULLRANGE_FILE_NAME); + List serviceEndpointsMetricsList = FileIOHelper.readListFromCSVFile(entitiesFullRangeReportFilePath, new ServiceEndpointMetricReportMap()); + + if (serviceEndpointsList != null) { - string snapshotSegmentCallGraphFilePath = Path.Combine(snapshotFolderPath, String.Format(EXTRACT_SNAPSHOT_SEGMENT_CALLGRAPH_FILE_NAME, snapshotSegment["id"])); + loggerConsole.Info("Entity Details for Service Endpoints ({0} entities)", serviceEndpointsList.Count); - if (((bool)snapshotSegment["fullCallgraph"] == true || (bool)snapshotSegment["delayedCallGraph"] == true) && File.Exists(snapshotSegmentCallGraphFilePath) == false) + stepTimingTarget.NumEntities = stepTimingTarget.NumEntities + serviceEndpointsList.Count; + + int j = 0; + + if (programOptions.ProcessSequentially == false) { - string snapshotSegmentJson = controllerApi.GetSnapshotSegmentCallGraph((long)snapshotSegment["id"], fromTimeUnix, toTimeUnix, differenceInMinutes); - if (snapshotSegmentJson != String.Empty) FileIOHelper.saveFileToFolder(snapshotSegmentJson, snapshotSegmentCallGraphFilePath); + var serviceEndpointsListChunks = serviceEndpointsList.BreakListIntoChunks(METRIC_DETAILS_REPORT_NUMBER_OF_ENTITIES_TO_PROCESS_PER_THREAD); + + Parallel.ForEach, int>( + serviceEndpointsListChunks, + () => 0, + (serviceEndpointsListChunk, loop, subtotal) => + { + subtotal += reportMetricDetailServiceEndpoints( + programOptions, + jobConfiguration, + jobTarget, + serviceEndpointsListChunk, + serviceEndpointsMetricsList, + eventsAllList, + healthRuleViolationEventsAllList, + snapshotsAllList, + segmentsAllList, + exitCallsAllList, + serviceEndpointCallsAllList, + detectedErrorsAllList, + businessDataAllList, + false); + return subtotal; + }, + (finalResult) => + { + j = Interlocked.Add(ref j, finalResult); + Console.Write("[{0}].", j); + } + ); + } + else + { + j = reportMetricDetailServiceEndpoints( + programOptions, + jobConfiguration, + jobTarget, + serviceEndpointsList, + serviceEndpointsMetricsList, + eventsAllList, + healthRuleViolationEventsAllList, + snapshotsAllList, + segmentsAllList, + exitCallsAllList, + serviceEndpointCallsAllList, + detectedErrorsAllList, + businessDataAllList, + true); } + + loggerConsole.Info("{0} entities", j); } - } - #endregion + #endregion - } + #region Errors - if (progressToConsole == true) - { - j++; - if (j % 10 == 0) + List errorsList = FileIOHelper.readListFromCSVFile(errorsReportFilePath, new ErrorEntityReportMap()); + + metricsEntityFolderPath = Path.Combine(metricsFolderPath, ERRORS_TYPE_SHORT); + entitiesFullRangeReportFilePath = Path.Combine(metricsEntityFolderPath, CONVERT_ENTITIES_METRICS_FULLRANGE_FILE_NAME); + List errorsMetricsList = FileIOHelper.readListFromCSVFile(entitiesFullRangeReportFilePath, new ErrorMetricReportMap()); + + if (errorsList != null) + { + loggerConsole.Info("Entity Details for Errors ({0} entities)", errorsList.Count); + + stepTimingTarget.NumEntities = stepTimingTarget.NumEntities + errorsList.Count; + + int j = 0; + + if (programOptions.ProcessSequentially == false) + { + var errorsListChunks = errorsList.BreakListIntoChunks(METRIC_DETAILS_REPORT_NUMBER_OF_ENTITIES_TO_PROCESS_PER_THREAD); + + Parallel.ForEach, int>( + errorsListChunks, + () => 0, + (errorsListChunk, loop, subtotal) => + { + subtotal += reportMetricDetailErrors( + programOptions, + jobConfiguration, + jobTarget, + errorsListChunk, + errorsMetricsList, + eventsAllList, + healthRuleViolationEventsAllList, + snapshotsAllList, + segmentsAllList, + exitCallsAllList, + serviceEndpointCallsAllList, + detectedErrorsAllList, + businessDataAllList, + false); + return subtotal; + }, + (finalResult) => + { + j = Interlocked.Add(ref j, finalResult); + Console.Write("[{0}].", j); + } + ); + } + else + { + j = reportMetricDetailErrors( + programOptions, + jobConfiguration, + jobTarget, + errorsList, + errorsMetricsList, + eventsAllList, + healthRuleViolationEventsAllList, + snapshotsAllList, + segmentsAllList, + exitCallsAllList, + serviceEndpointCallsAllList, + detectedErrorsAllList, + businessDataAllList, + true); + } + + loggerConsole.Info("{0} entities", j); + } + + #endregion + + } + catch (Exception ex) { - Console.Write("[{0}].", j); + logger.Warn(ex); + loggerConsole.Warn(ex); + } + finally + { + stopWatchTarget.Stop(); + + logger.Info("{0}({0:d}): [{1}/{2}], {3} {4} duration {5:c} ({6} ms)", jobStatus, i + 1, jobConfiguration.Target.Count, jobTarget.Controller, jobTarget.Application, stopWatchTarget.Elapsed, stopWatchTarget.ElapsedMilliseconds); + loggerConsole.Trace("{0}({0:d}): [{1}/{2}], {3} {4} duration {5:c} ({6} ms)", jobStatus, i + 1, jobConfiguration.Target.Count, jobTarget.Controller, jobTarget.Application, stopWatchTarget.Elapsed, stopWatchTarget.ElapsedMilliseconds); + + stepTimingTarget.EndTime = DateTime.Now; + stepTimingTarget.Duration = stopWatchTarget.Elapsed; + stepTimingTarget.DurationMS = stopWatchTarget.ElapsedMilliseconds; + + List stepTimings = new List(1); + stepTimings.Add(stepTimingTarget); + FileIOHelper.writeListToCSVFile(stepTimings, new StepTimingReportMap(), stepTimingReportFilePath, true); } } + + return true; } + catch (Exception ex) + { + logger.Error(ex); + loggerConsole.Error(ex); - return entityList.Count; + return false; + } + finally + { + stopWatch.Stop(); + + logger.Info("{0}({0:d}): total duration {1:c} ({2} ms)", jobStatus, stopWatch.Elapsed, stopWatch.ElapsedMilliseconds); + loggerConsole.Trace("{0}({0:d}): total duration {1:c} ({2} ms)", jobStatus, stopWatch.Elapsed, stopWatch.ElapsedMilliseconds); + + stepTimingFunction.EndTime = DateTime.Now; + stepTimingFunction.Duration = stopWatch.Elapsed; + stepTimingFunction.DurationMS = stopWatch.ElapsedMilliseconds; + + List stepTimings = new List(1); + stepTimings.Add(stepTimingFunction); + FileIOHelper.writeListToCSVFile(stepTimings, new StepTimingReportMap(), stepTimingReportFilePath, true); + } } #endregion - #region Metric detail conversion functions + #region Metric extraction functions - private static void fillFullRangeMetricEntityRow( - EntityBase entityRow, - JobTimeRange jobTimeRange, - string entityMetricPathPrefix, - string metricsEntityFolderPath, - List metricDataART, - List metricDataCPM, - List metricDataEPM, - List metricDataEXCPM, - List metricDataHTTPEPM) + private static void getMetricDataForMetricForAllRanges(ControllerApi controllerApi, JobTarget jobTarget, string metricPath, string metricName, JobConfiguration jobConfiguration, string metricsEntityFolderPath, bool progressToConsole) { - entityRow.Duration = (int)(jobTimeRange.To - jobTimeRange.From).Duration().TotalMinutes; - entityRow.From = jobTimeRange.From.ToLocalTime(); - entityRow.To = jobTimeRange.To.ToLocalTime(); - entityRow.FromUtc = jobTimeRange.From; - entityRow.ToUtc = jobTimeRange.To; + string metricEntitySubFolderName = metricNameToShortMetricNameMapping[metricName]; - // Determine the entity ID to bve used in ensuring we get only one specific entity - // This is to address identically named Entities - // Backends can be named identically - see Azure Table exits - // Errors can also occasionally be named identically - long entityID = -1; - if (entityRow is EntityApplication) - { - // Application level metrics don't need ever have anything unusual - } - else if (entityRow is EntityTier) - { - entityID = entityRow.TierID; - } - else if (entityRow is EntityNode) - { - entityID = entityRow.TierID; - } - else if (entityRow is EntityBackend) - { - entityID = ((EntityBackend)entityRow).BackendID; - } - else if (entityRow is EntityBusinessTransaction) - { - entityID = ((EntityBusinessTransaction)entityRow).BTID; - } - else if (entityRow is EntityServiceEndpoint) - { - entityID = ((EntityServiceEndpoint)entityRow).SEPID; - } - else if (entityRow is EntityError) - { - entityID = ((EntityError)entityRow).ErrorID; - } - else if (entityRow is EntityInformationPoint) - { - entityID = ((EntityInformationPoint)entityRow).IPID; - } - entityRow.MetricsIDs = new List(5); + // Get the full range + JobTimeRange jobTimeRange = jobConfiguration.Input.ExpandedTimeRange; - AppDRESTMetric thisEntityMetricData = null; + logger.Info("Retrieving metric for Application {0}({1}), Metric='{2}', From {3:o}, To {4:o}", jobTarget.Application, jobTarget.ApplicationID, metricPath, jobTimeRange.From, jobTimeRange.To); - #region Read and convert metrics + string metricsJson = String.Empty; - // ART - string metricsDataFolderPath = Path.Combine(metricsEntityFolderPath, METRIC_ART_SHORTNAME); - string entityMetricSummaryReportFilePath = Path.Combine(metricsDataFolderPath, CONVERT_METRIC_SUMMARY_FILE_NAME); - if (metricDataART != null && metricDataART.Count > 0) + string metricsDataFilePath = Path.Combine(metricsEntityFolderPath, metricEntitySubFolderName, String.Format(EXTRACT_METRIC_FULL_FILE_NAME, jobTimeRange.From, jobTimeRange.To)); + if (File.Exists(metricsDataFilePath) == false) { - if (entityID != -1) - { - thisEntityMetricData = metricDataART.Where(m => m.metricPath.StartsWith(entityMetricPathPrefix) == true && m.metricName.Contains(entityID.ToString()) == true).FirstOrDefault(); - } - else + if (progressToConsole == true) { - thisEntityMetricData = metricDataART.Where(m => m.metricPath.StartsWith(entityMetricPathPrefix) == true).FirstOrDefault(); + Console.Write("."); } - if (thisEntityMetricData != null) - { - if (thisEntityMetricData.metricValues.Count > 0) - { - entityRow.ART = thisEntityMetricData.metricValues[0].value; - entityRow.TimeTotal = thisEntityMetricData.metricValues[0].sum; - } - if (File.Exists(entityMetricSummaryReportFilePath) == false) - { - List metricSummaries = convertMetricSummaryToTypedListForCSV(thisEntityMetricData, entityRow, jobTimeRange); - FileIOHelper.writeListToCSVFile(metricSummaries, new MetricSummaryMetricReportMap(), entityMetricSummaryReportFilePath, false); - } + // First range is the whole thing + metricsJson = controllerApi.GetMetricData( + jobTarget.ApplicationID, + metricPath, + convertToUnixTimestamp(jobTimeRange.From), + convertToUnixTimestamp(jobTimeRange.To), + true); - entityRow.MetricsIDs.Add(thisEntityMetricData.metricId); - } + if (metricsJson != String.Empty) FileIOHelper.saveFileToFolder(metricsJson, metricsDataFilePath); } - // CPM - metricsDataFolderPath = Path.Combine(metricsEntityFolderPath, METRIC_CPM_SHORTNAME); - entityMetricSummaryReportFilePath = Path.Combine(metricsDataFolderPath, CONVERT_METRIC_SUMMARY_FILE_NAME); - if (metricDataCPM != null && metricDataCPM.Count > 0) + // Get the hourly time ranges + for (int j = 0; j < jobConfiguration.Input.HourlyTimeRanges.Count; j++) { - if (entityID != -1) + if (progressToConsole == true) { - thisEntityMetricData = metricDataCPM.Where(m => m.metricPath.StartsWith(entityMetricPathPrefix) == true && m.metricName.Contains(entityID.ToString()) == true).FirstOrDefault(); + Console.Write("."); } - else + + jobTimeRange = jobConfiguration.Input.HourlyTimeRanges[j]; + + logger.Info("Retrieving metric for Application {0}({1}), Metric='{2}', From {3:o}, To {4:o}", jobTarget.Application, jobTarget.ApplicationID, metricPath, jobTimeRange.From, jobTimeRange.To); + + metricsDataFilePath = Path.Combine(metricsEntityFolderPath, metricEntitySubFolderName, String.Format(EXTRACT_METRIC_HOUR_FILE_NAME, jobTimeRange.From, jobTimeRange.To)); + + if (File.Exists(metricsDataFilePath) == false) { - thisEntityMetricData = metricDataCPM.Where(m => m.metricPath.StartsWith(entityMetricPathPrefix) == true).FirstOrDefault(); + // Subsequent ones are details + metricsJson = controllerApi.GetMetricData( + jobTarget.ApplicationID, + metricPath, + convertToUnixTimestamp(jobTimeRange.From), + convertToUnixTimestamp(jobTimeRange.To), + false); + + if (metricsJson != String.Empty) FileIOHelper.saveFileToFolder(metricsJson, metricsDataFilePath); } - if (thisEntityMetricData != null) - { - if (thisEntityMetricData.metricValues.Count > 0) - { - entityRow.CPM = thisEntityMetricData.metricValues[0].value; - entityRow.Calls = thisEntityMetricData.metricValues[0].sum; - } + } + } - if (File.Exists(entityMetricSummaryReportFilePath) == false) - { - List metricSummaries = convertMetricSummaryToTypedListForCSV(thisEntityMetricData, entityRow, jobTimeRange); - FileIOHelper.writeListToCSVFile(metricSummaries, new MetricSummaryMetricReportMap(), entityMetricSummaryReportFilePath, false); - } + #endregion - entityRow.MetricsIDs.Add(thisEntityMetricData.metricId); - } + #region Flowmap extraction functions + + private static int extractFlowmapsApplication(JobConfiguration jobConfiguration, JobTarget jobTarget, ControllerApi controllerApi, string metricsFolderPath, long fromTimeUnix, long toTimeUnix, long differenceInMinutes) + { + logger.Info("Retrieving flowmap for Application {0}, From {1:o}, To {2:o}", jobTarget.Application, jobConfiguration.Input.ExpandedTimeRange.From, jobConfiguration.Input.ExpandedTimeRange.To); + + string flowmapDataFilePath = Path.Combine( + metricsFolderPath, + APPLICATION_TYPE_SHORT, + String.Format(EXTRACT_ENTITY_FLOWMAP_FILE_NAME, jobConfiguration.Input.ExpandedTimeRange.From, jobConfiguration.Input.ExpandedTimeRange.To)); + + string flowmapJson = String.Empty; + + if (File.Exists(flowmapDataFilePath) == false) + { + flowmapJson = controllerApi.GetFlowmapApplication(jobTarget.ApplicationID, fromTimeUnix, toTimeUnix, differenceInMinutes); + if (flowmapJson != String.Empty) FileIOHelper.saveFileToFolder(flowmapJson, flowmapDataFilePath); } - // EPM - metricsDataFolderPath = Path.Combine(metricsEntityFolderPath, METRIC_EPM_SHORTNAME); - entityMetricSummaryReportFilePath = Path.Combine(metricsDataFolderPath, CONVERT_METRIC_SUMMARY_FILE_NAME); - if (metricDataEPM != null && metricDataEPM.Count > 0) + return 1; + } + + private static int extractFlowmapsTiers(JobConfiguration jobConfiguration, JobTarget jobTarget, ControllerApi controllerApi, List entityList, string metricsFolderPath, long fromTimeUnix, long toTimeUnix, long differenceInMinutes, bool progressToConsole) + { + int j = 0; + + foreach (AppDRESTTier tier in entityList) { - if (entityID != -1) - { - thisEntityMetricData = metricDataEPM.Where(m => m.metricPath.StartsWith(entityMetricPathPrefix) == true && m.metricName.Contains(entityID.ToString()) == true).FirstOrDefault(); - } - else + logger.Info("Retrieving flowmap for Application {0}, Tier {1}, From {2:o}, To {3:o}", jobTarget.Application, tier.name, jobConfiguration.Input.ExpandedTimeRange.From, jobConfiguration.Input.ExpandedTimeRange.To); + + string flowmapDataFilePath = Path.Combine( + metricsFolderPath, + TIERS_TYPE_SHORT, + getShortenedEntityNameForFileSystem(tier.name, tier.id), + String.Format(EXTRACT_ENTITY_FLOWMAP_FILE_NAME, jobConfiguration.Input.ExpandedTimeRange.From, jobConfiguration.Input.ExpandedTimeRange.To)); + + if (File.Exists(flowmapDataFilePath) == false) { - thisEntityMetricData = metricDataEPM.Where(m => m.metricPath.StartsWith(entityMetricPathPrefix) == true).FirstOrDefault(); + string flowmapJson = controllerApi.GetFlowmapTier(tier.id, fromTimeUnix, toTimeUnix, differenceInMinutes); + if (flowmapJson != String.Empty) FileIOHelper.saveFileToFolder(flowmapJson, flowmapDataFilePath); } - if (thisEntityMetricData != null) - { - if (thisEntityMetricData.metricValues.Count > 0) - { - entityRow.EPM = thisEntityMetricData.metricValues[0].value; - entityRow.Errors = thisEntityMetricData.metricValues[0].sum; - entityRow.ErrorsPercentage = Math.Round((double)(double)entityRow.Errors / (double)entityRow.Calls * 100, 2); - if (Double.IsNaN(entityRow.ErrorsPercentage) == true) entityRow.ErrorsPercentage = 0; - } - if (File.Exists(entityMetricSummaryReportFilePath) == false) + if (progressToConsole == true) + { + j++; + if (j % 10 == 0) { - List metricSummaries = convertMetricSummaryToTypedListForCSV(thisEntityMetricData, entityRow, jobTimeRange); - FileIOHelper.writeListToCSVFile(metricSummaries, new MetricSummaryMetricReportMap(), entityMetricSummaryReportFilePath, false); + Console.Write("[{0}].", j); } - - entityRow.MetricsIDs.Add(thisEntityMetricData.metricId); } } - // EXCPM - metricsDataFolderPath = Path.Combine(metricsEntityFolderPath, METRIC_EXCPM_SHORTNAME); - entityMetricSummaryReportFilePath = Path.Combine(metricsDataFolderPath, CONVERT_METRIC_SUMMARY_FILE_NAME); - if (metricDataEXCPM != null && metricDataEXCPM.Count > 0) + return entityList.Count; + } + + private static int extractFlowmapsNodes(JobConfiguration jobConfiguration, JobTarget jobTarget, ControllerApi controllerApi, List entityList, string metricsFolderPath, long fromTimeUnix, long toTimeUnix, long differenceInMinutes, bool progressToConsole) + { + int j = 0; + + foreach (AppDRESTNode node in entityList) { - if (entityID != -1) - { - thisEntityMetricData = metricDataEXCPM.Where(m => m.metricPath.StartsWith(entityMetricPathPrefix) == true && m.metricName.Contains(entityID.ToString()) == true).FirstOrDefault(); - } - else + logger.Info("Retrieving flowmap for Application {0}, Tier {1}, Node {2}, From {3:o}, To {4:o}", jobTarget.Application, node.tierName, node.name, jobConfiguration.Input.ExpandedTimeRange.From, jobConfiguration.Input.ExpandedTimeRange.To); + + string flowmapDataFilePath = Path.Combine( + metricsFolderPath, + NODES_TYPE_SHORT, + getShortenedEntityNameForFileSystem(node.tierName, node.tierId), + getShortenedEntityNameForFileSystem(node.name, node.id), + String.Format(EXTRACT_ENTITY_FLOWMAP_FILE_NAME, jobConfiguration.Input.ExpandedTimeRange.From, jobConfiguration.Input.ExpandedTimeRange.To)); + + if (File.Exists(flowmapDataFilePath) == false) { - thisEntityMetricData = metricDataEXCPM.Where(m => m.metricPath.StartsWith(entityMetricPathPrefix) == true).FirstOrDefault(); + string flowmapJson = controllerApi.GetFlowmapNode(node.id, fromTimeUnix, toTimeUnix, differenceInMinutes); + if (flowmapJson != String.Empty) FileIOHelper.saveFileToFolder(flowmapJson, flowmapDataFilePath); } - if (thisEntityMetricData != null) - { - if (thisEntityMetricData.metricValues.Count > 0) - { - entityRow.EXCPM = thisEntityMetricData.metricValues[0].value; - entityRow.Exceptions = thisEntityMetricData.metricValues[0].sum; - } - if (File.Exists(entityMetricSummaryReportFilePath) == false) + if (progressToConsole == true) + { + j++; + if (j % 10 == 0) { - List metricSummaries = convertMetricSummaryToTypedListForCSV(thisEntityMetricData, entityRow, jobTimeRange); - FileIOHelper.writeListToCSVFile(metricSummaries, new MetricSummaryMetricReportMap(), entityMetricSummaryReportFilePath, false); + Console.Write("[{0}].", j); } - - entityRow.MetricsIDs.Add(thisEntityMetricData.metricId); } } - // HTTPEPM - metricsDataFolderPath = Path.Combine(metricsEntityFolderPath, METRIC_HTTPEPM_SHORTNAME); - entityMetricSummaryReportFilePath = Path.Combine(metricsDataFolderPath, CONVERT_METRIC_SUMMARY_FILE_NAME); - if (metricDataHTTPEPM != null && metricDataHTTPEPM.Count > 0) - { - if (entityID != -1) - { - thisEntityMetricData = metricDataHTTPEPM.Where(m => m.metricPath.StartsWith(entityMetricPathPrefix) == true && m.metricName.Contains(entityID.ToString()) == true).FirstOrDefault(); - } - else + return entityList.Count; + } + + private static int extractFlowmapsBackends(JobConfiguration jobConfiguration, JobTarget jobTarget, ControllerApi controllerApi, List entityList, string metricsFolderPath, long fromTimeUnix, long toTimeUnix, long differenceInMinutes, bool progressToConsole) + { + int j = 0; + + foreach (AppDRESTBackend backend in entityList) + { + logger.Info("Retrieving flowmap for Application {0}, Backend {1}, From {2:o}, To {3:o}", jobTarget.Application, backend.name, jobConfiguration.Input.ExpandedTimeRange.From, jobConfiguration.Input.ExpandedTimeRange.To); + + string flowmapDataFilePath = Path.Combine( + metricsFolderPath, + BACKENDS_TYPE_SHORT, + getShortenedEntityNameForFileSystem(backend.name, backend.id), + String.Format(EXTRACT_ENTITY_FLOWMAP_FILE_NAME, jobConfiguration.Input.ExpandedTimeRange.From, jobConfiguration.Input.ExpandedTimeRange.To)); + + if (File.Exists(flowmapDataFilePath) == false) { - thisEntityMetricData = metricDataHTTPEPM.Where(m => m.metricPath.StartsWith(entityMetricPathPrefix) == true).FirstOrDefault(); + string flowmapJson = controllerApi.GetFlowmapBackend(backend.id, fromTimeUnix, toTimeUnix, differenceInMinutes); + if (flowmapJson != String.Empty) FileIOHelper.saveFileToFolder(flowmapJson, flowmapDataFilePath); } - if (thisEntityMetricData != null) - { - if (thisEntityMetricData.metricValues.Count > 0) - { - entityRow.HTTPEPM = thisEntityMetricData.metricValues[0].value; - entityRow.HttpErrors = thisEntityMetricData.metricValues[0].sum; - } - if (File.Exists(entityMetricSummaryReportFilePath) == false) + if (progressToConsole == true) + { + j++; + if (j % 10 == 0) { - List metricSummaries = convertMetricSummaryToTypedListForCSV(thisEntityMetricData, entityRow, jobTimeRange); - FileIOHelper.writeListToCSVFile(metricSummaries, new MetricSummaryMetricReportMap(), entityMetricSummaryReportFilePath, false); + Console.Write("[{0}].", j); } - - entityRow.MetricsIDs.Add(thisEntityMetricData.metricId); } } - #endregion - - if (entityRow.ART == 0 && entityRow.TimeTotal == 0 && - entityRow.CPM == 0 && entityRow.Calls == 0 && - entityRow.EPM == 0 && entityRow.Errors == 0 && - entityRow.EXCPM == 0 && entityRow.Exceptions == 0 && - entityRow.HTTPEPM == 0 && entityRow.HttpErrors == 0) - { - entityRow.HasActivity = false; - } - else - { - entityRow.HasActivity = true; - } - - // Add link to the metrics - updateEntityWithDeeplinks(entityRow, jobTimeRange); - - return; + return entityList.Count; } - private static void fillHourlyRangeMetricEntityRowAndConvertMetricsToCSV( - EntityBase entityRow, - JobTimeRange jobTimeRange, - string entityMetricPathPrefix, - string metricsEntityFolderPath, - int timeRangeIndex, - List metricDataART, - List metricDataCPM, - List metricDataEPM, - List metricDataEXCPM, - List metricDataHTTPEPM) + private static int extractFlowmapsBusinessTransactions(JobConfiguration jobConfiguration, JobTarget jobTarget, ControllerApi controllerApi, List entityList, string metricsFolderPath, long fromTimeUnix, long toTimeUnix, long differenceInMinutes, bool progressToConsole) { - entityRow.Duration = (int)(jobTimeRange.To - jobTimeRange.From).Duration().TotalMinutes; - entityRow.From = jobTimeRange.From.ToLocalTime(); - entityRow.To = jobTimeRange.To.ToLocalTime(); - entityRow.FromUtc = jobTimeRange.From; - entityRow.ToUtc = jobTimeRange.To; + int j = 0; - // Determine the entity ID to bve used in ensuring we get only one specific entity - // This is to address identically named Entities - // Backends can be named identically - see Azure Table exits - // Errors can also occasionally be named identically - long entityID = -1; - if (entityRow is EntityApplication) - { - // Application level metrics don't need ever have anything unusual - } - else if (entityRow is EntityTier) - { - entityID = entityRow.TierID; - } - else if (entityRow is EntityNode) - { - entityID = entityRow.TierID; - } - else if (entityRow is EntityBackend) - { - entityID = ((EntityBackend)entityRow).BackendID; - } - else if (entityRow is EntityBusinessTransaction) - { - entityID = ((EntityBusinessTransaction)entityRow).BTID; - } - else if (entityRow is EntityServiceEndpoint) - { - entityID = ((EntityServiceEndpoint)entityRow).SEPID; - } - else if (entityRow is EntityError) - { - entityID = ((EntityError)entityRow).ErrorID; - } - else if (entityRow is EntityInformationPoint) + foreach (AppDRESTBusinessTransaction businessTransaction in entityList) { - entityID = ((EntityInformationPoint)entityRow).IPID; - } - - if (entityRow.MetricsIDs == null) { entityRow.MetricsIDs = new List(5); } - - bool appendRecordsToExistingFile = true; - if (timeRangeIndex == 0) { appendRecordsToExistingFile = false; } - - AppDRESTMetric thisEntityMetricData = null; + logger.Info("Retrieving flowmap for Application {0}, Tier {1}, Business Transaction {2}, From {3:o}, To {4:o}", jobTarget.Application, businessTransaction.tierName, businessTransaction.name, jobConfiguration.Input.ExpandedTimeRange.From, jobConfiguration.Input.ExpandedTimeRange.To); - #region Read and convert metrics + string flowmapDataFilePath = Path.Combine( + metricsFolderPath, + BUSINESS_TRANSACTIONS_TYPE_SHORT, + getShortenedEntityNameForFileSystem(businessTransaction.tierName, businessTransaction.tierId), + getShortenedEntityNameForFileSystem(businessTransaction.name, businessTransaction.id), + String.Format(EXTRACT_ENTITY_FLOWMAP_FILE_NAME, jobConfiguration.Input.ExpandedTimeRange.From, jobConfiguration.Input.ExpandedTimeRange.To)); - // ART - string metricsDataFolderPath = Path.Combine(metricsEntityFolderPath, METRIC_ART_SHORTNAME); - string entityMetricReportFilePath = Path.Combine(metricsDataFolderPath, CONVERT_METRIC_VALUES_FILE_NAME); - if (metricDataART != null && metricDataART.Count > 0) - { - if (entityID != -1) - { - thisEntityMetricData = metricDataART.Where(m => m.metricPath.StartsWith(entityMetricPathPrefix) == true && m.metricName.Contains(entityID.ToString()) == true).FirstOrDefault(); - } - else + if (File.Exists(flowmapDataFilePath) == false) { - thisEntityMetricData = metricDataART.Where(m => m.metricPath.StartsWith(entityMetricPathPrefix) == true).FirstOrDefault(); + string flowmapJson = controllerApi.GetFlowmapBusinessTransaction(jobTarget.ApplicationID, businessTransaction.id, fromTimeUnix, toTimeUnix, differenceInMinutes); + if (flowmapJson != String.Empty) FileIOHelper.saveFileToFolder(flowmapJson, flowmapDataFilePath); } - if (thisEntityMetricData != null) + + if (progressToConsole == true) { - if (thisEntityMetricData.metricValues.Count > 0) + j++; + if (j % 10 == 0) { - double intermediateART = (double)thisEntityMetricData.metricValues.Sum(mv => mv.sum) / (double)thisEntityMetricData.metricValues.Sum(mv => mv.count); - if (Double.IsNaN(intermediateART) == true) - { - entityRow.ART = 0; - } - else - { - entityRow.ART = (long)Math.Round(intermediateART, 0); - } - entityRow.TimeTotal = thisEntityMetricData.metricValues.Sum(mv => mv.sum); + Console.Write("[{0}].", j); } + } + } - List metricValues = convertMetricValueToTypedListForCSV(thisEntityMetricData); - FileIOHelper.writeListToCSVFile(metricValues, new MetricValueMetricReportMap(), entityMetricReportFilePath, appendRecordsToExistingFile); + return entityList.Count; + } - entityRow.MetricsIDs.Add(thisEntityMetricData.metricId); - } + #endregion + + #region Event extraction functions + + private static int extractEvents(JobConfiguration jobConfiguration, JobTarget jobTarget, ControllerApi controllerApi, string eventsFolderPath, string eventType, bool progressToConsole) + { + if (progressToConsole == true) + { + loggerConsole.Info("Extract {0} events ({1} time ranges)", eventType, jobConfiguration.Input.HourlyTimeRanges.Count); } - // CPM - metricsDataFolderPath = Path.Combine(metricsEntityFolderPath, METRIC_CPM_SHORTNAME); - entityMetricReportFilePath = Path.Combine(metricsDataFolderPath, CONVERT_METRIC_VALUES_FILE_NAME); - if (metricDataCPM != null && metricDataCPM.Count > 0) + JArray listOfEvents = new JArray(); + int totalEventsFound = 0; + foreach (JobTimeRange jobTimeRange in jobConfiguration.Input.HourlyTimeRanges) { - if (entityID != -1) - { - thisEntityMetricData = metricDataCPM.Where(m => m.metricPath.StartsWith(entityMetricPathPrefix) == true && m.metricName.Contains(entityID.ToString()) == true).FirstOrDefault(); - } - else - { - thisEntityMetricData = metricDataCPM.Where(m => m.metricPath.StartsWith(entityMetricPathPrefix) == true).FirstOrDefault(); - } - if (thisEntityMetricData != null) + long fromTimeUnix = convertToUnixTimestamp(jobTimeRange.From); + long toTimeUnix = convertToUnixTimestamp(jobTimeRange.To); + + string eventsJSON = controllerApi.GetEvents(jobTarget.ApplicationID, eventType, fromTimeUnix, toTimeUnix); + if (eventsJSON != String.Empty) { - if (thisEntityMetricData.metricValues.Count > 0) + // Load events + JArray eventsInHour = JArray.Parse(eventsJSON); + foreach (JObject interestingEvent in eventsInHour) { - entityRow.CPM = (long)Math.Round((double)((double)thisEntityMetricData.metricValues.Sum(mv => mv.sum) / (double)entityRow.Duration), 0); - entityRow.Calls = thisEntityMetricData.metricValues.Sum(mv => mv.sum); + listOfEvents.Add(interestingEvent); } + totalEventsFound = totalEventsFound + eventsInHour.Count; - List metricValues = convertMetricValueToTypedListForCSV(thisEntityMetricData); - FileIOHelper.writeListToCSVFile(metricValues, new MetricValueMetricReportMap(), entityMetricReportFilePath, appendRecordsToExistingFile); - - entityRow.MetricsIDs.Add(thisEntityMetricData.metricId); + if (progressToConsole == true) + { + Console.Write("+{0}", eventsInHour.Count); + } } } - // EPM - metricsDataFolderPath = Path.Combine(metricsEntityFolderPath, METRIC_EPM_SHORTNAME); - entityMetricReportFilePath = Path.Combine(metricsDataFolderPath, CONVERT_METRIC_VALUES_FILE_NAME); - if (metricDataEPM != null && metricDataEPM.Count > 0) + if (listOfEvents.Count > 0) { - if (entityID != -1) - { - thisEntityMetricData = metricDataEPM.Where(m => m.metricPath.StartsWith(entityMetricPathPrefix) == true && m.metricName.Contains(entityID.ToString()) == true).FirstOrDefault(); - } - else + string eventsFilePath = Path.Combine( + eventsFolderPath, + String.Format(EVENTS_FILE_NAME, eventType, jobConfiguration.Input.ExpandedTimeRange.From, jobConfiguration.Input.ExpandedTimeRange.To)); + + FileIOHelper.writeJArrayToFile(listOfEvents, eventsFilePath); + + logger.Info("{0} events from {1:o} to {2:o}", listOfEvents.Count, jobConfiguration.Input.ExpandedTimeRange.From, jobConfiguration.Input.ExpandedTimeRange.To); + if (progressToConsole == true) { - thisEntityMetricData = metricDataEPM.Where(m => m.metricPath.StartsWith(entityMetricPathPrefix) == true).FirstOrDefault(); + Console.Write("="); + loggerConsole.Info("{0} {1} events", listOfEvents.Count, eventType); } - if (thisEntityMetricData != null) + } + else + { + if (progressToConsole == true) { - if (thisEntityMetricData.metricValues.Count > 0) - { - entityRow.EPM = (long)Math.Round((double)((double)thisEntityMetricData.metricValues.Sum(mv => mv.sum) / (double)entityRow.Duration), 0); - entityRow.Errors = thisEntityMetricData.metricValues.Sum(mv => mv.sum); - entityRow.ErrorsPercentage = Math.Round((double)(double)entityRow.Errors / (double)entityRow.Calls * 100, 2); - if (Double.IsNaN(entityRow.ErrorsPercentage) == true) entityRow.ErrorsPercentage = 0; - } - - List metricValues = convertMetricValueToTypedListForCSV(thisEntityMetricData); - FileIOHelper.writeListToCSVFile(metricValues, new MetricValueMetricReportMap(), entityMetricReportFilePath, appendRecordsToExistingFile); - - entityRow.MetricsIDs.Add(thisEntityMetricData.metricId); + Console.WriteLine(); } } - // EXCPM - metricsDataFolderPath = Path.Combine(metricsEntityFolderPath, METRIC_EXCPM_SHORTNAME); - entityMetricReportFilePath = Path.Combine(metricsDataFolderPath, CONVERT_METRIC_VALUES_FILE_NAME); - if (metricDataEXCPM != null && metricDataEXCPM.Count > 0) + return listOfEvents.Count; + } + + #endregion + + #region Snapshot extraction functions + + private static int extractSnapshots(JobConfiguration jobConfiguration, JobTarget jobTarget, ControllerApi controllerApi, List entityList, string snapshotsFolderPath, bool progressToConsole) + { + int j = 0; + + foreach (JToken snapshot in entityList) { - if (entityID != -1) - { - thisEntityMetricData = metricDataEXCPM.Where(m => m.metricPath.StartsWith(entityMetricPathPrefix) == true && m.metricName.Contains(entityID.ToString()) == true).FirstOrDefault(); - } - else - { - thisEntityMetricData = metricDataEXCPM.Where(m => m.metricPath.StartsWith(entityMetricPathPrefix) == true).FirstOrDefault(); - } - if (thisEntityMetricData != null) + // Only do first in chain + if ((bool)snapshot["firstInChain"] == true) { - if (thisEntityMetricData.metricValues.Count > 0) + logger.Info("Retrieving snapshot for Application {0}, Tier {1}, Business Transaction {2}, RequestGUID {3}", jobTarget.Application, snapshot["applicationComponentName"], snapshot["businessTransactionName"], snapshot["requestGUID"]); + + #region Target step variables + + DateTime snapshotTime = convertFromUnixTimestamp((long)snapshot["serverStartTime"]); + + string snapshotFolderPath = Path.Combine( + snapshotsFolderPath, + getShortenedEntityNameForFileSystem(snapshot["applicationComponentName"].ToString(), (long)snapshot["applicationComponentId"]), + getShortenedEntityNameForFileSystem(snapshot["businessTransactionName"].ToString(), (long)snapshot["businessTransactionId"]), + String.Format("{0:yyyyMMddHH}", snapshotTime), + userExperienceFolderNameMapping[snapshot["userExperience"].ToString()], + String.Format(SNAPSHOT_FOLDER_NAME, snapshot["requestGUID"], snapshotTime)); + + // Must strip out the milliseconds, because the segment list retrieval doesn't seem to like them in the datetimes + DateTime snapshotTimeFrom = snapshotTime.AddMinutes(-30).AddMilliseconds(snapshotTime.Millisecond * -1); + DateTime snapshotTimeTo = snapshotTime.AddMinutes(30).AddMilliseconds(snapshotTime.Millisecond * -1); + + long fromTimeUnix = convertToUnixTimestamp(snapshotTimeFrom); + long toTimeUnix = convertToUnixTimestamp(snapshotTimeTo); + int differenceInMinutes = (int)(snapshotTimeTo - snapshotTimeFrom).TotalMinutes; + + #endregion + + #region Get Snapshot Flowmap + + // Get snapshot flow map + string snapshotFlowmapDataFilePath = Path.Combine(snapshotFolderPath, EXTRACT_SNAPSHOT_FLOWMAP_FILE_NAME); + + if (File.Exists(snapshotFlowmapDataFilePath) == false) { - entityRow.EXCPM = (long)Math.Round((double)((double)thisEntityMetricData.metricValues.Sum(mv => mv.sum) / (double)entityRow.Duration), 0); - entityRow.Exceptions = thisEntityMetricData.metricValues.Sum(mv => mv.sum); + string snapshotFlowmapJson = controllerApi.GetFlowmapSnapshot(jobTarget.ApplicationID, (int)snapshot["businessTransactionId"], snapshot["requestGUID"].ToString(), fromTimeUnix, toTimeUnix, differenceInMinutes); + if (snapshotFlowmapJson != String.Empty) FileIOHelper.saveFileToFolder(snapshotFlowmapJson, snapshotFlowmapDataFilePath); } - List metricValues = convertMetricValueToTypedListForCSV(thisEntityMetricData); - FileIOHelper.writeListToCSVFile(metricValues, new MetricValueMetricReportMap(), entityMetricReportFilePath, appendRecordsToExistingFile); + #endregion - entityRow.MetricsIDs.Add(thisEntityMetricData.metricId); - } - } + #region Get List of Segments - // HTTPEPM - metricsDataFolderPath = Path.Combine(metricsEntityFolderPath, METRIC_HTTPEPM_SHORTNAME); - entityMetricReportFilePath = Path.Combine(metricsDataFolderPath, CONVERT_METRIC_VALUES_FILE_NAME); - if (metricDataHTTPEPM != null && metricDataHTTPEPM.Count > 0) - { - if (entityID != -1) - { - thisEntityMetricData = metricDataHTTPEPM.Where(m => m.metricPath.StartsWith(entityMetricPathPrefix) == true && m.metricName.Contains(entityID.ToString()) == true).FirstOrDefault(); - } - else - { - thisEntityMetricData = metricDataHTTPEPM.Where(m => m.metricPath.StartsWith(entityMetricPathPrefix) == true).FirstOrDefault(); - } - if (thisEntityMetricData != null) - { - if (thisEntityMetricData.metricValues.Count > 0) + // Get list of segments + string snapshotSegmentsDataFilePath = Path.Combine(snapshotFolderPath, EXTRACT_SNAPSHOT_SEGMENT_FILE_NAME); + + if (File.Exists(snapshotSegmentsDataFilePath) == false) { - entityRow.HTTPEPM = (long)Math.Round((double)((double)thisEntityMetricData.metricValues.Sum(mv => mv.sum) / (double)entityRow.Duration), 0); - entityRow.HttpErrors = thisEntityMetricData.metricValues.Sum(mv => mv.sum); + string snapshotSegmentsJson = controllerApi.GetSnapshotSegments(snapshot["requestGUID"].ToString(), snapshotTimeFrom, snapshotTimeTo, differenceInMinutes); + if (snapshotSegmentsJson != String.Empty) FileIOHelper.saveFileToFolder(snapshotSegmentsJson, snapshotSegmentsDataFilePath); } - List metricValues = convertMetricValueToTypedListForCSV(thisEntityMetricData); - FileIOHelper.writeListToCSVFile(metricValues, new MetricValueMetricReportMap(), entityMetricReportFilePath, appendRecordsToExistingFile); + #endregion + + #region Get Details for Each Segment + + JArray snapshotSegmentsList = FileIOHelper.loadJArrayFromFile(snapshotSegmentsDataFilePath); + if (snapshotSegmentsList != null) + { + // Get details for segment + foreach (JToken snapshotSegment in snapshotSegmentsList) + { + string snapshotSegmentDataFilePath = Path.Combine(snapshotFolderPath, String.Format(EXTRACT_SNAPSHOT_SEGMENT_DATA_FILE_NAME, snapshotSegment["id"])); + + if (File.Exists(snapshotSegmentDataFilePath) == false) + { + string snapshotSegmentJson = controllerApi.GetSnapshotSegmentDetails((long)snapshotSegment["id"], fromTimeUnix, toTimeUnix, differenceInMinutes); + if (snapshotSegmentJson != String.Empty) FileIOHelper.saveFileToFolder(snapshotSegmentJson, snapshotSegmentDataFilePath); + } + } + + // Get errors for segment + foreach (JToken snapshotSegment in snapshotSegmentsList) + { + string snapshotSegmentErrorFilePath = Path.Combine(snapshotFolderPath, String.Format(EXTRACT_SNAPSHOT_SEGMENT_ERROR_FILE_NAME, snapshotSegment["id"])); + + if ((bool)snapshotSegment["errorOccurred"] == true && File.Exists(snapshotSegmentErrorFilePath) == false) + { + string snapshotSegmentJson = controllerApi.GetSnapshotSegmentErrors((long)snapshotSegment["id"], fromTimeUnix, toTimeUnix, differenceInMinutes); + if (snapshotSegmentJson != String.Empty) + { + // "[ ]" == empty data. Don't create the file + if (snapshotSegmentJson.Length > 3) + { + FileIOHelper.saveFileToFolder(snapshotSegmentJson, snapshotSegmentErrorFilePath); + } + } + } + } + + // Get call graphs for segment + foreach (JToken snapshotSegment in snapshotSegmentsList) + { + string snapshotSegmentCallGraphFilePath = Path.Combine(snapshotFolderPath, String.Format(EXTRACT_SNAPSHOT_SEGMENT_CALLGRAPH_FILE_NAME, snapshotSegment["id"])); + + if (((bool)snapshotSegment["fullCallgraph"] == true || (bool)snapshotSegment["delayedCallGraph"] == true) && File.Exists(snapshotSegmentCallGraphFilePath) == false) + { + string snapshotSegmentJson = controllerApi.GetSnapshotSegmentCallGraph((long)snapshotSegment["id"], fromTimeUnix, toTimeUnix, differenceInMinutes); + if (snapshotSegmentJson != String.Empty) FileIOHelper.saveFileToFolder(snapshotSegmentJson, snapshotSegmentCallGraphFilePath); + } + } + } + + #endregion - entityRow.MetricsIDs.Add(thisEntityMetricData.metricId); } - } - if (entityRow.ART == 0 && entityRow.TimeTotal == 0 && - entityRow.CPM == 0 && entityRow.Calls == 0 && - entityRow.EPM == 0 && entityRow.Errors == 0 && - entityRow.EXCPM == 0 && entityRow.Exceptions == 0 && - entityRow.HTTPEPM == 0 && entityRow.HttpErrors == 0) - { - entityRow.HasActivity = false; - } - else - { - entityRow.HasActivity = true; + if (progressToConsole == true) + { + j++; + if (j % 10 == 0) + { + Console.Write("[{0}].", j); + } + } } - #endregion + return entityList.Count; + } - // Add link to the metrics - updateEntityWithDeeplinks(entityRow, jobTimeRange); + #endregion - return; - } - private static bool updateEntityWithDeeplinks(EntityBase entityRow) - { - return updateEntityWithDeeplinks(entityRow, null); - } + #region Metric detail conversion functions - private static bool updateEntityWithDeeplinks(EntityBase entityRow, JobTimeRange jobTimeRange) + private static void fillFullRangeMetricEntityRow( + EntityBase entityRow, + JobTimeRange jobTimeRange, + string entityMetricPathPrefix, + string metricsEntityFolderPath, + List metricDataART, + List metricDataCPM, + List metricDataEPM, + List metricDataEXCPM, + List metricDataHTTPEPM) { - // Decide what kind of timerange - string DEEPLINK_THIS_TIMERANGE = DEEPLINK_TIMERANGE_LAST_15_MINUTES; - if (jobTimeRange != null) - { - long fromTimeUnix = convertToUnixTimestamp(jobTimeRange.From); - long toTimeUnix = convertToUnixTimestamp(jobTimeRange.To); - long differenceInMinutes = (toTimeUnix - fromTimeUnix) / (60000); - DEEPLINK_THIS_TIMERANGE = String.Format(DEEPLINK_TIMERANGE_BETWEEN_TIMES, toTimeUnix, fromTimeUnix, differenceInMinutes); - } + entityRow.Duration = (int)(jobTimeRange.To - jobTimeRange.From).Duration().TotalMinutes; + entityRow.From = jobTimeRange.From.ToLocalTime(); + entityRow.To = jobTimeRange.To.ToLocalTime(); + entityRow.FromUtc = jobTimeRange.From; + entityRow.ToUtc = jobTimeRange.To; - // Determine what kind of entity we are dealing with and adjust accordingly - string deepLinkMetricTemplateInMetricBrowser = DEEPLINK_METRIC_APPLICATION_TARGET_METRIC_ID; - long entityIdForMetricBrowser = entityRow.ApplicationID; + // Determine the entity ID to bve used in ensuring we get only one specific entity + // This is to address identically named Entities + // Backends can be named identically - see Azure Table exits + // Errors can also occasionally be named identically + long entityID = -1; if (entityRow is EntityApplication) { - entityRow.ControllerLink = String.Format(DEEPLINK_CONTROLLER, entityRow.Controller, DEEPLINK_THIS_TIMERANGE); - entityRow.ApplicationLink = String.Format(DEEPLINK_APPLICATION, entityRow.Controller, entityRow.ApplicationID, DEEPLINK_THIS_TIMERANGE); + // Application level metrics don't need ever have anything unusual } else if (entityRow is EntityTier) { - entityRow.ControllerLink = String.Format(DEEPLINK_CONTROLLER, entityRow.Controller, DEEPLINK_THIS_TIMERANGE); - entityRow.ApplicationLink = String.Format(DEEPLINK_APPLICATION, entityRow.Controller, entityRow.ApplicationID, DEEPLINK_THIS_TIMERANGE); - entityRow.TierLink = String.Format(DEEPLINK_TIER, entityRow.Controller, entityRow.ApplicationID, entityRow.TierID, DEEPLINK_THIS_TIMERANGE); - deepLinkMetricTemplateInMetricBrowser = DEEPLINK_METRIC_TIER_TARGET_METRIC_ID; - entityIdForMetricBrowser = entityRow.TierID; + entityID = entityRow.TierID; } else if (entityRow is EntityNode) { - entityRow.ControllerLink = String.Format(DEEPLINK_CONTROLLER, entityRow.Controller, DEEPLINK_THIS_TIMERANGE); - entityRow.ApplicationLink = String.Format(DEEPLINK_APPLICATION, entityRow.Controller, entityRow.ApplicationID, DEEPLINK_THIS_TIMERANGE); - entityRow.TierLink = String.Format(DEEPLINK_TIER, entityRow.Controller, entityRow.ApplicationID, entityRow.TierID, DEEPLINK_THIS_TIMERANGE); - entityRow.NodeLink = String.Format(DEEPLINK_NODE, entityRow.Controller, entityRow.ApplicationID, entityRow.NodeID, DEEPLINK_THIS_TIMERANGE); - deepLinkMetricTemplateInMetricBrowser = DEEPLINK_METRIC_NODE_TARGET_METRIC_ID; - entityIdForMetricBrowser = entityRow.NodeID; + entityID = entityRow.TierID; } else if (entityRow is EntityBackend) { - entityRow.ControllerLink = String.Format(DEEPLINK_CONTROLLER, entityRow.Controller, DEEPLINK_THIS_TIMERANGE); - entityRow.ApplicationLink = String.Format(DEEPLINK_APPLICATION, entityRow.Controller, entityRow.ApplicationID, DEEPLINK_THIS_TIMERANGE); - ((EntityBackend)entityRow).BackendLink = String.Format(DEEPLINK_BACKEND, entityRow.Controller, entityRow.ApplicationID, ((EntityBackend)entityRow).BackendID, DEEPLINK_THIS_TIMERANGE); + entityID = ((EntityBackend)entityRow).BackendID; } else if (entityRow is EntityBusinessTransaction) { - entityRow.ControllerLink = String.Format(DEEPLINK_CONTROLLER, entityRow.Controller, DEEPLINK_THIS_TIMERANGE); - entityRow.ApplicationLink = String.Format(DEEPLINK_APPLICATION, entityRow.Controller, entityRow.ApplicationID, DEEPLINK_THIS_TIMERANGE); - entityRow.TierLink = String.Format(DEEPLINK_TIER, entityRow.Controller, entityRow.ApplicationID, entityRow.TierID, DEEPLINK_THIS_TIMERANGE); - ((EntityBusinessTransaction)entityRow).BTLink = String.Format(DEEPLINK_BUSINESS_TRANSACTION, entityRow.Controller, entityRow.ApplicationID, ((EntityBusinessTransaction)entityRow).BTID, DEEPLINK_THIS_TIMERANGE); - deepLinkMetricTemplateInMetricBrowser = DEEPLINK_METRIC_TIER_TARGET_METRIC_ID; - entityIdForMetricBrowser = entityRow.TierID; + entityID = ((EntityBusinessTransaction)entityRow).BTID; } else if (entityRow is EntityServiceEndpoint) { - entityRow.ControllerLink = String.Format(DEEPLINK_CONTROLLER, entityRow.Controller, DEEPLINK_THIS_TIMERANGE); - entityRow.ApplicationLink = String.Format(DEEPLINK_APPLICATION, entityRow.Controller, entityRow.ApplicationID, DEEPLINK_THIS_TIMERANGE); - entityRow.TierLink = String.Format(DEEPLINK_TIER, entityRow.Controller, entityRow.ApplicationID, entityRow.TierID, DEEPLINK_THIS_TIMERANGE); - ((EntityServiceEndpoint)entityRow).SEPLink = String.Format(DEEPLINK_SERVICE_ENDPOINT, entityRow.Controller, entityRow.ApplicationID, entityRow.TierID, ((EntityServiceEndpoint)entityRow).SEPID, DEEPLINK_THIS_TIMERANGE); + entityID = ((EntityServiceEndpoint)entityRow).SEPID; } else if (entityRow is EntityError) { - entityRow.ControllerLink = String.Format(DEEPLINK_CONTROLLER, entityRow.Controller, DEEPLINK_THIS_TIMERANGE); - entityRow.ApplicationLink = String.Format(DEEPLINK_APPLICATION, entityRow.Controller, entityRow.ApplicationID, DEEPLINK_THIS_TIMERANGE); - entityRow.TierLink = String.Format(DEEPLINK_TIER, entityRow.Controller, entityRow.ApplicationID, entityRow.TierID, DEEPLINK_THIS_TIMERANGE); - ((EntityError)entityRow).ErrorLink = String.Format(DEEPLINK_ERROR, entityRow.Controller, entityRow.ApplicationID, ((EntityError)entityRow).ErrorID, DEEPLINK_THIS_TIMERANGE); + entityID = ((EntityError)entityRow).ErrorID; } else if (entityRow is EntityInformationPoint) { - entityRow.ControllerLink = String.Format(DEEPLINK_CONTROLLER, entityRow.Controller, DEEPLINK_THIS_TIMERANGE); - entityRow.ApplicationLink = String.Format(DEEPLINK_APPLICATION, entityRow.Controller, entityRow.ApplicationID, DEEPLINK_THIS_TIMERANGE); - ((EntityInformationPoint)entityRow).IPLink = String.Format(DEEPLINK_INFORMATION_POINT, entityRow.Controller, entityRow.ApplicationID, ((EntityInformationPoint)entityRow).IPID, DEEPLINK_THIS_TIMERANGE); + entityID = ((EntityInformationPoint)entityRow).IPID; } + entityRow.MetricsIDs = new List(5); - if (entityRow.MetricsIDs != null && entityRow.MetricsIDs.Count > 0) - { - StringBuilder sb = new StringBuilder(128); - foreach (int metricID in entityRow.MetricsIDs) + AppDRESTMetric thisEntityMetricData = null; + + #region Read and convert metrics + + // ART + string metricsDataFolderPath = Path.Combine(metricsEntityFolderPath, METRIC_ART_SHORTNAME); + string entityMetricSummaryReportFilePath = Path.Combine(metricsDataFolderPath, CONVERT_METRIC_SUMMARY_FILE_NAME); + if (metricDataART != null && metricDataART.Count > 0) + { + if (entityID != -1) { - sb.Append(String.Format(deepLinkMetricTemplateInMetricBrowser, entityIdForMetricBrowser, metricID)); - sb.Append(","); + thisEntityMetricData = metricDataART.Where(m => m.metricPath.StartsWith(entityMetricPathPrefix) == true && m.metricName.Contains(entityID.ToString()) == true).FirstOrDefault(); } - sb.Remove(sb.Length - 1, 1); - entityRow.MetricLink = String.Format(DEEPLINK_METRIC, entityRow.Controller, entityRow.ApplicationID, sb.ToString(), DEEPLINK_THIS_TIMERANGE); - } + else + { + thisEntityMetricData = metricDataART.Where(m => m.metricPath.StartsWith(entityMetricPathPrefix) == true).FirstOrDefault(); + } + if (thisEntityMetricData != null) + { + if (thisEntityMetricData.metricValues.Count > 0) + { + entityRow.ART = thisEntityMetricData.metricValues[0].value; + entityRow.TimeTotal = thisEntityMetricData.metricValues[0].sum; + } - return true; - } + if (File.Exists(entityMetricSummaryReportFilePath) == false) + { + List metricSummaries = convertMetricSummaryToTypedListForCSV(thisEntityMetricData, entityRow, jobTimeRange); + FileIOHelper.writeListToCSVFile(metricSummaries, new MetricSummaryMetricReportMap(), entityMetricSummaryReportFilePath, false); + } - private static void updateEntitiesWithReportDetailLinksApplication(ProgramOptions programOptions, JobConfiguration jobConfiguration, JobTarget jobTarget, List entityList) - { - string controllerFolderPath = Path.Combine(programOptions.OutputJobFolderPath, getFileSystemSafeString(new Uri(jobTarget.Controller).Host)); - string applicationFolderPath = Path.Combine(controllerFolderPath, getShortenedEntityNameForFileSystem(jobTarget.Application, jobTarget.ApplicationID)); - string entitiesFolderPath = Path.Combine(applicationFolderPath, ENTITIES_FOLDER_NAME); - string reportsFolderPath = Path.Combine(programOptions.OutputJobFolderPath, REPORTS_FOLDER_NAME); + entityRow.MetricsIDs.Add(thisEntityMetricData.metricId); + } + } - for (int i = 0; i < entityList.Count; i++) + // CPM + metricsDataFolderPath = Path.Combine(metricsEntityFolderPath, METRIC_CPM_SHORTNAME); + entityMetricSummaryReportFilePath = Path.Combine(metricsDataFolderPath, CONVERT_METRIC_SUMMARY_FILE_NAME); + if (metricDataCPM != null && metricDataCPM.Count > 0) { - EntityBase entityRow = entityList[i]; - entityRow.DetailLink = String.Format(@"=HYPERLINK(""{0}"", """")", getEntityMetricReportFilePath(programOptions, jobConfiguration, jobTarget, entityRow).Substring(reportsFolderPath.Length + 1)); - } - } + if (entityID != -1) + { + thisEntityMetricData = metricDataCPM.Where(m => m.metricPath.StartsWith(entityMetricPathPrefix) == true && m.metricName.Contains(entityID.ToString()) == true).FirstOrDefault(); + } + else + { + thisEntityMetricData = metricDataCPM.Where(m => m.metricPath.StartsWith(entityMetricPathPrefix) == true).FirstOrDefault(); + } + if (thisEntityMetricData != null) + { + if (thisEntityMetricData.metricValues.Count > 0) + { + entityRow.CPM = thisEntityMetricData.metricValues[0].value; + entityRow.Calls = thisEntityMetricData.metricValues[0].sum; + } - private static void updateEntitiesWithReportDetailLinksTiers(ProgramOptions programOptions, JobConfiguration jobConfiguration, JobTarget jobTarget, List entityList) - { - string controllerFolderPath = Path.Combine(programOptions.OutputJobFolderPath, getFileSystemSafeString(new Uri(jobTarget.Controller).Host)); - string applicationFolderPath = Path.Combine(controllerFolderPath, getShortenedEntityNameForFileSystem(jobTarget.Application, jobTarget.ApplicationID)); - string entitiesFolderPath = Path.Combine(applicationFolderPath, ENTITIES_FOLDER_NAME); - string reportsFolderPath = Path.Combine(programOptions.OutputJobFolderPath, REPORTS_FOLDER_NAME); + if (File.Exists(entityMetricSummaryReportFilePath) == false) + { + List metricSummaries = convertMetricSummaryToTypedListForCSV(thisEntityMetricData, entityRow, jobTimeRange); + FileIOHelper.writeListToCSVFile(metricSummaries, new MetricSummaryMetricReportMap(), entityMetricSummaryReportFilePath, false); + } - for (int i = 0; i < entityList.Count; i++) - { - EntityBase entityRow = entityList[i]; - entityRow.DetailLink = String.Format(@"=HYPERLINK(""{0}"", """")", getEntityMetricReportFilePath(programOptions, jobConfiguration, jobTarget, entityRow).Substring(reportsFolderPath.Length + 1)); + entityRow.MetricsIDs.Add(thisEntityMetricData.metricId); + } } - } - - private static void updateEntitiesWithReportDetailLinksNodes(ProgramOptions programOptions, JobConfiguration jobConfiguration, JobTarget jobTarget, List entityList) - { - string controllerFolderPath = Path.Combine(programOptions.OutputJobFolderPath, getFileSystemSafeString(new Uri(jobTarget.Controller).Host)); - string applicationFolderPath = Path.Combine(controllerFolderPath, getShortenedEntityNameForFileSystem(jobTarget.Application, jobTarget.ApplicationID)); - string entitiesFolderPath = Path.Combine(applicationFolderPath, ENTITIES_FOLDER_NAME); - string reportsFolderPath = Path.Combine(programOptions.OutputJobFolderPath, REPORTS_FOLDER_NAME); - for (int i = 0; i < entityList.Count; i++) + // EPM + metricsDataFolderPath = Path.Combine(metricsEntityFolderPath, METRIC_EPM_SHORTNAME); + entityMetricSummaryReportFilePath = Path.Combine(metricsDataFolderPath, CONVERT_METRIC_SUMMARY_FILE_NAME); + if (metricDataEPM != null && metricDataEPM.Count > 0) { - EntityBase entityRow = entityList[i]; - entityRow.DetailLink = String.Format(@"=HYPERLINK(""{0}"", """")", getEntityMetricReportFilePath(programOptions, jobConfiguration, jobTarget, entityRow).Substring(reportsFolderPath.Length + 1)); - } - } + if (entityID != -1) + { + thisEntityMetricData = metricDataEPM.Where(m => m.metricPath.StartsWith(entityMetricPathPrefix) == true && m.metricName.Contains(entityID.ToString()) == true).FirstOrDefault(); + } + else + { + thisEntityMetricData = metricDataEPM.Where(m => m.metricPath.StartsWith(entityMetricPathPrefix) == true).FirstOrDefault(); + } + if (thisEntityMetricData != null) + { + if (thisEntityMetricData.metricValues.Count > 0) + { + entityRow.EPM = thisEntityMetricData.metricValues[0].value; + entityRow.Errors = thisEntityMetricData.metricValues[0].sum; + entityRow.ErrorsPercentage = Math.Round((double)(double)entityRow.Errors / (double)entityRow.Calls * 100, 2); + if (Double.IsNaN(entityRow.ErrorsPercentage) == true) entityRow.ErrorsPercentage = 0; + } - private static void updateEntitiesWithReportDetailLinksBackends(ProgramOptions programOptions, JobConfiguration jobConfiguration, JobTarget jobTarget, List entityList) - { - string controllerFolderPath = Path.Combine(programOptions.OutputJobFolderPath, getFileSystemSafeString(new Uri(jobTarget.Controller).Host)); - string applicationFolderPath = Path.Combine(controllerFolderPath, getShortenedEntityNameForFileSystem(jobTarget.Application, jobTarget.ApplicationID)); - string entitiesFolderPath = Path.Combine(applicationFolderPath, ENTITIES_FOLDER_NAME); - string reportsFolderPath = Path.Combine(programOptions.OutputJobFolderPath, REPORTS_FOLDER_NAME); + if (File.Exists(entityMetricSummaryReportFilePath) == false) + { + List metricSummaries = convertMetricSummaryToTypedListForCSV(thisEntityMetricData, entityRow, jobTimeRange); + FileIOHelper.writeListToCSVFile(metricSummaries, new MetricSummaryMetricReportMap(), entityMetricSummaryReportFilePath, false); + } - for (int i = 0; i < entityList.Count; i++) - { - EntityBase entityRow = entityList[i]; - entityRow.DetailLink = String.Format(@"=HYPERLINK(""{0}"", """")", getEntityMetricReportFilePath(programOptions, jobConfiguration, jobTarget, entityRow).Substring(reportsFolderPath.Length + 1)); + entityRow.MetricsIDs.Add(thisEntityMetricData.metricId); + } } - } - - private static void updateEntitiesWithReportDetailLinksBusinessTransactions(ProgramOptions programOptions, JobConfiguration jobConfiguration, JobTarget jobTarget, List entityList) - { - string controllerFolderPath = Path.Combine(programOptions.OutputJobFolderPath, getFileSystemSafeString(new Uri(jobTarget.Controller).Host)); - string applicationFolderPath = Path.Combine(controllerFolderPath, getShortenedEntityNameForFileSystem(jobTarget.Application, jobTarget.ApplicationID)); - string entitiesFolderPath = Path.Combine(applicationFolderPath, ENTITIES_FOLDER_NAME); - string reportsFolderPath = Path.Combine(programOptions.OutputJobFolderPath, REPORTS_FOLDER_NAME); - for (int i = 0; i < entityList.Count; i++) + // EXCPM + metricsDataFolderPath = Path.Combine(metricsEntityFolderPath, METRIC_EXCPM_SHORTNAME); + entityMetricSummaryReportFilePath = Path.Combine(metricsDataFolderPath, CONVERT_METRIC_SUMMARY_FILE_NAME); + if (metricDataEXCPM != null && metricDataEXCPM.Count > 0) { - EntityBase entityRow = entityList[i]; - entityRow.DetailLink = String.Format(@"=HYPERLINK(""{0}"", """")", getEntityMetricReportFilePath(programOptions, jobConfiguration, jobTarget, entityRow).Substring(reportsFolderPath.Length + 1)); - } - } + if (entityID != -1) + { + thisEntityMetricData = metricDataEXCPM.Where(m => m.metricPath.StartsWith(entityMetricPathPrefix) == true && m.metricName.Contains(entityID.ToString()) == true).FirstOrDefault(); + } + else + { + thisEntityMetricData = metricDataEXCPM.Where(m => m.metricPath.StartsWith(entityMetricPathPrefix) == true).FirstOrDefault(); + } + if (thisEntityMetricData != null) + { + if (thisEntityMetricData.metricValues.Count > 0) + { + entityRow.EXCPM = thisEntityMetricData.metricValues[0].value; + entityRow.Exceptions = thisEntityMetricData.metricValues[0].sum; + } - private static void updateEntitiesWithReportDetailLinksServiceEndpoints(ProgramOptions programOptions, JobConfiguration jobConfiguration, JobTarget jobTarget, List entityList) - { - string controllerFolderPath = Path.Combine(programOptions.OutputJobFolderPath, getFileSystemSafeString(new Uri(jobTarget.Controller).Host)); - string applicationFolderPath = Path.Combine(controllerFolderPath, getShortenedEntityNameForFileSystem(jobTarget.Application, jobTarget.ApplicationID)); - string entitiesFolderPath = Path.Combine(applicationFolderPath, ENTITIES_FOLDER_NAME); - string reportsFolderPath = Path.Combine(programOptions.OutputJobFolderPath, REPORTS_FOLDER_NAME); + if (File.Exists(entityMetricSummaryReportFilePath) == false) + { + List metricSummaries = convertMetricSummaryToTypedListForCSV(thisEntityMetricData, entityRow, jobTimeRange); + FileIOHelper.writeListToCSVFile(metricSummaries, new MetricSummaryMetricReportMap(), entityMetricSummaryReportFilePath, false); + } - for (int i = 0; i < entityList.Count; i++) - { - EntityBase entityRow = entityList[i]; - entityRow.DetailLink = String.Format(@"=HYPERLINK(""{0}"", """")", getEntityMetricReportFilePath(programOptions, jobConfiguration, jobTarget, entityRow).Substring(reportsFolderPath.Length + 1)); + entityRow.MetricsIDs.Add(thisEntityMetricData.metricId); + } } - } - - private static void updateEntitiesWithReportDetailLinksErrors(ProgramOptions programOptions, JobConfiguration jobConfiguration, JobTarget jobTarget, List entityList) - { - string controllerFolderPath = Path.Combine(programOptions.OutputJobFolderPath, getFileSystemSafeString(new Uri(jobTarget.Controller).Host)); - string applicationFolderPath = Path.Combine(controllerFolderPath, getShortenedEntityNameForFileSystem(jobTarget.Application, jobTarget.ApplicationID)); - string entitiesFolderPath = Path.Combine(applicationFolderPath, ENTITIES_FOLDER_NAME); - string reportsFolderPath = Path.Combine(programOptions.OutputJobFolderPath, REPORTS_FOLDER_NAME); - for (int i = 0; i < entityList.Count; i++) + // HTTPEPM + metricsDataFolderPath = Path.Combine(metricsEntityFolderPath, METRIC_HTTPEPM_SHORTNAME); + entityMetricSummaryReportFilePath = Path.Combine(metricsDataFolderPath, CONVERT_METRIC_SUMMARY_FILE_NAME); + if (metricDataHTTPEPM != null && metricDataHTTPEPM.Count > 0) { - EntityBase entityRow = entityList[i]; - entityRow.DetailLink = String.Format(@"=HYPERLINK(""{0}"", """")", getEntityMetricReportFilePath(programOptions, jobConfiguration, jobTarget, entityRow).Substring(reportsFolderPath.Length + 1)); + if (entityID != -1) + { + thisEntityMetricData = metricDataHTTPEPM.Where(m => m.metricPath.StartsWith(entityMetricPathPrefix) == true && m.metricName.Contains(entityID.ToString()) == true).FirstOrDefault(); + } + else + { + thisEntityMetricData = metricDataHTTPEPM.Where(m => m.metricPath.StartsWith(entityMetricPathPrefix) == true).FirstOrDefault(); + } + if (thisEntityMetricData != null) + { + if (thisEntityMetricData.metricValues.Count > 0) + { + entityRow.HTTPEPM = thisEntityMetricData.metricValues[0].value; + entityRow.HttpErrors = thisEntityMetricData.metricValues[0].sum; + } + + if (File.Exists(entityMetricSummaryReportFilePath) == false) + { + List metricSummaries = convertMetricSummaryToTypedListForCSV(thisEntityMetricData, entityRow, jobTimeRange); + FileIOHelper.writeListToCSVFile(metricSummaries, new MetricSummaryMetricReportMap(), entityMetricSummaryReportFilePath, false); + } + + entityRow.MetricsIDs.Add(thisEntityMetricData.metricId); + } } - } - private static void updateEntitiesWithReportDetailLinksInformationPoints(ProgramOptions programOptions, JobConfiguration jobConfiguration, JobTarget jobTarget, List entityList) - { - string controllerFolderPath = Path.Combine(programOptions.OutputJobFolderPath, getFileSystemSafeString(new Uri(jobTarget.Controller).Host)); - string applicationFolderPath = Path.Combine(controllerFolderPath, getShortenedEntityNameForFileSystem(jobTarget.Application, jobTarget.ApplicationID)); - string entitiesFolderPath = Path.Combine(applicationFolderPath, ENTITIES_FOLDER_NAME); - string reportsFolderPath = Path.Combine(programOptions.OutputJobFolderPath, REPORTS_FOLDER_NAME); + #endregion - for (int i = 0; i < entityList.Count; i++) + if (entityRow.ART == 0 && entityRow.TimeTotal == 0 && + entityRow.CPM == 0 && entityRow.Calls == 0 && + entityRow.EPM == 0 && entityRow.Errors == 0 && + entityRow.EXCPM == 0 && entityRow.Exceptions == 0 && + entityRow.HTTPEPM == 0 && entityRow.HttpErrors == 0) { - EntityBase entityRow = entityList[i]; - entityRow.DetailLink = String.Format(@"=HYPERLINK(""{0}"", """")", getEntityMetricReportFilePath(programOptions, jobConfiguration, jobTarget, entityRow).Substring(reportsFolderPath.Length + 1)); + entityRow.HasActivity = false; + } + else + { + entityRow.HasActivity = true; } + + // Add link to the metrics + updateEntityWithDeeplinks(entityRow, jobTimeRange); + + return; } - private static List convertMetricValueToTypedListForCSV(AppDRESTMetric metricValueObject) - { - List metricValues = new List(metricValueObject.metricValues.Count); - foreach (AppDRESTMetricValue mv in metricValueObject.metricValues) - { - MetricValue metricValue = new MetricValue(); - metricValue.EventTimeStampUtc = convertFromUnixTimestamp(mv.startTimeInMillis); - metricValue.EventTimeStamp = metricValue.EventTimeStampUtc.ToLocalTime(); - metricValue.EventTime = metricValue.EventTimeStamp; - metricValue.Count = mv.count; - metricValue.Min = mv.min; - metricValue.Max = mv.max; - metricValue.Occurences = mv.occurrences; - metricValue.Sum = mv.sum; - metricValue.Value = mv.value; - - metricValue.MetricID = metricValueObject.metricId; - switch (metricValueObject.frequency) - { - case "SIXTY_MIN": - { - metricValue.MetricResolution = MetricResolution.SIXTY_MIN; - break; - } - case "TEN_MIN": - { - metricValue.MetricResolution = MetricResolution.TEN_MIN; - break; - } - case "ONE_MIN": - { - metricValue.MetricResolution = MetricResolution.ONE_MIN; - break; - } - default: - { - metricValue.MetricResolution = MetricResolution.ONE_MIN; - break; - } - } - metricValues.Add(metricValue); - } - - return metricValues; - } - - private static List convertMetricSummaryToTypedListForCSV(AppDRESTMetric metricValueObject, EntityBase entityRow, JobTimeRange jobTimeRange) + private static void fillHourlyRangeMetricEntityRowAndConvertMetricsToCSV( + EntityBase entityRow, + JobTimeRange jobTimeRange, + string entityMetricPathPrefix, + string metricsEntityFolderPath, + int timeRangeIndex, + List metricDataART, + List metricDataCPM, + List metricDataEPM, + List metricDataEXCPM, + List metricDataHTTPEPM) { - List metricSummaries = new List(); - metricSummaries.Add(new MetricSummary() { - PropertyName = "Controller", - PropertyValue = entityRow.Controller, - Link = entityRow.ControllerLink }); - metricSummaries.Add(new MetricSummary() { - PropertyName = "Application", - PropertyValue = entityRow.ApplicationName, - Link = entityRow.ApplicationLink }); + entityRow.Duration = (int)(jobTimeRange.To - jobTimeRange.From).Duration().TotalMinutes; + entityRow.From = jobTimeRange.From.ToLocalTime(); + entityRow.To = jobTimeRange.To.ToLocalTime(); + entityRow.FromUtc = jobTimeRange.From; + entityRow.ToUtc = jobTimeRange.To; - string deepLinkMetricTemplateInMetricBrowser = DEEPLINK_METRIC_APPLICATION_TARGET_METRIC_ID; - long entityIdForMetricBrowser = entityRow.ApplicationID; + // Determine the entity ID to bve used in ensuring we get only one specific entity + // This is to address identically named Entities + // Backends can be named identically - see Azure Table exits + // Errors can also occasionally be named identically + long entityID = -1; if (entityRow is EntityApplication) { - metricSummaries.Add(new MetricSummary() { PropertyName = "EntityType", PropertyValue = "Application" }); - metricSummaries.Add(new MetricSummary() { PropertyName = "ApplicationID", PropertyValue = entityRow.ApplicationID }); + // Application level metrics don't need ever have anything unusual } else if (entityRow is EntityTier) { - metricSummaries.Add(new MetricSummary() { PropertyName = "EntityType", PropertyValue = "Tier" }); - metricSummaries.Add(new MetricSummary() { - PropertyName = "Tier", - PropertyValue = entityRow.TierName, - Link = entityRow.TierLink }); - metricSummaries.Add(new MetricSummary() { PropertyName = "ApplicationID", PropertyValue = entityRow.ApplicationID }); - metricSummaries.Add(new MetricSummary() { PropertyName = "TierID", PropertyValue = entityRow.TierID }); - deepLinkMetricTemplateInMetricBrowser = DEEPLINK_METRIC_TIER_TARGET_METRIC_ID; - entityIdForMetricBrowser = entityRow.TierID; + entityID = entityRow.TierID; } else if (entityRow is EntityNode) { - metricSummaries.Add(new MetricSummary() { PropertyName = "EntityType", PropertyValue = "Node" }); - metricSummaries.Add(new MetricSummary() - { - PropertyName = "Tier", - PropertyValue = entityRow.TierName, - Link = entityRow.TierLink - }); - metricSummaries.Add(new MetricSummary() - { - PropertyName = "Node", - PropertyValue = entityRow.NodeName, - Link = entityRow.NodeLink - }); - metricSummaries.Add(new MetricSummary() { PropertyName = "ApplicationID", PropertyValue = entityRow.ApplicationID }); - metricSummaries.Add(new MetricSummary() { PropertyName = "TierID", PropertyValue = entityRow.TierID }); - metricSummaries.Add(new MetricSummary() { PropertyName = "NodeID", PropertyValue = entityRow.NodeID }); - deepLinkMetricTemplateInMetricBrowser = DEEPLINK_METRIC_NODE_TARGET_METRIC_ID; - entityIdForMetricBrowser = entityRow.NodeID; + entityID = entityRow.TierID; } else if (entityRow is EntityBackend) { - metricSummaries.Add(new MetricSummary() { PropertyName = "EntityType", PropertyValue = "Backend" }); - metricSummaries.Add(new MetricSummary() - { - PropertyName = "Tier", - PropertyValue = entityRow.TierName, - Link = entityRow.TierLink - }); - metricSummaries.Add(new MetricSummary() - { - PropertyName = "Backend", - PropertyValue = ((EntityBackend)entityRow).BackendName, - Link = ((EntityBackend)entityRow).BackendLink - }); - metricSummaries.Add(new MetricSummary() { PropertyName = "ApplicationID", PropertyValue = entityRow.ApplicationID }); - metricSummaries.Add(new MetricSummary() { PropertyName = "TierID", PropertyValue = entityRow.TierID }); - metricSummaries.Add(new MetricSummary() { PropertyName = "BackendID", PropertyValue = ((EntityBackend)entityRow).BackendID }); + entityID = ((EntityBackend)entityRow).BackendID; } else if (entityRow is EntityBusinessTransaction) { - metricSummaries.Add(new MetricSummary() { PropertyName = "EntityType", PropertyValue = "Business Transaction" }); - metricSummaries.Add(new MetricSummary() - { - PropertyName = "Tier", - PropertyValue = entityRow.TierName, - Link = entityRow.TierLink - }); - metricSummaries.Add(new MetricSummary() - { - PropertyName = "Business Transaction", - PropertyValue = ((EntityBusinessTransaction)entityRow).BTName, - Link = ((EntityBusinessTransaction)entityRow).BTLink - }); - metricSummaries.Add(new MetricSummary() { PropertyName = "ApplicationID", PropertyValue = entityRow.ApplicationID }); - metricSummaries.Add(new MetricSummary() { PropertyName = "TierID", PropertyValue = entityRow.TierID }); - metricSummaries.Add(new MetricSummary() { PropertyName = "BTID", PropertyValue = ((EntityBusinessTransaction)entityRow).BTID }); - deepLinkMetricTemplateInMetricBrowser = DEEPLINK_METRIC_TIER_TARGET_METRIC_ID; - entityIdForMetricBrowser = entityRow.TierID; + entityID = ((EntityBusinessTransaction)entityRow).BTID; } else if (entityRow is EntityServiceEndpoint) { - metricSummaries.Add(new MetricSummary() { PropertyName = "EntityType", PropertyValue = "Service Endpoint" }); - metricSummaries.Add(new MetricSummary() - { - PropertyName = "Tier", - PropertyValue = entityRow.TierName, - Link = entityRow.TierLink - }); - metricSummaries.Add(new MetricSummary() - { - PropertyName = "Service Endpoint", - PropertyValue = ((EntityServiceEndpoint)entityRow).SEPName, - Link = ((EntityServiceEndpoint)entityRow).SEPLink - }); - metricSummaries.Add(new MetricSummary() { PropertyName = "ApplicationID", PropertyValue = entityRow.ApplicationID }); - metricSummaries.Add(new MetricSummary() { PropertyName = "TierID", PropertyValue = entityRow.TierID }); - metricSummaries.Add(new MetricSummary() { PropertyName = "SEPID", PropertyValue = ((EntityServiceEndpoint)entityRow).SEPID }); + entityID = ((EntityServiceEndpoint)entityRow).SEPID; } else if (entityRow is EntityError) { - metricSummaries.Add(new MetricSummary() { PropertyName = "EntityType", PropertyValue = "Error" }); - metricSummaries.Add(new MetricSummary() - { - PropertyName = "Tier", - PropertyValue = entityRow.TierName, - Link = entityRow.TierLink - }); - metricSummaries.Add(new MetricSummary() - { - PropertyName = "Error", - PropertyValue = ((EntityError)entityRow).ErrorName, - Link = ((EntityError)entityRow).ErrorLink - }); - metricSummaries.Add(new MetricSummary() { PropertyName = "ApplicationID", PropertyValue = entityRow.ApplicationID }); - metricSummaries.Add(new MetricSummary() { PropertyName = "TierID", PropertyValue = entityRow.TierID }); - metricSummaries.Add(new MetricSummary() { PropertyName = "ErrorID", PropertyValue = ((EntityError)entityRow).ErrorID }); + entityID = ((EntityError)entityRow).ErrorID; } - - // Decide what kind of timerange - string DEEPLINK_THIS_TIMERANGE = DEEPLINK_TIMERANGE_LAST_15_MINUTES; - if (jobTimeRange != null) + else if (entityRow is EntityInformationPoint) { - long fromTimeUnix = convertToUnixTimestamp(jobTimeRange.From); - long toTimeUnix = convertToUnixTimestamp(jobTimeRange.To); - long differenceInMinutes = (toTimeUnix - fromTimeUnix) / (60000); - DEEPLINK_THIS_TIMERANGE = String.Format(DEEPLINK_TIMERANGE_BETWEEN_TIMES, toTimeUnix, fromTimeUnix, differenceInMinutes); + entityID = ((EntityInformationPoint)entityRow).IPID; } - metricSummaries.Add(new MetricSummary() - { - PropertyName = "Metric ID", - PropertyValue = metricValueObject.metricId, - Link = String.Format(DEEPLINK_METRIC, entityRow.Controller, entityRow.ApplicationID, String.Format(deepLinkMetricTemplateInMetricBrowser, entityIdForMetricBrowser, metricValueObject.metricId), DEEPLINK_THIS_TIMERANGE) - }); + if (entityRow.MetricsIDs == null) { entityRow.MetricsIDs = new List(5); } - // Name of the metric is always the last one in the metric path - string[] metricPathComponents = metricValueObject.metricPath.Split('|'); - string metricName = metricPathComponents[metricPathComponents.Length - 1]; - MetricSummary metricNameMetricSummary = new MetricSummary() { PropertyName = "Metric Name", PropertyValue = metricName }; - metricSummaries.Add(metricNameMetricSummary); - metricSummaries.Add(new MetricSummary() { PropertyName = "Metric Name (Short)", PropertyValue = metricNameToShortMetricNameMapping[metricNameMetricSummary.PropertyValue.ToString()] }); - metricSummaries.Add(new MetricSummary() { PropertyName = "Metric Name (Full)", PropertyValue = metricValueObject.metricName }); - metricSummaries.Add(new MetricSummary() { PropertyName = "Metric Path", PropertyValue = metricValueObject.metricPath }); + bool appendRecordsToExistingFile = true; + if (timeRangeIndex == 0) { appendRecordsToExistingFile = false; } - // Only the metrics with Average Response Time (ms) are times - // As long as we are not in Application Infrastructure Performance area - if (metricName.IndexOf(METRIC_TIME_MS) > 0) - { - metricSummaries.Add(new MetricSummary() { PropertyName = "Rollup Type", PropertyValue = MetricType.Duration.ToString() }); - } - else - { - metricSummaries.Add(new MetricSummary() { PropertyName = "Rollup Type", PropertyValue = MetricType.Count.ToString() }); - } + AppDRESTMetric thisEntityMetricData = null; - return metricSummaries; - } + #region Read and convert metrics - #endregion + // ART + string metricsDataFolderPath = Path.Combine(metricsEntityFolderPath, METRIC_ART_SHORTNAME); + string entityMetricReportFilePath = Path.Combine(metricsDataFolderPath, CONVERT_METRIC_VALUES_FILE_NAME); + if (metricDataART != null && metricDataART.Count > 0) + { + if (entityID != -1) + { + thisEntityMetricData = metricDataART.Where(m => m.metricPath.StartsWith(entityMetricPathPrefix) == true && m.metricName.Contains(entityID.ToString()) == true).FirstOrDefault(); + } + else + { + thisEntityMetricData = metricDataART.Where(m => m.metricPath.StartsWith(entityMetricPathPrefix) == true).FirstOrDefault(); + } + if (thisEntityMetricData != null) + { + if (thisEntityMetricData.metricValues.Count > 0) + { + double intermediateART = (double)thisEntityMetricData.metricValues.Sum(mv => mv.sum) / (double)thisEntityMetricData.metricValues.Sum(mv => mv.count); + if (Double.IsNaN(intermediateART) == true) + { + entityRow.ART = 0; + } + else + { + entityRow.ART = (long)Math.Round(intermediateART, 0); + } + entityRow.TimeTotal = thisEntityMetricData.metricValues.Sum(mv => mv.sum); + } - #region Configuration detail conversion functions + List metricValues = convertMetricValueToTypedListForCSV(thisEntityMetricData); + FileIOHelper.writeListToCSVFile(metricValues, new MetricValueMetricReportMap(), entityMetricReportFilePath, appendRecordsToExistingFile); - private static string getNameValueDetailsFromNameValueCollection(XmlNode xmlNodeWithNameValuePairs) - { - if (xmlNodeWithNameValuePairs == null) return String.Empty; + entityRow.MetricsIDs.Add(thisEntityMetricData.metricId); + } + } - StringBuilder sb = new StringBuilder(); - foreach (XmlNode xmlNodeNameValue in xmlNodeWithNameValuePairs.SelectNodes("name-values")) + // CPM + metricsDataFolderPath = Path.Combine(metricsEntityFolderPath, METRIC_CPM_SHORTNAME); + entityMetricReportFilePath = Path.Combine(metricsDataFolderPath, CONVERT_METRIC_VALUES_FILE_NAME); + if (metricDataCPM != null && metricDataCPM.Count > 0) { - sb.AppendFormat("{0}={1};", xmlNodeNameValue.SelectSingleNode("name").InnerText, xmlNodeNameValue.SelectSingleNode("value").InnerText); - } - - return sb.ToString(); - } + if (entityID != -1) + { + thisEntityMetricData = metricDataCPM.Where(m => m.metricPath.StartsWith(entityMetricPathPrefix) == true && m.metricName.Contains(entityID.ToString()) == true).FirstOrDefault(); + } + else + { + thisEntityMetricData = metricDataCPM.Where(m => m.metricPath.StartsWith(entityMetricPathPrefix) == true).FirstOrDefault(); + } + if (thisEntityMetricData != null) + { + if (thisEntityMetricData.metricValues.Count > 0) + { + entityRow.CPM = (long)Math.Round((double)((double)thisEntityMetricData.metricValues.Sum(mv => mv.sum) / (double)entityRow.Duration), 0); + entityRow.Calls = thisEntityMetricData.metricValues.Sum(mv => mv.sum); + } - private static string getNameValueDetailsFromParametersCollection(XmlNode xmlNodeWithParameters) - { - if (xmlNodeWithParameters == null) return String.Empty; + List metricValues = convertMetricValueToTypedListForCSV(thisEntityMetricData); + FileIOHelper.writeListToCSVFile(metricValues, new MetricValueMetricReportMap(), entityMetricReportFilePath, appendRecordsToExistingFile); - StringBuilder sb = new StringBuilder(); - foreach (XmlNode xmlNodeNameValue in xmlNodeWithParameters.SelectNodes("parameter")) - { - sb.AppendFormat( - "{0}:{1}/{2}={3}/{4};", - xmlNodeNameValue.Attributes["match-type"].Value, - xmlNodeNameValue.SelectSingleNode("name").Attributes["filter-value"].Value, - xmlNodeNameValue.SelectSingleNode("name").Attributes["filter-type"].Value, - xmlNodeNameValue.SelectSingleNode("value").Attributes["filter-value"].Value, - xmlNodeNameValue.SelectSingleNode("value").Attributes["filter-type"].Value); + entityRow.MetricsIDs.Add(thisEntityMetricData.metricId); + } } - return sb.ToString(); - } - - private static int getIntegerValueFromXmlNode(XmlNode xmlNode) - { - if (xmlNode == null) return 0; - - if (((XmlElement)xmlNode).IsEmpty == true) - { - return 0; - } - else + // EPM + metricsDataFolderPath = Path.Combine(metricsEntityFolderPath, METRIC_EPM_SHORTNAME); + entityMetricReportFilePath = Path.Combine(metricsDataFolderPath, CONVERT_METRIC_VALUES_FILE_NAME); + if (metricDataEPM != null && metricDataEPM.Count > 0) { - int value; - if (Int32.TryParse(xmlNode.InnerText, out value) == true) + if (entityID != -1) { - return value; + thisEntityMetricData = metricDataEPM.Where(m => m.metricPath.StartsWith(entityMetricPathPrefix) == true && m.metricName.Contains(entityID.ToString()) == true).FirstOrDefault(); } else { - double value1; - if (Double.TryParse(xmlNode.InnerText, out value1) == true) - { - return Convert.ToInt32(Math.Floor(value1)); - } - else + thisEntityMetricData = metricDataEPM.Where(m => m.metricPath.StartsWith(entityMetricPathPrefix) == true).FirstOrDefault(); + } + if (thisEntityMetricData != null) + { + if (thisEntityMetricData.metricValues.Count > 0) { - return 0; + entityRow.EPM = (long)Math.Round((double)((double)thisEntityMetricData.metricValues.Sum(mv => mv.sum) / (double)entityRow.Duration), 0); + entityRow.Errors = thisEntityMetricData.metricValues.Sum(mv => mv.sum); + entityRow.ErrorsPercentage = Math.Round((double)(double)entityRow.Errors / (double)entityRow.Calls * 100, 2); + if (Double.IsNaN(entityRow.ErrorsPercentage) == true) entityRow.ErrorsPercentage = 0; } - } - } - } - private static long getLongValueFromXmlNode(XmlNode xmlNode) - { - if (xmlNode == null) return 0; + List metricValues = convertMetricValueToTypedListForCSV(thisEntityMetricData); + FileIOHelper.writeListToCSVFile(metricValues, new MetricValueMetricReportMap(), entityMetricReportFilePath, appendRecordsToExistingFile); - if (((XmlElement)xmlNode).IsEmpty == true) - { - return 0; + entityRow.MetricsIDs.Add(thisEntityMetricData.metricId); + } } - else + + // EXCPM + metricsDataFolderPath = Path.Combine(metricsEntityFolderPath, METRIC_EXCPM_SHORTNAME); + entityMetricReportFilePath = Path.Combine(metricsDataFolderPath, CONVERT_METRIC_VALUES_FILE_NAME); + if (metricDataEXCPM != null && metricDataEXCPM.Count > 0) { - long value; - if (Int64.TryParse(xmlNode.InnerText, out value) == true) + if (entityID != -1) { - return value; + thisEntityMetricData = metricDataEXCPM.Where(m => m.metricPath.StartsWith(entityMetricPathPrefix) == true && m.metricName.Contains(entityID.ToString()) == true).FirstOrDefault(); } else { - double value1; - if (Double.TryParse(xmlNode.InnerText, out value1) == true) - { - return Convert.ToInt64(Math.Floor(value1)); - } - else + thisEntityMetricData = metricDataEXCPM.Where(m => m.metricPath.StartsWith(entityMetricPathPrefix) == true).FirstOrDefault(); + } + if (thisEntityMetricData != null) + { + if (thisEntityMetricData.metricValues.Count > 0) { - return 0; + entityRow.EXCPM = (long)Math.Round((double)((double)thisEntityMetricData.metricValues.Sum(mv => mv.sum) / (double)entityRow.Duration), 0); + entityRow.Exceptions = thisEntityMetricData.metricValues.Sum(mv => mv.sum); } - } - } - } - private static bool getBoolValueFromXmlNode(XmlNode xmlNode) - { - if (xmlNode == null) return false; + List metricValues = convertMetricValueToTypedListForCSV(thisEntityMetricData); + FileIOHelper.writeListToCSVFile(metricValues, new MetricValueMetricReportMap(), entityMetricReportFilePath, appendRecordsToExistingFile); - if (((XmlElement)xmlNode).IsEmpty == true) - { - return false; + entityRow.MetricsIDs.Add(thisEntityMetricData.metricId); + } } - else + + // HTTPEPM + metricsDataFolderPath = Path.Combine(metricsEntityFolderPath, METRIC_HTTPEPM_SHORTNAME); + entityMetricReportFilePath = Path.Combine(metricsDataFolderPath, CONVERT_METRIC_VALUES_FILE_NAME); + if (metricDataHTTPEPM != null && metricDataHTTPEPM.Count > 0) { - bool value; - if (Boolean.TryParse(xmlNode.InnerText, out value) == true) + if (entityID != -1) { - return value; + thisEntityMetricData = metricDataHTTPEPM.Where(m => m.metricPath.StartsWith(entityMetricPathPrefix) == true && m.metricName.Contains(entityID.ToString()) == true).FirstOrDefault(); } else { - return false; + thisEntityMetricData = metricDataHTTPEPM.Where(m => m.metricPath.StartsWith(entityMetricPathPrefix) == true).FirstOrDefault(); } - } - } + if (thisEntityMetricData != null) + { + if (thisEntityMetricData.metricValues.Count > 0) + { + entityRow.HTTPEPM = (long)Math.Round((double)((double)thisEntityMetricData.metricValues.Sum(mv => mv.sum) / (double)entityRow.Duration), 0); + entityRow.HttpErrors = thisEntityMetricData.metricValues.Sum(mv => mv.sum); + } - private static string getStringValueFromXmlNode(XmlNode xmlNode) - { - if (xmlNode == null) return String.Empty; + List metricValues = convertMetricValueToTypedListForCSV(thisEntityMetricData); + FileIOHelper.writeListToCSVFile(metricValues, new MetricValueMetricReportMap(), entityMetricReportFilePath, appendRecordsToExistingFile); - if (((XmlElement)xmlNode).IsEmpty == true) - { - return String.Empty; - } - else - { - return xmlNode.InnerText; + entityRow.MetricsIDs.Add(thisEntityMetricData.metricId); + } } - } - - /// - /// https://stackoverflow.com/questions/1123718/format-xml-string-to-print-friendly-xml-string - /// - /// - /// - private static string makeXMLFormattedAndIndented(String XML) - { - string Result = ""; - - MemoryStream MS = new MemoryStream(); - XmlTextWriter W = new XmlTextWriter(MS, Encoding.Unicode); - XmlDocument D = new XmlDocument(); - try + if (entityRow.ART == 0 && entityRow.TimeTotal == 0 && + entityRow.CPM == 0 && entityRow.Calls == 0 && + entityRow.EPM == 0 && entityRow.Errors == 0 && + entityRow.EXCPM == 0 && entityRow.Exceptions == 0 && + entityRow.HTTPEPM == 0 && entityRow.HttpErrors == 0) { - // Load the XmlDocument with the XML. - D.LoadXml(XML); - - W.Formatting = Formatting.Indented; - - // Write the XML into a formatting XmlTextWriter - D.WriteContentTo(W); - W.Flush(); - MS.Flush(); - - // Have to rewind the MemoryStream in order to read - // its contents. - MS.Position = 0; - - // Read MemoryStream contents into a StreamReader. - StreamReader SR = new StreamReader(MS); - - // Extract the text from the StreamReader. - String FormattedXML = SR.ReadToEnd(); - - Result = FormattedXML; + entityRow.HasActivity = false; } - catch (XmlException) + else { + entityRow.HasActivity = true; } - MS.Close(); - W.Close(); + #endregion - return Result; + // Add link to the metrics + updateEntityWithDeeplinks(entityRow, jobTimeRange); + + return; } - private static string makeXMLFormattedAndIndented(XmlNode xmlNode) + private static bool updateEntityWithDeeplinks(EntityBase entityRow) { - if (xmlNode != null) - { - return makeXMLFormattedAndIndented(xmlNode.OuterXml); - } - else - { - return String.Empty; - } + return updateEntityWithDeeplinks(entityRow, null); } - private static string makeXMLFormattedAndIndented(XmlNodeList xmlNodeList) + private static bool updateEntityWithDeeplinks(EntityBase entityRow, JobTimeRange jobTimeRange) { - if (xmlNodeList.Count > 0) + // Decide what kind of timerange + string DEEPLINK_THIS_TIMERANGE = DEEPLINK_TIMERANGE_LAST_15_MINUTES; + if (jobTimeRange != null) { - StringBuilder sb = new StringBuilder(128 * xmlNodeList.Count); - foreach (XmlNode xmlNode in xmlNodeList) - { - sb.Append(makeXMLFormattedAndIndented(xmlNode)); - sb.AppendLine(); - } - sb.Remove(sb.Length - 1, 1); - return sb.ToString(); + long fromTimeUnix = convertToUnixTimestamp(jobTimeRange.From); + long toTimeUnix = convertToUnixTimestamp(jobTimeRange.To); + long differenceInMinutes = (toTimeUnix - fromTimeUnix) / (60000); + DEEPLINK_THIS_TIMERANGE = String.Format(DEEPLINK_TIMERANGE_BETWEEN_TIMES, toTimeUnix, fromTimeUnix, differenceInMinutes); } - else + + // Determine what kind of entity we are dealing with and adjust accordingly + string deepLinkMetricTemplateInMetricBrowser = DEEPLINK_METRIC_APPLICATION_TARGET_METRIC_ID; + long entityIdForMetricBrowser = entityRow.ApplicationID; + if (entityRow is EntityApplication) { - return String.Empty; + entityRow.ControllerLink = String.Format(DEEPLINK_CONTROLLER, entityRow.Controller, DEEPLINK_THIS_TIMERANGE); + entityRow.ApplicationLink = String.Format(DEEPLINK_APPLICATION, entityRow.Controller, entityRow.ApplicationID, DEEPLINK_THIS_TIMERANGE); + } + else if (entityRow is EntityTier) + { + entityRow.ControllerLink = String.Format(DEEPLINK_CONTROLLER, entityRow.Controller, DEEPLINK_THIS_TIMERANGE); + entityRow.ApplicationLink = String.Format(DEEPLINK_APPLICATION, entityRow.Controller, entityRow.ApplicationID, DEEPLINK_THIS_TIMERANGE); + entityRow.TierLink = String.Format(DEEPLINK_TIER, entityRow.Controller, entityRow.ApplicationID, entityRow.TierID, DEEPLINK_THIS_TIMERANGE); + deepLinkMetricTemplateInMetricBrowser = DEEPLINK_METRIC_TIER_TARGET_METRIC_ID; + entityIdForMetricBrowser = entityRow.TierID; + } + else if (entityRow is EntityNode) + { + entityRow.ControllerLink = String.Format(DEEPLINK_CONTROLLER, entityRow.Controller, DEEPLINK_THIS_TIMERANGE); + entityRow.ApplicationLink = String.Format(DEEPLINK_APPLICATION, entityRow.Controller, entityRow.ApplicationID, DEEPLINK_THIS_TIMERANGE); + entityRow.TierLink = String.Format(DEEPLINK_TIER, entityRow.Controller, entityRow.ApplicationID, entityRow.TierID, DEEPLINK_THIS_TIMERANGE); + entityRow.NodeLink = String.Format(DEEPLINK_NODE, entityRow.Controller, entityRow.ApplicationID, entityRow.NodeID, DEEPLINK_THIS_TIMERANGE); + deepLinkMetricTemplateInMetricBrowser = DEEPLINK_METRIC_NODE_TARGET_METRIC_ID; + entityIdForMetricBrowser = entityRow.NodeID; + } + else if (entityRow is EntityBackend) + { + entityRow.ControllerLink = String.Format(DEEPLINK_CONTROLLER, entityRow.Controller, DEEPLINK_THIS_TIMERANGE); + entityRow.ApplicationLink = String.Format(DEEPLINK_APPLICATION, entityRow.Controller, entityRow.ApplicationID, DEEPLINK_THIS_TIMERANGE); + ((EntityBackend)entityRow).BackendLink = String.Format(DEEPLINK_BACKEND, entityRow.Controller, entityRow.ApplicationID, ((EntityBackend)entityRow).BackendID, DEEPLINK_THIS_TIMERANGE); + } + else if (entityRow is EntityBusinessTransaction) + { + entityRow.ControllerLink = String.Format(DEEPLINK_CONTROLLER, entityRow.Controller, DEEPLINK_THIS_TIMERANGE); + entityRow.ApplicationLink = String.Format(DEEPLINK_APPLICATION, entityRow.Controller, entityRow.ApplicationID, DEEPLINK_THIS_TIMERANGE); + entityRow.TierLink = String.Format(DEEPLINK_TIER, entityRow.Controller, entityRow.ApplicationID, entityRow.TierID, DEEPLINK_THIS_TIMERANGE); + ((EntityBusinessTransaction)entityRow).BTLink = String.Format(DEEPLINK_BUSINESS_TRANSACTION, entityRow.Controller, entityRow.ApplicationID, ((EntityBusinessTransaction)entityRow).BTID, DEEPLINK_THIS_TIMERANGE); + deepLinkMetricTemplateInMetricBrowser = DEEPLINK_METRIC_TIER_TARGET_METRIC_ID; + entityIdForMetricBrowser = entityRow.TierID; + } + else if (entityRow is EntityServiceEndpoint) + { + entityRow.ControllerLink = String.Format(DEEPLINK_CONTROLLER, entityRow.Controller, DEEPLINK_THIS_TIMERANGE); + entityRow.ApplicationLink = String.Format(DEEPLINK_APPLICATION, entityRow.Controller, entityRow.ApplicationID, DEEPLINK_THIS_TIMERANGE); + entityRow.TierLink = String.Format(DEEPLINK_TIER, entityRow.Controller, entityRow.ApplicationID, entityRow.TierID, DEEPLINK_THIS_TIMERANGE); + ((EntityServiceEndpoint)entityRow).SEPLink = String.Format(DEEPLINK_SERVICE_ENDPOINT, entityRow.Controller, entityRow.ApplicationID, entityRow.TierID, ((EntityServiceEndpoint)entityRow).SEPID, DEEPLINK_THIS_TIMERANGE); + } + else if (entityRow is EntityError) + { + entityRow.ControllerLink = String.Format(DEEPLINK_CONTROLLER, entityRow.Controller, DEEPLINK_THIS_TIMERANGE); + entityRow.ApplicationLink = String.Format(DEEPLINK_APPLICATION, entityRow.Controller, entityRow.ApplicationID, DEEPLINK_THIS_TIMERANGE); + entityRow.TierLink = String.Format(DEEPLINK_TIER, entityRow.Controller, entityRow.ApplicationID, entityRow.TierID, DEEPLINK_THIS_TIMERANGE); + ((EntityError)entityRow).ErrorLink = String.Format(DEEPLINK_ERROR, entityRow.Controller, entityRow.ApplicationID, ((EntityError)entityRow).ErrorID, DEEPLINK_THIS_TIMERANGE); + } + else if (entityRow is EntityInformationPoint) + { + entityRow.ControllerLink = String.Format(DEEPLINK_CONTROLLER, entityRow.Controller, DEEPLINK_THIS_TIMERANGE); + entityRow.ApplicationLink = String.Format(DEEPLINK_APPLICATION, entityRow.Controller, entityRow.ApplicationID, DEEPLINK_THIS_TIMERANGE); + ((EntityInformationPoint)entityRow).IPLink = String.Format(DEEPLINK_INFORMATION_POINT, entityRow.Controller, entityRow.ApplicationID, ((EntityInformationPoint)entityRow).IPID, DEEPLINK_THIS_TIMERANGE); } - } - - private static BusinessTransactionDiscoveryRule fillBusinessTransactionDiscoveryRule(XmlNode entryMatchPointConfigurationNode, XmlNode entryMatchPointTransactionConfigurationNode, EntityApplicationConfiguration applicationConfiguration, XmlNode applicationComponentNode) - { - BusinessTransactionDiscoveryRule businessTransactionDiscoveryRule = new BusinessTransactionDiscoveryRule(); - - businessTransactionDiscoveryRule.Controller = applicationConfiguration.Controller; - businessTransactionDiscoveryRule.ControllerLink = applicationConfiguration.ControllerLink; - businessTransactionDiscoveryRule.ApplicationName = applicationConfiguration.ApplicationName; - businessTransactionDiscoveryRule.ApplicationID = applicationConfiguration.ApplicationID; - businessTransactionDiscoveryRule.ApplicationLink = applicationConfiguration.ApplicationLink; - - businessTransactionDiscoveryRule.AgentType = entryMatchPointConfigurationNode.SelectSingleNode("agent-type").InnerText; - businessTransactionDiscoveryRule.EntryPointType = entryMatchPointTransactionConfigurationNode.Attributes["transaction-entry-point-type"].Value; - businessTransactionDiscoveryRule.IsMonitoringEnabled = getBoolValueFromXmlNode(entryMatchPointTransactionConfigurationNode.SelectSingleNode("enable")); - businessTransactionDiscoveryRule.DiscoveryType = entryMatchPointTransactionConfigurationNode.SelectSingleNode("discovery-config").Attributes["discovery-resolution"].Value; - businessTransactionDiscoveryRule.IsDiscoveryEnabled = getBoolValueFromXmlNode(entryMatchPointTransactionConfigurationNode.SelectSingleNode("discovery-config/discovery-config-enabled")); - businessTransactionDiscoveryRule.NamingConfigType = entryMatchPointTransactionConfigurationNode.SelectSingleNode("discovery-config/naming-config").Attributes["scheme"].Value; - - businessTransactionDiscoveryRule.RuleRawValue = makeXMLFormattedAndIndented(entryMatchPointTransactionConfigurationNode); - if (applicationComponentNode != null) + if (entityRow.MetricsIDs != null && entityRow.MetricsIDs.Count > 0) { - businessTransactionDiscoveryRule.TierName = applicationComponentNode.SelectSingleNode("name").InnerText; + StringBuilder sb = new StringBuilder(128); + foreach (int metricID in entityRow.MetricsIDs) + { + sb.Append(String.Format(deepLinkMetricTemplateInMetricBrowser, entityIdForMetricBrowser, metricID)); + sb.Append(","); + } + sb.Remove(sb.Length - 1, 1); + entityRow.MetricLink = String.Format(DEEPLINK_METRIC, entityRow.Controller, entityRow.ApplicationID, sb.ToString(), DEEPLINK_THIS_TIMERANGE); } - return businessTransactionDiscoveryRule; + return true; } - private static BusinessTransactionEntryRule fillBusinessTransactionExcludeRule(XmlNode entryMatchPointConfigurationNode, XmlNode entryMatchPointTransactionConfigurationNode, XmlNode entryMatchPointCustomMatchPointConfigurationNode, EntityApplicationConfiguration applicationConfiguration, XmlNode applicationComponentNode) + private static void updateEntitiesWithReportDetailLinksApplication(ProgramOptions programOptions, JobConfiguration jobConfiguration, JobTarget jobTarget, List entityList) { - BusinessTransactionEntryRule businessTransactionEntryRule = new BusinessTransactionEntryRule(); - - businessTransactionEntryRule.Controller = applicationConfiguration.Controller; - businessTransactionEntryRule.ControllerLink = applicationConfiguration.ControllerLink; - businessTransactionEntryRule.ApplicationName = applicationConfiguration.ApplicationName; - businessTransactionEntryRule.ApplicationID = applicationConfiguration.ApplicationID; - businessTransactionEntryRule.ApplicationLink = applicationConfiguration.ApplicationLink; - - businessTransactionEntryRule.AgentType = getStringValueFromXmlNode(entryMatchPointConfigurationNode.SelectSingleNode("agent-type")); - businessTransactionEntryRule.EntryPointType = entryMatchPointTransactionConfigurationNode.Attributes["transaction-entry-point-type"].Value; - businessTransactionEntryRule.RuleName = entryMatchPointCustomMatchPointConfigurationNode.Attributes["name"].Value; - businessTransactionEntryRule.IsExclusion = true; + string controllerFolderPath = Path.Combine(programOptions.OutputJobFolderPath, getFileSystemSafeString(new Uri(jobTarget.Controller).Host)); + string applicationFolderPath = Path.Combine(controllerFolderPath, getShortenedEntityNameForFileSystem(jobTarget.Application, jobTarget.ApplicationID)); + string entitiesFolderPath = Path.Combine(applicationFolderPath, ENTITIES_FOLDER_NAME); + string reportsFolderPath = Path.Combine(programOptions.OutputJobFolderPath, REPORTS_FOLDER_NAME); - XmlNode matchRule = entryMatchPointCustomMatchPointConfigurationNode.ChildNodes[0]; - fillMatchRuleDetails(businessTransactionEntryRule, matchRule); + for (int i = 0; i < entityList.Count; i++) + { + EntityBase entityRow = entityList[i]; + entityRow.DetailLink = String.Format(@"=HYPERLINK(""{0}"", """")", getEntityMetricReportFilePath(programOptions, jobConfiguration, jobTarget, entityRow).Substring(reportsFolderPath.Length + 1)); + } + } - businessTransactionEntryRule.RuleRawValue = makeXMLFormattedAndIndented(entryMatchPointCustomMatchPointConfigurationNode); + private static void updateEntitiesWithReportDetailLinksTiers(ProgramOptions programOptions, JobConfiguration jobConfiguration, JobTarget jobTarget, List entityList) + { + string controllerFolderPath = Path.Combine(programOptions.OutputJobFolderPath, getFileSystemSafeString(new Uri(jobTarget.Controller).Host)); + string applicationFolderPath = Path.Combine(controllerFolderPath, getShortenedEntityNameForFileSystem(jobTarget.Application, jobTarget.ApplicationID)); + string entitiesFolderPath = Path.Combine(applicationFolderPath, ENTITIES_FOLDER_NAME); + string reportsFolderPath = Path.Combine(programOptions.OutputJobFolderPath, REPORTS_FOLDER_NAME); - if (applicationComponentNode != null) + for (int i = 0; i < entityList.Count; i++) { - businessTransactionEntryRule.TierName = applicationComponentNode.SelectSingleNode("name").InnerText; + EntityBase entityRow = entityList[i]; + entityRow.DetailLink = String.Format(@"=HYPERLINK(""{0}"", """")", getEntityMetricReportFilePath(programOptions, jobConfiguration, jobTarget, entityRow).Substring(reportsFolderPath.Length + 1)); } - - return businessTransactionEntryRule; } - private static BusinessTransactionEntryRule fillBusinessTransactionEntryRule(XmlNode entryMatchPointConfigurationNode, XmlNode entryMatchPointCustomMatchPointConfigurationNode, EntityApplicationConfiguration applicationConfiguration, XmlNode applicationComponentNode, List businessTransactionsList) + private static void updateEntitiesWithReportDetailLinksNodes(ProgramOptions programOptions, JobConfiguration jobConfiguration, JobTarget jobTarget, List entityList) { - BusinessTransactionEntryRule businessTransactionEntryRule = new BusinessTransactionEntryRule(); + string controllerFolderPath = Path.Combine(programOptions.OutputJobFolderPath, getFileSystemSafeString(new Uri(jobTarget.Controller).Host)); + string applicationFolderPath = Path.Combine(controllerFolderPath, getShortenedEntityNameForFileSystem(jobTarget.Application, jobTarget.ApplicationID)); + string entitiesFolderPath = Path.Combine(applicationFolderPath, ENTITIES_FOLDER_NAME); + string reportsFolderPath = Path.Combine(programOptions.OutputJobFolderPath, REPORTS_FOLDER_NAME); - businessTransactionEntryRule.Controller = applicationConfiguration.Controller; - businessTransactionEntryRule.ControllerLink = applicationConfiguration.ControllerLink; - businessTransactionEntryRule.ApplicationName = applicationConfiguration.ApplicationName; - businessTransactionEntryRule.ApplicationID = applicationConfiguration.ApplicationID; - businessTransactionEntryRule.ApplicationLink = applicationConfiguration.ApplicationLink; + for (int i = 0; i < entityList.Count; i++) + { + EntityBase entityRow = entityList[i]; + entityRow.DetailLink = String.Format(@"=HYPERLINK(""{0}"", """")", getEntityMetricReportFilePath(programOptions, jobConfiguration, jobTarget, entityRow).Substring(reportsFolderPath.Length + 1)); + } + } - businessTransactionEntryRule.AgentType = getStringValueFromXmlNode(entryMatchPointConfigurationNode.SelectSingleNode("agent-type")); - businessTransactionEntryRule.EntryPointType = entryMatchPointCustomMatchPointConfigurationNode.Attributes["transaction-entry-point-type"].Value; - businessTransactionEntryRule.RuleName = getStringValueFromXmlNode(entryMatchPointCustomMatchPointConfigurationNode.SelectSingleNode("name")); - businessTransactionEntryRule.IsBackground = getBoolValueFromXmlNode(entryMatchPointCustomMatchPointConfigurationNode.SelectSingleNode("background")); - businessTransactionEntryRule.IsExclusion = false; + private static void updateEntitiesWithReportDetailLinksBackends(ProgramOptions programOptions, JobConfiguration jobConfiguration, JobTarget jobTarget, List entityList) + { + string controllerFolderPath = Path.Combine(programOptions.OutputJobFolderPath, getFileSystemSafeString(new Uri(jobTarget.Controller).Host)); + string applicationFolderPath = Path.Combine(controllerFolderPath, getShortenedEntityNameForFileSystem(jobTarget.Application, jobTarget.ApplicationID)); + string entitiesFolderPath = Path.Combine(applicationFolderPath, ENTITIES_FOLDER_NAME); + string reportsFolderPath = Path.Combine(programOptions.OutputJobFolderPath, REPORTS_FOLDER_NAME); - XmlNode matchRule = entryMatchPointCustomMatchPointConfigurationNode.SelectSingleNode("match-rule").ChildNodes[0]; - fillMatchRuleDetails(businessTransactionEntryRule, matchRule); + for (int i = 0; i < entityList.Count; i++) + { + EntityBase entityRow = entityList[i]; + entityRow.DetailLink = String.Format(@"=HYPERLINK(""{0}"", """")", getEntityMetricReportFilePath(programOptions, jobConfiguration, jobTarget, entityRow).Substring(reportsFolderPath.Length + 1)); + } + } - businessTransactionEntryRule.RuleRawValue = makeXMLFormattedAndIndented(entryMatchPointCustomMatchPointConfigurationNode); + private static void updateEntitiesWithReportDetailLinksBusinessTransactions(ProgramOptions programOptions, JobConfiguration jobConfiguration, JobTarget jobTarget, List entityList) + { + string controllerFolderPath = Path.Combine(programOptions.OutputJobFolderPath, getFileSystemSafeString(new Uri(jobTarget.Controller).Host)); + string applicationFolderPath = Path.Combine(controllerFolderPath, getShortenedEntityNameForFileSystem(jobTarget.Application, jobTarget.ApplicationID)); + string entitiesFolderPath = Path.Combine(applicationFolderPath, ENTITIES_FOLDER_NAME); + string reportsFolderPath = Path.Combine(programOptions.OutputJobFolderPath, REPORTS_FOLDER_NAME); - if (applicationComponentNode != null) + for (int i = 0; i < entityList.Count; i++) { - businessTransactionEntryRule.TierName = getStringValueFromXmlNode(applicationComponentNode.SelectSingleNode("name")); + EntityBase entityRow = entityList[i]; + entityRow.DetailLink = String.Format(@"=HYPERLINK(""{0}"", """")", getEntityMetricReportFilePath(programOptions, jobConfiguration, jobTarget, entityRow).Substring(reportsFolderPath.Length + 1)); } + } - if (businessTransactionsList != null) - { - List businessTransactionsForThisRule = new List(); - businessTransactionsForThisRule.AddRange(businessTransactionsList.Where(b => b.BTName == businessTransactionEntryRule.RuleName).ToList()); - businessTransactionsForThisRule.AddRange(businessTransactionsList.Where(b => b.BTName.StartsWith(String.Format("{0}.", businessTransactionEntryRule.RuleName))).ToList()); - businessTransactionsForThisRule.AddRange(businessTransactionsList.Where(b => b.BTNameOriginal == businessTransactionEntryRule.RuleName).ToList()); - businessTransactionsForThisRule.AddRange(businessTransactionsList.Where(b => b.BTNameOriginal.StartsWith(String.Format("{0}.", businessTransactionEntryRule.RuleName))).ToList()); - businessTransactionsForThisRule = businessTransactionsForThisRule.Distinct().ToList(); - businessTransactionEntryRule.NumDetectedBTs = businessTransactionsForThisRule.Count; - if (businessTransactionsForThisRule.Count > 0) - { - StringBuilder sb = new StringBuilder(32 * businessTransactionsForThisRule.Count); - foreach (EntityBusinessTransaction bt in businessTransactionsForThisRule) - { - sb.AppendFormat("{0}/{1};\n", bt.TierName, bt.BTName); - } - sb.Remove(sb.Length - 1, 1); + private static void updateEntitiesWithReportDetailLinksServiceEndpoints(ProgramOptions programOptions, JobConfiguration jobConfiguration, JobTarget jobTarget, List entityList) + { + string controllerFolderPath = Path.Combine(programOptions.OutputJobFolderPath, getFileSystemSafeString(new Uri(jobTarget.Controller).Host)); + string applicationFolderPath = Path.Combine(controllerFolderPath, getShortenedEntityNameForFileSystem(jobTarget.Application, jobTarget.ApplicationID)); + string entitiesFolderPath = Path.Combine(applicationFolderPath, ENTITIES_FOLDER_NAME); + string reportsFolderPath = Path.Combine(programOptions.OutputJobFolderPath, REPORTS_FOLDER_NAME); - businessTransactionEntryRule.DetectedBTs = sb.ToString(); - } + for (int i = 0; i < entityList.Count; i++) + { + EntityBase entityRow = entityList[i]; + entityRow.DetailLink = String.Format(@"=HYPERLINK(""{0}"", """")", getEntityMetricReportFilePath(programOptions, jobConfiguration, jobTarget, entityRow).Substring(reportsFolderPath.Length + 1)); } - - return businessTransactionEntryRule; } - private static BusinessTransactionEntryScope fillBusinessTransactionEntryScope(XmlNode scopeConfigurationNode, XmlNode scopeToRuleMappingConfigurationNode, EntityApplicationConfiguration applicationConfiguration) + private static void updateEntitiesWithReportDetailLinksErrors(ProgramOptions programOptions, JobConfiguration jobConfiguration, JobTarget jobTarget, List entityList) { - BusinessTransactionEntryScope businessTransactionEntryScope = new BusinessTransactionEntryScope(); + string controllerFolderPath = Path.Combine(programOptions.OutputJobFolderPath, getFileSystemSafeString(new Uri(jobTarget.Controller).Host)); + string applicationFolderPath = Path.Combine(controllerFolderPath, getShortenedEntityNameForFileSystem(jobTarget.Application, jobTarget.ApplicationID)); + string entitiesFolderPath = Path.Combine(applicationFolderPath, ENTITIES_FOLDER_NAME); + string reportsFolderPath = Path.Combine(programOptions.OutputJobFolderPath, REPORTS_FOLDER_NAME); - businessTransactionEntryScope.Controller = applicationConfiguration.Controller; - businessTransactionEntryScope.ControllerLink = applicationConfiguration.ControllerLink; - businessTransactionEntryScope.ApplicationName = applicationConfiguration.ApplicationName; - businessTransactionEntryScope.ApplicationID = applicationConfiguration.ApplicationID; - businessTransactionEntryScope.ApplicationLink = applicationConfiguration.ApplicationLink; + for (int i = 0; i < entityList.Count; i++) + { + EntityBase entityRow = entityList[i]; + entityRow.DetailLink = String.Format(@"=HYPERLINK(""{0}"", """")", getEntityMetricReportFilePath(programOptions, jobConfiguration, jobTarget, entityRow).Substring(reportsFolderPath.Length + 1)); + } + } - businessTransactionEntryScope.ScopeName = scopeConfigurationNode.Attributes["scope-name"].Value; - businessTransactionEntryScope.ScopeType = scopeConfigurationNode.Attributes["scope-type"].Value; - businessTransactionEntryScope.Description = scopeConfigurationNode.Attributes["scope-description"].Value; - businessTransactionEntryScope.Version = Convert.ToInt32(scopeConfigurationNode.Attributes["scope-version"].Value); + private static void updateEntitiesWithReportDetailLinksInformationPoints(ProgramOptions programOptions, JobConfiguration jobConfiguration, JobTarget jobTarget, List entityList) + { + string controllerFolderPath = Path.Combine(programOptions.OutputJobFolderPath, getFileSystemSafeString(new Uri(jobTarget.Controller).Host)); + string applicationFolderPath = Path.Combine(controllerFolderPath, getShortenedEntityNameForFileSystem(jobTarget.Application, jobTarget.ApplicationID)); + string entitiesFolderPath = Path.Combine(applicationFolderPath, ENTITIES_FOLDER_NAME); + string reportsFolderPath = Path.Combine(programOptions.OutputJobFolderPath, REPORTS_FOLDER_NAME); - XmlNodeList includedTierNodeList = scopeConfigurationNode.SelectNodes("included-tiers/tier-name"); - businessTransactionEntryScope.NumTiers = includedTierNodeList.Count; - if (businessTransactionEntryScope.NumTiers > 0) + for (int i = 0; i < entityList.Count; i++) { - List includedTiersList = new List(businessTransactionEntryScope.NumTiers); - foreach (XmlNode includedTierNode in includedTierNodeList) - { - includedTiersList.Add(includedTierNode.InnerText); - } - includedTiersList.Sort(); - - StringBuilder sb = new StringBuilder(32 * businessTransactionEntryScope.NumTiers); - foreach (string includedTier in includedTiersList) - { - sb.AppendFormat("{0};\n", includedTier); - } - sb.Remove(sb.Length - 1, 1); - businessTransactionEntryScope.IncludedTiers = sb.ToString(); + EntityBase entityRow = entityList[i]; + entityRow.DetailLink = String.Format(@"=HYPERLINK(""{0}"", """")", getEntityMetricReportFilePath(programOptions, jobConfiguration, jobTarget, entityRow).Substring(reportsFolderPath.Length + 1)); } + } - XmlNodeList ruleMappingNodeList = scopeToRuleMappingConfigurationNode.SelectNodes(String.Format("scope-rule-mapping[@scope-name='{0}']/rule", businessTransactionEntryScope.ScopeName)); - businessTransactionEntryScope.NumRules = ruleMappingNodeList.Count; - if (businessTransactionEntryScope.NumRules > 0) + private static List convertMetricValueToTypedListForCSV(AppDRESTMetric metricValueObject) + { + List metricValues = new List(metricValueObject.metricValues.Count); + foreach (AppDRESTMetricValue mv in metricValueObject.metricValues) { - List ruleMappingList = new List(businessTransactionEntryScope.NumRules); - foreach (XmlNode ruleMappingNode in ruleMappingNodeList) - { - string ruleName = ruleMappingNode.Attributes["rule-name"].Value; - string ruleDescription = ruleMappingNode.Attributes["rule-description"].Value; - string ruleNameAndDescription = String.Empty; - if (ruleDescription.Length > 0 && ruleDescription != ruleName) - { - ruleMappingList.Add(String.Format("{0} ({1})", ruleName, ruleDescription)); - } - else - { - ruleMappingList.Add(ruleName); - } - } - ruleMappingList.Sort(); + MetricValue metricValue = new MetricValue(); + metricValue.EventTimeStampUtc = convertFromUnixTimestamp(mv.startTimeInMillis); + metricValue.EventTimeStamp = metricValue.EventTimeStampUtc.ToLocalTime(); + metricValue.EventTime = metricValue.EventTimeStamp; + metricValue.Count = mv.count; + metricValue.Min = mv.min; + metricValue.Max = mv.max; + metricValue.Occurrences = mv.occurrences; + metricValue.Sum = mv.sum; + metricValue.Value = mv.value; - StringBuilder sb = new StringBuilder(32 * businessTransactionEntryScope.NumRules); - foreach (string ruleMapping in ruleMappingList) + metricValue.MetricID = metricValueObject.metricId; + switch (metricValueObject.frequency) { - sb.AppendFormat("{0};\n", ruleMapping); + case "SIXTY_MIN": + { + metricValue.MetricResolution = MetricResolution.SIXTY_MIN; + break; + } + case "TEN_MIN": + { + metricValue.MetricResolution = MetricResolution.TEN_MIN; + break; + } + case "ONE_MIN": + { + metricValue.MetricResolution = MetricResolution.ONE_MIN; + break; + } + default: + { + metricValue.MetricResolution = MetricResolution.ONE_MIN; + break; + } } - sb.Remove(sb.Length - 1, 1); - businessTransactionEntryScope.IncludedRules = sb.ToString(); + metricValues.Add(metricValue); } - return businessTransactionEntryScope; + return metricValues; } - private static BusinessTransactionEntryRule20 fillBusinessTransactionEntryRule20(XmlNode ruleConfigurationNode, XmlNode scopeToRuleMappingConfigurationNode, EntityApplicationConfiguration applicationConfiguration, List businessTransactionsList) + private static List convertMetricSummaryToTypedListForCSV(AppDRESTMetric metricValueObject, EntityBase entityRow, JobTimeRange jobTimeRange) { - BusinessTransactionEntryRule20 businessTransactionEntryRule = new BusinessTransactionEntryRule20(); - - businessTransactionEntryRule.Controller = applicationConfiguration.Controller; - businessTransactionEntryRule.ControllerLink = applicationConfiguration.ControllerLink; - businessTransactionEntryRule.ApplicationName = applicationConfiguration.ApplicationName; - businessTransactionEntryRule.ApplicationID = applicationConfiguration.ApplicationID; - businessTransactionEntryRule.ApplicationLink = applicationConfiguration.ApplicationLink; - - businessTransactionEntryRule.AgentType = ruleConfigurationNode.Attributes["agent-type"].Value; - businessTransactionEntryRule.RuleName = ruleConfigurationNode.Attributes["rule-name"].Value; - businessTransactionEntryRule.Description = ruleConfigurationNode.Attributes["rule-description"].Value; - businessTransactionEntryRule.Version = Convert.ToInt32(ruleConfigurationNode.Attributes["version"].Value); - - businessTransactionEntryRule.IsEnabled = Convert.ToBoolean(ruleConfigurationNode.Attributes["enabled"].Value); - businessTransactionEntryRule.Priority = Convert.ToInt32(ruleConfigurationNode.Attributes["priority"].Value); + List metricSummaries = new List(); + metricSummaries.Add(new MetricSummary() { + PropertyName = "Controller", + PropertyValue = entityRow.Controller, + Link = entityRow.ControllerLink }); + metricSummaries.Add(new MetricSummary() { + PropertyName = "Application", + PropertyValue = entityRow.ApplicationName, + Link = entityRow.ApplicationLink }); - JObject txRuleSettings = JObject.Parse(getStringValueFromXmlNode(ruleConfigurationNode.SelectSingleNode("tx-match-rule"))); - if (txRuleSettings != null) + string deepLinkMetricTemplateInMetricBrowser = DEEPLINK_METRIC_APPLICATION_TARGET_METRIC_ID; + long entityIdForMetricBrowser = entityRow.ApplicationID; + if (entityRow is EntityApplication) { - if (txRuleSettings["type"].ToString() != "CUSTOM") + metricSummaries.Add(new MetricSummary() { PropertyName = "EntityType", PropertyValue = "Application" }); + metricSummaries.Add(new MetricSummary() { PropertyName = "ApplicationID", PropertyValue = entityRow.ApplicationID }); + } + else if (entityRow is EntityTier) + { + metricSummaries.Add(new MetricSummary() { PropertyName = "EntityType", PropertyValue = "Tier" }); + metricSummaries.Add(new MetricSummary() { + PropertyName = "Tier", + PropertyValue = entityRow.TierName, + Link = entityRow.TierLink }); + metricSummaries.Add(new MetricSummary() { PropertyName = "ApplicationID", PropertyValue = entityRow.ApplicationID }); + metricSummaries.Add(new MetricSummary() { PropertyName = "TierID", PropertyValue = entityRow.TierID }); + deepLinkMetricTemplateInMetricBrowser = DEEPLINK_METRIC_TIER_TARGET_METRIC_ID; + entityIdForMetricBrowser = entityRow.TierID; + } + else if (entityRow is EntityNode) + { + metricSummaries.Add(new MetricSummary() { PropertyName = "EntityType", PropertyValue = "Node" }); + metricSummaries.Add(new MetricSummary() { - // This is likely autodiscovery rule, do not fill it out and bail - return null; - } - - JToken txCustomRuleSettings = txRuleSettings["txcustomrule"]; - if (txCustomRuleSettings != null) + PropertyName = "Tier", + PropertyValue = entityRow.TierName, + Link = entityRow.TierLink + }); + metricSummaries.Add(new MetricSummary() { - if (txCustomRuleSettings["type"].ToString() == "EXCLUDE") - { - businessTransactionEntryRule.IsExclusion = true; - } - else if (txCustomRuleSettings["type"].ToString() == "INCLUDE") - { - businessTransactionEntryRule.IsExclusion = false; - } - - businessTransactionEntryRule.EntryPointType = txCustomRuleSettings["txentrypointtype"].ToString(); - - JToken isBackgroundProperty = txCustomRuleSettings["properties"].Where(p => p["name"].ToString() == "BACKGROUND_TASK").FirstOrDefault(); - if (isBackgroundProperty != null) - { - businessTransactionEntryRule.IsBackground = (bool)isBackgroundProperty["booleanvalue"]; - } - - businessTransactionEntryRule.MatchConditions = txCustomRuleSettings["matchconditions"].ToString(); - businessTransactionEntryRule.Actions = txCustomRuleSettings["actions"].ToString(); - businessTransactionEntryRule.Properties = txCustomRuleSettings["properties"].ToString(); - } + PropertyName = "Node", + PropertyValue = entityRow.NodeName, + Link = entityRow.NodeLink + }); + metricSummaries.Add(new MetricSummary() { PropertyName = "ApplicationID", PropertyValue = entityRow.ApplicationID }); + metricSummaries.Add(new MetricSummary() { PropertyName = "TierID", PropertyValue = entityRow.TierID }); + metricSummaries.Add(new MetricSummary() { PropertyName = "NodeID", PropertyValue = entityRow.NodeID }); + deepLinkMetricTemplateInMetricBrowser = DEEPLINK_METRIC_NODE_TARGET_METRIC_ID; + entityIdForMetricBrowser = entityRow.NodeID; } - - // I really want to do it, but some of our rules have apostrophes - // Spring WS - Base servlet for Spring's web framework - // And the query for scope-rule-mapping/rule[@rule-name='Spring WS - Base servlet for Spring's web framework'] breaks - // So going to do it the hard way - //XmlNode scopeForThisRuleNode = scopeToRuleMappingConfigurationNode.SelectSingleNode(String.Format("scope-rule-mapping/rule[@rule-name='{0}']", businessTransactionEntryRule.RuleName)); - foreach (XmlNode scopeNode in scopeToRuleMappingConfigurationNode.SelectNodes("scope-rule-mapping/rule")) + else if (entityRow is EntityBackend) { - if (scopeNode.Attributes["rule-name"].Value == businessTransactionEntryRule.RuleName) + metricSummaries.Add(new MetricSummary() { PropertyName = "EntityType", PropertyValue = "Backend" }); + metricSummaries.Add(new MetricSummary() { - businessTransactionEntryRule.ScopeName = scopeNode.ParentNode.Attributes["scope-name"].Value; - break; - } + PropertyName = "Tier", + PropertyValue = entityRow.TierName, + Link = entityRow.TierLink + }); + metricSummaries.Add(new MetricSummary() + { + PropertyName = "Backend", + PropertyValue = ((EntityBackend)entityRow).BackendName, + Link = ((EntityBackend)entityRow).BackendLink + }); + metricSummaries.Add(new MetricSummary() { PropertyName = "ApplicationID", PropertyValue = entityRow.ApplicationID }); + metricSummaries.Add(new MetricSummary() { PropertyName = "TierID", PropertyValue = entityRow.TierID }); + metricSummaries.Add(new MetricSummary() { PropertyName = "BackendID", PropertyValue = ((EntityBackend)entityRow).BackendID }); } - - if (businessTransactionsList != null) + else if (entityRow is EntityBusinessTransaction) { - List businessTransactionsForThisRule = new List(); - businessTransactionsForThisRule.AddRange(businessTransactionsList.Where(b => b.BTName == businessTransactionEntryRule.RuleName).ToList()); - businessTransactionsForThisRule.AddRange(businessTransactionsList.Where(b => b.BTName.StartsWith(String.Format("{0}.", businessTransactionEntryRule.RuleName))).ToList()); - businessTransactionsForThisRule.AddRange(businessTransactionsList.Where(b => b.BTNameOriginal == businessTransactionEntryRule.RuleName).ToList()); - businessTransactionsForThisRule.AddRange(businessTransactionsList.Where(b => b.BTNameOriginal.StartsWith(String.Format("{0}.", businessTransactionEntryRule.RuleName))).ToList()); - businessTransactionsForThisRule = businessTransactionsForThisRule.Distinct().ToList(); - businessTransactionEntryRule.NumDetectedBTs = businessTransactionsForThisRule.Count; - if (businessTransactionsForThisRule.Count > 0) + metricSummaries.Add(new MetricSummary() { PropertyName = "EntityType", PropertyValue = "Business Transaction" }); + metricSummaries.Add(new MetricSummary() { - StringBuilder sb = new StringBuilder(32 * businessTransactionsForThisRule.Count); - foreach (EntityBusinessTransaction bt in businessTransactionsForThisRule) - { - sb.AppendFormat("{0}/{1};\n", bt.TierName, bt.BTName); - } - sb.Remove(sb.Length - 1, 1); - - businessTransactionEntryRule.DetectedBTs = sb.ToString(); - } + PropertyName = "Tier", + PropertyValue = entityRow.TierName, + Link = entityRow.TierLink + }); + metricSummaries.Add(new MetricSummary() + { + PropertyName = "Business Transaction", + PropertyValue = ((EntityBusinessTransaction)entityRow).BTName, + Link = ((EntityBusinessTransaction)entityRow).BTLink + }); + metricSummaries.Add(new MetricSummary() { PropertyName = "ApplicationID", PropertyValue = entityRow.ApplicationID }); + metricSummaries.Add(new MetricSummary() { PropertyName = "TierID", PropertyValue = entityRow.TierID }); + metricSummaries.Add(new MetricSummary() { PropertyName = "BTID", PropertyValue = ((EntityBusinessTransaction)entityRow).BTID }); + deepLinkMetricTemplateInMetricBrowser = DEEPLINK_METRIC_TIER_TARGET_METRIC_ID; + entityIdForMetricBrowser = entityRow.TierID; } - - businessTransactionEntryRule.RuleRawValue = makeXMLFormattedAndIndented(ruleConfigurationNode); - - return businessTransactionEntryRule; - } - - private static List fillBusinessTransactionDiscoveryRule20(XmlNode ruleConfigurationNode, XmlNode scopeToRuleMappingConfigurationNode, EntityApplicationConfiguration applicationConfiguration, List businessTransactionsList) - { - List businessTransactionDiscoveryRule20List = new List(); - - JObject txRuleSettings = JObject.Parse(getStringValueFromXmlNode(ruleConfigurationNode.SelectSingleNode("tx-match-rule"))); - if (txRuleSettings != null) + else if (entityRow is EntityServiceEndpoint) { - if (txRuleSettings["type"].ToString() != "AUTOMATIC_DISCOVERY") + metricSummaries.Add(new MetricSummary() { PropertyName = "EntityType", PropertyValue = "Service Endpoint" }); + metricSummaries.Add(new MetricSummary() { - // This is not an autodiscovery rule, do not fill it out and bail - return null; - } - - JArray txDiscoveryConfigs = (JArray)txRuleSettings["txautodiscoveryrule"]["autodiscoveryconfigs"]; - if (txDiscoveryConfigs != null && txDiscoveryConfigs.Count > 0) + PropertyName = "Tier", + PropertyValue = entityRow.TierName, + Link = entityRow.TierLink + }); + metricSummaries.Add(new MetricSummary() { - foreach (JToken txDiscoveryConfig in txDiscoveryConfigs) - { - BusinessTransactionDiscoveryRule20 businessTransactionDiscoveryRule20 = new BusinessTransactionDiscoveryRule20(); - - businessTransactionDiscoveryRule20.Controller = applicationConfiguration.Controller; - businessTransactionDiscoveryRule20.ControllerLink = applicationConfiguration.ControllerLink; - businessTransactionDiscoveryRule20.ApplicationName = applicationConfiguration.ApplicationName; - businessTransactionDiscoveryRule20.ApplicationID = applicationConfiguration.ApplicationID; - businessTransactionDiscoveryRule20.ApplicationLink = applicationConfiguration.ApplicationLink; - - businessTransactionDiscoveryRule20.AgentType = ruleConfigurationNode.Attributes["agent-type"].Value; - businessTransactionDiscoveryRule20.RuleName = ruleConfigurationNode.Attributes["rule-name"].Value; - businessTransactionDiscoveryRule20.Description = ruleConfigurationNode.Attributes["rule-description"].Value; - businessTransactionDiscoveryRule20.Version = Convert.ToInt32(ruleConfigurationNode.Attributes["version"].Value); - - businessTransactionDiscoveryRule20.IsEnabled = Convert.ToBoolean(ruleConfigurationNode.Attributes["enabled"].Value); - businessTransactionDiscoveryRule20.Priority = Convert.ToInt32(ruleConfigurationNode.Attributes["priority"].Value); + PropertyName = "Service Endpoint", + PropertyValue = ((EntityServiceEndpoint)entityRow).SEPName, + Link = ((EntityServiceEndpoint)entityRow).SEPLink + }); + metricSummaries.Add(new MetricSummary() { PropertyName = "ApplicationID", PropertyValue = entityRow.ApplicationID }); + metricSummaries.Add(new MetricSummary() { PropertyName = "TierID", PropertyValue = entityRow.TierID }); + metricSummaries.Add(new MetricSummary() { PropertyName = "SEPID", PropertyValue = ((EntityServiceEndpoint)entityRow).SEPID }); + } + else if (entityRow is EntityError) + { + metricSummaries.Add(new MetricSummary() { PropertyName = "EntityType", PropertyValue = "Error" }); + metricSummaries.Add(new MetricSummary() + { + PropertyName = "Tier", + PropertyValue = entityRow.TierName, + Link = entityRow.TierLink + }); + metricSummaries.Add(new MetricSummary() + { + PropertyName = "Error", + PropertyValue = ((EntityError)entityRow).ErrorName, + Link = ((EntityError)entityRow).ErrorLink + }); + metricSummaries.Add(new MetricSummary() { PropertyName = "ApplicationID", PropertyValue = entityRow.ApplicationID }); + metricSummaries.Add(new MetricSummary() { PropertyName = "TierID", PropertyValue = entityRow.TierID }); + metricSummaries.Add(new MetricSummary() { PropertyName = "ErrorID", PropertyValue = ((EntityError)entityRow).ErrorID }); + } - businessTransactionDiscoveryRule20.EntryPointType = txDiscoveryConfig["txentrypointtype"].ToString(); - businessTransactionDiscoveryRule20.IsMonitoringEnabled = (bool)txDiscoveryConfig["monitoringenabled"]; - businessTransactionDiscoveryRule20.IsDiscoveryEnabled = (bool)txDiscoveryConfig["discoveryenabled"]; - businessTransactionDiscoveryRule20.NamingConfigType = txDiscoveryConfig["namingschemetype"].ToString(); + // Decide what kind of timerange + string DEEPLINK_THIS_TIMERANGE = DEEPLINK_TIMERANGE_LAST_15_MINUTES; + if (jobTimeRange != null) + { + long fromTimeUnix = convertToUnixTimestamp(jobTimeRange.From); + long toTimeUnix = convertToUnixTimestamp(jobTimeRange.To); + long differenceInMinutes = (toTimeUnix - fromTimeUnix) / (60000); + DEEPLINK_THIS_TIMERANGE = String.Format(DEEPLINK_TIMERANGE_BETWEEN_TIMES, toTimeUnix, fromTimeUnix, differenceInMinutes); + } - businessTransactionDiscoveryRule20.HTTPAutoDiscovery = txDiscoveryConfig["httpautodiscovery"].ToString(); + metricSummaries.Add(new MetricSummary() + { + PropertyName = "Metric ID", + PropertyValue = metricValueObject.metricId, + Link = String.Format(DEEPLINK_METRIC, entityRow.Controller, entityRow.ApplicationID, String.Format(deepLinkMetricTemplateInMetricBrowser, entityIdForMetricBrowser, metricValueObject.metricId), DEEPLINK_THIS_TIMERANGE) + }); - // I really want to do it, but some of our rules have apostrophes - // Spring WS - Base servlet for Spring's web framework - // And the query for scope-rule-mapping/rule[@rule-name='Spring WS - Base servlet for Spring's web framework'] breaks - // So going to do it the hard way - //XmlNode scopeForThisRuleNode = scopeToRuleMappingConfigurationNode.SelectSingleNode(String.Format("scope-rule-mapping/rule[@rule-name='{0}']", businessTransactionEntryRule.RuleName)); - foreach (XmlNode scopeNode in scopeToRuleMappingConfigurationNode.SelectNodes("scope-rule-mapping/rule")) - { - if (scopeNode.Attributes["rule-name"].Value == businessTransactionDiscoveryRule20.RuleName) - { - businessTransactionDiscoveryRule20.ScopeName = scopeNode.ParentNode.Attributes["scope-name"].Value; - break; - } - } + // Name of the metric is always the last one in the metric path + string[] metricPathComponents = metricValueObject.metricPath.Split('|'); + string metricName = metricPathComponents[metricPathComponents.Length - 1]; + MetricSummary metricNameMetricSummary = new MetricSummary() { PropertyName = "Metric Name", PropertyValue = metricName }; + metricSummaries.Add(metricNameMetricSummary); + metricSummaries.Add(new MetricSummary() { PropertyName = "Metric Name (Short)", PropertyValue = metricNameToShortMetricNameMapping[metricNameMetricSummary.PropertyValue.ToString()] }); + metricSummaries.Add(new MetricSummary() { PropertyName = "Metric Name (Full)", PropertyValue = metricValueObject.metricName }); + metricSummaries.Add(new MetricSummary() { PropertyName = "Metric Path", PropertyValue = metricValueObject.metricPath }); - businessTransactionDiscoveryRule20List.Add(businessTransactionDiscoveryRule20); - } - } + // Only the metrics with Average Response Time (ms) are times + // As long as we are not in Application Infrastructure Performance area + if (metricName.IndexOf(METRIC_TIME_MS) > 0) + { + metricSummaries.Add(new MetricSummary() { PropertyName = "Rollup Type", PropertyValue = MetricType.Duration.ToString() }); + } + else + { + metricSummaries.Add(new MetricSummary() { PropertyName = "Rollup Type", PropertyValue = MetricType.Count.ToString() }); } - return businessTransactionDiscoveryRule20List; + return metricSummaries; } - private static BackendDiscoveryRule fillBackendDiscoveryRule(XmlNode backendDiscoveryMatchPointConfigurationNode, XmlNode backendDiscoveryConfigurationNode, EntityApplicationConfiguration applicationConfiguration, XmlNode applicationComponentNode, List backendsList) - { - BackendDiscoveryRule backendDiscoveryRule = new BackendDiscoveryRule(); + #endregion - backendDiscoveryRule.Controller = applicationConfiguration.Controller; - backendDiscoveryRule.ControllerLink = applicationConfiguration.ControllerLink; - backendDiscoveryRule.ApplicationName = applicationConfiguration.ApplicationName; - backendDiscoveryRule.ApplicationID = applicationConfiguration.ApplicationID; - backendDiscoveryRule.ApplicationLink = applicationConfiguration.ApplicationLink; + #region Configuration detail conversion functions - backendDiscoveryRule.AgentType = getStringValueFromXmlNode(backendDiscoveryMatchPointConfigurationNode.SelectSingleNode("agent-type")); - backendDiscoveryRule.ExitType = getStringValueFromXmlNode(backendDiscoveryConfigurationNode.SelectSingleNode("exit-point-type")); - if (backendDiscoveryRule.ExitType == "CUSTOM") + private static string getNameValueDetailsFromNameValueCollection(XmlNode xmlNodeWithNameValuePairs) + { + if (xmlNodeWithNameValuePairs == null) return String.Empty; + + StringBuilder sb = new StringBuilder(); + foreach (XmlNode xmlNodeNameValue in xmlNodeWithNameValuePairs.SelectNodes("name-values")) { - backendDiscoveryRule.ExitType = getStringValueFromXmlNode(backendDiscoveryConfigurationNode.SelectSingleNode("exit-point-subtype")); + sb.AppendFormat("{0}={1};", xmlNodeNameValue.SelectSingleNode("name").InnerText, xmlNodeNameValue.SelectSingleNode("value").InnerText); } - backendDiscoveryRule.RuleName = getStringValueFromXmlNode(backendDiscoveryConfigurationNode.SelectSingleNode("name")); - backendDiscoveryRule.IsEnabled = getBoolValueFromXmlNode(backendDiscoveryConfigurationNode.SelectSingleNode("discovery-enabled")); - backendDiscoveryRule.IsCorrelationSupported = getBoolValueFromXmlNode(backendDiscoveryConfigurationNode.SelectSingleNode("supports-correlation")); - backendDiscoveryRule.IsCorrelationEnabled = getBoolValueFromXmlNode(backendDiscoveryConfigurationNode.SelectSingleNode("correlation-enabled")); - backendDiscoveryRule.Priority = getIntegerValueFromXmlNode(backendDiscoveryConfigurationNode.SelectSingleNode("priority")); - backendDiscoveryRule.IdentityOptions = makeXMLFormattedAndIndented(backendDiscoveryConfigurationNode.SelectSingleNode("backend-identity-options")); - backendDiscoveryRule.DiscoveryConditions = makeXMLFormattedAndIndented(backendDiscoveryConfigurationNode.SelectSingleNode("backend-identity-options")); + return sb.ToString(); + } - backendDiscoveryRule.RuleRawValue = makeXMLFormattedAndIndented(backendDiscoveryConfigurationNode); + private static string getNameValueDetailsFromParametersCollection(XmlNode xmlNodeWithParameters) + { + if (xmlNodeWithParameters == null) return String.Empty; - if (applicationComponentNode != null) + StringBuilder sb = new StringBuilder(); + foreach (XmlNode xmlNodeNameValue in xmlNodeWithParameters.SelectNodes("parameter")) { - backendDiscoveryRule.TierName = getStringValueFromXmlNode(applicationComponentNode.SelectSingleNode("name")); + sb.AppendFormat( + "{0}:{1}/{2}={3}/{4};", + xmlNodeNameValue.Attributes["match-type"].Value, + xmlNodeNameValue.SelectSingleNode("name").Attributes["filter-value"].Value, + xmlNodeNameValue.SelectSingleNode("name").Attributes["filter-type"].Value, + xmlNodeNameValue.SelectSingleNode("value").Attributes["filter-value"].Value, + xmlNodeNameValue.SelectSingleNode("value").Attributes["filter-type"].Value); } - if (backendsList != null) - { - List backendsForThisRule = new List(); + return sb.ToString(); + } - // Try to find them by match first - backendsForThisRule.AddRange(backendsList.Where(b => b.BackendName == backendDiscoveryRule.RuleName).ToList()); - backendsForThisRule.AddRange(backendsList.Where(b => b.BackendName.StartsWith(String.Format("{0}", backendDiscoveryRule.RuleName))).ToList()); - backendsForThisRule = backendsForThisRule.Distinct().ToList(); - if (backendsForThisRule.Count == 0) + private static int getIntegerValueFromXmlNode(XmlNode xmlNode) + { + if (xmlNode == null) return 0; + + if (((XmlElement)xmlNode).IsEmpty == true) + { + return 0; + } + else + { + int value; + if (Int32.TryParse(xmlNode.InnerText, out value) == true) { - // If by name doesn't match, let's do by type - // Nope, this doesn't work. Backend is differentiated by the Agent Type - // Because of that the backend matches every darn type starting with Default - // backendsForThisRule.AddRange(backendsList.Where(b => b.BackendType == backendDiscoveryRule.ExitType).ToList()); + return value; } - backendDiscoveryRule.NumDetectedBackends = backendsForThisRule.Count; - if (backendsForThisRule.Count > 0) + else { - StringBuilder sb = new StringBuilder(32 * backendsForThisRule.Count); - foreach (EntityBackend backend in backendsForThisRule) + double value1; + if (Double.TryParse(xmlNode.InnerText, out value1) == true) { - sb.AppendFormat("{0} ({1});\n", backend.BackendName, backend.BackendID); + return Convert.ToInt32(Math.Floor(value1)); + } + else + { + return 0; } - sb.Remove(sb.Length - 1, 1); - - backendDiscoveryRule.DetectedBackends = sb.ToString(); } } - - return backendDiscoveryRule; } - private static CustomExitRule fillCustomExitRule(XmlNode backendDiscoveryMatchPointConfigurationNode, XmlNode customExitConfigurationNode, EntityApplicationConfiguration applicationConfiguration, XmlNode applicationComponentNode, List backendsList) + private static long getLongValueFromXmlNode(XmlNode xmlNode) { - CustomExitRule customExitRule = new CustomExitRule(); - - customExitRule.Controller = applicationConfiguration.Controller; - customExitRule.ControllerLink = applicationConfiguration.ControllerLink; - customExitRule.ApplicationName = applicationConfiguration.ApplicationName; - customExitRule.ApplicationID = applicationConfiguration.ApplicationID; - customExitRule.ApplicationLink = applicationConfiguration.ApplicationLink; - - customExitRule.AgentType = getStringValueFromXmlNode(backendDiscoveryMatchPointConfigurationNode.SelectSingleNode("agent-type")); - customExitRule.ExitType = getStringValueFromXmlNode(customExitConfigurationNode.SelectSingleNode("type")); - - customExitRule.RuleName = getStringValueFromXmlNode(customExitConfigurationNode.SelectSingleNode("name")); - customExitRule.MatchClass = getStringValueFromXmlNode(customExitConfigurationNode.SelectSingleNode("instrumentation-point/pojo-method-definition/class-name")); - customExitRule.MatchMethod = getStringValueFromXmlNode(customExitConfigurationNode.SelectSingleNode("instrumentation-point/pojo-method-definition/method-name")); - customExitRule.MatchType = getStringValueFromXmlNode(customExitConfigurationNode.SelectSingleNode("instrumentation-point/pojo-method-definition/match-type")); - customExitRule.MatchParameterTypes = getStringValueFromXmlNode(customExitConfigurationNode.SelectSingleNode("instrumentation-point/pojo-method-definition/method-parameter-types")); - - customExitRule.IsApplyToAllBTs = getBoolValueFromXmlNode(customExitConfigurationNode.SelectSingleNode("instrumentation-point/apply-to-all-bts")); - - customExitRule.DataCollectorsConfig = makeXMLFormattedAndIndented(customExitConfigurationNode.SelectNodes("instrumentation-point/method-invocation-data-gatherer-config")); - customExitRule.InfoPointsConfig = makeXMLFormattedAndIndented(customExitConfigurationNode.SelectNodes("instrumentation-point/info-point-metric-definition")); - - customExitRule.RuleRawValue = makeXMLFormattedAndIndented(customExitConfigurationNode); + if (xmlNode == null) return 0; - if (applicationComponentNode != null) + if (((XmlElement)xmlNode).IsEmpty == true) { - customExitRule.TierName = getStringValueFromXmlNode(applicationComponentNode.SelectSingleNode("name")); + return 0; } - - if (backendsList != null) + else { - List backendsForThisRule = new List(); - - // Try to find them by match first - backendsForThisRule.AddRange(backendsList.Where(b => b.BackendName == customExitRule.RuleName).ToList()); - backendsForThisRule.AddRange(backendsList.Where(b => b.BackendName.StartsWith(String.Format("{0}", customExitRule.RuleName))).ToList()); - backendsForThisRule = backendsForThisRule.Distinct().ToList(); - if (backendsForThisRule.Count == 0) + long value; + if (Int64.TryParse(xmlNode.InnerText, out value) == true) { - // If by name doesn't match, let's do by type - // Nope, this doesn't work. Backend is differentiated by the Agent Type - // Because of that the backend matches every darn type starting with Default - // backendsForThisRule.AddRange(backendsList.Where(b => b.BackendType == customExitRule.ExitType).ToList()); + return value; } - customExitRule.NumDetectedBackends = backendsForThisRule.Count; - if (backendsForThisRule.Count > 0) + else { - StringBuilder sb = new StringBuilder(32 * backendsForThisRule.Count); - foreach (EntityBackend backend in backendsForThisRule) + double value1; + if (Double.TryParse(xmlNode.InnerText, out value1) == true) { - sb.AppendFormat("{0} ({1});\n", backend.BackendName, backend.BackendID); + return Convert.ToInt64(Math.Floor(value1)); + } + else + { + return 0; } - sb.Remove(sb.Length - 1, 1); - - customExitRule.DetectedBackends = sb.ToString(); } } - - return customExitRule; } - private static InformationPointRule fillInformationPointRule(XmlNode informationPointConfigurationNode, EntityApplicationConfiguration applicationConfiguration) + private static bool getBoolValueFromXmlNode(XmlNode xmlNode) { - InformationPointRule informationPointRule = new InformationPointRule(); - - informationPointRule.Controller = applicationConfiguration.Controller; - informationPointRule.ControllerLink = applicationConfiguration.ControllerLink; - informationPointRule.ApplicationName = applicationConfiguration.ApplicationName; - informationPointRule.ApplicationID = applicationConfiguration.ApplicationID; - informationPointRule.ApplicationLink = applicationConfiguration.ApplicationLink; - - informationPointRule.AgentType = getStringValueFromXmlNode(informationPointConfigurationNode.SelectSingleNode("agent-type")); + if (xmlNode == null) return false; - informationPointRule.RuleName = getStringValueFromXmlNode(informationPointConfigurationNode.SelectSingleNode("name")); - informationPointRule.MatchClass = getStringValueFromXmlNode(informationPointConfigurationNode.SelectSingleNode("pojo-method-definition/class-name")); - informationPointRule.MatchMethod = getStringValueFromXmlNode(informationPointConfigurationNode.SelectSingleNode("pojo-method-definition/method-name")); - informationPointRule.MatchType = getStringValueFromXmlNode(informationPointConfigurationNode.SelectSingleNode("pojo-method-definition/match-type")); - informationPointRule.MatchParameterTypes = getStringValueFromXmlNode(informationPointConfigurationNode.SelectSingleNode("pojo-method-definition/method-parameter-types")); - informationPointRule.MatchCondition = makeXMLFormattedAndIndented(informationPointConfigurationNode.SelectSingleNode("pojo-method-definition/match-condition")); - - informationPointRule.InfoPointsConfig = makeXMLFormattedAndIndented(informationPointConfigurationNode.SelectNodes("info-point-metric-definition")); - - informationPointRule.RuleRawValue = makeXMLFormattedAndIndented(informationPointConfigurationNode); - - return informationPointRule; + if (((XmlElement)xmlNode).IsEmpty == true) + { + return false; + } + else + { + bool value; + if (Boolean.TryParse(xmlNode.InnerText, out value) == true) + { + return value; + } + else + { + return false; + } + } } - private static AgentConfigurationProperty fillAgentConfigurationProperty(XmlNode agentConfigurationNode, XmlNode agentPropertyDefinitionConfigurationNode, XmlNode agentPropertyValueConfigurationNode, EntityApplicationConfiguration applicationConfiguration, XmlNode applicationComponentNode) + private static string getStringValueFromXmlNode(XmlNode xmlNode) { - AgentConfigurationProperty agentConfigurationProperty = new AgentConfigurationProperty(); + if (xmlNode == null) return String.Empty; - agentConfigurationProperty.Controller = applicationConfiguration.Controller; - agentConfigurationProperty.ControllerLink = applicationConfiguration.ControllerLink; - agentConfigurationProperty.ApplicationName = applicationConfiguration.ApplicationName; - agentConfigurationProperty.ApplicationID = applicationConfiguration.ApplicationID; - agentConfigurationProperty.ApplicationLink = applicationConfiguration.ApplicationLink; + if (((XmlElement)xmlNode).IsEmpty == true) + { + return String.Empty; + } + else + { + return xmlNode.InnerText; + } + } - agentConfigurationProperty.AgentType = getStringValueFromXmlNode(agentConfigurationNode.SelectSingleNode("agent-type")); + /// + /// https://stackoverflow.com/questions/1123718/format-xml-string-to-print-friendly-xml-string + /// + /// + /// + private static string makeXMLFormattedAndIndented(String XML) + { + string Result = ""; - agentConfigurationProperty.PropertyName = getStringValueFromXmlNode(agentPropertyDefinitionConfigurationNode.SelectSingleNode("name")); - agentConfigurationProperty.PropertyType = getStringValueFromXmlNode(agentPropertyDefinitionConfigurationNode.SelectSingleNode("type")); - agentConfigurationProperty.Description = getStringValueFromXmlNode(agentPropertyDefinitionConfigurationNode.SelectSingleNode("description")); - agentConfigurationProperty.IsRequired = getBoolValueFromXmlNode(agentPropertyDefinitionConfigurationNode.SelectSingleNode("required")); + MemoryStream MS = new MemoryStream(); + XmlTextWriter W = new XmlTextWriter(MS, Encoding.Unicode); + XmlDocument D = new XmlDocument(); - switch (agentConfigurationProperty.PropertyType) + try { - case "STRING": - agentConfigurationProperty.StringValue = getStringValueFromXmlNode(agentPropertyValueConfigurationNode.SelectSingleNode("string-value")); - agentConfigurationProperty.StringDefaultValue = getStringValueFromXmlNode(agentPropertyDefinitionConfigurationNode.SelectSingleNode("default-string-value")); - agentConfigurationProperty.StringMaxLength = getIntegerValueFromXmlNode(agentPropertyDefinitionConfigurationNode.SelectSingleNode("string-max-length")); - agentConfigurationProperty.StringAllowedValues = getStringValueFromXmlNode(agentPropertyDefinitionConfigurationNode.SelectSingleNode("allowed-string-values")); + // Load the XmlDocument with the XML. + D.LoadXml(XML); - agentConfigurationProperty.IsDefault = (agentConfigurationProperty.StringDefaultValue == agentConfigurationProperty.StringDefaultValue); - break; + W.Formatting = Formatting.Indented; - case "BOOLEAN": - agentConfigurationProperty.BooleanValue = getBoolValueFromXmlNode(agentPropertyValueConfigurationNode.SelectSingleNode("string-value")); - agentConfigurationProperty.BooleanDefaultValue = getBoolValueFromXmlNode(agentPropertyDefinitionConfigurationNode.SelectSingleNode("default-string-value")); + // Write the XML into a formatting XmlTextWriter + D.WriteContentTo(W); + W.Flush(); + MS.Flush(); - agentConfigurationProperty.IsDefault = (agentConfigurationProperty.BooleanValue == agentConfigurationProperty.BooleanDefaultValue); - break; + // Have to rewind the MemoryStream in order to read + // its contents. + MS.Position = 0; - case "INTEGER": - agentConfigurationProperty.IntegerValue = getIntegerValueFromXmlNode(agentPropertyValueConfigurationNode.SelectSingleNode("string-value")); - agentConfigurationProperty.IntegerDefaultValue = getIntegerValueFromXmlNode(agentPropertyDefinitionConfigurationNode.SelectSingleNode("default-string-value")); - agentConfigurationProperty.IntegerMinValue = getIntegerValueFromXmlNode(agentPropertyDefinitionConfigurationNode.SelectSingleNode("lower-numeric-bound")); - agentConfigurationProperty.IntegerMaxValue = getIntegerValueFromXmlNode(agentPropertyDefinitionConfigurationNode.SelectSingleNode("upper-numeric-bound")); + // Read MemoryStream contents into a StreamReader. + StreamReader SR = new StreamReader(MS); - agentConfigurationProperty.IsDefault = (agentConfigurationProperty.IntegerValue == agentConfigurationProperty.IntegerDefaultValue); - break; + // Extract the text from the StreamReader. + String FormattedXML = SR.ReadToEnd(); - default: - agentConfigurationProperty.StringValue = getStringValueFromXmlNode(agentPropertyValueConfigurationNode.SelectSingleNode("string-value")); - break; + Result = FormattedXML; } - - if (applicationComponentNode != null) + catch (XmlException) { - agentConfigurationProperty.TierName = getStringValueFromXmlNode(applicationComponentNode.SelectSingleNode("name")); } - return agentConfigurationProperty; + MS.Close(); + W.Close(); + + return Result; } - private static MethodInvocationDataCollector fillMethodInvocationDataCollector(XmlNode methodInvocationDataCollectorConfigurationNode, XmlNode dataGathererConfigurationNode, EntityApplicationConfiguration applicationConfiguration, List entityBusinessTransactionConfigurationsList) + private static string makeXMLFormattedAndIndented(XmlNode xmlNode) { - MethodInvocationDataCollector methodInvocationDataCollector = new MethodInvocationDataCollector(); - - methodInvocationDataCollector.Controller = applicationConfiguration.Controller; - methodInvocationDataCollector.ControllerLink = applicationConfiguration.ControllerLink; - methodInvocationDataCollector.ApplicationName = applicationConfiguration.ApplicationName; - methodInvocationDataCollector.ApplicationID = applicationConfiguration.ApplicationID; - methodInvocationDataCollector.ApplicationLink = applicationConfiguration.ApplicationLink; - - methodInvocationDataCollector.CollectorName = getStringValueFromXmlNode(methodInvocationDataCollectorConfigurationNode.SelectSingleNode("name")); - - methodInvocationDataCollector.IsAPM = Convert.ToBoolean(methodInvocationDataCollectorConfigurationNode.Attributes["enabled-for-apm"].Value); - methodInvocationDataCollector.IsAnalytics = Convert.ToBoolean(methodInvocationDataCollectorConfigurationNode.Attributes["enabled-for-analytics"].Value); - methodInvocationDataCollector.IsAssignedToNewBTs = Convert.ToBoolean(methodInvocationDataCollectorConfigurationNode.Attributes["attach-to-new-bts"].Value); - - methodInvocationDataCollector.MatchClass = getStringValueFromXmlNode(methodInvocationDataCollectorConfigurationNode.SelectSingleNode("pojo-method-definition/class-name")); - methodInvocationDataCollector.MatchMethod = getStringValueFromXmlNode(methodInvocationDataCollectorConfigurationNode.SelectSingleNode("pojo-method-definition/method-name")); - methodInvocationDataCollector.MatchType = getStringValueFromXmlNode(methodInvocationDataCollectorConfigurationNode.SelectSingleNode("pojo-method-definition/match-type")); - methodInvocationDataCollector.MatchParameterTypes = getStringValueFromXmlNode(methodInvocationDataCollectorConfigurationNode.SelectSingleNode("pojo-method-definition/method-parameter-types")); - - methodInvocationDataCollector.DataGathererName = getStringValueFromXmlNode(dataGathererConfigurationNode.SelectSingleNode("name")); - methodInvocationDataCollector.DataGathererType = getStringValueFromXmlNode(dataGathererConfigurationNode.SelectSingleNode("gatherer-type")); - methodInvocationDataCollector.DataGathererPosition = getIntegerValueFromXmlNode(dataGathererConfigurationNode.SelectSingleNode("position")); - methodInvocationDataCollector.DataGathererTransform = getStringValueFromXmlNode(dataGathererConfigurationNode.SelectSingleNode("transformer-type")); - methodInvocationDataCollector.DataGathererGetter = getStringValueFromXmlNode(dataGathererConfigurationNode.SelectSingleNode("transformer-value")); - - methodInvocationDataCollector.IsAssignedToBTs = false; - - methodInvocationDataCollector.RuleRawValue = makeXMLFormattedAndIndented(methodInvocationDataCollectorConfigurationNode); - - if (entityBusinessTransactionConfigurationsList != null) + if (xmlNode != null) { - List entityBusinessTransactionConfigurationsForThisDCList = entityBusinessTransactionConfigurationsList.Where(b => b.AssignedMIDCs.Contains(String.Format("{0};", methodInvocationDataCollector.CollectorName)) == true).ToList(); + return makeXMLFormattedAndIndented(xmlNode.OuterXml); + } + else + { + return String.Empty; + } + } - if (entityBusinessTransactionConfigurationsForThisDCList.Count > 0) + private static string makeXMLFormattedAndIndented(XmlNodeList xmlNodeList) + { + if (xmlNodeList.Count > 0) + { + StringBuilder sb = new StringBuilder(128 * xmlNodeList.Count); + foreach (XmlNode xmlNode in xmlNodeList) { - methodInvocationDataCollector.IsAssignedToBTs = true; - methodInvocationDataCollector.NumAssignedBTs = entityBusinessTransactionConfigurationsForThisDCList.Count; - - StringBuilder sb = new StringBuilder(32 * entityBusinessTransactionConfigurationsForThisDCList.Count); - foreach (EntityBusinessTransactionConfiguration bt in entityBusinessTransactionConfigurationsForThisDCList) - { - sb.AppendFormat("{0}/{1};\n", bt.TierName, bt.BTName); - } - sb.Remove(sb.Length - 1, 1); - methodInvocationDataCollector.AssignedBTs = sb.ToString(); + sb.Append(makeXMLFormattedAndIndented(xmlNode)); + sb.AppendLine(); } + sb.Remove(sb.Length - 1, 1); + return sb.ToString(); + } + else + { + return String.Empty; } - - return methodInvocationDataCollector; } - private static HTTPDataCollector fillHTTPDataCollector(XmlNode httpDataCollectorConfigurationNode, XmlNode dataGathererConfigurationNode, EntityApplicationConfiguration applicationConfiguration, List entityBusinessTransactionConfigurationsList) + private static BusinessTransactionDiscoveryRule fillBusinessTransactionDiscoveryRule(XmlNode entryMatchPointConfigurationNode, XmlNode entryMatchPointTransactionConfigurationNode, EntityApplicationConfiguration applicationConfiguration, XmlNode applicationComponentNode) { - HTTPDataCollector httpDataCollector = new HTTPDataCollector(); - - httpDataCollector.Controller = applicationConfiguration.Controller; - httpDataCollector.ControllerLink = applicationConfiguration.ControllerLink; - httpDataCollector.ApplicationName = applicationConfiguration.ApplicationName; - httpDataCollector.ApplicationID = applicationConfiguration.ApplicationID; - httpDataCollector.ApplicationLink = applicationConfiguration.ApplicationLink; + BusinessTransactionDiscoveryRule businessTransactionDiscoveryRule = new BusinessTransactionDiscoveryRule(); - httpDataCollector.CollectorName = getStringValueFromXmlNode(httpDataCollectorConfigurationNode.SelectSingleNode("name")); + businessTransactionDiscoveryRule.Controller = applicationConfiguration.Controller; + businessTransactionDiscoveryRule.ControllerLink = applicationConfiguration.ControllerLink; + businessTransactionDiscoveryRule.ApplicationName = applicationConfiguration.ApplicationName; + businessTransactionDiscoveryRule.ApplicationID = applicationConfiguration.ApplicationID; + businessTransactionDiscoveryRule.ApplicationLink = applicationConfiguration.ApplicationLink; - httpDataCollector.IsAPM = Convert.ToBoolean(httpDataCollectorConfigurationNode.Attributes["enabled-for-apm"].Value); - httpDataCollector.IsAnalytics = Convert.ToBoolean(httpDataCollectorConfigurationNode.Attributes["enabled-for-analytics"].Value); - httpDataCollector.IsAssignedToNewBTs = Convert.ToBoolean(httpDataCollectorConfigurationNode.Attributes["attach-to-new-bts"].Value); + businessTransactionDiscoveryRule.AgentType = entryMatchPointConfigurationNode.SelectSingleNode("agent-type").InnerText; + businessTransactionDiscoveryRule.EntryPointType = entryMatchPointTransactionConfigurationNode.Attributes["transaction-entry-point-type"].Value; + businessTransactionDiscoveryRule.IsMonitoringEnabled = getBoolValueFromXmlNode(entryMatchPointTransactionConfigurationNode.SelectSingleNode("enable")); + businessTransactionDiscoveryRule.DiscoveryType = entryMatchPointTransactionConfigurationNode.SelectSingleNode("discovery-config").Attributes["discovery-resolution"].Value; + businessTransactionDiscoveryRule.IsDiscoveryEnabled = getBoolValueFromXmlNode(entryMatchPointTransactionConfigurationNode.SelectSingleNode("discovery-config/discovery-config-enabled")); + businessTransactionDiscoveryRule.NamingConfigType = entryMatchPointTransactionConfigurationNode.SelectSingleNode("discovery-config/naming-config").Attributes["scheme"].Value; - httpDataCollector.IsURLEnabled = getBoolValueFromXmlNode(httpDataCollectorConfigurationNode.SelectSingleNode("gather-url")); - httpDataCollector.IsSessionIDEnabled = getBoolValueFromXmlNode(httpDataCollectorConfigurationNode.SelectSingleNode("gather-session-id")); - httpDataCollector.IsUserPrincipalEnabled = getBoolValueFromXmlNode(httpDataCollectorConfigurationNode.SelectSingleNode("gather-user-principal")); + businessTransactionDiscoveryRule.RuleRawValue = makeXMLFormattedAndIndented(entryMatchPointTransactionConfigurationNode); - if (dataGathererConfigurationNode != null) + if (applicationComponentNode != null) { - httpDataCollector.DataGathererName = getStringValueFromXmlNode(dataGathererConfigurationNode.SelectSingleNode("display-name")); - httpDataCollector.DataGathererValue = getStringValueFromXmlNode(dataGathererConfigurationNode.SelectSingleNode("name")); + businessTransactionDiscoveryRule.TierName = applicationComponentNode.SelectSingleNode("name").InnerText; } - httpDataCollector.IsAssignedToBTs = false; + return businessTransactionDiscoveryRule; + } - httpDataCollector.RuleRawValue = makeXMLFormattedAndIndented(httpDataCollectorConfigurationNode); + private static BusinessTransactionEntryRule fillBusinessTransactionExcludeRule(XmlNode entryMatchPointConfigurationNode, XmlNode entryMatchPointTransactionConfigurationNode, XmlNode entryMatchPointCustomMatchPointConfigurationNode, EntityApplicationConfiguration applicationConfiguration, XmlNode applicationComponentNode) + { + BusinessTransactionEntryRule businessTransactionEntryRule = new BusinessTransactionEntryRule(); - if (entityBusinessTransactionConfigurationsList != null) - { - List entityBusinessTransactionConfigurationsForThisDCList = entityBusinessTransactionConfigurationsList.Where(b => b.AssignedMIDCs.Contains(String.Format("{0};", httpDataCollector.CollectorName)) == true).ToList(); + businessTransactionEntryRule.Controller = applicationConfiguration.Controller; + businessTransactionEntryRule.ControllerLink = applicationConfiguration.ControllerLink; + businessTransactionEntryRule.ApplicationName = applicationConfiguration.ApplicationName; + businessTransactionEntryRule.ApplicationID = applicationConfiguration.ApplicationID; + businessTransactionEntryRule.ApplicationLink = applicationConfiguration.ApplicationLink; - if (entityBusinessTransactionConfigurationsForThisDCList.Count > 0) - { - httpDataCollector.IsAssignedToBTs = true; - httpDataCollector.NumAssignedBTs = entityBusinessTransactionConfigurationsForThisDCList.Count; + businessTransactionEntryRule.AgentType = getStringValueFromXmlNode(entryMatchPointConfigurationNode.SelectSingleNode("agent-type")); + businessTransactionEntryRule.EntryPointType = entryMatchPointTransactionConfigurationNode.Attributes["transaction-entry-point-type"].Value; + businessTransactionEntryRule.RuleName = entryMatchPointCustomMatchPointConfigurationNode.Attributes["name"].Value; + businessTransactionEntryRule.IsExclusion = true; - StringBuilder sb = new StringBuilder(32 * entityBusinessTransactionConfigurationsForThisDCList.Count); - foreach (EntityBusinessTransactionConfiguration bt in entityBusinessTransactionConfigurationsForThisDCList) - { - sb.AppendFormat("{0}/{1};\n", bt.TierName, bt.BTName); - } - sb.Remove(sb.Length - 1, 1); - httpDataCollector.AssignedBTs = sb.ToString(); - } + XmlNode matchRule = entryMatchPointCustomMatchPointConfigurationNode.ChildNodes[0]; + fillMatchRuleDetails(businessTransactionEntryRule, matchRule); + + businessTransactionEntryRule.RuleRawValue = makeXMLFormattedAndIndented(entryMatchPointCustomMatchPointConfigurationNode); + + if (applicationComponentNode != null) + { + businessTransactionEntryRule.TierName = applicationComponentNode.SelectSingleNode("name").InnerText; } - return httpDataCollector; + return businessTransactionEntryRule; } - private static EntityTierConfiguration fillEntityTierConfiguration(XmlNode applicationComponentNode, EntityApplicationConfiguration applicationConfiguration, List tiersList, List entityBusinessTransactionConfigurationsList) + private static BusinessTransactionEntryRule fillBusinessTransactionEntryRule(XmlNode entryMatchPointConfigurationNode, XmlNode entryMatchPointCustomMatchPointConfigurationNode, EntityApplicationConfiguration applicationConfiguration, XmlNode applicationComponentNode, List businessTransactionsList) { - EntityTierConfiguration entityTierConfiguration = new EntityTierConfiguration(); + BusinessTransactionEntryRule businessTransactionEntryRule = new BusinessTransactionEntryRule(); - entityTierConfiguration.Controller = applicationConfiguration.Controller; - entityTierConfiguration.ControllerLink = applicationConfiguration.ControllerLink; - entityTierConfiguration.ApplicationName = applicationConfiguration.ApplicationName; - entityTierConfiguration.ApplicationID = applicationConfiguration.ApplicationID; - entityTierConfiguration.ApplicationLink = applicationConfiguration.ApplicationLink; + businessTransactionEntryRule.Controller = applicationConfiguration.Controller; + businessTransactionEntryRule.ControllerLink = applicationConfiguration.ControllerLink; + businessTransactionEntryRule.ApplicationName = applicationConfiguration.ApplicationName; + businessTransactionEntryRule.ApplicationID = applicationConfiguration.ApplicationID; + businessTransactionEntryRule.ApplicationLink = applicationConfiguration.ApplicationLink; - entityTierConfiguration.TierName = getStringValueFromXmlNode(applicationComponentNode.SelectSingleNode("name")); - entityTierConfiguration.TierDescription = getStringValueFromXmlNode(applicationComponentNode.SelectSingleNode("description")); - entityTierConfiguration.TierType = getStringValueFromXmlNode(applicationComponentNode.SelectSingleNode("component-type")); - if (tiersList != null) - { - EntityTier tier = tiersList.Where(t => t.TierName == entityTierConfiguration.TierName).FirstOrDefault(); - if (tier != null) - { - entityTierConfiguration.TierID = tier.TierID; - } - } + businessTransactionEntryRule.AgentType = getStringValueFromXmlNode(entryMatchPointConfigurationNode.SelectSingleNode("agent-type")); + businessTransactionEntryRule.EntryPointType = entryMatchPointCustomMatchPointConfigurationNode.Attributes["transaction-entry-point-type"].Value; + businessTransactionEntryRule.RuleName = getStringValueFromXmlNode(entryMatchPointCustomMatchPointConfigurationNode.SelectSingleNode("name")); + businessTransactionEntryRule.IsBackground = getBoolValueFromXmlNode(entryMatchPointCustomMatchPointConfigurationNode.SelectSingleNode("background")); + businessTransactionEntryRule.IsExclusion = false; - entityTierConfiguration.IsDynamicScalingEnabled = getBoolValueFromXmlNode(applicationComponentNode.SelectSingleNode("dynamic-scaling-enabled")); + XmlNode matchRule = entryMatchPointCustomMatchPointConfigurationNode.SelectSingleNode("match-rule").ChildNodes[0]; + fillMatchRuleDetails(businessTransactionEntryRule, matchRule); - entityTierConfiguration.MemoryConfig = makeXMLFormattedAndIndented(applicationComponentNode.SelectSingleNode("memory-configuration")); - entityTierConfiguration.CacheConfig = makeXMLFormattedAndIndented(applicationComponentNode.SelectSingleNode("cache-configuration")); - entityTierConfiguration.CustomCacheConfig = makeXMLFormattedAndIndented(applicationComponentNode.SelectSingleNode("custom-cache-configurations")); + businessTransactionEntryRule.RuleRawValue = makeXMLFormattedAndIndented(entryMatchPointCustomMatchPointConfigurationNode); - if (entityBusinessTransactionConfigurationsList != null) + if (applicationComponentNode != null) { - List businessTransactionsList = entityBusinessTransactionConfigurationsList.Where(b => b.TierID == entityTierConfiguration.TierID).ToList(); - entityTierConfiguration.NumBTs = businessTransactionsList.Count; + businessTransactionEntryRule.TierName = getStringValueFromXmlNode(applicationComponentNode.SelectSingleNode("name")); + } - var businessTransactionsListGroup = businessTransactionsList.GroupBy(b => b.BTType); - entityTierConfiguration.NumBTTypes = businessTransactionsListGroup.Count(); + if (businessTransactionsList != null) + { + List businessTransactionsForThisRule = new List(); + businessTransactionsForThisRule.AddRange(businessTransactionsList.Where(b => b.BTName == businessTransactionEntryRule.RuleName).ToList()); + businessTransactionsForThisRule.AddRange(businessTransactionsList.Where(b => b.BTName.StartsWith(String.Format("{0}.", businessTransactionEntryRule.RuleName))).ToList()); + businessTransactionsForThisRule.AddRange(businessTransactionsList.Where(b => b.BTNameOriginal == businessTransactionEntryRule.RuleName).ToList()); + businessTransactionsForThisRule.AddRange(businessTransactionsList.Where(b => b.BTNameOriginal.StartsWith(String.Format("{0}.", businessTransactionEntryRule.RuleName))).ToList()); + businessTransactionsForThisRule = businessTransactionsForThisRule.Distinct().ToList(); + businessTransactionEntryRule.NumDetectedBTs = businessTransactionsForThisRule.Count; + if (businessTransactionsForThisRule.Count > 0) + { + StringBuilder sb = new StringBuilder(32 * businessTransactionsForThisRule.Count); + foreach (EntityBusinessTransaction bt in businessTransactionsForThisRule) + { + sb.AppendFormat("{0}/{1};\n", bt.TierName, bt.BTName); + } + sb.Remove(sb.Length - 1, 1); + + businessTransactionEntryRule.DetectedBTs = sb.ToString(); + } } - return entityTierConfiguration; + return businessTransactionEntryRule; } - private static EntityBusinessTransactionConfiguration fillEntityBusinessTransactionConfiguration(XmlNode applicationComponentNode, XmlNode businessTransactionConfigurationtNode, EntityApplicationConfiguration applicationConfiguration, List tiersList, List businessTransactionsList) + private static BusinessTransactionEntryScope fillBusinessTransactionEntryScope(XmlNode scopeConfigurationNode, XmlNode scopeToRuleMappingConfigurationNode, EntityApplicationConfiguration applicationConfiguration) { - EntityBusinessTransactionConfiguration entityBusinessTransactionConfiguration = new EntityBusinessTransactionConfiguration(); + BusinessTransactionEntryScope businessTransactionEntryScope = new BusinessTransactionEntryScope(); - entityBusinessTransactionConfiguration.Controller = applicationConfiguration.Controller; - entityBusinessTransactionConfiguration.ControllerLink = applicationConfiguration.ControllerLink; - entityBusinessTransactionConfiguration.ApplicationName = applicationConfiguration.ApplicationName; - entityBusinessTransactionConfiguration.ApplicationID = applicationConfiguration.ApplicationID; - entityBusinessTransactionConfiguration.ApplicationLink = applicationConfiguration.ApplicationLink; + businessTransactionEntryScope.Controller = applicationConfiguration.Controller; + businessTransactionEntryScope.ControllerLink = applicationConfiguration.ControllerLink; + businessTransactionEntryScope.ApplicationName = applicationConfiguration.ApplicationName; + businessTransactionEntryScope.ApplicationID = applicationConfiguration.ApplicationID; + businessTransactionEntryScope.ApplicationLink = applicationConfiguration.ApplicationLink; - entityBusinessTransactionConfiguration.TierName = getStringValueFromXmlNode(applicationComponentNode.SelectSingleNode("name")); - if (tiersList != null) + businessTransactionEntryScope.ScopeName = scopeConfigurationNode.Attributes["scope-name"].Value; + businessTransactionEntryScope.ScopeType = scopeConfigurationNode.Attributes["scope-type"].Value; + businessTransactionEntryScope.Description = scopeConfigurationNode.Attributes["scope-description"].Value; + businessTransactionEntryScope.Version = Convert.ToInt32(scopeConfigurationNode.Attributes["scope-version"].Value); + + XmlNodeList includedTierNodeList = scopeConfigurationNode.SelectNodes("included-tiers/tier-name"); + businessTransactionEntryScope.NumTiers = includedTierNodeList.Count; + if (businessTransactionEntryScope.NumTiers > 0) { - EntityTier tier = tiersList.Where(t => t.TierName == entityBusinessTransactionConfiguration.TierName).FirstOrDefault(); - if (tier != null) + List includedTiersList = new List(businessTransactionEntryScope.NumTiers); + foreach (XmlNode includedTierNode in includedTierNodeList) { - entityBusinessTransactionConfiguration.TierID = tier.TierID; + includedTiersList.Add(includedTierNode.InnerText); } - } + includedTiersList.Sort(); - entityBusinessTransactionConfiguration.BTName = getStringValueFromXmlNode(businessTransactionConfigurationtNode.SelectSingleNode("name")); - entityBusinessTransactionConfiguration.BTType = businessTransactionConfigurationtNode.Attributes["transaction-entry-point-type"].Value; - if (businessTransactionsList != null) - { - EntityBusinessTransaction businessTransaction = businessTransactionsList.Where(b => b.BTName == entityBusinessTransactionConfiguration.BTName && b.TierName == entityBusinessTransactionConfiguration.TierName).FirstOrDefault(); - if (businessTransaction != null) + StringBuilder sb = new StringBuilder(32 * businessTransactionEntryScope.NumTiers); + foreach (string includedTier in includedTiersList) { - entityBusinessTransactionConfiguration.BTID = businessTransaction.BTID; + sb.AppendFormat("{0};\n", includedTier); } + sb.Remove(sb.Length - 1, 1); + businessTransactionEntryScope.IncludedTiers = sb.ToString(); } - entityBusinessTransactionConfiguration.IsExcluded = Convert.ToBoolean(businessTransactionConfigurationtNode.Attributes["excluded"].Value); - entityBusinessTransactionConfiguration.IsBackground = getBoolValueFromXmlNode(businessTransactionConfigurationtNode.SelectSingleNode("background")); - - entityBusinessTransactionConfiguration.IsEUMEnabled = getBoolValueFromXmlNode(businessTransactionConfigurationtNode.SelectSingleNode("enabled-for-eum")); - entityBusinessTransactionConfiguration.IsEUMPossible = getStringValueFromXmlNode(businessTransactionConfigurationtNode.SelectSingleNode("eum-auto-enable-possible")); - entityBusinessTransactionConfiguration.IsAnalyticsEnabled = getBoolValueFromXmlNode(businessTransactionConfigurationtNode.SelectSingleNode("analytics-enabled")); - - entityBusinessTransactionConfiguration.BTSLAConfig = makeXMLFormattedAndIndented(businessTransactionConfigurationtNode.SelectSingleNode("sla")); - entityBusinessTransactionConfiguration.BTSnapshotCollectionConfig = makeXMLFormattedAndIndented(businessTransactionConfigurationtNode.SelectSingleNode("business-transaction-config/snapshot-collection-policy")); - entityBusinessTransactionConfiguration.BTRequestThresholdConfig = makeXMLFormattedAndIndented(businessTransactionConfigurationtNode.SelectSingleNode("business-transaction-config/bt-request-thresholds")); - entityBusinessTransactionConfiguration.BTBackgroundSnapshotCollectionConfig = makeXMLFormattedAndIndented(businessTransactionConfigurationtNode.SelectSingleNode("background-business-transaction-config/snapshot-collection-policy")); - entityBusinessTransactionConfiguration.BTBackgroundRequestThresholdConfig = makeXMLFormattedAndIndented(businessTransactionConfigurationtNode.SelectSingleNode("background-business-transaction-config/bt-request-thresholds")); - - entityBusinessTransactionConfiguration.NumAssignedMIDCs = businessTransactionConfigurationtNode.SelectNodes("data-gatherer-config").Count; - entityBusinessTransactionConfiguration.AssignedMIDCs = String.Empty; - if (entityBusinessTransactionConfiguration.NumAssignedMIDCs > 0) + XmlNodeList ruleMappingNodeList = scopeToRuleMappingConfigurationNode.SelectNodes(String.Format("scope-rule-mapping[@scope-name='{0}']/rule", businessTransactionEntryScope.ScopeName)); + businessTransactionEntryScope.NumRules = ruleMappingNodeList.Count; + if (businessTransactionEntryScope.NumRules > 0) { - StringBuilder sb = new StringBuilder(32 * entityBusinessTransactionConfiguration.NumAssignedMIDCs); - foreach (XmlNode dataGathererXmlNode in businessTransactionConfigurationtNode.SelectNodes("data-gatherer-config")) + List ruleMappingList = new List(businessTransactionEntryScope.NumRules); + foreach (XmlNode ruleMappingNode in ruleMappingNodeList) { - sb.AppendFormat("{0};\n", dataGathererXmlNode.InnerText); + string ruleName = ruleMappingNode.Attributes["rule-name"].Value; + string ruleDescription = ruleMappingNode.Attributes["rule-description"].Value; + string ruleNameAndDescription = String.Empty; + if (ruleDescription.Length > 0 && ruleDescription != ruleName) + { + ruleMappingList.Add(String.Format("{0} ({1})", ruleName, ruleDescription)); + } + else + { + ruleMappingList.Add(ruleName); + } + } + ruleMappingList.Sort(); + + StringBuilder sb = new StringBuilder(32 * businessTransactionEntryScope.NumRules); + foreach (string ruleMapping in ruleMappingList) + { + sb.AppendFormat("{0};\n", ruleMapping); } sb.Remove(sb.Length - 1, 1); - entityBusinessTransactionConfiguration.AssignedMIDCs = sb.ToString(); + businessTransactionEntryScope.IncludedRules = sb.ToString(); } - return entityBusinessTransactionConfiguration; + return businessTransactionEntryScope; } - private static AgentCallGraphSetting fillAgentCallGraphSetting(XmlNode agentCallGraphSettingConfigurationNode, EntityApplicationConfiguration applicationConfiguration) + private static BusinessTransactionEntryRule20 fillBusinessTransactionEntryRule20(XmlNode ruleConfigurationNode, XmlNode scopeToRuleMappingConfigurationNode, EntityApplicationConfiguration applicationConfiguration, List businessTransactionsList) { - AgentCallGraphSetting agentCallGraphSetting = new AgentCallGraphSetting(); + BusinessTransactionEntryRule20 businessTransactionEntryRule = new BusinessTransactionEntryRule20(); - agentCallGraphSetting.Controller = applicationConfiguration.Controller; - agentCallGraphSetting.ControllerLink = applicationConfiguration.ControllerLink; - agentCallGraphSetting.ApplicationName = applicationConfiguration.ApplicationName; - agentCallGraphSetting.ApplicationID = applicationConfiguration.ApplicationID; - agentCallGraphSetting.ApplicationLink = applicationConfiguration.ApplicationLink; + businessTransactionEntryRule.Controller = applicationConfiguration.Controller; + businessTransactionEntryRule.ControllerLink = applicationConfiguration.ControllerLink; + businessTransactionEntryRule.ApplicationName = applicationConfiguration.ApplicationName; + businessTransactionEntryRule.ApplicationID = applicationConfiguration.ApplicationID; + businessTransactionEntryRule.ApplicationLink = applicationConfiguration.ApplicationLink; - agentCallGraphSetting.AgentType = agentCallGraphSettingConfigurationNode.Attributes["agent-type"].Value; + businessTransactionEntryRule.AgentType = ruleConfigurationNode.Attributes["agent-type"].Value; + businessTransactionEntryRule.RuleName = ruleConfigurationNode.Attributes["rule-name"].Value; + businessTransactionEntryRule.Description = ruleConfigurationNode.Attributes["rule-description"].Value; + businessTransactionEntryRule.Version = Convert.ToInt32(ruleConfigurationNode.Attributes["version"].Value); - agentCallGraphSetting.SamplingRate = getIntegerValueFromXmlNode(agentCallGraphSettingConfigurationNode.SelectSingleNode("sampling-rate")); - agentCallGraphSetting.IncludePackages = getStringValueFromXmlNode(agentCallGraphSettingConfigurationNode.SelectSingleNode("include-packages")); - agentCallGraphSetting.NumIncludePackages = agentCallGraphSetting.IncludePackages.Split('|').Count(); - agentCallGraphSetting.IncludePackages = agentCallGraphSetting.IncludePackages.Replace("|", ";\n"); - agentCallGraphSetting.ExcludePackages = getStringValueFromXmlNode(agentCallGraphSettingConfigurationNode.SelectSingleNode("exclude-packages")); - agentCallGraphSetting.NumExcludePackages = agentCallGraphSetting.ExcludePackages.Split('|').Count(); - agentCallGraphSetting.ExcludePackages = agentCallGraphSetting.ExcludePackages.Replace("|", ";\n"); - agentCallGraphSetting.MinSQLDuration = getIntegerValueFromXmlNode(agentCallGraphSettingConfigurationNode.SelectSingleNode("min-duration-for-db-calls")); - agentCallGraphSetting.IsRawSQLEnabled = getBoolValueFromXmlNode(agentCallGraphSettingConfigurationNode.SelectSingleNode("raw-sql")); - agentCallGraphSetting.IsHotSpotEnabled = getBoolValueFromXmlNode(agentCallGraphSettingConfigurationNode.SelectSingleNode("hotspots-enabled")); + businessTransactionEntryRule.IsEnabled = Convert.ToBoolean(ruleConfigurationNode.Attributes["enabled"].Value); + businessTransactionEntryRule.Priority = Convert.ToInt32(ruleConfigurationNode.Attributes["priority"].Value); - return agentCallGraphSetting; - } + JObject txRuleSettings = JObject.Parse(getStringValueFromXmlNode(ruleConfigurationNode.SelectSingleNode("tx-match-rule"))); + if (txRuleSettings != null) + { + if (txRuleSettings["type"].ToString() != "CUSTOM") + { + // This is likely autodiscovery rule, do not fill it out and bail + return null; + } - private static HealthRule fillHealthRule(XmlNode healthRuleConfigurationNode, EntityApplicationConfiguration applicationConfiguration) - { - HealthRule healthRule = new HealthRule(); + JToken txCustomRuleSettings = txRuleSettings["txcustomrule"]; + if (txCustomRuleSettings != null) + { + if (txCustomRuleSettings["type"].ToString() == "EXCLUDE") + { + businessTransactionEntryRule.IsExclusion = true; + } + else if (txCustomRuleSettings["type"].ToString() == "INCLUDE") + { + businessTransactionEntryRule.IsExclusion = false; + } - healthRule.Controller = applicationConfiguration.Controller; - healthRule.ControllerLink = applicationConfiguration.ControllerLink; - healthRule.ApplicationName = applicationConfiguration.ApplicationName; - healthRule.ApplicationID = applicationConfiguration.ApplicationID; - healthRule.ApplicationLink = applicationConfiguration.ApplicationLink; + businessTransactionEntryRule.EntryPointType = txCustomRuleSettings["txentrypointtype"].ToString(); - healthRule.RuleName = getStringValueFromXmlNode(healthRuleConfigurationNode.SelectSingleNode("name")); - healthRule.RuleType = getStringValueFromXmlNode(healthRuleConfigurationNode.SelectSingleNode("type")); - healthRule.Description = getStringValueFromXmlNode(healthRuleConfigurationNode.SelectSingleNode("description")); - healthRule.IsEnabled = getBoolValueFromXmlNode(healthRuleConfigurationNode.SelectSingleNode("enabled")); - healthRule.IsDefault = getBoolValueFromXmlNode(healthRuleConfigurationNode.SelectSingleNode("is-default")); - healthRule.IsAlwaysEnabled = getBoolValueFromXmlNode(healthRuleConfigurationNode.SelectSingleNode("always-enabled")); - healthRule.Schedule = getStringValueFromXmlNode(healthRuleConfigurationNode.SelectSingleNode("schedule")); - healthRule.DurationOfEvalPeriod = getIntegerValueFromXmlNode(healthRuleConfigurationNode.SelectSingleNode("duration-min")); - healthRule.WaitTimeAfterViolation = getIntegerValueFromXmlNode(healthRuleConfigurationNode.SelectSingleNode("wait-time-min")); + JToken isBackgroundProperty = txCustomRuleSettings["properties"].Where(p => p["name"].ToString() == "BACKGROUND_TASK").FirstOrDefault(); + if (isBackgroundProperty != null) + { + businessTransactionEntryRule.IsBackground = (bool)isBackgroundProperty["booleanvalue"]; + } - healthRule.AffectedEntitiesRawValue = makeXMLFormattedAndIndented(healthRuleConfigurationNode.SelectSingleNode("affected-entities-match-criteria")); - healthRule.CriticalConditionRawValue = makeXMLFormattedAndIndented(healthRuleConfigurationNode.SelectSingleNode("critical-execution-criteria")); - healthRule.WarningConditionRawValue = makeXMLFormattedAndIndented(healthRuleConfigurationNode.SelectSingleNode("warning-execution-criteria")); + businessTransactionEntryRule.MatchConditions = txCustomRuleSettings["matchconditions"].ToString(); + businessTransactionEntryRule.Actions = txCustomRuleSettings["actions"].ToString(); + businessTransactionEntryRule.Properties = txCustomRuleSettings["properties"].ToString(); + } + } - // Affected entity selection - XmlNode affectedWrapperXmlNode = healthRuleConfigurationNode.SelectSingleNode("affected-entities-match-criteria").ChildNodes[0]; - if (affectedWrapperXmlNode != null) + // I really want to do it, but some of our rules have apostrophes + // Spring WS - Base servlet for Spring's web framework + // And the query for scope-rule-mapping/rule[@rule-name='Spring WS - Base servlet for Spring's web framework'] breaks + // So going to do it the hard way + //XmlNode scopeForThisRuleNode = scopeToRuleMappingConfigurationNode.SelectSingleNode(String.Format("scope-rule-mapping/rule[@rule-name='{0}']", businessTransactionEntryRule.RuleName)); + foreach (XmlNode scopeNode in scopeToRuleMappingConfigurationNode.SelectNodes("scope-rule-mapping/rule")) { - healthRule.AffectsEntityType = getStringValueFromXmlNode(affectedWrapperXmlNode.SelectSingleNode("type")); - healthRule.AffectsEntityMatchType = getStringValueFromXmlNode(affectedWrapperXmlNode.SelectSingleNode("match-type")); - healthRule.AffectsEntityMatchPattern = getStringValueFromXmlNode(affectedWrapperXmlNode.SelectSingleNode("match-pattern")); - healthRule.AffectsEntityMatchIsInverse = getBoolValueFromXmlNode(affectedWrapperXmlNode.SelectSingleNode("inverse")); - healthRule.AffectsEntityMatchCriteria = makeXMLFormattedAndIndented(affectedWrapperXmlNode.SelectNodes("*[not(self::type) and not(self::match-type) and not(self::match-pattern) and not(self::inverse)]")); + if (scopeNode.Attributes["rule-name"].Value == businessTransactionEntryRule.RuleName) + { + businessTransactionEntryRule.ScopeName = scopeNode.ParentNode.Attributes["scope-name"].Value; + break; + } } - // XML can look like that for single element - // - // - // ANY - // 0 - // - // - // leaf - // condition 1 - // ABSOLUTE - // 0.0 - // GREATER_THAN - // - // false - // true - // - // leaf - // VALUE - // 0 - // false - // null - // - // LOGICAL_METRIC - // Agent|App|Availability - // - // - // - // - - // Or like that for multiple - // - // - // AGGREGATE - // 0 - // - // - // boolean - // AND - // - // leaf - // Average Response Time (ms) Baseline Condition - // BASELINE_STANDARD_DEVIATION - // 3.0 - // GREATER_THAN - // - // true - // false - // - // leaf - // VALUE - // 0 - // false - // null - // - // LOGICAL_METRIC - // Average Response Time (ms) - // - // - // - // - // leaf - // Calls per Minute Condition - // ABSOLUTE - // 50.0 - // GREATER_THAN - // - // false - // false - // - // leaf - // VALUE - // 0 - // false - // null - // - // LOGICAL_METRIC - // Calls per Minute - // - // - // - // - // - - // Critical - XmlNode criticalExecutionCriteriaXmlNode = healthRuleConfigurationNode.SelectSingleNode("critical-execution-criteria"); - if (criticalExecutionCriteriaXmlNode != null) + if (businessTransactionsList != null) { - healthRule.CriticalAggregateType = getStringValueFromXmlNode(criticalExecutionCriteriaXmlNode.SelectSingleNode("entity-aggregation-scope/type")); - - XmlNode firstCondition = criticalExecutionCriteriaXmlNode.SelectSingleNode("policy-condition"); - XmlNodeList condition1sXmlNodeList = criticalExecutionCriteriaXmlNode.SelectNodes("policy-condition//condition1"); - XmlNodeList condition2sXmlNodeList = criticalExecutionCriteriaXmlNode.SelectNodes("policy-condition//condition2"); - - List conditionsList = new List(); - if (condition1sXmlNodeList.Count == 0) - { - healthRule.CriticalEntityConditionType = "AND"; - conditionsList.Add(firstCondition); - } - else - { - healthRule.CriticalEntityConditionType = getStringValueFromXmlNode(criticalExecutionCriteriaXmlNode.SelectSingleNode("policy-condition/operator")); - foreach (XmlNode xmlNode in condition1sXmlNodeList) - { - conditionsList.Add(xmlNode); - } - conditionsList.Add(condition2sXmlNodeList[condition2sXmlNodeList.Count - 1]); - } - - healthRule.CriticalNumConditions = conditionsList.Count; - - int i = 1; - foreach (XmlNode conditionXmlNode in conditionsList) + List businessTransactionsForThisRule = new List(); + businessTransactionsForThisRule.AddRange(businessTransactionsList.Where(b => b.BTName == businessTransactionEntryRule.RuleName).ToList()); + businessTransactionsForThisRule.AddRange(businessTransactionsList.Where(b => b.BTName.StartsWith(String.Format("{0}.", businessTransactionEntryRule.RuleName))).ToList()); + businessTransactionsForThisRule.AddRange(businessTransactionsList.Where(b => b.BTNameOriginal == businessTransactionEntryRule.RuleName).ToList()); + businessTransactionsForThisRule.AddRange(businessTransactionsList.Where(b => b.BTNameOriginal.StartsWith(String.Format("{0}.", businessTransactionEntryRule.RuleName))).ToList()); + businessTransactionsForThisRule = businessTransactionsForThisRule.Distinct().ToList(); + businessTransactionEntryRule.NumDetectedBTs = businessTransactionsForThisRule.Count; + if (businessTransactionsForThisRule.Count > 0) { - healthRule.GetType().GetProperty(String.Format("Crit{0}Name", i)).SetValue(healthRule, getStringValueFromXmlNode(conditionXmlNode.SelectSingleNode("display-name")), null); - healthRule.GetType().GetProperty(String.Format("Crit{0}Type", i)).SetValue(healthRule, getStringValueFromXmlNode(conditionXmlNode.SelectSingleNode("condition-value-type")), null); - healthRule.GetType().GetProperty(String.Format("Crit{0}Value", i)).SetValue(healthRule, getLongValueFromXmlNode(conditionXmlNode.SelectSingleNode("condition-value")), null); - healthRule.GetType().GetProperty(String.Format("Crit{0}Operator", i)).SetValue(healthRule, getStringValueFromXmlNode(conditionXmlNode.SelectSingleNode("operator")), null); - healthRule.GetType().GetProperty(String.Format("Crit{0}Expression", i)).SetValue(healthRule, getStringValueFromXmlNode(conditionXmlNode.SelectSingleNode("condition-expression")), null); - if (getBoolValueFromXmlNode(conditionXmlNode.SelectSingleNode("use-active-baseline")) == true) - { - healthRule.GetType().GetProperty(String.Format("Crit{0}BaselineUsed", i)).SetValue(healthRule, "Default Baseline", null); - } - else + StringBuilder sb = new StringBuilder(32 * businessTransactionsForThisRule.Count); + foreach (EntityBusinessTransaction bt in businessTransactionsForThisRule) { - healthRule.GetType().GetProperty(String.Format("Crit{0}BaselineUsed", i)).SetValue(healthRule, getStringValueFromXmlNode(conditionXmlNode.SelectSingleNode("metric-baseline/name")), null); + sb.AppendFormat("{0}/{1};\n", bt.TierName, bt.BTName); } - healthRule.GetType().GetProperty(String.Format("Crit{0}TriggerOnNoData", i)).SetValue(healthRule, getBoolValueFromXmlNode(conditionXmlNode.SelectSingleNode("trigger-on-no-data")), null); - healthRule.GetType().GetProperty(String.Format("Crit{0}MetricName", i)).SetValue(healthRule, getStringValueFromXmlNode(conditionXmlNode.SelectSingleNode("metric-expression/metric-definition/logical-metric-name")), null); - healthRule.GetType().GetProperty(String.Format("Crit{0}MetricFunction", i)).SetValue(healthRule, getStringValueFromXmlNode(conditionXmlNode.SelectSingleNode("metric-expression/function-type")), null); - healthRule.GetType().GetProperty(String.Format("Crit{0}MetricExpressionConfig", i)).SetValue(healthRule, makeXMLFormattedAndIndented(conditionXmlNode.SelectSingleNode("metric-expression")), null); + sb.Remove(sb.Length - 1, 1); - i++; - if (i > 5) break; + businessTransactionEntryRule.DetectedBTs = sb.ToString(); } } - // Warning - XmlNode warningExecutionCriteriaXmlNode = healthRuleConfigurationNode.SelectSingleNode("warning-execution-criteria"); - if (warningExecutionCriteriaXmlNode != null) - { - healthRule.WarningAggregateType = getStringValueFromXmlNode(warningExecutionCriteriaXmlNode.SelectSingleNode("entity-aggregation-scope/type")); + businessTransactionEntryRule.RuleRawValue = makeXMLFormattedAndIndented(ruleConfigurationNode); - XmlNode firstCondition = warningExecutionCriteriaXmlNode.SelectSingleNode("policy-condition"); - XmlNodeList condition1sXmlNodeList = warningExecutionCriteriaXmlNode.SelectNodes("policy-condition//condition1"); - XmlNodeList condition2sXmlNodeList = warningExecutionCriteriaXmlNode.SelectNodes("policy-condition//condition2"); + return businessTransactionEntryRule; + } - List conditionsList = new List(); - if (condition1sXmlNodeList.Count == 0) + private static List fillBusinessTransactionDiscoveryRule20(XmlNode ruleConfigurationNode, XmlNode scopeToRuleMappingConfigurationNode, EntityApplicationConfiguration applicationConfiguration, List businessTransactionsList) + { + List businessTransactionDiscoveryRule20List = new List(); + + JObject txRuleSettings = JObject.Parse(getStringValueFromXmlNode(ruleConfigurationNode.SelectSingleNode("tx-match-rule"))); + if (txRuleSettings != null) + { + if (txRuleSettings["type"].ToString() != "AUTOMATIC_DISCOVERY") { - healthRule.WarningEntityConditionType = "AND"; - conditionsList.Add(firstCondition); + // This is not an autodiscovery rule, do not fill it out and bail + return null; } - else + + JArray txDiscoveryConfigs = (JArray)txRuleSettings["txautodiscoveryrule"]["autodiscoveryconfigs"]; + if (txDiscoveryConfigs != null && txDiscoveryConfigs.Count > 0) { - healthRule.WarningEntityConditionType = getStringValueFromXmlNode(warningExecutionCriteriaXmlNode.SelectSingleNode("policy-condition/operator")); - foreach (XmlNode xmlNode in condition1sXmlNodeList) + foreach (JToken txDiscoveryConfig in txDiscoveryConfigs) { - conditionsList.Add(xmlNode); - } - conditionsList.Add(condition2sXmlNodeList[condition2sXmlNodeList.Count - 1]); - } + BusinessTransactionDiscoveryRule20 businessTransactionDiscoveryRule20 = new BusinessTransactionDiscoveryRule20(); - healthRule.WarningNumConditions = conditionsList.Count; + businessTransactionDiscoveryRule20.Controller = applicationConfiguration.Controller; + businessTransactionDiscoveryRule20.ControllerLink = applicationConfiguration.ControllerLink; + businessTransactionDiscoveryRule20.ApplicationName = applicationConfiguration.ApplicationName; + businessTransactionDiscoveryRule20.ApplicationID = applicationConfiguration.ApplicationID; + businessTransactionDiscoveryRule20.ApplicationLink = applicationConfiguration.ApplicationLink; - int i = 1; - foreach (XmlNode conditionXmlNode in conditionsList) - { - healthRule.GetType().GetProperty(String.Format("Warn{0}Name", i)).SetValue(healthRule, getStringValueFromXmlNode(conditionXmlNode.SelectSingleNode("display-name")), null); - healthRule.GetType().GetProperty(String.Format("Warn{0}Type", i)).SetValue(healthRule, getStringValueFromXmlNode(conditionXmlNode.SelectSingleNode("condition-value-type")), null); - healthRule.GetType().GetProperty(String.Format("Warn{0}Value", i)).SetValue(healthRule, getLongValueFromXmlNode(conditionXmlNode.SelectSingleNode("condition-value")), null); - healthRule.GetType().GetProperty(String.Format("Warn{0}Operator", i)).SetValue(healthRule, getStringValueFromXmlNode(conditionXmlNode.SelectSingleNode("operator")), null); - healthRule.GetType().GetProperty(String.Format("Warn{0}Expression", i)).SetValue(healthRule, getStringValueFromXmlNode(conditionXmlNode.SelectSingleNode("condition-expression")), null); - if (getBoolValueFromXmlNode(conditionXmlNode.SelectSingleNode("use-active-baseline")) == true) - { - healthRule.GetType().GetProperty(String.Format("Warn{0}BaselineUsed", i)).SetValue(healthRule, "Default Baseline", null); - } - else - { - healthRule.GetType().GetProperty(String.Format("Warn{0}BaselineUsed", i)).SetValue(healthRule, getStringValueFromXmlNode(conditionXmlNode.SelectSingleNode("metric-baseline/name")), null); - } - healthRule.GetType().GetProperty(String.Format("Warn{0}TriggerOnNoData", i)).SetValue(healthRule, getBoolValueFromXmlNode(conditionXmlNode.SelectSingleNode("trigger-on-no-data")), null); - healthRule.GetType().GetProperty(String.Format("Warn{0}MetricName", i)).SetValue(healthRule, getStringValueFromXmlNode(conditionXmlNode.SelectSingleNode("metric-expression/metric-definition/logical-metric-name")), null); - healthRule.GetType().GetProperty(String.Format("Warn{0}MetricFunction", i)).SetValue(healthRule, getStringValueFromXmlNode(conditionXmlNode.SelectSingleNode("metric-expression/function-type")), null); - healthRule.GetType().GetProperty(String.Format("Warn{0}MetricExpressionConfig", i)).SetValue(healthRule, makeXMLFormattedAndIndented(conditionXmlNode.SelectSingleNode("metric-expression")), null); + businessTransactionDiscoveryRule20.AgentType = ruleConfigurationNode.Attributes["agent-type"].Value; + businessTransactionDiscoveryRule20.RuleName = ruleConfigurationNode.Attributes["rule-name"].Value; + businessTransactionDiscoveryRule20.Description = ruleConfigurationNode.Attributes["rule-description"].Value; + businessTransactionDiscoveryRule20.Version = Convert.ToInt32(ruleConfigurationNode.Attributes["version"].Value); - i++; - if (i > 5) break; + businessTransactionDiscoveryRule20.IsEnabled = Convert.ToBoolean(ruleConfigurationNode.Attributes["enabled"].Value); + businessTransactionDiscoveryRule20.Priority = Convert.ToInt32(ruleConfigurationNode.Attributes["priority"].Value); + + businessTransactionDiscoveryRule20.EntryPointType = txDiscoveryConfig["txentrypointtype"].ToString(); + businessTransactionDiscoveryRule20.IsMonitoringEnabled = (bool)txDiscoveryConfig["monitoringenabled"]; + businessTransactionDiscoveryRule20.IsDiscoveryEnabled = (bool)txDiscoveryConfig["discoveryenabled"]; + businessTransactionDiscoveryRule20.NamingConfigType = txDiscoveryConfig["namingschemetype"].ToString(); + + if (txDiscoveryConfig["httpautodiscovery"] != null) + { + businessTransactionDiscoveryRule20.HTTPAutoDiscovery = txDiscoveryConfig["httpautodiscovery"].ToString(); + } + + // I really want to do it, but some of our rules have apostrophes + // Spring WS - Base servlet for Spring's web framework + // And the query for scope-rule-mapping/rule[@rule-name='Spring WS - Base servlet for Spring's web framework'] breaks + // So going to do it the hard way + //XmlNode scopeForThisRuleNode = scopeToRuleMappingConfigurationNode.SelectSingleNode(String.Format("scope-rule-mapping/rule[@rule-name='{0}']", businessTransactionEntryRule.RuleName)); + foreach (XmlNode scopeNode in scopeToRuleMappingConfigurationNode.SelectNodes("scope-rule-mapping/rule")) + { + if (scopeNode.Attributes["rule-name"].Value == businessTransactionDiscoveryRule20.RuleName) + { + businessTransactionDiscoveryRule20.ScopeName = scopeNode.ParentNode.Attributes["scope-name"].Value; + break; + } + } + + businessTransactionDiscoveryRule20List.Add(businessTransactionDiscoveryRule20); + } } } - return healthRule; + return businessTransactionDiscoveryRule20List; } - private static void fillMatchRuleDetails(BusinessTransactionEntryRule businessTransactionEntryRule, XmlNode matchRule) + private static BackendDiscoveryRule fillBackendDiscoveryRule(XmlNode backendDiscoveryMatchPointConfigurationNode, XmlNode backendDiscoveryConfigurationNode, EntityApplicationConfiguration applicationConfiguration, XmlNode applicationComponentNode, List backendsList) { - // Enabled seems to be set inside of the match-rule, not couple of levels up - businessTransactionEntryRule.IsEnabled = Convert.ToBoolean(matchRule.SelectSingleNode("enabled").InnerText); - businessTransactionEntryRule.Priority = Convert.ToInt32(matchRule.SelectSingleNode("priority").InnerText); - businessTransactionEntryRule.IsExcluded = Convert.ToBoolean(matchRule.SelectSingleNode("excluded").InnerText); + BackendDiscoveryRule backendDiscoveryRule = new BackendDiscoveryRule(); - switch (businessTransactionEntryRule.EntryPointType) + backendDiscoveryRule.Controller = applicationConfiguration.Controller; + backendDiscoveryRule.ControllerLink = applicationConfiguration.ControllerLink; + backendDiscoveryRule.ApplicationName = applicationConfiguration.ApplicationName; + backendDiscoveryRule.ApplicationID = applicationConfiguration.ApplicationID; + backendDiscoveryRule.ApplicationLink = applicationConfiguration.ApplicationLink; + + backendDiscoveryRule.AgentType = getStringValueFromXmlNode(backendDiscoveryMatchPointConfigurationNode.SelectSingleNode("agent-type")); + backendDiscoveryRule.ExitType = getStringValueFromXmlNode(backendDiscoveryConfigurationNode.SelectSingleNode("exit-point-type")); + if (backendDiscoveryRule.ExitType == "CUSTOM") { - case "ASP_DOTNET": - businessTransactionEntryRule.MatchURI = makeXMLFormattedAndIndented(matchRule.SelectSingleNode("uri")); - //businessTransactionEntryRule.Parameters = getNameValueDetailsFromParametersCollection(matchRule.SelectSingleNode("parameters")); - businessTransactionEntryRule.Parameters = makeXMLFormattedAndIndented(matchRule.SelectSingleNode("parameters")); - businessTransactionEntryRule.SplitConfig = makeXMLFormattedAndIndented(matchRule.SelectSingleNode("split-config")); - businessTransactionEntryRule.MatchClass = makeXMLFormattedAndIndented(matchRule.SelectSingleNode("class-name")); + backendDiscoveryRule.ExitType = getStringValueFromXmlNode(backendDiscoveryConfigurationNode.SelectSingleNode("exit-point-subtype")); + } + backendDiscoveryRule.RuleName = getStringValueFromXmlNode(backendDiscoveryConfigurationNode.SelectSingleNode("name")); + backendDiscoveryRule.IsEnabled = getBoolValueFromXmlNode(backendDiscoveryConfigurationNode.SelectSingleNode("discovery-enabled")); + backendDiscoveryRule.IsCorrelationSupported = getBoolValueFromXmlNode(backendDiscoveryConfigurationNode.SelectSingleNode("supports-correlation")); + backendDiscoveryRule.IsCorrelationEnabled = getBoolValueFromXmlNode(backendDiscoveryConfigurationNode.SelectSingleNode("correlation-enabled")); + backendDiscoveryRule.Priority = getIntegerValueFromXmlNode(backendDiscoveryConfigurationNode.SelectSingleNode("priority")); - break; + backendDiscoveryRule.IdentityOptions = makeXMLFormattedAndIndented(backendDiscoveryConfigurationNode.SelectSingleNode("backend-identity-options")); + backendDiscoveryRule.DiscoveryConditions = makeXMLFormattedAndIndented(backendDiscoveryConfigurationNode.SelectSingleNode("backend-identity-options")); - case "NODEJS_WEB": - businessTransactionEntryRule.MatchURI = makeXMLFormattedAndIndented(matchRule.SelectSingleNode("uri")); - //businessTransactionEntryRule.Parameters = getNameValueDetailsFromParametersCollection(matchRule.SelectSingleNode("parameters")); - businessTransactionEntryRule.Parameters = makeXMLFormattedAndIndented(matchRule.SelectSingleNode("parameters")); - businessTransactionEntryRule.SplitConfig = makeXMLFormattedAndIndented(matchRule.SelectSingleNode("split-config")); - businessTransactionEntryRule.MatchClass = makeXMLFormattedAndIndented(matchRule.SelectSingleNode("http-method")); + backendDiscoveryRule.RuleRawValue = makeXMLFormattedAndIndented(backendDiscoveryConfigurationNode); - break; + if (applicationComponentNode != null) + { + backendDiscoveryRule.TierName = getStringValueFromXmlNode(applicationComponentNode.SelectSingleNode("name")); + } - case "PYTHON_WEB": - businessTransactionEntryRule.MatchURI = makeXMLFormattedAndIndented(matchRule.SelectSingleNode("uri")); - //businessTransactionEntryRule.Parameters = getNameValueDetailsFromParametersCollection(matchRule.SelectSingleNode("parameters")); - businessTransactionEntryRule.Parameters = makeXMLFormattedAndIndented(matchRule.SelectSingleNode("parameters")); - businessTransactionEntryRule.SplitConfig = makeXMLFormattedAndIndented(matchRule.SelectSingleNode("split-config")); - businessTransactionEntryRule.MatchClass = makeXMLFormattedAndIndented(matchRule.SelectSingleNode("http-method")); + if (backendsList != null) + { + List backendsForThisRule = new List(); - break; + // Try to find them by match first + backendsForThisRule.AddRange(backendsList.Where(b => b.BackendName == backendDiscoveryRule.RuleName).ToList()); + backendsForThisRule.AddRange(backendsList.Where(b => b.BackendName.StartsWith(String.Format("{0}", backendDiscoveryRule.RuleName))).ToList()); + backendsForThisRule = backendsForThisRule.Distinct().ToList(); + if (backendsForThisRule.Count == 0) + { + // If by name doesn't match, let's do by type + // Nope, this doesn't work. Backend is differentiated by the Agent Type + // Because of that the backend matches every darn type starting with Default + // backendsForThisRule.AddRange(backendsList.Where(b => b.BackendType == backendDiscoveryRule.ExitType).ToList()); + } + backendDiscoveryRule.NumDetectedBackends = backendsForThisRule.Count; + if (backendsForThisRule.Count > 0) + { + StringBuilder sb = new StringBuilder(32 * backendsForThisRule.Count); + foreach (EntityBackend backend in backendsForThisRule) + { + sb.AppendFormat("{0} ({1});\n", backend.BackendName, backend.BackendID); + } + sb.Remove(sb.Length - 1, 1); - case "POCO": - // Background is really only set for POCOs - businessTransactionEntryRule.IsBackground = Convert.ToBoolean(matchRule.SelectSingleNode("background").InnerText); - businessTransactionEntryRule.MatchClass = makeXMLFormattedAndIndented(matchRule.SelectSingleNode("match-class")); - businessTransactionEntryRule.MatchMethod = makeXMLFormattedAndIndented(matchRule.SelectSingleNode("match-method")); - businessTransactionEntryRule.SplitConfig = makeXMLFormattedAndIndented(matchRule.SelectSingleNode("split-config")); + backendDiscoveryRule.DetectedBackends = sb.ToString(); + } + } - break; + return backendDiscoveryRule; + } - case "POJO": - // Background is really only set for POJOs - businessTransactionEntryRule.IsBackground = Convert.ToBoolean(matchRule.SelectSingleNode("background").InnerText); - businessTransactionEntryRule.MatchClass = makeXMLFormattedAndIndented(matchRule.SelectSingleNode("match-class")); - businessTransactionEntryRule.MatchMethod = makeXMLFormattedAndIndented(matchRule.SelectSingleNode("match-method")); - businessTransactionEntryRule.SplitConfig = makeXMLFormattedAndIndented(matchRule.SelectSingleNode("split-config")); + private static CustomExitRule fillCustomExitRule(XmlNode backendDiscoveryMatchPointConfigurationNode, XmlNode customExitConfigurationNode, EntityApplicationConfiguration applicationConfiguration, XmlNode applicationComponentNode, List backendsList) + { + CustomExitRule customExitRule = new CustomExitRule(); - break; + customExitRule.Controller = applicationConfiguration.Controller; + customExitRule.ControllerLink = applicationConfiguration.ControllerLink; + customExitRule.ApplicationName = applicationConfiguration.ApplicationName; + customExitRule.ApplicationID = applicationConfiguration.ApplicationID; + customExitRule.ApplicationLink = applicationConfiguration.ApplicationLink; - case "SERVLET": - businessTransactionEntryRule.MatchURI = makeXMLFormattedAndIndented(matchRule.SelectSingleNode("uri")); - //businessTransactionEntryRule.Parameters = getNameValueDetailsFromParametersCollection(matchRule.SelectSingleNode("parameters")); - businessTransactionEntryRule.Parameters = makeXMLFormattedAndIndented(matchRule.SelectSingleNode("parameters")); - businessTransactionEntryRule.SplitConfig = makeXMLFormattedAndIndented(matchRule.SelectSingleNode("split-config")); - businessTransactionEntryRule.MatchClass = makeXMLFormattedAndIndented(matchRule.SelectSingleNode("class-name")); + customExitRule.AgentType = getStringValueFromXmlNode(backendDiscoveryMatchPointConfigurationNode.SelectSingleNode("agent-type")); + customExitRule.ExitType = getStringValueFromXmlNode(customExitConfigurationNode.SelectSingleNode("type")); - break; + customExitRule.RuleName = getStringValueFromXmlNode(customExitConfigurationNode.SelectSingleNode("name")); + customExitRule.MatchClass = getStringValueFromXmlNode(customExitConfigurationNode.SelectSingleNode("instrumentation-point/pojo-method-definition/class-name")); + customExitRule.MatchMethod = getStringValueFromXmlNode(customExitConfigurationNode.SelectSingleNode("instrumentation-point/pojo-method-definition/method-name")); + customExitRule.MatchType = getStringValueFromXmlNode(customExitConfigurationNode.SelectSingleNode("instrumentation-point/pojo-method-definition/match-type")); + customExitRule.MatchParameterTypes = getStringValueFromXmlNode(customExitConfigurationNode.SelectSingleNode("instrumentation-point/pojo-method-definition/method-parameter-types")); - case "STRUTS_ACTION": - businessTransactionEntryRule.MatchClass = makeXMLFormattedAndIndented(matchRule.SelectSingleNode("action-class-name")); - businessTransactionEntryRule.MatchMethod = makeXMLFormattedAndIndented(matchRule.SelectSingleNode("action-method-name")); - // There is also Struts Action Name in the UI, but I don't know how it shows up + customExitRule.IsApplyToAllBTs = getBoolValueFromXmlNode(customExitConfigurationNode.SelectSingleNode("instrumentation-point/apply-to-all-bts")); - break; + customExitRule.DataCollectorsConfig = makeXMLFormattedAndIndented(customExitConfigurationNode.SelectNodes("instrumentation-point/method-invocation-data-gatherer-config")); + customExitRule.InfoPointsConfig = makeXMLFormattedAndIndented(customExitConfigurationNode.SelectNodes("instrumentation-point/info-point-metric-definition")); - case "WCF": - businessTransactionEntryRule.MatchClass = makeXMLFormattedAndIndented(matchRule.SelectSingleNode("web-service-name")); - businessTransactionEntryRule.MatchMethod = makeXMLFormattedAndIndented(matchRule.SelectSingleNode("operation-name")); + customExitRule.RuleRawValue = makeXMLFormattedAndIndented(customExitConfigurationNode); - break; + if (applicationComponentNode != null) + { + customExitRule.TierName = getStringValueFromXmlNode(applicationComponentNode.SelectSingleNode("name")); + } - case "WEB": - businessTransactionEntryRule.MatchURI = makeXMLFormattedAndIndented(matchRule.SelectSingleNode("uri")); - //businessTransactionEntryRule.Parameters = getNameValueDetailsFromParametersCollection(matchRule.SelectSingleNode("parameters")); - businessTransactionEntryRule.Parameters = makeXMLFormattedAndIndented(matchRule.SelectSingleNode("parameters")); - businessTransactionEntryRule.SplitConfig = makeXMLFormattedAndIndented(matchRule.SelectSingleNode("split-config")); + if (backendsList != null) + { + List backendsForThisRule = new List(); - break; + // Try to find them by match first + backendsForThisRule.AddRange(backendsList.Where(b => b.BackendName == customExitRule.RuleName).ToList()); + backendsForThisRule.AddRange(backendsList.Where(b => b.BackendName.StartsWith(String.Format("{0}", customExitRule.RuleName))).ToList()); + backendsForThisRule = backendsForThisRule.Distinct().ToList(); + if (backendsForThisRule.Count == 0) + { + // If by name doesn't match, let's do by type + // Nope, this doesn't work. Backend is differentiated by the Agent Type + // Because of that the backend matches every darn type starting with Default + // backendsForThisRule.AddRange(backendsList.Where(b => b.BackendType == customExitRule.ExitType).ToList()); + } + customExitRule.NumDetectedBackends = backendsForThisRule.Count; + if (backendsForThisRule.Count > 0) + { + StringBuilder sb = new StringBuilder(32 * backendsForThisRule.Count); + foreach (EntityBackend backend in backendsForThisRule) + { + sb.AppendFormat("{0} ({1});\n", backend.BackendName, backend.BackendID); + } + sb.Remove(sb.Length - 1, 1); - default: - break; + customExitRule.DetectedBackends = sb.ToString(); + } } + return customExitRule; } - #endregion + private static InformationPointRule fillInformationPointRule(XmlNode informationPointConfigurationNode, EntityApplicationConfiguration applicationConfiguration) + { + InformationPointRule informationPointRule = new InformationPointRule(); - #region Flowmap detail conversion functions + informationPointRule.Controller = applicationConfiguration.Controller; + informationPointRule.ControllerLink = applicationConfiguration.ControllerLink; + informationPointRule.ApplicationName = applicationConfiguration.ApplicationName; + informationPointRule.ApplicationID = applicationConfiguration.ApplicationID; + informationPointRule.ApplicationLink = applicationConfiguration.ApplicationLink; - private static void convertFlowmapApplication(ProgramOptions programOptions, JobConfiguration jobConfiguration, JobTarget jobTarget, EntityApplication applicationRow, string metricsFolderPath) - { - string metricsEntityFolderPath = Path.Combine( - metricsFolderPath, - APPLICATION_TYPE_SHORT); + informationPointRule.AgentType = getStringValueFromXmlNode(informationPointConfigurationNode.SelectSingleNode("agent-type")); - string flowmapDataFilePath = Path.Combine( - metricsEntityFolderPath, - String.Format(EXTRACT_ENTITY_FLOWMAP_FILE_NAME, jobConfiguration.Input.ExpandedTimeRange.From, jobConfiguration.Input.ExpandedTimeRange.To)); + informationPointRule.RuleName = getStringValueFromXmlNode(informationPointConfigurationNode.SelectSingleNode("name")); + informationPointRule.MatchClass = getStringValueFromXmlNode(informationPointConfigurationNode.SelectSingleNode("pojo-method-definition/class-name")); + informationPointRule.MatchMethod = getStringValueFromXmlNode(informationPointConfigurationNode.SelectSingleNode("pojo-method-definition/method-name")); + informationPointRule.MatchType = getStringValueFromXmlNode(informationPointConfigurationNode.SelectSingleNode("pojo-method-definition/match-type")); + informationPointRule.MatchParameterTypes = getStringValueFromXmlNode(informationPointConfigurationNode.SelectSingleNode("pojo-method-definition/method-parameter-types")); + informationPointRule.MatchCondition = makeXMLFormattedAndIndented(informationPointConfigurationNode.SelectSingleNode("pojo-method-definition/match-condition")); - JObject flowmapData = FileIOHelper.loadJObjectFromFile(flowmapDataFilePath); - if (flowmapData == null) - { - return; - } + informationPointRule.InfoPointsConfig = makeXMLFormattedAndIndented(informationPointConfigurationNode.SelectNodes("info-point-metric-definition")); - long fromTimeUnix = convertToUnixTimestamp(jobConfiguration.Input.ExpandedTimeRange.From); - long toTimeUnix = convertToUnixTimestamp(jobConfiguration.Input.ExpandedTimeRange.To); - long differenceInMinutes = (toTimeUnix - fromTimeUnix) / (60000); - string DEEPLINK_THIS_TIMERANGE = String.Format(DEEPLINK_TIMERANGE_BETWEEN_TIMES, toTimeUnix, fromTimeUnix, differenceInMinutes); + informationPointRule.RuleRawValue = makeXMLFormattedAndIndented(informationPointConfigurationNode); - List activityFlowsList = null; - JArray flowmapEntities = (JArray)flowmapData["nodes"]; - JArray flowmapEntityConnections = (JArray)flowmapData["edges"]; - if (flowmapEntities != null && flowmapEntityConnections != null) - { - activityFlowsList = new List(flowmapEntities.Count + flowmapEntityConnections.Count); + return informationPointRule; + } - // Process each of the individual Tiers, Backends and Applications as individual icons on the flow map - foreach (JToken entity in flowmapEntities) - { - ActivityFlow activityFlowRow = new ActivityFlow(); - activityFlowRow.MetricsIDs = new List(3); + private static AgentConfigurationProperty fillAgentConfigurationProperty(XmlNode agentConfigurationNode, XmlNode agentPropertyDefinitionConfigurationNode, XmlNode agentPropertyValueConfigurationNode, EntityApplicationConfiguration applicationConfiguration, XmlNode applicationComponentNode) + { + AgentConfigurationProperty agentConfigurationProperty = new AgentConfigurationProperty(); - activityFlowRow.Controller = applicationRow.Controller; - activityFlowRow.ApplicationName = applicationRow.ApplicationName; - activityFlowRow.ApplicationID = applicationRow.ApplicationID; + agentConfigurationProperty.Controller = applicationConfiguration.Controller; + agentConfigurationProperty.ControllerLink = applicationConfiguration.ControllerLink; + agentConfigurationProperty.ApplicationName = applicationConfiguration.ApplicationName; + agentConfigurationProperty.ApplicationID = applicationConfiguration.ApplicationID; + agentConfigurationProperty.ApplicationLink = applicationConfiguration.ApplicationLink; - activityFlowRow.ControllerLink = String.Format(DEEPLINK_CONTROLLER, activityFlowRow.Controller, DEEPLINK_THIS_TIMERANGE); - activityFlowRow.ApplicationLink = String.Format(DEEPLINK_APPLICATION, activityFlowRow.Controller, activityFlowRow.ApplicationID, DEEPLINK_THIS_TIMERANGE); + agentConfigurationProperty.AgentType = getStringValueFromXmlNode(agentConfigurationNode.SelectSingleNode("agent-type")); - activityFlowRow.Duration = (int)(jobConfiguration.Input.ExpandedTimeRange.To - jobConfiguration.Input.ExpandedTimeRange.From).Duration().TotalMinutes; - activityFlowRow.From = jobConfiguration.Input.ExpandedTimeRange.From.ToLocalTime(); - activityFlowRow.To = jobConfiguration.Input.ExpandedTimeRange.To.ToLocalTime(); - activityFlowRow.FromUtc = jobConfiguration.Input.ExpandedTimeRange.From; - activityFlowRow.ToUtc = jobConfiguration.Input.ExpandedTimeRange.To; + agentConfigurationProperty.PropertyName = getStringValueFromXmlNode(agentPropertyDefinitionConfigurationNode.SelectSingleNode("name")); + agentConfigurationProperty.PropertyType = getStringValueFromXmlNode(agentPropertyDefinitionConfigurationNode.SelectSingleNode("type")); + agentConfigurationProperty.Description = getStringValueFromXmlNode(agentPropertyDefinitionConfigurationNode.SelectSingleNode("description")); + agentConfigurationProperty.IsRequired = getBoolValueFromXmlNode(agentPropertyDefinitionConfigurationNode.SelectSingleNode("required")); - activityFlowRow.CallDirection = "Total"; + switch (agentConfigurationProperty.PropertyType) + { + case "STRING": + agentConfigurationProperty.StringValue = getStringValueFromXmlNode(agentPropertyValueConfigurationNode.SelectSingleNode("string-value")); + agentConfigurationProperty.StringDefaultValue = getStringValueFromXmlNode(agentPropertyDefinitionConfigurationNode.SelectSingleNode("default-string-value")); + agentConfigurationProperty.StringMaxLength = getIntegerValueFromXmlNode(agentPropertyDefinitionConfigurationNode.SelectSingleNode("string-max-length")); + agentConfigurationProperty.StringAllowedValues = getStringValueFromXmlNode(agentPropertyDefinitionConfigurationNode.SelectSingleNode("allowed-string-values")); - activityFlowRow.FromEntityID = (long)entity["idNum"]; - activityFlowRow.FromName = entity["name"].ToString(); + agentConfigurationProperty.IsDefault = (agentConfigurationProperty.StringDefaultValue == agentConfigurationProperty.StringDefaultValue); + break; - string deepLinkMetricTemplateInMetricBrowser = DEEPLINK_METRIC_APPLICATION_TARGET_METRIC_ID; - long entityIdForMetricBrowser = activityFlowRow.ApplicationID; - switch (entity["entityType"].ToString()) - { - case ENTITY_TYPE_TIER: - deepLinkMetricTemplateInMetricBrowser = DEEPLINK_METRIC_TIER_TARGET_METRIC_ID; - entityIdForMetricBrowser = activityFlowRow.FromEntityID; - activityFlowRow.CallType = "Total"; - activityFlowRow.FromType = "Tier"; - activityFlowRow.FromLink = String.Format(DEEPLINK_TIER, activityFlowRow.Controller, activityFlowRow.ApplicationID, activityFlowRow.FromEntityID, DEEPLINK_THIS_TIMERANGE); - break; + case "BOOLEAN": + agentConfigurationProperty.BooleanValue = getBoolValueFromXmlNode(agentPropertyValueConfigurationNode.SelectSingleNode("string-value")); + agentConfigurationProperty.BooleanDefaultValue = getBoolValueFromXmlNode(agentPropertyDefinitionConfigurationNode.SelectSingleNode("default-string-value")); - case ENTITY_TYPE_BACKEND: - activityFlowRow.CallType = "Total"; - activityFlowRow.FromType = "Backend"; - activityFlowRow.FromLink = String.Format(DEEPLINK_BACKEND, activityFlowRow.Controller, activityFlowRow.ApplicationID, activityFlowRow.FromEntityID, DEEPLINK_THIS_TIMERANGE); - break; + agentConfigurationProperty.IsDefault = (agentConfigurationProperty.BooleanValue == agentConfigurationProperty.BooleanDefaultValue); + break; - case ENTITY_TYPE_APPLICATION: - deepLinkMetricTemplateInMetricBrowser = DEEPLINK_METRIC_TIER_TARGET_METRIC_ID; - activityFlowRow.CallType = "Total"; - activityFlowRow.FromType = "Application"; - activityFlowRow.FromLink = String.Format(DEEPLINK_APPLICATION, activityFlowRow.Controller, activityFlowRow.FromEntityID, DEEPLINK_THIS_TIMERANGE); - break; + case "INTEGER": + agentConfigurationProperty.IntegerValue = getIntegerValueFromXmlNode(agentPropertyValueConfigurationNode.SelectSingleNode("string-value")); + agentConfigurationProperty.IntegerDefaultValue = getIntegerValueFromXmlNode(agentPropertyDefinitionConfigurationNode.SelectSingleNode("default-string-value")); + agentConfigurationProperty.IntegerMinValue = getIntegerValueFromXmlNode(agentPropertyDefinitionConfigurationNode.SelectSingleNode("lower-numeric-bound")); + agentConfigurationProperty.IntegerMaxValue = getIntegerValueFromXmlNode(agentPropertyDefinitionConfigurationNode.SelectSingleNode("upper-numeric-bound")); - default: - activityFlowRow.CallType = entity["entityType"].ToString(); - activityFlowRow.FromType = "Unknown"; - break; - } + agentConfigurationProperty.IsDefault = (agentConfigurationProperty.IntegerValue == agentConfigurationProperty.IntegerDefaultValue); + break; - //activityFlowRow.ToName = activityFlowRow.FromName; - //activityFlowRow.ToType= activityFlowRow.FromType; - activityFlowRow.ToEntityID = activityFlowRow.FromEntityID; - //activityFlowRow.ToLink = activityFlowRow.FromLink; + default: + agentConfigurationProperty.StringValue = getStringValueFromXmlNode(agentPropertyValueConfigurationNode.SelectSingleNode("string-value")); + break; + } - activityFlowRow.ART = (long)entity["stats"]["averageResponseTime"]["metricValue"]; - activityFlowRow.CPM = (long)entity["stats"]["callsPerMinute"]["metricValue"]; - activityFlowRow.EPM = (long)entity["stats"]["errorsPerMinute"]["metricValue"]; - activityFlowRow.Calls = (long)entity["stats"]["numberOfCalls"]["metricValue"]; - activityFlowRow.Errors = (long)entity["stats"]["numberOfErrors"]["metricValue"]; + if (applicationComponentNode != null) + { + agentConfigurationProperty.TierName = getStringValueFromXmlNode(applicationComponentNode.SelectSingleNode("name")); + } - if (activityFlowRow.ART < 0) { activityFlowRow.ART = 0; } - if (activityFlowRow.CPM < 0) { activityFlowRow.ART = 0; } - if (activityFlowRow.EPM < 0) { activityFlowRow.EPM = 0; } - if (activityFlowRow.Calls < 0) { activityFlowRow.Calls = 0; } - if (activityFlowRow.Errors < 0) { activityFlowRow.Errors = 0; } + return agentConfigurationProperty; + } - activityFlowRow.ErrorsPercentage = Math.Round((double)(double)activityFlowRow.Errors / (double)activityFlowRow.Calls * 100, 2); - if (Double.IsNaN(activityFlowRow.ErrorsPercentage) == true) activityFlowRow.ErrorsPercentage = 0; + private static MethodInvocationDataCollector fillMethodInvocationDataCollector(XmlNode methodInvocationDataCollectorConfigurationNode, XmlNode dataGathererConfigurationNode, EntityApplicationConfiguration applicationConfiguration, List entityBusinessTransactionConfigurationsList) + { + MethodInvocationDataCollector methodInvocationDataCollector = new MethodInvocationDataCollector(); - activityFlowRow.MetricsIDs.Add((int)entity["stats"]["averageResponseTime"]["metricId"]); - activityFlowRow.MetricsIDs.Add((int)entity["stats"]["callsPerMinute"]["metricId"]); - activityFlowRow.MetricsIDs.Add((int)entity["stats"]["errorsPerMinute"]["metricId"]); - activityFlowRow.MetricsIDs.RemoveAll(m => m == -1); + methodInvocationDataCollector.Controller = applicationConfiguration.Controller; + methodInvocationDataCollector.ControllerLink = applicationConfiguration.ControllerLink; + methodInvocationDataCollector.ApplicationName = applicationConfiguration.ApplicationName; + methodInvocationDataCollector.ApplicationID = applicationConfiguration.ApplicationID; + methodInvocationDataCollector.ApplicationLink = applicationConfiguration.ApplicationLink; - if (activityFlowRow.MetricsIDs != null && activityFlowRow.MetricsIDs.Count > 0) - { - StringBuilder sb = new StringBuilder(128); - foreach (int metricID in activityFlowRow.MetricsIDs) - { - sb.Append(String.Format(deepLinkMetricTemplateInMetricBrowser, entityIdForMetricBrowser, metricID)); - sb.Append(","); - } - sb.Remove(sb.Length - 1, 1); - activityFlowRow.MetricLink = String.Format(DEEPLINK_METRIC, activityFlowRow.Controller, activityFlowRow.ApplicationID, sb.ToString(), DEEPLINK_THIS_TIMERANGE); - } + methodInvocationDataCollector.CollectorName = getStringValueFromXmlNode(methodInvocationDataCollectorConfigurationNode.SelectSingleNode("name")); - activityFlowsList.Add(activityFlowRow); - } + methodInvocationDataCollector.IsAPM = Convert.ToBoolean(methodInvocationDataCollectorConfigurationNode.Attributes["enabled-for-apm"].Value); + methodInvocationDataCollector.IsAnalytics = Convert.ToBoolean(methodInvocationDataCollectorConfigurationNode.Attributes["enabled-for-analytics"].Value); + methodInvocationDataCollector.IsAssignedToNewBTs = Convert.ToBoolean(methodInvocationDataCollectorConfigurationNode.Attributes["attach-to-new-bts"].Value); - // Process each call between Tiers, Tiers and Backends, and Tiers and Applications - foreach (JToken entityConnection in flowmapEntityConnections) - { - ActivityFlow activityFlowRowTemplate = new ActivityFlow(); + methodInvocationDataCollector.MatchClass = getStringValueFromXmlNode(methodInvocationDataCollectorConfigurationNode.SelectSingleNode("pojo-method-definition/class-name")); + methodInvocationDataCollector.MatchMethod = getStringValueFromXmlNode(methodInvocationDataCollectorConfigurationNode.SelectSingleNode("pojo-method-definition/method-name")); + methodInvocationDataCollector.MatchType = getStringValueFromXmlNode(methodInvocationDataCollectorConfigurationNode.SelectSingleNode("pojo-method-definition/match-type")); + methodInvocationDataCollector.MatchParameterTypes = getStringValueFromXmlNode(methodInvocationDataCollectorConfigurationNode.SelectSingleNode("pojo-method-definition/method-parameter-types")); - // Prepare the row - activityFlowRowTemplate.MetricsIDs = new List(3); + methodInvocationDataCollector.DataGathererName = getStringValueFromXmlNode(dataGathererConfigurationNode.SelectSingleNode("name")); + methodInvocationDataCollector.DataGathererType = getStringValueFromXmlNode(dataGathererConfigurationNode.SelectSingleNode("gatherer-type")); + methodInvocationDataCollector.DataGathererPosition = getIntegerValueFromXmlNode(dataGathererConfigurationNode.SelectSingleNode("position")); + methodInvocationDataCollector.DataGathererTransform = getStringValueFromXmlNode(dataGathererConfigurationNode.SelectSingleNode("transformer-type")); + methodInvocationDataCollector.DataGathererGetter = getStringValueFromXmlNode(dataGathererConfigurationNode.SelectSingleNode("transformer-value")); - activityFlowRowTemplate.Controller = applicationRow.Controller; - activityFlowRowTemplate.ApplicationName = applicationRow.ApplicationName; - activityFlowRowTemplate.ApplicationID = applicationRow.ApplicationID; + methodInvocationDataCollector.IsAssignedToBTs = false; - activityFlowRowTemplate.ControllerLink = String.Format(DEEPLINK_CONTROLLER, activityFlowRowTemplate.Controller, DEEPLINK_THIS_TIMERANGE); - activityFlowRowTemplate.ApplicationLink = String.Format(DEEPLINK_APPLICATION, activityFlowRowTemplate.Controller, activityFlowRowTemplate.ApplicationID, DEEPLINK_THIS_TIMERANGE); + methodInvocationDataCollector.RuleRawValue = makeXMLFormattedAndIndented(methodInvocationDataCollectorConfigurationNode); - activityFlowRowTemplate.Duration = (int)(jobConfiguration.Input.ExpandedTimeRange.To - jobConfiguration.Input.ExpandedTimeRange.From).Duration().TotalMinutes; - activityFlowRowTemplate.From = jobConfiguration.Input.ExpandedTimeRange.From.ToLocalTime(); - activityFlowRowTemplate.To = jobConfiguration.Input.ExpandedTimeRange.To.ToLocalTime(); - activityFlowRowTemplate.FromUtc = jobConfiguration.Input.ExpandedTimeRange.From; - activityFlowRowTemplate.ToUtc = jobConfiguration.Input.ExpandedTimeRange.To; + if (entityBusinessTransactionConfigurationsList != null) + { + List entityBusinessTransactionConfigurationsForThisDCList = entityBusinessTransactionConfigurationsList.Where(b => b.AssignedMIDCs.Contains(String.Format("{0};", methodInvocationDataCollector.CollectorName)) == true).ToList(); - activityFlowRowTemplate.CallDirection = "Exit"; + if (entityBusinessTransactionConfigurationsForThisDCList.Count > 0) + { + methodInvocationDataCollector.IsAssignedToBTs = true; + methodInvocationDataCollector.NumAssignedBTs = entityBusinessTransactionConfigurationsForThisDCList.Count; - activityFlowRowTemplate.FromEntityID = (long)entityConnection["sourceNodeDefinition"]["entityId"]; - JObject entity = (JObject)flowmapEntities.Where(e => (long)e["idNum"] == activityFlowRowTemplate.FromEntityID && e["entityType"].ToString() == entityConnection["sourceNodeDefinition"]["entityType"].ToString()).FirstOrDefault(); - if (entity != null) + StringBuilder sb = new StringBuilder(32 * entityBusinessTransactionConfigurationsForThisDCList.Count); + foreach (EntityBusinessTransactionConfiguration bt in entityBusinessTransactionConfigurationsForThisDCList) { - activityFlowRowTemplate.FromName = entity["name"].ToString(); + sb.AppendFormat("{0}/{1};\n", bt.TierName, bt.BTName); } - string deepLinkMetricTemplateInMetricBrowser = DEEPLINK_METRIC_APPLICATION_TARGET_METRIC_ID; - long entityIdForMetricBrowser = activityFlowRowTemplate.ApplicationID; - switch (entityConnection["sourceNodeDefinition"]["entityType"].ToString()) - { - case ENTITY_TYPE_TIER: - deepLinkMetricTemplateInMetricBrowser = DEEPLINK_METRIC_TIER_TARGET_METRIC_ID; - entityIdForMetricBrowser = activityFlowRowTemplate.FromEntityID; - activityFlowRowTemplate.FromType = "Tier"; - activityFlowRowTemplate.FromLink = String.Format(DEEPLINK_TIER, activityFlowRowTemplate.Controller, activityFlowRowTemplate.ApplicationID, activityFlowRowTemplate.FromEntityID, DEEPLINK_THIS_TIMERANGE); - break; - - case ENTITY_TYPE_BACKEND: - activityFlowRowTemplate.FromType = "Backend"; - activityFlowRowTemplate.FromLink = String.Format(DEEPLINK_BACKEND, activityFlowRowTemplate.Controller, activityFlowRowTemplate.ApplicationID, activityFlowRowTemplate.FromEntityID, DEEPLINK_THIS_TIMERANGE); - break; + sb.Remove(sb.Length - 1, 1); + methodInvocationDataCollector.AssignedBTs = sb.ToString(); + } + } - case ENTITY_TYPE_APPLICATION: - deepLinkMetricTemplateInMetricBrowser = DEEPLINK_METRIC_TIER_TARGET_METRIC_ID; - activityFlowRowTemplate.FromType = "Application"; - activityFlowRowTemplate.FromLink = String.Format(DEEPLINK_APPLICATION, activityFlowRowTemplate.Controller, activityFlowRowTemplate.FromEntityID, DEEPLINK_THIS_TIMERANGE); - break; + return methodInvocationDataCollector; + } - default: - activityFlowRowTemplate.FromName = entityConnection["sourceNode"].ToString(); - activityFlowRowTemplate.FromType = entityConnection["sourceNodeDefinition"]["entityType"].ToString(); - break; - } + private static HTTPDataCollector fillHTTPDataCollector(XmlNode httpDataCollectorConfigurationNode, XmlNode dataGathererConfigurationNode, EntityApplicationConfiguration applicationConfiguration, List entityBusinessTransactionConfigurationsList) + { + HTTPDataCollector httpDataCollector = new HTTPDataCollector(); - activityFlowRowTemplate.ToEntityID = (long)entityConnection["targetNodeDefinition"]["entityId"]; - entity = (JObject)flowmapEntities.Where(e => (long)e["idNum"] == activityFlowRowTemplate.ToEntityID && e["entityType"].ToString() == entityConnection["targetNodeDefinition"]["entityType"].ToString()).FirstOrDefault(); - if (entity != null) - { - activityFlowRowTemplate.ToName = entity["name"].ToString(); - } - switch (entityConnection["targetNodeDefinition"]["entityType"].ToString()) - { - case ENTITY_TYPE_TIER: - activityFlowRowTemplate.ToType = "Tier"; - activityFlowRowTemplate.ToLink = String.Format(DEEPLINK_TIER, activityFlowRowTemplate.Controller, activityFlowRowTemplate.ApplicationID, activityFlowRowTemplate.ToEntityID, DEEPLINK_THIS_TIMERANGE); - break; + httpDataCollector.Controller = applicationConfiguration.Controller; + httpDataCollector.ControllerLink = applicationConfiguration.ControllerLink; + httpDataCollector.ApplicationName = applicationConfiguration.ApplicationName; + httpDataCollector.ApplicationID = applicationConfiguration.ApplicationID; + httpDataCollector.ApplicationLink = applicationConfiguration.ApplicationLink; - case ENTITY_TYPE_BACKEND: - activityFlowRowTemplate.ToType = "Backend"; - activityFlowRowTemplate.ToLink = String.Format(DEEPLINK_BACKEND, activityFlowRowTemplate.Controller, activityFlowRowTemplate.ApplicationID, activityFlowRowTemplate.ToEntityID, DEEPLINK_THIS_TIMERANGE); - break; + httpDataCollector.CollectorName = getStringValueFromXmlNode(httpDataCollectorConfigurationNode.SelectSingleNode("name")); - case ENTITY_TYPE_APPLICATION: - activityFlowRowTemplate.ToType = "Application"; - activityFlowRowTemplate.ToLink = String.Format(DEEPLINK_APPLICATION, activityFlowRowTemplate.Controller, activityFlowRowTemplate.ToEntityID, DEEPLINK_THIS_TIMERANGE); - break; + httpDataCollector.IsAPM = Convert.ToBoolean(httpDataCollectorConfigurationNode.Attributes["enabled-for-apm"].Value); + httpDataCollector.IsAnalytics = Convert.ToBoolean(httpDataCollectorConfigurationNode.Attributes["enabled-for-analytics"].Value); + httpDataCollector.IsAssignedToNewBTs = Convert.ToBoolean(httpDataCollectorConfigurationNode.Attributes["attach-to-new-bts"].Value); - default: - activityFlowRowTemplate.ToName = entityConnection["targetNode"].ToString(); - activityFlowRowTemplate.ToType = entityConnection["targetNodeDefinition"]["entityType"].ToString(); - break; - } + httpDataCollector.IsURLEnabled = getBoolValueFromXmlNode(httpDataCollectorConfigurationNode.SelectSingleNode("gather-url")); + httpDataCollector.IsSessionIDEnabled = getBoolValueFromXmlNode(httpDataCollectorConfigurationNode.SelectSingleNode("gather-session-id")); + httpDataCollector.IsUserPrincipalEnabled = getBoolValueFromXmlNode(httpDataCollectorConfigurationNode.SelectSingleNode("gather-user-principal")); - // Process each of the stats nodes, duplicating things as we need them - foreach (JToken entityConnectionStat in entityConnection["stats"]) - { - ActivityFlow activityFlowRow = activityFlowRowTemplate.Clone(); + if (dataGathererConfigurationNode != null) + { + httpDataCollector.DataGathererName = getStringValueFromXmlNode(dataGathererConfigurationNode.SelectSingleNode("display-name")); + httpDataCollector.DataGathererValue = getStringValueFromXmlNode(dataGathererConfigurationNode.SelectSingleNode("name")); + } - activityFlowRow.CallType = entityConnectionStat["exitPointCall"]["exitPointType"].ToString(); - if (((bool)entityConnectionStat["exitPointCall"]["synchronous"]) == false) - { - activityFlowRow.CallType = String.Format("{0} async", activityFlowRow.CallType); - } + httpDataCollector.IsAssignedToBTs = false; - if (entityConnectionStat["averageResponseTime"].HasValues == true) - { - activityFlowRow.ART = (long)entityConnectionStat["averageResponseTime"]["metricValue"]; - activityFlowRow.MetricsIDs.Add((long)entityConnectionStat["averageResponseTime"]["metricId"]); - } - if (entityConnectionStat["callsPerMinute"].HasValues == true) - { - activityFlowRow.CPM = (long)entityConnectionStat["callsPerMinute"]["metricValue"]; - activityFlowRow.MetricsIDs.Add((long)entityConnectionStat["callsPerMinute"]["metricId"]); - } - if (entityConnectionStat["errorsPerMinute"].HasValues == true) - { - activityFlowRow.EPM = (long)entityConnectionStat["errorsPerMinute"]["metricValue"]; - activityFlowRow.MetricsIDs.Add((long)entityConnectionStat["errorsPerMinute"]["metricId"]); - } - if (entityConnectionStat["numberOfCalls"].HasValues == true) { activityFlowRow.Calls = (long)entityConnectionStat["numberOfCalls"]["metricValue"]; } - if (entityConnectionStat["numberOfErrors"].HasValues == true) { activityFlowRow.Errors = (long)entityConnectionStat["numberOfErrors"]["metricValue"]; } + httpDataCollector.RuleRawValue = makeXMLFormattedAndIndented(httpDataCollectorConfigurationNode); - if (activityFlowRow.ART < 0) { activityFlowRow.ART = 0; } - if (activityFlowRow.CPM < 0) { activityFlowRow.ART = 0; } - if (activityFlowRow.EPM < 0) { activityFlowRow.EPM = 0; } - if (activityFlowRow.Calls < 0) { activityFlowRow.Calls = 0; } - if (activityFlowRow.Errors < 0) { activityFlowRow.Errors = 0; } + if (entityBusinessTransactionConfigurationsList != null) + { + List entityBusinessTransactionConfigurationsForThisDCList = entityBusinessTransactionConfigurationsList.Where(b => b.AssignedMIDCs.Contains(String.Format("{0};", httpDataCollector.CollectorName)) == true).ToList(); - activityFlowRow.ErrorsPercentage = Math.Round((double)(double)activityFlowRow.Errors / (double)activityFlowRow.Calls * 100, 2); - if (Double.IsNaN(activityFlowRow.ErrorsPercentage) == true) activityFlowRow.ErrorsPercentage = 0; - - activityFlowRow.MetricsIDs.RemoveAll(m => m == -1); + if (entityBusinessTransactionConfigurationsForThisDCList.Count > 0) + { + httpDataCollector.IsAssignedToBTs = true; + httpDataCollector.NumAssignedBTs = entityBusinessTransactionConfigurationsForThisDCList.Count; - if (activityFlowRow.MetricsIDs != null && activityFlowRow.MetricsIDs.Count > 0) - { - StringBuilder sb = new StringBuilder(128); - foreach (int metricID in activityFlowRow.MetricsIDs) - { - sb.Append(String.Format(deepLinkMetricTemplateInMetricBrowser, entityIdForMetricBrowser, metricID)); - sb.Append(","); - } - sb.Remove(sb.Length - 1, 1); - activityFlowRow.MetricLink = String.Format(DEEPLINK_METRIC, activityFlowRow.Controller, activityFlowRow.ApplicationID, sb.ToString(), DEEPLINK_THIS_TIMERANGE); - } - activityFlowsList.Add(activityFlowRow); + StringBuilder sb = new StringBuilder(32 * entityBusinessTransactionConfigurationsForThisDCList.Count); + foreach (EntityBusinessTransactionConfiguration bt in entityBusinessTransactionConfigurationsForThisDCList) + { + sb.AppendFormat("{0}/{1};\n", bt.TierName, bt.BTName); } + sb.Remove(sb.Length - 1, 1); + httpDataCollector.AssignedBTs = sb.ToString(); } } - // Sort them - activityFlowsList = activityFlowsList.OrderBy(a => a.CallDirection).ThenBy(a => a.FromType).ThenBy(a => a.FromName).ThenBy(a => a.ToName).ThenBy(a => a.CallType).ThenBy(a => a.CPM).ToList(); + return httpDataCollector; + } - string activityGridReportFileName = Path.Combine( - metricsEntityFolderPath, - CONVERT_ACTIVITY_GRID_FILE_NAME); + private static EntityTierConfiguration fillEntityTierConfiguration(XmlNode applicationComponentNode, EntityApplicationConfiguration applicationConfiguration, List tiersList, List entityBusinessTransactionConfigurationsList) + { + EntityTierConfiguration entityTierConfiguration = new EntityTierConfiguration(); - FileIOHelper.writeListToCSVFile(activityFlowsList, new ActivityFlowReportMap(), activityGridReportFileName); + entityTierConfiguration.Controller = applicationConfiguration.Controller; + entityTierConfiguration.ControllerLink = applicationConfiguration.ControllerLink; + entityTierConfiguration.ApplicationName = applicationConfiguration.ApplicationName; + entityTierConfiguration.ApplicationID = applicationConfiguration.ApplicationID; + entityTierConfiguration.ApplicationLink = applicationConfiguration.ApplicationLink; - return; - } + entityTierConfiguration.TierName = getStringValueFromXmlNode(applicationComponentNode.SelectSingleNode("name")); + entityTierConfiguration.TierDescription = getStringValueFromXmlNode(applicationComponentNode.SelectSingleNode("description")); + entityTierConfiguration.TierType = getStringValueFromXmlNode(applicationComponentNode.SelectSingleNode("component-type")); + if (tiersList != null) + { + EntityTier tier = tiersList.Where(t => t.TierName == entityTierConfiguration.TierName).FirstOrDefault(); + if (tier != null) + { + entityTierConfiguration.TierID = tier.TierID; + } + } - private static void convertFlowmapTier(ProgramOptions programOptions, JobConfiguration jobConfiguration, JobTarget jobTarget, EntityTier tierRow, string metricsFolderPath) - { - string metricsEntityFolderPath = Path.Combine( - metricsFolderPath, - TIERS_TYPE_SHORT, - getShortenedEntityNameForFileSystem(tierRow.TierName, tierRow.TierID)); + entityTierConfiguration.IsDynamicScalingEnabled = getBoolValueFromXmlNode(applicationComponentNode.SelectSingleNode("dynamic-scaling-enabled")); - string flowmapDataFilePath = Path.Combine( - metricsEntityFolderPath, - String.Format(EXTRACT_ENTITY_FLOWMAP_FILE_NAME, jobConfiguration.Input.ExpandedTimeRange.From, jobConfiguration.Input.ExpandedTimeRange.To)); + entityTierConfiguration.MemoryConfig = makeXMLFormattedAndIndented(applicationComponentNode.SelectSingleNode("memory-configuration")); + entityTierConfiguration.CacheConfig = makeXMLFormattedAndIndented(applicationComponentNode.SelectSingleNode("cache-configuration")); + entityTierConfiguration.CustomCacheConfig = makeXMLFormattedAndIndented(applicationComponentNode.SelectSingleNode("custom-cache-configurations")); - JObject flowmapData = FileIOHelper.loadJObjectFromFile(flowmapDataFilePath); - if (flowmapData == null) + if (entityBusinessTransactionConfigurationsList != null) { - return; + List businessTransactionsList = entityBusinessTransactionConfigurationsList.Where(b => b.TierID == entityTierConfiguration.TierID).ToList(); + entityTierConfiguration.NumBTs = businessTransactionsList.Count; + + var businessTransactionsListGroup = businessTransactionsList.GroupBy(b => b.BTType); + entityTierConfiguration.NumBTTypes = businessTransactionsListGroup.Count(); } - long fromTimeUnix = convertToUnixTimestamp(jobConfiguration.Input.ExpandedTimeRange.From); - long toTimeUnix = convertToUnixTimestamp(jobConfiguration.Input.ExpandedTimeRange.To); - long differenceInMinutes = (toTimeUnix - fromTimeUnix) / (60000); - string DEEPLINK_THIS_TIMERANGE = String.Format(DEEPLINK_TIMERANGE_BETWEEN_TIMES, toTimeUnix, fromTimeUnix, differenceInMinutes); + return entityTierConfiguration; + } - List activityFlowsList = null; - JArray flowmapEntities = (JArray)flowmapData["nodes"]; - JArray flowmapEntityConnections = (JArray)flowmapData["edges"]; - if (flowmapEntities != null && flowmapEntityConnections != null) - { - activityFlowsList = new List(flowmapEntityConnections.Count); + private static EntityBusinessTransactionConfiguration fillEntityBusinessTransactionConfiguration(XmlNode applicationComponentNode, XmlNode businessTransactionConfigurationtNode, EntityApplicationConfiguration applicationConfiguration, List tiersList, List businessTransactionsList) + { + EntityBusinessTransactionConfiguration entityBusinessTransactionConfiguration = new EntityBusinessTransactionConfiguration(); - // For Tiers, not going to process individual entities, but only connecting lines + entityBusinessTransactionConfiguration.Controller = applicationConfiguration.Controller; + entityBusinessTransactionConfiguration.ControllerLink = applicationConfiguration.ControllerLink; + entityBusinessTransactionConfiguration.ApplicationName = applicationConfiguration.ApplicationName; + entityBusinessTransactionConfiguration.ApplicationID = applicationConfiguration.ApplicationID; + entityBusinessTransactionConfiguration.ApplicationLink = applicationConfiguration.ApplicationLink; - // Process each call between Tiers, Tiers and Backends, and Tiers and Applications - foreach (JToken entityConnection in flowmapEntityConnections) + entityBusinessTransactionConfiguration.TierName = getStringValueFromXmlNode(applicationComponentNode.SelectSingleNode("name")); + if (tiersList != null) + { + EntityTier tier = tiersList.Where(t => t.TierName == entityBusinessTransactionConfiguration.TierName).FirstOrDefault(); + if (tier != null) { - ActivityFlow activityFlowRowTemplate = new ActivityFlow(); - - // Prepare the row - activityFlowRowTemplate.MetricsIDs = new List(3); + entityBusinessTransactionConfiguration.TierID = tier.TierID; + } + } - activityFlowRowTemplate.Controller = tierRow.Controller; - activityFlowRowTemplate.ApplicationName = tierRow.ApplicationName; - activityFlowRowTemplate.ApplicationID = tierRow.ApplicationID; + entityBusinessTransactionConfiguration.BTName = getStringValueFromXmlNode(businessTransactionConfigurationtNode.SelectSingleNode("name")); + entityBusinessTransactionConfiguration.BTType = businessTransactionConfigurationtNode.Attributes["transaction-entry-point-type"].Value; + if (businessTransactionsList != null) + { + EntityBusinessTransaction businessTransaction = businessTransactionsList.Where(b => b.BTName == entityBusinessTransactionConfiguration.BTName && b.TierName == entityBusinessTransactionConfiguration.TierName).FirstOrDefault(); + if (businessTransaction != null) + { + entityBusinessTransactionConfiguration.BTID = businessTransaction.BTID; + } + } - activityFlowRowTemplate.ControllerLink = String.Format(DEEPLINK_CONTROLLER, activityFlowRowTemplate.Controller, DEEPLINK_THIS_TIMERANGE); - activityFlowRowTemplate.ApplicationLink = String.Format(DEEPLINK_APPLICATION, activityFlowRowTemplate.Controller, activityFlowRowTemplate.ApplicationID, DEEPLINK_THIS_TIMERANGE); + entityBusinessTransactionConfiguration.IsExcluded = Convert.ToBoolean(businessTransactionConfigurationtNode.Attributes["excluded"].Value); + entityBusinessTransactionConfiguration.IsBackground = getBoolValueFromXmlNode(businessTransactionConfigurationtNode.SelectSingleNode("background")); - activityFlowRowTemplate.Duration = (int)(jobConfiguration.Input.ExpandedTimeRange.To - jobConfiguration.Input.ExpandedTimeRange.From).Duration().TotalMinutes; - activityFlowRowTemplate.From = jobConfiguration.Input.ExpandedTimeRange.From.ToLocalTime(); - activityFlowRowTemplate.To = jobConfiguration.Input.ExpandedTimeRange.To.ToLocalTime(); - activityFlowRowTemplate.FromUtc = jobConfiguration.Input.ExpandedTimeRange.From; - activityFlowRowTemplate.ToUtc = jobConfiguration.Input.ExpandedTimeRange.To; + entityBusinessTransactionConfiguration.IsEUMEnabled = getBoolValueFromXmlNode(businessTransactionConfigurationtNode.SelectSingleNode("enabled-for-eum")); + entityBusinessTransactionConfiguration.IsEUMPossible = getStringValueFromXmlNode(businessTransactionConfigurationtNode.SelectSingleNode("eum-auto-enable-possible")); + entityBusinessTransactionConfiguration.IsAnalyticsEnabled = getBoolValueFromXmlNode(businessTransactionConfigurationtNode.SelectSingleNode("analytics-enabled")); - activityFlowRowTemplate.FromEntityID = (long)entityConnection["sourceNodeDefinition"]["entityId"]; - JObject entity = (JObject)flowmapEntities.Where(e => (long)e["idNum"] == activityFlowRowTemplate.FromEntityID && e["entityType"].ToString() == entityConnection["sourceNodeDefinition"]["entityType"].ToString()).FirstOrDefault(); - if (entity != null) - { - activityFlowRowTemplate.FromName = entity["name"].ToString(); - } - string deepLinkMetricTemplateInMetricBrowser = DEEPLINK_METRIC_APPLICATION_TARGET_METRIC_ID; - long entityIdForMetricBrowser = activityFlowRowTemplate.ApplicationID; - switch (entityConnection["sourceNodeDefinition"]["entityType"].ToString()) - { - case ENTITY_TYPE_TIER: - deepLinkMetricTemplateInMetricBrowser = DEEPLINK_METRIC_TIER_TARGET_METRIC_ID; - entityIdForMetricBrowser = activityFlowRowTemplate.FromEntityID; - activityFlowRowTemplate.FromType = "Tier"; - activityFlowRowTemplate.FromLink = String.Format(DEEPLINK_TIER, activityFlowRowTemplate.Controller, activityFlowRowTemplate.ApplicationID, activityFlowRowTemplate.FromEntityID, DEEPLINK_THIS_TIMERANGE); - break; + entityBusinessTransactionConfiguration.BTSLAConfig = makeXMLFormattedAndIndented(businessTransactionConfigurationtNode.SelectSingleNode("sla")); + entityBusinessTransactionConfiguration.BTSnapshotCollectionConfig = makeXMLFormattedAndIndented(businessTransactionConfigurationtNode.SelectSingleNode("business-transaction-config/snapshot-collection-policy")); + entityBusinessTransactionConfiguration.BTRequestThresholdConfig = makeXMLFormattedAndIndented(businessTransactionConfigurationtNode.SelectSingleNode("business-transaction-config/bt-request-thresholds")); + entityBusinessTransactionConfiguration.BTBackgroundSnapshotCollectionConfig = makeXMLFormattedAndIndented(businessTransactionConfigurationtNode.SelectSingleNode("background-business-transaction-config/snapshot-collection-policy")); + entityBusinessTransactionConfiguration.BTBackgroundRequestThresholdConfig = makeXMLFormattedAndIndented(businessTransactionConfigurationtNode.SelectSingleNode("background-business-transaction-config/bt-request-thresholds")); - case ENTITY_TYPE_BACKEND: - activityFlowRowTemplate.FromType = "Backend"; - activityFlowRowTemplate.FromLink = String.Format(DEEPLINK_BACKEND, activityFlowRowTemplate.Controller, activityFlowRowTemplate.ApplicationID, activityFlowRowTemplate.FromEntityID, DEEPLINK_THIS_TIMERANGE); - break; + entityBusinessTransactionConfiguration.NumAssignedMIDCs = businessTransactionConfigurationtNode.SelectNodes("data-gatherer-config").Count; + entityBusinessTransactionConfiguration.AssignedMIDCs = String.Empty; + if (entityBusinessTransactionConfiguration.NumAssignedMIDCs > 0) + { + StringBuilder sb = new StringBuilder(32 * entityBusinessTransactionConfiguration.NumAssignedMIDCs); + foreach (XmlNode dataGathererXmlNode in businessTransactionConfigurationtNode.SelectNodes("data-gatherer-config")) + { + sb.AppendFormat("{0};\n", dataGathererXmlNode.InnerText); + } + sb.Remove(sb.Length - 1, 1); + entityBusinessTransactionConfiguration.AssignedMIDCs = sb.ToString(); + } - case ENTITY_TYPE_APPLICATION: - deepLinkMetricTemplateInMetricBrowser = DEEPLINK_METRIC_TIER_TARGET_METRIC_ID; - activityFlowRowTemplate.FromType = "Application"; - activityFlowRowTemplate.FromLink = String.Format(DEEPLINK_APPLICATION, activityFlowRowTemplate.Controller, activityFlowRowTemplate.FromEntityID, DEEPLINK_THIS_TIMERANGE); - break; + return entityBusinessTransactionConfiguration; + } - default: - activityFlowRowTemplate.FromName = entityConnection["sourceNode"].ToString(); - activityFlowRowTemplate.FromType = entityConnection["sourceNodeDefinition"]["entityType"].ToString(); - break; - } + private static AgentCallGraphSetting fillAgentCallGraphSetting(XmlNode agentCallGraphSettingConfigurationNode, EntityApplicationConfiguration applicationConfiguration) + { + AgentCallGraphSetting agentCallGraphSetting = new AgentCallGraphSetting(); - activityFlowRowTemplate.ToEntityID = (long)entityConnection["targetNodeDefinition"]["entityId"]; - entity = (JObject)flowmapEntities.Where(e => (long)e["idNum"] == activityFlowRowTemplate.ToEntityID && e["entityType"].ToString() == entityConnection["targetNodeDefinition"]["entityType"].ToString()).FirstOrDefault(); - if (entity != null) - { - activityFlowRowTemplate.ToName = entity["name"].ToString(); - } - switch (entityConnection["targetNodeDefinition"]["entityType"].ToString()) - { - case ENTITY_TYPE_TIER: - activityFlowRowTemplate.ToType = "Tier"; - activityFlowRowTemplate.ToLink = String.Format(DEEPLINK_TIER, activityFlowRowTemplate.Controller, activityFlowRowTemplate.ApplicationID, activityFlowRowTemplate.ToEntityID, DEEPLINK_THIS_TIMERANGE); - break; + agentCallGraphSetting.Controller = applicationConfiguration.Controller; + agentCallGraphSetting.ControllerLink = applicationConfiguration.ControllerLink; + agentCallGraphSetting.ApplicationName = applicationConfiguration.ApplicationName; + agentCallGraphSetting.ApplicationID = applicationConfiguration.ApplicationID; + agentCallGraphSetting.ApplicationLink = applicationConfiguration.ApplicationLink; - case ENTITY_TYPE_BACKEND: - activityFlowRowTemplate.ToType = "Backend"; - activityFlowRowTemplate.ToLink = String.Format(DEEPLINK_BACKEND, activityFlowRowTemplate.Controller, activityFlowRowTemplate.ApplicationID, activityFlowRowTemplate.ToEntityID, DEEPLINK_THIS_TIMERANGE); - break; + agentCallGraphSetting.AgentType = agentCallGraphSettingConfigurationNode.Attributes["agent-type"].Value; - case ENTITY_TYPE_APPLICATION: - activityFlowRowTemplate.ToType = "Application"; - activityFlowRowTemplate.ToLink = String.Format(DEEPLINK_APPLICATION, activityFlowRowTemplate.Controller, activityFlowRowTemplate.ToEntityID, DEEPLINK_THIS_TIMERANGE); - break; + agentCallGraphSetting.SamplingRate = getIntegerValueFromXmlNode(agentCallGraphSettingConfigurationNode.SelectSingleNode("sampling-rate")); + agentCallGraphSetting.IncludePackages = getStringValueFromXmlNode(agentCallGraphSettingConfigurationNode.SelectSingleNode("include-packages")); + agentCallGraphSetting.NumIncludePackages = agentCallGraphSetting.IncludePackages.Split('|').Count(); + agentCallGraphSetting.IncludePackages = agentCallGraphSetting.IncludePackages.Replace("|", ";\n"); + agentCallGraphSetting.ExcludePackages = getStringValueFromXmlNode(agentCallGraphSettingConfigurationNode.SelectSingleNode("exclude-packages")); + agentCallGraphSetting.NumExcludePackages = agentCallGraphSetting.ExcludePackages.Split('|').Count(); + agentCallGraphSetting.ExcludePackages = agentCallGraphSetting.ExcludePackages.Replace("|", ";\n"); + agentCallGraphSetting.MinSQLDuration = getIntegerValueFromXmlNode(agentCallGraphSettingConfigurationNode.SelectSingleNode("min-duration-for-db-calls")); + agentCallGraphSetting.IsRawSQLEnabled = getBoolValueFromXmlNode(agentCallGraphSettingConfigurationNode.SelectSingleNode("raw-sql")); + agentCallGraphSetting.IsHotSpotEnabled = getBoolValueFromXmlNode(agentCallGraphSettingConfigurationNode.SelectSingleNode("hotspots-enabled")); - default: - activityFlowRowTemplate.ToName = entityConnection["targetNode"].ToString(); - activityFlowRowTemplate.ToType = entityConnection["targetNodeDefinition"]["entityType"].ToString(); - break; - } + return agentCallGraphSetting; + } - if (activityFlowRowTemplate.FromEntityID == tierRow.TierID) - { - activityFlowRowTemplate.CallDirection = "Outgoing"; - } - else - { - activityFlowRowTemplate.CallDirection = "Incoming"; - } + private static HealthRule fillHealthRule(XmlNode healthRuleConfigurationNode, EntityApplicationConfiguration applicationConfiguration) + { + HealthRule healthRule = new HealthRule(); - // Process each of the stats nodes, duplicating things as we need them - foreach (JToken entityConnectionStat in entityConnection["stats"]) - { - ActivityFlow activityFlowRow = activityFlowRowTemplate.Clone(); + healthRule.Controller = applicationConfiguration.Controller; + healthRule.ControllerLink = applicationConfiguration.ControllerLink; + healthRule.ApplicationName = applicationConfiguration.ApplicationName; + healthRule.ApplicationID = applicationConfiguration.ApplicationID; + healthRule.ApplicationLink = applicationConfiguration.ApplicationLink; - activityFlowRow.CallType = entityConnectionStat["exitPointCall"]["exitPointType"].ToString(); - if (((bool)entityConnectionStat["exitPointCall"]["synchronous"]) == false) - { - activityFlowRow.CallType = String.Format("{0} async", activityFlowRow.CallType); - } + healthRule.RuleName = getStringValueFromXmlNode(healthRuleConfigurationNode.SelectSingleNode("name")); + healthRule.RuleType = getStringValueFromXmlNode(healthRuleConfigurationNode.SelectSingleNode("type")); + healthRule.Description = getStringValueFromXmlNode(healthRuleConfigurationNode.SelectSingleNode("description")); + healthRule.IsEnabled = getBoolValueFromXmlNode(healthRuleConfigurationNode.SelectSingleNode("enabled")); + healthRule.IsDefault = getBoolValueFromXmlNode(healthRuleConfigurationNode.SelectSingleNode("is-default")); + healthRule.IsAlwaysEnabled = getBoolValueFromXmlNode(healthRuleConfigurationNode.SelectSingleNode("always-enabled")); + healthRule.Schedule = getStringValueFromXmlNode(healthRuleConfigurationNode.SelectSingleNode("schedule")); + healthRule.DurationOfEvalPeriod = getIntegerValueFromXmlNode(healthRuleConfigurationNode.SelectSingleNode("duration-min")); + healthRule.WaitTimeAfterViolation = getIntegerValueFromXmlNode(healthRuleConfigurationNode.SelectSingleNode("wait-time-min")); - if (entityConnectionStat["averageResponseTime"].HasValues == true) - { - activityFlowRow.ART = (long)entityConnectionStat["averageResponseTime"]["metricValue"]; - activityFlowRow.MetricsIDs.Add((long)entityConnectionStat["averageResponseTime"]["metricId"]); - } - if (entityConnectionStat["callsPerMinute"].HasValues == true) - { - activityFlowRow.CPM = (long)entityConnectionStat["callsPerMinute"]["metricValue"]; - activityFlowRow.MetricsIDs.Add((long)entityConnectionStat["callsPerMinute"]["metricId"]); - } - if (entityConnectionStat["errorsPerMinute"].HasValues == true) - { - activityFlowRow.EPM = (long)entityConnectionStat["errorsPerMinute"]["metricValue"]; - activityFlowRow.MetricsIDs.Add((long)entityConnectionStat["errorsPerMinute"]["metricId"]); - } - if (entityConnectionStat["numberOfCalls"].HasValues == true) { activityFlowRow.Calls = (long)entityConnectionStat["numberOfCalls"]["metricValue"]; } - if (entityConnectionStat["numberOfErrors"].HasValues == true) { activityFlowRow.Errors = (long)entityConnectionStat["numberOfErrors"]["metricValue"]; } + healthRule.AffectedEntitiesRawValue = makeXMLFormattedAndIndented(healthRuleConfigurationNode.SelectSingleNode("affected-entities-match-criteria")); + healthRule.CriticalConditionRawValue = makeXMLFormattedAndIndented(healthRuleConfigurationNode.SelectSingleNode("critical-execution-criteria")); + healthRule.WarningConditionRawValue = makeXMLFormattedAndIndented(healthRuleConfigurationNode.SelectSingleNode("warning-execution-criteria")); - if (activityFlowRow.ART < 0) { activityFlowRow.ART = 0; } - if (activityFlowRow.CPM < 0) { activityFlowRow.ART = 0; } - if (activityFlowRow.EPM < 0) { activityFlowRow.EPM = 0; } - if (activityFlowRow.Calls < 0) { activityFlowRow.Calls = 0; } - if (activityFlowRow.Errors < 0) { activityFlowRow.Errors = 0; } - - activityFlowRow.ErrorsPercentage = Math.Round((double)(double)activityFlowRow.Errors / (double)activityFlowRow.Calls * 100, 2); - if (Double.IsNaN(activityFlowRow.ErrorsPercentage) == true) activityFlowRow.ErrorsPercentage = 0; - - activityFlowRow.MetricsIDs.RemoveAll(m => m == -1); - - if (activityFlowRow.MetricsIDs != null && activityFlowRow.MetricsIDs.Count > 0) - { - StringBuilder sb = new StringBuilder(128); - foreach (int metricID in activityFlowRow.MetricsIDs) - { - sb.Append(String.Format(deepLinkMetricTemplateInMetricBrowser, entityIdForMetricBrowser, metricID)); - sb.Append(","); - } - sb.Remove(sb.Length - 1, 1); - activityFlowRow.MetricLink = String.Format(DEEPLINK_METRIC, activityFlowRow.Controller, activityFlowRow.ApplicationID, sb.ToString(), DEEPLINK_THIS_TIMERANGE); - } - activityFlowsList.Add(activityFlowRow); - } - } + // Affected entity selection + XmlNode affectedWrapperXmlNode = healthRuleConfigurationNode.SelectSingleNode("affected-entities-match-criteria").ChildNodes[0]; + if (affectedWrapperXmlNode != null) + { + healthRule.AffectsEntityType = getStringValueFromXmlNode(affectedWrapperXmlNode.SelectSingleNode("type")); + healthRule.AffectsEntityMatchType = getStringValueFromXmlNode(affectedWrapperXmlNode.SelectSingleNode("match-type")); + healthRule.AffectsEntityMatchPattern = getStringValueFromXmlNode(affectedWrapperXmlNode.SelectSingleNode("match-pattern")); + healthRule.AffectsEntityMatchIsInverse = getBoolValueFromXmlNode(affectedWrapperXmlNode.SelectSingleNode("inverse")); + healthRule.AffectsEntityMatchCriteria = makeXMLFormattedAndIndented(affectedWrapperXmlNode.SelectNodes("*[not(self::type) and not(self::match-type) and not(self::match-pattern) and not(self::inverse)]")); } - // Sort them - activityFlowsList = activityFlowsList.OrderBy(a => a.CallDirection).ThenBy(a => a.FromType).ThenBy(a => a.FromName).ThenBy(a => a.ToType).ThenBy(a => a.ToName).ThenBy(a => a.CallType).ThenBy(a => a.CPM).ToList(); + // XML can look like that for single element + // + // + // ANY + // 0 + // + // + // leaf + // condition 1 + // ABSOLUTE + // 0.0 + // GREATER_THAN + // + // false + // true + // + // leaf + // VALUE + // 0 + // false + // null + // + // LOGICAL_METRIC + // Agent|App|Availability + // + // + // + // - string activityGridReportFileName = Path.Combine( - metricsEntityFolderPath, - CONVERT_ACTIVITY_GRID_FILE_NAME); + // Or like that for multiple + // + // + // AGGREGATE + // 0 + // + // + // boolean + // AND + // + // leaf + // Average Response Time (ms) Baseline Condition + // BASELINE_STANDARD_DEVIATION + // 3.0 + // GREATER_THAN + // + // true + // false + // + // leaf + // VALUE + // 0 + // false + // null + // + // LOGICAL_METRIC + // Average Response Time (ms) + // + // + // + // + // leaf + // Calls per Minute Condition + // ABSOLUTE + // 50.0 + // GREATER_THAN + // + // false + // false + // + // leaf + // VALUE + // 0 + // false + // null + // + // LOGICAL_METRIC + // Calls per Minute + // + // + // + // + // - FileIOHelper.writeListToCSVFile(activityFlowsList, new ActivityFlowReportMap(), activityGridReportFileName); - } + // Critical + XmlNode criticalExecutionCriteriaXmlNode = healthRuleConfigurationNode.SelectSingleNode("critical-execution-criteria"); + if (criticalExecutionCriteriaXmlNode != null) + { + healthRule.CriticalAggregateType = getStringValueFromXmlNode(criticalExecutionCriteriaXmlNode.SelectSingleNode("entity-aggregation-scope/type")); - private static void convertFlowmapNode(ProgramOptions programOptions, JobConfiguration jobConfiguration, JobTarget jobTarget, EntityNode nodeRow, string metricsFolderPath) - { - string metricsEntityFolderPath = Path.Combine( - metricsFolderPath, - NODES_TYPE_SHORT, - getShortenedEntityNameForFileSystem(nodeRow.TierName, nodeRow.TierID), - getShortenedEntityNameForFileSystem(nodeRow.NodeName, nodeRow.NodeID)); + XmlNode firstCondition = criticalExecutionCriteriaXmlNode.SelectSingleNode("policy-condition"); + XmlNodeList condition1sXmlNodeList = criticalExecutionCriteriaXmlNode.SelectNodes("policy-condition//condition1"); + XmlNodeList condition2sXmlNodeList = criticalExecutionCriteriaXmlNode.SelectNodes("policy-condition//condition2"); - string flowmapDataFilePath = Path.Combine( - metricsEntityFolderPath, - String.Format(EXTRACT_ENTITY_FLOWMAP_FILE_NAME, jobConfiguration.Input.ExpandedTimeRange.From, jobConfiguration.Input.ExpandedTimeRange.To)); + List conditionsList = new List(); + if (condition1sXmlNodeList.Count == 0) + { + healthRule.CriticalEntityConditionType = "AND"; + conditionsList.Add(firstCondition); + } + else + { + healthRule.CriticalEntityConditionType = getStringValueFromXmlNode(criticalExecutionCriteriaXmlNode.SelectSingleNode("policy-condition/operator")); + foreach (XmlNode xmlNode in condition1sXmlNodeList) + { + conditionsList.Add(xmlNode); + } + conditionsList.Add(condition2sXmlNodeList[condition2sXmlNodeList.Count - 1]); + } + + healthRule.CriticalNumConditions = conditionsList.Count; - JObject flowmapData = FileIOHelper.loadJObjectFromFile(flowmapDataFilePath); - if (flowmapData == null) - { - return; - } + int i = 1; + foreach (XmlNode conditionXmlNode in conditionsList) + { + healthRule.GetType().GetProperty(String.Format("Crit{0}Name", i)).SetValue(healthRule, getStringValueFromXmlNode(conditionXmlNode.SelectSingleNode("display-name")), null); + healthRule.GetType().GetProperty(String.Format("Crit{0}Type", i)).SetValue(healthRule, getStringValueFromXmlNode(conditionXmlNode.SelectSingleNode("condition-value-type")), null); + healthRule.GetType().GetProperty(String.Format("Crit{0}Value", i)).SetValue(healthRule, getLongValueFromXmlNode(conditionXmlNode.SelectSingleNode("condition-value")), null); + healthRule.GetType().GetProperty(String.Format("Crit{0}Operator", i)).SetValue(healthRule, getStringValueFromXmlNode(conditionXmlNode.SelectSingleNode("operator")), null); + healthRule.GetType().GetProperty(String.Format("Crit{0}Expression", i)).SetValue(healthRule, getStringValueFromXmlNode(conditionXmlNode.SelectSingleNode("condition-expression")), null); + if (getBoolValueFromXmlNode(conditionXmlNode.SelectSingleNode("use-active-baseline")) == true) + { + healthRule.GetType().GetProperty(String.Format("Crit{0}BaselineUsed", i)).SetValue(healthRule, "Default Baseline", null); + } + else + { + healthRule.GetType().GetProperty(String.Format("Crit{0}BaselineUsed", i)).SetValue(healthRule, getStringValueFromXmlNode(conditionXmlNode.SelectSingleNode("metric-baseline/name")), null); + } + healthRule.GetType().GetProperty(String.Format("Crit{0}TriggerOnNoData", i)).SetValue(healthRule, getBoolValueFromXmlNode(conditionXmlNode.SelectSingleNode("trigger-on-no-data")), null); + healthRule.GetType().GetProperty(String.Format("Crit{0}MetricName", i)).SetValue(healthRule, getStringValueFromXmlNode(conditionXmlNode.SelectSingleNode("metric-expression/metric-definition/logical-metric-name")), null); + healthRule.GetType().GetProperty(String.Format("Crit{0}MetricFunction", i)).SetValue(healthRule, getStringValueFromXmlNode(conditionXmlNode.SelectSingleNode("metric-expression/function-type")), null); + healthRule.GetType().GetProperty(String.Format("Crit{0}MetricExpressionConfig", i)).SetValue(healthRule, makeXMLFormattedAndIndented(conditionXmlNode.SelectSingleNode("metric-expression")), null); - long fromTimeUnix = convertToUnixTimestamp(jobConfiguration.Input.ExpandedTimeRange.From); - long toTimeUnix = convertToUnixTimestamp(jobConfiguration.Input.ExpandedTimeRange.To); - long differenceInMinutes = (toTimeUnix - fromTimeUnix) / (60000); - string DEEPLINK_THIS_TIMERANGE = String.Format(DEEPLINK_TIMERANGE_BETWEEN_TIMES, toTimeUnix, fromTimeUnix, differenceInMinutes); + i++; + if (i > 5) break; + } + } - List activityFlowsList = null; - JArray flowmapEntities = (JArray)flowmapData["nodes"]; - JArray flowmapEntityConnections = (JArray)flowmapData["edges"]; - if (flowmapEntities != null && flowmapEntityConnections != null) + // Warning + XmlNode warningExecutionCriteriaXmlNode = healthRuleConfigurationNode.SelectSingleNode("warning-execution-criteria"); + if (warningExecutionCriteriaXmlNode != null) { - activityFlowsList = new List(flowmapEntityConnections.Count); + healthRule.WarningAggregateType = getStringValueFromXmlNode(warningExecutionCriteriaXmlNode.SelectSingleNode("entity-aggregation-scope/type")); - // For Nodes, not going to process individual entities, but only connecting lines + XmlNode firstCondition = warningExecutionCriteriaXmlNode.SelectSingleNode("policy-condition"); + XmlNodeList condition1sXmlNodeList = warningExecutionCriteriaXmlNode.SelectNodes("policy-condition//condition1"); + XmlNodeList condition2sXmlNodeList = warningExecutionCriteriaXmlNode.SelectNodes("policy-condition//condition2"); - // Process each call between Tiers, Tiers and Backends, and Tiers and Applications - foreach (JToken entityConnection in flowmapEntityConnections) + List conditionsList = new List(); + if (condition1sXmlNodeList.Count == 0) { - ActivityFlow activityFlowRowTemplate = new ActivityFlow(); - - // Prepare the row - activityFlowRowTemplate.MetricsIDs = new List(3); - - activityFlowRowTemplate.Controller = nodeRow.Controller; - activityFlowRowTemplate.ApplicationName = nodeRow.ApplicationName; - activityFlowRowTemplate.ApplicationID = nodeRow.ApplicationID; - - activityFlowRowTemplate.ControllerLink = String.Format(DEEPLINK_CONTROLLER, activityFlowRowTemplate.Controller, DEEPLINK_THIS_TIMERANGE); - activityFlowRowTemplate.ApplicationLink = String.Format(DEEPLINK_APPLICATION, activityFlowRowTemplate.Controller, activityFlowRowTemplate.ApplicationID, DEEPLINK_THIS_TIMERANGE); + healthRule.WarningEntityConditionType = "AND"; + conditionsList.Add(firstCondition); + } + else + { + healthRule.WarningEntityConditionType = getStringValueFromXmlNode(warningExecutionCriteriaXmlNode.SelectSingleNode("policy-condition/operator")); + foreach (XmlNode xmlNode in condition1sXmlNodeList) + { + conditionsList.Add(xmlNode); + } + conditionsList.Add(condition2sXmlNodeList[condition2sXmlNodeList.Count - 1]); + } - activityFlowRowTemplate.Duration = (int)(jobConfiguration.Input.ExpandedTimeRange.To - jobConfiguration.Input.ExpandedTimeRange.From).Duration().TotalMinutes; - activityFlowRowTemplate.From = jobConfiguration.Input.ExpandedTimeRange.From.ToLocalTime(); - activityFlowRowTemplate.To = jobConfiguration.Input.ExpandedTimeRange.To.ToLocalTime(); - activityFlowRowTemplate.FromUtc = jobConfiguration.Input.ExpandedTimeRange.From; - activityFlowRowTemplate.ToUtc = jobConfiguration.Input.ExpandedTimeRange.To; + healthRule.WarningNumConditions = conditionsList.Count; - activityFlowRowTemplate.FromEntityID = (long)entityConnection["sourceNodeDefinition"]["entityId"]; - JObject entity = (JObject)flowmapEntities.Where(e => (long)e["idNum"] == activityFlowRowTemplate.FromEntityID && e["entityType"].ToString() == entityConnection["sourceNodeDefinition"]["entityType"].ToString()).FirstOrDefault(); - if (entity != null) + int i = 1; + foreach (XmlNode conditionXmlNode in conditionsList) + { + healthRule.GetType().GetProperty(String.Format("Warn{0}Name", i)).SetValue(healthRule, getStringValueFromXmlNode(conditionXmlNode.SelectSingleNode("display-name")), null); + healthRule.GetType().GetProperty(String.Format("Warn{0}Type", i)).SetValue(healthRule, getStringValueFromXmlNode(conditionXmlNode.SelectSingleNode("condition-value-type")), null); + healthRule.GetType().GetProperty(String.Format("Warn{0}Value", i)).SetValue(healthRule, getLongValueFromXmlNode(conditionXmlNode.SelectSingleNode("condition-value")), null); + healthRule.GetType().GetProperty(String.Format("Warn{0}Operator", i)).SetValue(healthRule, getStringValueFromXmlNode(conditionXmlNode.SelectSingleNode("operator")), null); + healthRule.GetType().GetProperty(String.Format("Warn{0}Expression", i)).SetValue(healthRule, getStringValueFromXmlNode(conditionXmlNode.SelectSingleNode("condition-expression")), null); + if (getBoolValueFromXmlNode(conditionXmlNode.SelectSingleNode("use-active-baseline")) == true) { - activityFlowRowTemplate.FromName = entity["name"].ToString(); + healthRule.GetType().GetProperty(String.Format("Warn{0}BaselineUsed", i)).SetValue(healthRule, "Default Baseline", null); } - string deepLinkMetricTemplateInMetricBrowser = DEEPLINK_METRIC_APPLICATION_TARGET_METRIC_ID; - long entityIdForMetricBrowser = activityFlowRowTemplate.ApplicationID; - switch (entityConnection["sourceNodeDefinition"]["entityType"].ToString()) + else { - case ENTITY_TYPE_NODE: - deepLinkMetricTemplateInMetricBrowser = DEEPLINK_METRIC_NODE_TARGET_METRIC_ID; - entityIdForMetricBrowser = activityFlowRowTemplate.FromEntityID; - activityFlowRowTemplate.FromType = "Node"; - activityFlowRowTemplate.FromLink = String.Format(DEEPLINK_NODE, activityFlowRowTemplate.Controller, activityFlowRowTemplate.ApplicationID, activityFlowRowTemplate.FromEntityID, DEEPLINK_THIS_TIMERANGE); - break; + healthRule.GetType().GetProperty(String.Format("Warn{0}BaselineUsed", i)).SetValue(healthRule, getStringValueFromXmlNode(conditionXmlNode.SelectSingleNode("metric-baseline/name")), null); + } + healthRule.GetType().GetProperty(String.Format("Warn{0}TriggerOnNoData", i)).SetValue(healthRule, getBoolValueFromXmlNode(conditionXmlNode.SelectSingleNode("trigger-on-no-data")), null); + healthRule.GetType().GetProperty(String.Format("Warn{0}MetricName", i)).SetValue(healthRule, getStringValueFromXmlNode(conditionXmlNode.SelectSingleNode("metric-expression/metric-definition/logical-metric-name")), null); + healthRule.GetType().GetProperty(String.Format("Warn{0}MetricFunction", i)).SetValue(healthRule, getStringValueFromXmlNode(conditionXmlNode.SelectSingleNode("metric-expression/function-type")), null); + healthRule.GetType().GetProperty(String.Format("Warn{0}MetricExpressionConfig", i)).SetValue(healthRule, makeXMLFormattedAndIndented(conditionXmlNode.SelectSingleNode("metric-expression")), null); - case ENTITY_TYPE_TIER: - deepLinkMetricTemplateInMetricBrowser = DEEPLINK_METRIC_TIER_TARGET_METRIC_ID; - entityIdForMetricBrowser = activityFlowRowTemplate.FromEntityID; - activityFlowRowTemplate.FromType = "Tier"; - activityFlowRowTemplate.FromLink = String.Format(DEEPLINK_TIER, activityFlowRowTemplate.Controller, activityFlowRowTemplate.ApplicationID, activityFlowRowTemplate.FromEntityID, DEEPLINK_THIS_TIMERANGE); - break; + i++; + if (i > 5) break; + } + } - case ENTITY_TYPE_BACKEND: - activityFlowRowTemplate.FromType = "Backend"; - activityFlowRowTemplate.FromLink = String.Format(DEEPLINK_BACKEND, activityFlowRowTemplate.Controller, activityFlowRowTemplate.ApplicationID, activityFlowRowTemplate.FromEntityID, DEEPLINK_THIS_TIMERANGE); - break; + return healthRule; + } - case ENTITY_TYPE_APPLICATION: - deepLinkMetricTemplateInMetricBrowser = DEEPLINK_METRIC_TIER_TARGET_METRIC_ID; - activityFlowRowTemplate.FromType = "Application"; - activityFlowRowTemplate.FromLink = String.Format(DEEPLINK_APPLICATION, activityFlowRowTemplate.Controller, activityFlowRowTemplate.FromEntityID, DEEPLINK_THIS_TIMERANGE); - break; + private static void fillMatchRuleDetails(BusinessTransactionEntryRule businessTransactionEntryRule, XmlNode matchRule) + { + // Enabled seems to be set inside of the match-rule, not couple of levels up + businessTransactionEntryRule.IsEnabled = Convert.ToBoolean(matchRule.SelectSingleNode("enabled").InnerText); + businessTransactionEntryRule.Priority = Convert.ToInt32(matchRule.SelectSingleNode("priority").InnerText); + businessTransactionEntryRule.IsExcluded = Convert.ToBoolean(matchRule.SelectSingleNode("excluded").InnerText); - default: - activityFlowRowTemplate.FromName = entityConnection["sourceNode"].ToString(); - activityFlowRowTemplate.FromType = entityConnection["sourceNodeDefinition"]["entityType"].ToString(); - break; - } + switch (businessTransactionEntryRule.EntryPointType) + { + case "ASP_DOTNET": + businessTransactionEntryRule.MatchURI = makeXMLFormattedAndIndented(matchRule.SelectSingleNode("uri")); + //businessTransactionEntryRule.Parameters = getNameValueDetailsFromParametersCollection(matchRule.SelectSingleNode("parameters")); + businessTransactionEntryRule.Parameters = makeXMLFormattedAndIndented(matchRule.SelectSingleNode("parameters")); + businessTransactionEntryRule.SplitConfig = makeXMLFormattedAndIndented(matchRule.SelectSingleNode("split-config")); + businessTransactionEntryRule.MatchClass = makeXMLFormattedAndIndented(matchRule.SelectSingleNode("class-name")); - activityFlowRowTemplate.ToEntityID = (long)entityConnection["targetNodeDefinition"]["entityId"]; - entity = (JObject)flowmapEntities.Where(e => (long)e["idNum"] == activityFlowRowTemplate.ToEntityID && e["entityType"].ToString() == entityConnection["targetNodeDefinition"]["entityType"].ToString()).FirstOrDefault(); - if (entity != null) - { - activityFlowRowTemplate.ToName = entity["name"].ToString(); - } - switch (entityConnection["targetNodeDefinition"]["entityType"].ToString()) - { - case "APPLICATION_COMPONENT_NODE": - activityFlowRowTemplate.ToType = "Node"; - activityFlowRowTemplate.ToLink = String.Format(DEEPLINK_NODE, activityFlowRowTemplate.Controller, activityFlowRowTemplate.ApplicationID, activityFlowRowTemplate.ToEntityID, DEEPLINK_THIS_TIMERANGE); - break; + break; - case ENTITY_TYPE_TIER: - activityFlowRowTemplate.ToType = "Tier"; - activityFlowRowTemplate.ToLink = String.Format(DEEPLINK_TIER, activityFlowRowTemplate.Controller, activityFlowRowTemplate.ApplicationID, activityFlowRowTemplate.ToEntityID, DEEPLINK_THIS_TIMERANGE); - break; + case "NODEJS_WEB": + businessTransactionEntryRule.MatchURI = makeXMLFormattedAndIndented(matchRule.SelectSingleNode("uri")); + //businessTransactionEntryRule.Parameters = getNameValueDetailsFromParametersCollection(matchRule.SelectSingleNode("parameters")); + businessTransactionEntryRule.Parameters = makeXMLFormattedAndIndented(matchRule.SelectSingleNode("parameters")); + businessTransactionEntryRule.SplitConfig = makeXMLFormattedAndIndented(matchRule.SelectSingleNode("split-config")); + businessTransactionEntryRule.MatchClass = makeXMLFormattedAndIndented(matchRule.SelectSingleNode("http-method")); - case ENTITY_TYPE_BACKEND: - activityFlowRowTemplate.ToType = "Backend"; - activityFlowRowTemplate.ToLink = String.Format(DEEPLINK_BACKEND, activityFlowRowTemplate.Controller, activityFlowRowTemplate.ApplicationID, activityFlowRowTemplate.ToEntityID, DEEPLINK_THIS_TIMERANGE); - break; + break; - case ENTITY_TYPE_APPLICATION: - activityFlowRowTemplate.ToType = "Application"; - activityFlowRowTemplate.ToLink = String.Format(DEEPLINK_APPLICATION, activityFlowRowTemplate.Controller, activityFlowRowTemplate.ToEntityID, DEEPLINK_THIS_TIMERANGE); - break; + case "PYTHON_WEB": + businessTransactionEntryRule.MatchURI = makeXMLFormattedAndIndented(matchRule.SelectSingleNode("uri")); + //businessTransactionEntryRule.Parameters = getNameValueDetailsFromParametersCollection(matchRule.SelectSingleNode("parameters")); + businessTransactionEntryRule.Parameters = makeXMLFormattedAndIndented(matchRule.SelectSingleNode("parameters")); + businessTransactionEntryRule.SplitConfig = makeXMLFormattedAndIndented(matchRule.SelectSingleNode("split-config")); + businessTransactionEntryRule.MatchClass = makeXMLFormattedAndIndented(matchRule.SelectSingleNode("http-method")); - default: - activityFlowRowTemplate.ToName = entityConnection["targetNode"].ToString(); - activityFlowRowTemplate.ToType = entityConnection["targetNodeDefinition"]["entityType"].ToString(); - break; - } + break; - // Haven't seen the incoming calls on the flowmap for Nodes. But maybe? - if (activityFlowRowTemplate.FromEntityID == nodeRow.NodeID) - { - activityFlowRowTemplate.CallDirection = "Outgoing"; - } - else - { - activityFlowRowTemplate.CallDirection = "Incoming"; - } + case "POCO": + // Background is really only set for POCOs + businessTransactionEntryRule.IsBackground = Convert.ToBoolean(matchRule.SelectSingleNode("background").InnerText); + businessTransactionEntryRule.MatchClass = makeXMLFormattedAndIndented(matchRule.SelectSingleNode("match-class")); + businessTransactionEntryRule.MatchMethod = makeXMLFormattedAndIndented(matchRule.SelectSingleNode("match-method")); + businessTransactionEntryRule.SplitConfig = makeXMLFormattedAndIndented(matchRule.SelectSingleNode("split-config")); - // Process each of the stats nodes, duplicating things as we need them - foreach (JToken entityConnectionStat in entityConnection["stats"]) - { - ActivityFlow activityFlowRow = activityFlowRowTemplate.Clone(); + break; - activityFlowRow.CallType = entityConnectionStat["exitPointCall"]["exitPointType"].ToString(); - if (((bool)entityConnectionStat["exitPointCall"]["synchronous"]) == false) - { - activityFlowRow.CallType = String.Format("{0} async", activityFlowRow.CallType); - } + case "POJO": + // Background is really only set for POJOs + businessTransactionEntryRule.IsBackground = Convert.ToBoolean(matchRule.SelectSingleNode("background").InnerText); + businessTransactionEntryRule.MatchClass = makeXMLFormattedAndIndented(matchRule.SelectSingleNode("match-class")); + businessTransactionEntryRule.MatchMethod = makeXMLFormattedAndIndented(matchRule.SelectSingleNode("match-method")); + businessTransactionEntryRule.SplitConfig = makeXMLFormattedAndIndented(matchRule.SelectSingleNode("split-config")); - if (entityConnectionStat["averageResponseTime"].HasValues == true) - { - activityFlowRow.ART = (long)entityConnectionStat["averageResponseTime"]["metricValue"]; - activityFlowRow.MetricsIDs.Add((long)entityConnectionStat["averageResponseTime"]["metricId"]); - } - if (entityConnectionStat["callsPerMinute"].HasValues == true) - { - activityFlowRow.CPM = (long)entityConnectionStat["callsPerMinute"]["metricValue"]; - activityFlowRow.MetricsIDs.Add((long)entityConnectionStat["callsPerMinute"]["metricId"]); - } - if (entityConnectionStat["errorsPerMinute"].HasValues == true) - { - activityFlowRow.EPM = (long)entityConnectionStat["errorsPerMinute"]["metricValue"]; - activityFlowRow.MetricsIDs.Add((long)entityConnectionStat["errorsPerMinute"]["metricId"]); - } - if (entityConnectionStat["numberOfCalls"].HasValues == true) { activityFlowRow.Calls = (long)entityConnectionStat["numberOfCalls"]["metricValue"]; } - if (entityConnectionStat["numberOfErrors"].HasValues == true) { activityFlowRow.Errors = (long)entityConnectionStat["numberOfErrors"]["metricValue"]; } + break; - if (activityFlowRow.ART < 0) { activityFlowRow.ART = 0; } - if (activityFlowRow.CPM < 0) { activityFlowRow.ART = 0; } - if (activityFlowRow.EPM < 0) { activityFlowRow.EPM = 0; } - if (activityFlowRow.Calls < 0) { activityFlowRow.Calls = 0; } - if (activityFlowRow.Errors < 0) { activityFlowRow.Errors = 0; } + case "SERVLET": + businessTransactionEntryRule.MatchURI = makeXMLFormattedAndIndented(matchRule.SelectSingleNode("uri")); + //businessTransactionEntryRule.Parameters = getNameValueDetailsFromParametersCollection(matchRule.SelectSingleNode("parameters")); + businessTransactionEntryRule.Parameters = makeXMLFormattedAndIndented(matchRule.SelectSingleNode("parameters")); + businessTransactionEntryRule.SplitConfig = makeXMLFormattedAndIndented(matchRule.SelectSingleNode("split-config")); + businessTransactionEntryRule.MatchClass = makeXMLFormattedAndIndented(matchRule.SelectSingleNode("class-name")); - activityFlowRow.ErrorsPercentage = Math.Round((double)(double)activityFlowRow.Errors / (double)activityFlowRow.Calls * 100, 2); - if (Double.IsNaN(activityFlowRow.ErrorsPercentage) == true) activityFlowRow.ErrorsPercentage = 0; + break; - activityFlowRow.MetricsIDs.RemoveAll(m => m == -1); + case "STRUTS_ACTION": + businessTransactionEntryRule.MatchClass = makeXMLFormattedAndIndented(matchRule.SelectSingleNode("action-class-name")); + businessTransactionEntryRule.MatchMethod = makeXMLFormattedAndIndented(matchRule.SelectSingleNode("action-method-name")); + // There is also Struts Action Name in the UI, but I don't know how it shows up - if (activityFlowRow.MetricsIDs != null && activityFlowRow.MetricsIDs.Count > 0) - { - StringBuilder sb = new StringBuilder(128); - foreach (int metricID in activityFlowRow.MetricsIDs) - { - sb.Append(String.Format(deepLinkMetricTemplateInMetricBrowser, entityIdForMetricBrowser, metricID)); - sb.Append(","); - } - sb.Remove(sb.Length - 1, 1); - activityFlowRow.MetricLink = String.Format(DEEPLINK_METRIC, activityFlowRow.Controller, activityFlowRow.ApplicationID, sb.ToString(), DEEPLINK_THIS_TIMERANGE); - } - activityFlowsList.Add(activityFlowRow); - } - } - } + break; - // Sort them - activityFlowsList = activityFlowsList.OrderBy(a => a.CallDirection).ThenBy(a => a.FromType).ThenBy(a => a.FromName).ThenBy(a => a.ToType).ThenBy(a => a.ToName).ThenBy(a => a.CallType).ThenBy(a => a.CPM).ToList(); + case "WCF": + businessTransactionEntryRule.MatchClass = makeXMLFormattedAndIndented(matchRule.SelectSingleNode("web-service-name")); + businessTransactionEntryRule.MatchMethod = makeXMLFormattedAndIndented(matchRule.SelectSingleNode("operation-name")); - string activityGridReportFileName = Path.Combine( - metricsEntityFolderPath, - CONVERT_ACTIVITY_GRID_FILE_NAME); + break; + + case "WEB": + businessTransactionEntryRule.MatchURI = makeXMLFormattedAndIndented(matchRule.SelectSingleNode("uri")); + //businessTransactionEntryRule.Parameters = getNameValueDetailsFromParametersCollection(matchRule.SelectSingleNode("parameters")); + businessTransactionEntryRule.Parameters = makeXMLFormattedAndIndented(matchRule.SelectSingleNode("parameters")); + businessTransactionEntryRule.SplitConfig = makeXMLFormattedAndIndented(matchRule.SelectSingleNode("split-config")); + + break; + + default: + break; + } - FileIOHelper.writeListToCSVFile(activityFlowsList, new ActivityFlowReportMap(), activityGridReportFileName); } - private static void convertFlowmapsBusinessTransaction(ProgramOptions programOptions, JobConfiguration jobConfiguration, JobTarget jobTarget, EntityBusinessTransaction businessTransactionRow, string metricsFolderPath) + #endregion + + #region Flowmap detail conversion functions + + private static void convertFlowmapApplication(ProgramOptions programOptions, JobConfiguration jobConfiguration, JobTarget jobTarget, EntityApplication applicationRow, string metricsFolderPath) { string metricsEntityFolderPath = Path.Combine( metricsFolderPath, - BUSINESS_TRANSACTIONS_TYPE_SHORT, - getShortenedEntityNameForFileSystem(businessTransactionRow.TierName, businessTransactionRow.TierID), - getShortenedEntityNameForFileSystem(businessTransactionRow.BTName, businessTransactionRow.BTID)); + APPLICATION_TYPE_SHORT); string flowmapDataFilePath = Path.Combine( metricsEntityFolderPath, @@ -15681,44 +15730,134 @@ private static void convertFlowmapsBusinessTransaction(ProgramOptions programOpt JArray flowmapEntityConnections = (JArray)flowmapData["edges"]; if (flowmapEntities != null && flowmapEntityConnections != null) { - activityFlowsList = new List(flowmapEntityConnections.Count); - - // Controller shows a pretty complex grid view for jumps that continue from other tiers. - // I couldn't figure out how the JSON is converted into that - // For Business Transactions, not going to process individual entities, but only connecting lines - - // Assume that the first node is the - JObject startTier = (JObject)flowmapEntities.Where(e => (bool)e["startComponent"] == true).FirstOrDefault(); + activityFlowsList = new List(flowmapEntities.Count + flowmapEntityConnections.Count); - // Process each call between Tiers, Tiers and Backends, and Tiers and Applications - foreach (JToken entityConnection in flowmapEntityConnections) + // Process each of the individual Tiers, Backends and Applications as individual icons on the flow map + foreach (JToken entity in flowmapEntities) { - ActivityFlow activityFlowRowTemplate = new ActivityFlow(); + ActivityFlow activityFlowRow = new ActivityFlow(); + activityFlowRow.MetricsIDs = new List(3); - // Prepare the row - activityFlowRowTemplate.MetricsIDs = new List(3); + activityFlowRow.Controller = applicationRow.Controller; + activityFlowRow.ApplicationName = applicationRow.ApplicationName; + activityFlowRow.ApplicationID = applicationRow.ApplicationID; - activityFlowRowTemplate.Controller = businessTransactionRow.Controller; - activityFlowRowTemplate.ApplicationName = businessTransactionRow.ApplicationName; - activityFlowRowTemplate.ApplicationID = businessTransactionRow.ApplicationID; + activityFlowRow.ControllerLink = String.Format(DEEPLINK_CONTROLLER, activityFlowRow.Controller, DEEPLINK_THIS_TIMERANGE); + activityFlowRow.ApplicationLink = String.Format(DEEPLINK_APPLICATION, activityFlowRow.Controller, activityFlowRow.ApplicationID, DEEPLINK_THIS_TIMERANGE); - activityFlowRowTemplate.ControllerLink = String.Format(DEEPLINK_CONTROLLER, activityFlowRowTemplate.Controller, DEEPLINK_THIS_TIMERANGE); - activityFlowRowTemplate.ApplicationLink = String.Format(DEEPLINK_APPLICATION, activityFlowRowTemplate.Controller, activityFlowRowTemplate.ApplicationID, DEEPLINK_THIS_TIMERANGE); + activityFlowRow.Duration = (int)(jobConfiguration.Input.ExpandedTimeRange.To - jobConfiguration.Input.ExpandedTimeRange.From).Duration().TotalMinutes; + activityFlowRow.From = jobConfiguration.Input.ExpandedTimeRange.From.ToLocalTime(); + activityFlowRow.To = jobConfiguration.Input.ExpandedTimeRange.To.ToLocalTime(); + activityFlowRow.FromUtc = jobConfiguration.Input.ExpandedTimeRange.From; + activityFlowRow.ToUtc = jobConfiguration.Input.ExpandedTimeRange.To; - activityFlowRowTemplate.Duration = (int)(jobConfiguration.Input.ExpandedTimeRange.To - jobConfiguration.Input.ExpandedTimeRange.From).Duration().TotalMinutes; - activityFlowRowTemplate.From = jobConfiguration.Input.ExpandedTimeRange.From.ToLocalTime(); - activityFlowRowTemplate.To = jobConfiguration.Input.ExpandedTimeRange.To.ToLocalTime(); - activityFlowRowTemplate.FromUtc = jobConfiguration.Input.ExpandedTimeRange.From; - activityFlowRowTemplate.ToUtc = jobConfiguration.Input.ExpandedTimeRange.To; + activityFlowRow.CallDirection = "Total"; - activityFlowRowTemplate.FromEntityID = (long)entityConnection["sourceNodeDefinition"]["entityId"]; - JObject entity = (JObject)flowmapEntities.Where(e => (long)e["idNum"] == activityFlowRowTemplate.FromEntityID && e["entityType"].ToString() == entityConnection["sourceNodeDefinition"]["entityType"].ToString()).FirstOrDefault(); - if (entity != null) - { - activityFlowRowTemplate.FromName = entity["name"].ToString(); - } - string deepLinkMetricTemplateInMetricBrowser = DEEPLINK_METRIC_APPLICATION_TARGET_METRIC_ID; - long entityIdForMetricBrowser = activityFlowRowTemplate.ApplicationID; + activityFlowRow.FromEntityID = (long)entity["idNum"]; + activityFlowRow.FromName = entity["name"].ToString(); + + string deepLinkMetricTemplateInMetricBrowser = DEEPLINK_METRIC_APPLICATION_TARGET_METRIC_ID; + long entityIdForMetricBrowser = activityFlowRow.ApplicationID; + switch (entity["entityType"].ToString()) + { + case ENTITY_TYPE_TIER: + deepLinkMetricTemplateInMetricBrowser = DEEPLINK_METRIC_TIER_TARGET_METRIC_ID; + entityIdForMetricBrowser = activityFlowRow.FromEntityID; + activityFlowRow.CallType = "Total"; + activityFlowRow.FromType = "Tier"; + activityFlowRow.FromLink = String.Format(DEEPLINK_TIER, activityFlowRow.Controller, activityFlowRow.ApplicationID, activityFlowRow.FromEntityID, DEEPLINK_THIS_TIMERANGE); + break; + + case ENTITY_TYPE_BACKEND: + activityFlowRow.CallType = "Total"; + activityFlowRow.FromType = "Backend"; + activityFlowRow.FromLink = String.Format(DEEPLINK_BACKEND, activityFlowRow.Controller, activityFlowRow.ApplicationID, activityFlowRow.FromEntityID, DEEPLINK_THIS_TIMERANGE); + break; + + case ENTITY_TYPE_APPLICATION: + deepLinkMetricTemplateInMetricBrowser = DEEPLINK_METRIC_TIER_TARGET_METRIC_ID; + activityFlowRow.CallType = "Total"; + activityFlowRow.FromType = "Application"; + activityFlowRow.FromLink = String.Format(DEEPLINK_APPLICATION, activityFlowRow.Controller, activityFlowRow.FromEntityID, DEEPLINK_THIS_TIMERANGE); + break; + + default: + activityFlowRow.CallType = entity["entityType"].ToString(); + activityFlowRow.FromType = "Unknown"; + break; + } + + //activityFlowRow.ToName = activityFlowRow.FromName; + //activityFlowRow.ToType= activityFlowRow.FromType; + activityFlowRow.ToEntityID = activityFlowRow.FromEntityID; + //activityFlowRow.ToLink = activityFlowRow.FromLink; + + activityFlowRow.ART = (long)entity["stats"]["averageResponseTime"]["metricValue"]; + activityFlowRow.CPM = (long)entity["stats"]["callsPerMinute"]["metricValue"]; + activityFlowRow.EPM = (long)entity["stats"]["errorsPerMinute"]["metricValue"]; + activityFlowRow.Calls = (long)entity["stats"]["numberOfCalls"]["metricValue"]; + activityFlowRow.Errors = (long)entity["stats"]["numberOfErrors"]["metricValue"]; + + if (activityFlowRow.ART < 0) { activityFlowRow.ART = 0; } + if (activityFlowRow.CPM < 0) { activityFlowRow.ART = 0; } + if (activityFlowRow.EPM < 0) { activityFlowRow.EPM = 0; } + if (activityFlowRow.Calls < 0) { activityFlowRow.Calls = 0; } + if (activityFlowRow.Errors < 0) { activityFlowRow.Errors = 0; } + + activityFlowRow.ErrorsPercentage = Math.Round((double)(double)activityFlowRow.Errors / (double)activityFlowRow.Calls * 100, 2); + if (Double.IsNaN(activityFlowRow.ErrorsPercentage) == true) activityFlowRow.ErrorsPercentage = 0; + + activityFlowRow.MetricsIDs.Add((int)entity["stats"]["averageResponseTime"]["metricId"]); + activityFlowRow.MetricsIDs.Add((int)entity["stats"]["callsPerMinute"]["metricId"]); + activityFlowRow.MetricsIDs.Add((int)entity["stats"]["errorsPerMinute"]["metricId"]); + activityFlowRow.MetricsIDs.RemoveAll(m => m == -1); + + if (activityFlowRow.MetricsIDs != null && activityFlowRow.MetricsIDs.Count > 0) + { + StringBuilder sb = new StringBuilder(128); + foreach (int metricID in activityFlowRow.MetricsIDs) + { + sb.Append(String.Format(deepLinkMetricTemplateInMetricBrowser, entityIdForMetricBrowser, metricID)); + sb.Append(","); + } + sb.Remove(sb.Length - 1, 1); + activityFlowRow.MetricLink = String.Format(DEEPLINK_METRIC, activityFlowRow.Controller, activityFlowRow.ApplicationID, sb.ToString(), DEEPLINK_THIS_TIMERANGE); + } + + activityFlowsList.Add(activityFlowRow); + } + + // Process each call between Tiers, Tiers and Backends, and Tiers and Applications + foreach (JToken entityConnection in flowmapEntityConnections) + { + ActivityFlow activityFlowRowTemplate = new ActivityFlow(); + + // Prepare the row + activityFlowRowTemplate.MetricsIDs = new List(3); + + activityFlowRowTemplate.Controller = applicationRow.Controller; + activityFlowRowTemplate.ApplicationName = applicationRow.ApplicationName; + activityFlowRowTemplate.ApplicationID = applicationRow.ApplicationID; + + activityFlowRowTemplate.ControllerLink = String.Format(DEEPLINK_CONTROLLER, activityFlowRowTemplate.Controller, DEEPLINK_THIS_TIMERANGE); + activityFlowRowTemplate.ApplicationLink = String.Format(DEEPLINK_APPLICATION, activityFlowRowTemplate.Controller, activityFlowRowTemplate.ApplicationID, DEEPLINK_THIS_TIMERANGE); + + activityFlowRowTemplate.Duration = (int)(jobConfiguration.Input.ExpandedTimeRange.To - jobConfiguration.Input.ExpandedTimeRange.From).Duration().TotalMinutes; + activityFlowRowTemplate.From = jobConfiguration.Input.ExpandedTimeRange.From.ToLocalTime(); + activityFlowRowTemplate.To = jobConfiguration.Input.ExpandedTimeRange.To.ToLocalTime(); + activityFlowRowTemplate.FromUtc = jobConfiguration.Input.ExpandedTimeRange.From; + activityFlowRowTemplate.ToUtc = jobConfiguration.Input.ExpandedTimeRange.To; + + activityFlowRowTemplate.CallDirection = "Exit"; + + activityFlowRowTemplate.FromEntityID = (long)entityConnection["sourceNodeDefinition"]["entityId"]; + JObject entity = (JObject)flowmapEntities.Where(e => (long)e["idNum"] == activityFlowRowTemplate.FromEntityID && e["entityType"].ToString() == entityConnection["sourceNodeDefinition"]["entityType"].ToString()).FirstOrDefault(); + if (entity != null) + { + activityFlowRowTemplate.FromName = entity["name"].ToString(); + } + string deepLinkMetricTemplateInMetricBrowser = DEEPLINK_METRIC_APPLICATION_TARGET_METRIC_ID; + long entityIdForMetricBrowser = activityFlowRowTemplate.ApplicationID; switch (entityConnection["sourceNodeDefinition"]["entityType"].ToString()) { case ENTITY_TYPE_TIER: @@ -15774,19 +15913,6 @@ private static void convertFlowmapsBusinessTransaction(ProgramOptions programOpt break; } - // Haven't seen the incoming calls on the flowmap for Nodes. But maybe? - if (startTier != null) - { - if (activityFlowRowTemplate.FromEntityID == (long)startTier["idNum"]) - { - activityFlowRowTemplate.CallDirection = "FirstHop"; - } - else - { - activityFlowRowTemplate.CallDirection = "SubsequentHop"; - } - } - // Process each of the stats nodes, duplicating things as we need them foreach (JToken entityConnectionStat in entityConnection["stats"]) { @@ -15824,7 +15950,7 @@ private static void convertFlowmapsBusinessTransaction(ProgramOptions programOpt activityFlowRow.ErrorsPercentage = Math.Round((double)(double)activityFlowRow.Errors / (double)activityFlowRow.Calls * 100, 2); if (Double.IsNaN(activityFlowRow.ErrorsPercentage) == true) activityFlowRow.ErrorsPercentage = 0; - + activityFlowRow.MetricsIDs.RemoveAll(m => m == -1); if (activityFlowRow.MetricsIDs != null && activityFlowRow.MetricsIDs.Count > 0) @@ -15844,21 +15970,23 @@ private static void convertFlowmapsBusinessTransaction(ProgramOptions programOpt } // Sort them - activityFlowsList = activityFlowsList.OrderBy(a => a.CallDirection).ThenBy(a => a.FromType).ThenBy(a => a.FromName).ThenBy(a => a.ToType).ThenBy(a => a.ToName).ThenBy(a => a.CallType).ThenBy(a => a.CPM).ToList(); + activityFlowsList = activityFlowsList.OrderBy(a => a.CallDirection).ThenBy(a => a.FromType).ThenBy(a => a.FromName).ThenBy(a => a.ToName).ThenBy(a => a.CallType).ThenBy(a => a.CPM).ToList(); string activityGridReportFileName = Path.Combine( metricsEntityFolderPath, CONVERT_ACTIVITY_GRID_FILE_NAME); FileIOHelper.writeListToCSVFile(activityFlowsList, new ActivityFlowReportMap(), activityGridReportFileName); + + return; } - private static void convertFlowmapBackend(ProgramOptions programOptions, JobConfiguration jobConfiguration, JobTarget jobTarget, EntityBackend backendRow, string metricsFolderPath) + private static void convertFlowmapTier(ProgramOptions programOptions, JobConfiguration jobConfiguration, JobTarget jobTarget, EntityTier tierRow, string metricsFolderPath) { string metricsEntityFolderPath = Path.Combine( metricsFolderPath, - BACKENDS_TYPE_SHORT, - getShortenedEntityNameForFileSystem(backendRow.BackendName, backendRow.BackendID)); + TIERS_TYPE_SHORT, + getShortenedEntityNameForFileSystem(tierRow.TierName, tierRow.TierID)); string flowmapDataFilePath = Path.Combine( metricsEntityFolderPath, @@ -15882,10 +16010,9 @@ private static void convertFlowmapBackend(ProgramOptions programOptions, JobConf { activityFlowsList = new List(flowmapEntityConnections.Count); - // We don't display grid for Backends. But it is quite similar to Tier view - // For Backends, not going to process individual entities, but only connecting lines + // For Tiers, not going to process individual entities, but only connecting lines - // Process each call between Tiers, Tiers and Backends + // Process each call between Tiers, Tiers and Backends, and Tiers and Applications foreach (JToken entityConnection in flowmapEntityConnections) { ActivityFlow activityFlowRowTemplate = new ActivityFlow(); @@ -15893,9 +16020,9 @@ private static void convertFlowmapBackend(ProgramOptions programOptions, JobConf // Prepare the row activityFlowRowTemplate.MetricsIDs = new List(3); - activityFlowRowTemplate.Controller = backendRow.Controller; - activityFlowRowTemplate.ApplicationName = backendRow.ApplicationName; - activityFlowRowTemplate.ApplicationID = backendRow.ApplicationID; + activityFlowRowTemplate.Controller = tierRow.Controller; + activityFlowRowTemplate.ApplicationName = tierRow.ApplicationName; + activityFlowRowTemplate.ApplicationID = tierRow.ApplicationID; activityFlowRowTemplate.ControllerLink = String.Format(DEEPLINK_CONTROLLER, activityFlowRowTemplate.Controller, DEEPLINK_THIS_TIMERANGE); activityFlowRowTemplate.ApplicationLink = String.Format(DEEPLINK_APPLICATION, activityFlowRowTemplate.Controller, activityFlowRowTemplate.ApplicationID, DEEPLINK_THIS_TIMERANGE); @@ -15969,7 +16096,7 @@ private static void convertFlowmapBackend(ProgramOptions programOptions, JobConf break; } - if (activityFlowRowTemplate.FromEntityID == backendRow.BackendID) + if (activityFlowRowTemplate.FromEntityID == tierRow.TierID) { activityFlowRowTemplate.CallDirection = "Outgoing"; } @@ -16044,1250 +16171,2851 @@ private static void convertFlowmapBackend(ProgramOptions programOptions, JobConf FileIOHelper.writeListToCSVFile(activityFlowsList, new ActivityFlowReportMap(), activityGridReportFileName); } - #endregion - - #region Snapshot conversion functions - - private static int indexSnapshots(ProgramOptions programOptions, JobConfiguration jobConfiguration, JobTarget jobTarget, JobTimeRange jobTimeRange, List entityList, List tiersList, List backendsList, List serviceEndpointsList, List errorsList, bool progressToConsole) + private static void convertFlowmapNode(ProgramOptions programOptions, JobConfiguration jobConfiguration, JobTarget jobTarget, EntityNode nodeRow, string metricsFolderPath) { - int j = 0; + string metricsEntityFolderPath = Path.Combine( + metricsFolderPath, + NODES_TYPE_SHORT, + getShortenedEntityNameForFileSystem(nodeRow.TierName, nodeRow.TierID), + getShortenedEntityNameForFileSystem(nodeRow.NodeName, nodeRow.NodeID)); - #region Target step variables + string flowmapDataFilePath = Path.Combine( + metricsEntityFolderPath, + String.Format(EXTRACT_ENTITY_FLOWMAP_FILE_NAME, jobConfiguration.Input.ExpandedTimeRange.From, jobConfiguration.Input.ExpandedTimeRange.To)); - string controllerFolderPath = Path.Combine(programOptions.OutputJobFolderPath, getFileSystemSafeString(new Uri(jobTarget.Controller).Host)); - string applicationFolderPath = Path.Combine(controllerFolderPath, getShortenedEntityNameForFileSystem(jobTarget.Application, jobTarget.ApplicationID)); - string snapshotsFolderPath = Path.Combine(applicationFolderPath, SNAPSHOTS_FOLDER_NAME); - string reportsFolderPath = Path.Combine(programOptions.OutputJobFolderPath, REPORTS_FOLDER_NAME); + JObject flowmapData = FileIOHelper.loadJObjectFromFile(flowmapDataFilePath); + if (flowmapData == null) + { + return; + } - #endregion + long fromTimeUnix = convertToUnixTimestamp(jobConfiguration.Input.ExpandedTimeRange.From); + long toTimeUnix = convertToUnixTimestamp(jobConfiguration.Input.ExpandedTimeRange.To); + long differenceInMinutes = (toTimeUnix - fromTimeUnix) / (60000); + string DEEPLINK_THIS_TIMERANGE = String.Format(DEEPLINK_TIMERANGE_BETWEEN_TIMES, toTimeUnix, fromTimeUnix, differenceInMinutes); - foreach (JToken snapshotToken in entityList) + List activityFlowsList = null; + JArray flowmapEntities = (JArray)flowmapData["nodes"]; + JArray flowmapEntityConnections = (JArray)flowmapData["edges"]; + if (flowmapEntities != null && flowmapEntityConnections != null) { - // Only do first in chain - if ((bool)snapshotToken["firstInChain"] == false) + activityFlowsList = new List(flowmapEntityConnections.Count); + + // For Nodes, not going to process individual entities, but only connecting lines + + // Process each call between Tiers, Tiers and Backends, and Tiers and Applications + foreach (JToken entityConnection in flowmapEntityConnections) { - continue; - } + ActivityFlow activityFlowRowTemplate = new ActivityFlow(); - logger.Info("Indexing snapshot for Application {0}, Tier {1}, Business Transaction {2}, RequestGUID {3}", jobTarget.Application, snapshotToken["applicationComponentName"], snapshotToken["businessTransactionName"], snapshotToken["requestGUID"]); + // Prepare the row + activityFlowRowTemplate.MetricsIDs = new List(3); - #region Target step variables + activityFlowRowTemplate.Controller = nodeRow.Controller; + activityFlowRowTemplate.ApplicationName = nodeRow.ApplicationName; + activityFlowRowTemplate.ApplicationID = nodeRow.ApplicationID; - DateTime snapshotTime = convertFromUnixTimestamp((long)snapshotToken["serverStartTime"]); + activityFlowRowTemplate.ControllerLink = String.Format(DEEPLINK_CONTROLLER, activityFlowRowTemplate.Controller, DEEPLINK_THIS_TIMERANGE); + activityFlowRowTemplate.ApplicationLink = String.Format(DEEPLINK_APPLICATION, activityFlowRowTemplate.Controller, activityFlowRowTemplate.ApplicationID, DEEPLINK_THIS_TIMERANGE); - string snapshotFolderPath = Path.Combine( - snapshotsFolderPath, - getShortenedEntityNameForFileSystem(snapshotToken["applicationComponentName"].ToString(), (long)snapshotToken["applicationComponentId"]), - getShortenedEntityNameForFileSystem(snapshotToken["businessTransactionName"].ToString(), (long)snapshotToken["businessTransactionId"]), - String.Format("{0:yyyyMMddHH}", snapshotTime), - userExperienceFolderNameMapping[snapshotToken["userExperience"].ToString()], - String.Format(SNAPSHOT_FOLDER_NAME, snapshotToken["requestGUID"], snapshotTime)); + activityFlowRowTemplate.Duration = (int)(jobConfiguration.Input.ExpandedTimeRange.To - jobConfiguration.Input.ExpandedTimeRange.From).Duration().TotalMinutes; + activityFlowRowTemplate.From = jobConfiguration.Input.ExpandedTimeRange.From.ToLocalTime(); + activityFlowRowTemplate.To = jobConfiguration.Input.ExpandedTimeRange.To.ToLocalTime(); + activityFlowRowTemplate.FromUtc = jobConfiguration.Input.ExpandedTimeRange.From; + activityFlowRowTemplate.ToUtc = jobConfiguration.Input.ExpandedTimeRange.To; - string snapshotSegmentsDataFilePath = Path.Combine(snapshotFolderPath, EXTRACT_SNAPSHOT_SEGMENT_FILE_NAME); + activityFlowRowTemplate.FromEntityID = (long)entityConnection["sourceNodeDefinition"]["entityId"]; + JObject entity = (JObject)flowmapEntities.Where(e => (long)e["idNum"] == activityFlowRowTemplate.FromEntityID && e["entityType"].ToString() == entityConnection["sourceNodeDefinition"]["entityType"].ToString()).FirstOrDefault(); + if (entity != null) + { + activityFlowRowTemplate.FromName = entity["name"].ToString(); + } + string deepLinkMetricTemplateInMetricBrowser = DEEPLINK_METRIC_APPLICATION_TARGET_METRIC_ID; + long entityIdForMetricBrowser = activityFlowRowTemplate.ApplicationID; + switch (entityConnection["sourceNodeDefinition"]["entityType"].ToString()) + { + case ENTITY_TYPE_NODE: + deepLinkMetricTemplateInMetricBrowser = DEEPLINK_METRIC_NODE_TARGET_METRIC_ID; + entityIdForMetricBrowser = activityFlowRowTemplate.FromEntityID; + activityFlowRowTemplate.FromType = "Node"; + activityFlowRowTemplate.FromLink = String.Format(DEEPLINK_NODE, activityFlowRowTemplate.Controller, activityFlowRowTemplate.ApplicationID, activityFlowRowTemplate.FromEntityID, DEEPLINK_THIS_TIMERANGE); + break; - string snapshotsFileName = Path.Combine(snapshotFolderPath, CONVERT_SNAPSHOT_FILE_NAME); - string segmentsFileName = Path.Combine(snapshotFolderPath, CONVERT_SNAPSHOT_SEGMENTS_FILE_NAME); - string exitCallsFileName = Path.Combine(snapshotFolderPath, CONVERT_SNAPSHOT_SEGMENTS_EXIT_CALLS_FILE_NAME); - string serviceEndpointCallsFileName = Path.Combine(snapshotFolderPath, CONVERT_SNAPSHOT_SEGMENTS_SERVICE_ENDPOINT_CALLS_FILE_NAME); - string detectedErrorsFileName = Path.Combine(snapshotFolderPath, CONVERT_SNAPSHOT_SEGMENTS_DETECTED_ERRORS_FILE_NAME); - string businessDataFileName = Path.Combine(snapshotFolderPath, CONVERT_SNAPSHOT_SEGMENTS_BUSINESS_DATA_FILE_NAME); + case ENTITY_TYPE_TIER: + deepLinkMetricTemplateInMetricBrowser = DEEPLINK_METRIC_TIER_TARGET_METRIC_ID; + entityIdForMetricBrowser = activityFlowRowTemplate.FromEntityID; + activityFlowRowTemplate.FromType = "Tier"; + activityFlowRowTemplate.FromLink = String.Format(DEEPLINK_TIER, activityFlowRowTemplate.Controller, activityFlowRowTemplate.ApplicationID, activityFlowRowTemplate.FromEntityID, DEEPLINK_THIS_TIMERANGE); + break; - #endregion + case ENTITY_TYPE_BACKEND: + activityFlowRowTemplate.FromType = "Backend"; + activityFlowRowTemplate.FromLink = String.Format(DEEPLINK_BACKEND, activityFlowRowTemplate.Controller, activityFlowRowTemplate.ApplicationID, activityFlowRowTemplate.FromEntityID, DEEPLINK_THIS_TIMERANGE); + break; - if (File.Exists(snapshotsFileName) == false || - File.Exists(segmentsFileName) == false || - File.Exists(exitCallsFileName) == false || - File.Exists(serviceEndpointCallsFileName) == false || - File.Exists(detectedErrorsFileName) == false || - File.Exists(businessDataFileName) == false) - { - #region Fill in Snapshot data + case ENTITY_TYPE_APPLICATION: + deepLinkMetricTemplateInMetricBrowser = DEEPLINK_METRIC_TIER_TARGET_METRIC_ID; + activityFlowRowTemplate.FromType = "Application"; + activityFlowRowTemplate.FromLink = String.Format(DEEPLINK_APPLICATION, activityFlowRowTemplate.Controller, activityFlowRowTemplate.FromEntityID, DEEPLINK_THIS_TIMERANGE); + break; - Snapshot snapshot = new Snapshot(); - snapshot.Controller = jobTarget.Controller; - snapshot.ApplicationName = jobTarget.Application; - snapshot.ApplicationID = jobTarget.ApplicationID; - snapshot.TierID = (long)snapshotToken["applicationComponentId"]; - snapshot.TierName = snapshotToken["applicationComponentName"].ToString(); - snapshot.BTID = (long)snapshotToken["businessTransactionId"]; - snapshot.BTName = snapshotToken["businessTransactionName"].ToString(); - snapshot.NodeID = (long)snapshotToken["applicationComponentNodeId"]; - snapshot.NodeName = snapshotToken["applicationComponentNodeName"].ToString(); - - snapshot.OccuredUtc = convertFromUnixTimestamp((long)snapshotToken["serverStartTime"]); - snapshot.Occured = snapshot.OccuredUtc.ToLocalTime(); - - snapshot.RequestID = snapshotToken["requestGUID"].ToString(); - snapshot.UserExperience = snapshotToken["userExperience"].ToString(); - snapshot.Duration = (long)snapshotToken["timeTakenInMilliSecs"]; - snapshot.DiagSessionID = snapshotToken["diagnosticSessionGUID"].ToString(); - if (snapshotToken["url"] != null) { snapshot.URL = snapshotToken["url"].ToString(); } + default: + activityFlowRowTemplate.FromName = entityConnection["sourceNode"].ToString(); + activityFlowRowTemplate.FromType = entityConnection["sourceNodeDefinition"]["entityType"].ToString(); + break; + } - snapshot.TakenSummary = snapshotToken["summary"].ToString(); - if (snapshot.TakenSummary.Contains("Scheduled Snapshots:") == true) + activityFlowRowTemplate.ToEntityID = (long)entityConnection["targetNodeDefinition"]["entityId"]; + entity = (JObject)flowmapEntities.Where(e => (long)e["idNum"] == activityFlowRowTemplate.ToEntityID && e["entityType"].ToString() == entityConnection["targetNodeDefinition"]["entityType"].ToString()).FirstOrDefault(); + if (entity != null) { - snapshot.TakenReason = "Scheduled"; + activityFlowRowTemplate.ToName = entity["name"].ToString(); } - else if (snapshot.TakenSummary.Contains("[Manual Diagnostic Session]") == true) + switch (entityConnection["targetNodeDefinition"]["entityType"].ToString()) { - snapshot.TakenReason = "Diagnostic Session"; + case "APPLICATION_COMPONENT_NODE": + activityFlowRowTemplate.ToType = "Node"; + activityFlowRowTemplate.ToLink = String.Format(DEEPLINK_NODE, activityFlowRowTemplate.Controller, activityFlowRowTemplate.ApplicationID, activityFlowRowTemplate.ToEntityID, DEEPLINK_THIS_TIMERANGE); + break; + + case ENTITY_TYPE_TIER: + activityFlowRowTemplate.ToType = "Tier"; + activityFlowRowTemplate.ToLink = String.Format(DEEPLINK_TIER, activityFlowRowTemplate.Controller, activityFlowRowTemplate.ApplicationID, activityFlowRowTemplate.ToEntityID, DEEPLINK_THIS_TIMERANGE); + break; + + case ENTITY_TYPE_BACKEND: + activityFlowRowTemplate.ToType = "Backend"; + activityFlowRowTemplate.ToLink = String.Format(DEEPLINK_BACKEND, activityFlowRowTemplate.Controller, activityFlowRowTemplate.ApplicationID, activityFlowRowTemplate.ToEntityID, DEEPLINK_THIS_TIMERANGE); + break; + + case ENTITY_TYPE_APPLICATION: + activityFlowRowTemplate.ToType = "Application"; + activityFlowRowTemplate.ToLink = String.Format(DEEPLINK_APPLICATION, activityFlowRowTemplate.Controller, activityFlowRowTemplate.ToEntityID, DEEPLINK_THIS_TIMERANGE); + break; + + default: + activityFlowRowTemplate.ToName = entityConnection["targetNode"].ToString(); + activityFlowRowTemplate.ToType = entityConnection["targetNodeDefinition"]["entityType"].ToString(); + break; } - else if (snapshot.TakenSummary.Contains("[Error]") == true) + + // Haven't seen the incoming calls on the flowmap for Nodes. But maybe? + if (activityFlowRowTemplate.FromEntityID == nodeRow.NodeID) { - snapshot.TakenReason = "Error"; + activityFlowRowTemplate.CallDirection = "Outgoing"; } - else if (snapshot.TakenSummary.Contains("Request was slower than the Standard Deviation threshold") == true) + else { - snapshot.TakenReason = "Slower than StDev"; + activityFlowRowTemplate.CallDirection = "Incoming"; } - else if (snapshot.TakenSummary.Contains("of requests were slow in the last minute starting") == true) + + // Process each of the stats nodes, duplicating things as we need them + foreach (JToken entityConnectionStat in entityConnection["stats"]) { - snapshot.TakenReason = "Slow Rate in Minute"; + ActivityFlow activityFlowRow = activityFlowRowTemplate.Clone(); + + activityFlowRow.CallType = entityConnectionStat["exitPointCall"]["exitPointType"].ToString(); + if (((bool)entityConnectionStat["exitPointCall"]["synchronous"]) == false) + { + activityFlowRow.CallType = String.Format("{0} async", activityFlowRow.CallType); + } + + if (entityConnectionStat["averageResponseTime"].HasValues == true) + { + activityFlowRow.ART = (long)entityConnectionStat["averageResponseTime"]["metricValue"]; + activityFlowRow.MetricsIDs.Add((long)entityConnectionStat["averageResponseTime"]["metricId"]); + } + if (entityConnectionStat["callsPerMinute"].HasValues == true) + { + activityFlowRow.CPM = (long)entityConnectionStat["callsPerMinute"]["metricValue"]; + activityFlowRow.MetricsIDs.Add((long)entityConnectionStat["callsPerMinute"]["metricId"]); + } + if (entityConnectionStat["errorsPerMinute"].HasValues == true) + { + activityFlowRow.EPM = (long)entityConnectionStat["errorsPerMinute"]["metricValue"]; + activityFlowRow.MetricsIDs.Add((long)entityConnectionStat["errorsPerMinute"]["metricId"]); + } + if (entityConnectionStat["numberOfCalls"].HasValues == true) { activityFlowRow.Calls = (long)entityConnectionStat["numberOfCalls"]["metricValue"]; } + if (entityConnectionStat["numberOfErrors"].HasValues == true) { activityFlowRow.Errors = (long)entityConnectionStat["numberOfErrors"]["metricValue"]; } + + if (activityFlowRow.ART < 0) { activityFlowRow.ART = 0; } + if (activityFlowRow.CPM < 0) { activityFlowRow.ART = 0; } + if (activityFlowRow.EPM < 0) { activityFlowRow.EPM = 0; } + if (activityFlowRow.Calls < 0) { activityFlowRow.Calls = 0; } + if (activityFlowRow.Errors < 0) { activityFlowRow.Errors = 0; } + + activityFlowRow.ErrorsPercentage = Math.Round((double)(double)activityFlowRow.Errors / (double)activityFlowRow.Calls * 100, 2); + if (Double.IsNaN(activityFlowRow.ErrorsPercentage) == true) activityFlowRow.ErrorsPercentage = 0; + + activityFlowRow.MetricsIDs.RemoveAll(m => m == -1); + + if (activityFlowRow.MetricsIDs != null && activityFlowRow.MetricsIDs.Count > 0) + { + StringBuilder sb = new StringBuilder(128); + foreach (int metricID in activityFlowRow.MetricsIDs) + { + sb.Append(String.Format(deepLinkMetricTemplateInMetricBrowser, entityIdForMetricBrowser, metricID)); + sb.Append(","); + } + sb.Remove(sb.Length - 1, 1); + activityFlowRow.MetricLink = String.Format(DEEPLINK_METRIC, activityFlowRow.Controller, activityFlowRow.ApplicationID, sb.ToString(), DEEPLINK_THIS_TIMERANGE); + } + activityFlowsList.Add(activityFlowRow); } - else if (snapshot.TakenSummary.Contains("of requests had errors in the last minute starting") == true) + } + } + + // Sort them + activityFlowsList = activityFlowsList.OrderBy(a => a.CallDirection).ThenBy(a => a.FromType).ThenBy(a => a.FromName).ThenBy(a => a.ToType).ThenBy(a => a.ToName).ThenBy(a => a.CallType).ThenBy(a => a.CPM).ToList(); + + string activityGridReportFileName = Path.Combine( + metricsEntityFolderPath, + CONVERT_ACTIVITY_GRID_FILE_NAME); + + FileIOHelper.writeListToCSVFile(activityFlowsList, new ActivityFlowReportMap(), activityGridReportFileName); + } + + private static void convertFlowmapsBusinessTransaction(ProgramOptions programOptions, JobConfiguration jobConfiguration, JobTarget jobTarget, EntityBusinessTransaction businessTransactionRow, string metricsFolderPath) + { + string metricsEntityFolderPath = Path.Combine( + metricsFolderPath, + BUSINESS_TRANSACTIONS_TYPE_SHORT, + getShortenedEntityNameForFileSystem(businessTransactionRow.TierName, businessTransactionRow.TierID), + getShortenedEntityNameForFileSystem(businessTransactionRow.BTName, businessTransactionRow.BTID)); + + string flowmapDataFilePath = Path.Combine( + metricsEntityFolderPath, + String.Format(EXTRACT_ENTITY_FLOWMAP_FILE_NAME, jobConfiguration.Input.ExpandedTimeRange.From, jobConfiguration.Input.ExpandedTimeRange.To)); + + JObject flowmapData = FileIOHelper.loadJObjectFromFile(flowmapDataFilePath); + if (flowmapData == null) + { + return; + } + + long fromTimeUnix = convertToUnixTimestamp(jobConfiguration.Input.ExpandedTimeRange.From); + long toTimeUnix = convertToUnixTimestamp(jobConfiguration.Input.ExpandedTimeRange.To); + long differenceInMinutes = (toTimeUnix - fromTimeUnix) / (60000); + string DEEPLINK_THIS_TIMERANGE = String.Format(DEEPLINK_TIMERANGE_BETWEEN_TIMES, toTimeUnix, fromTimeUnix, differenceInMinutes); + + List activityFlowsList = null; + JArray flowmapEntities = (JArray)flowmapData["nodes"]; + JArray flowmapEntityConnections = (JArray)flowmapData["edges"]; + if (flowmapEntities != null && flowmapEntityConnections != null) + { + activityFlowsList = new List(flowmapEntityConnections.Count); + + // Controller shows a pretty complex grid view for jumps that continue from other tiers. + // I couldn't figure out how the JSON is converted into that + // For Business Transactions, not going to process individual entities, but only connecting lines + + // Assume that the first node is the + JObject startTier = (JObject)flowmapEntities.Where(e => (bool)e["startComponent"] == true).FirstOrDefault(); + + // Process each call between Tiers, Tiers and Backends, and Tiers and Applications + foreach (JToken entityConnection in flowmapEntityConnections) + { + ActivityFlow activityFlowRowTemplate = new ActivityFlow(); + + // Prepare the row + activityFlowRowTemplate.MetricsIDs = new List(3); + + activityFlowRowTemplate.Controller = businessTransactionRow.Controller; + activityFlowRowTemplate.ApplicationName = businessTransactionRow.ApplicationName; + activityFlowRowTemplate.ApplicationID = businessTransactionRow.ApplicationID; + + activityFlowRowTemplate.ControllerLink = String.Format(DEEPLINK_CONTROLLER, activityFlowRowTemplate.Controller, DEEPLINK_THIS_TIMERANGE); + activityFlowRowTemplate.ApplicationLink = String.Format(DEEPLINK_APPLICATION, activityFlowRowTemplate.Controller, activityFlowRowTemplate.ApplicationID, DEEPLINK_THIS_TIMERANGE); + + activityFlowRowTemplate.Duration = (int)(jobConfiguration.Input.ExpandedTimeRange.To - jobConfiguration.Input.ExpandedTimeRange.From).Duration().TotalMinutes; + activityFlowRowTemplate.From = jobConfiguration.Input.ExpandedTimeRange.From.ToLocalTime(); + activityFlowRowTemplate.To = jobConfiguration.Input.ExpandedTimeRange.To.ToLocalTime(); + activityFlowRowTemplate.FromUtc = jobConfiguration.Input.ExpandedTimeRange.From; + activityFlowRowTemplate.ToUtc = jobConfiguration.Input.ExpandedTimeRange.To; + + activityFlowRowTemplate.FromEntityID = (long)entityConnection["sourceNodeDefinition"]["entityId"]; + JObject entity = (JObject)flowmapEntities.Where(e => (long)e["idNum"] == activityFlowRowTemplate.FromEntityID && e["entityType"].ToString() == entityConnection["sourceNodeDefinition"]["entityType"].ToString()).FirstOrDefault(); + if (entity != null) { - snapshot.TakenReason = "Error Rate in Minute"; + activityFlowRowTemplate.FromName = entity["name"].ToString(); } - else + string deepLinkMetricTemplateInMetricBrowser = DEEPLINK_METRIC_APPLICATION_TARGET_METRIC_ID; + long entityIdForMetricBrowser = activityFlowRowTemplate.ApplicationID; + switch (entityConnection["sourceNodeDefinition"]["entityType"].ToString()) { - snapshot.TakenReason = ""; - } + case ENTITY_TYPE_TIER: + deepLinkMetricTemplateInMetricBrowser = DEEPLINK_METRIC_TIER_TARGET_METRIC_ID; + entityIdForMetricBrowser = activityFlowRowTemplate.FromEntityID; + activityFlowRowTemplate.FromType = "Tier"; + activityFlowRowTemplate.FromLink = String.Format(DEEPLINK_TIER, activityFlowRowTemplate.Controller, activityFlowRowTemplate.ApplicationID, activityFlowRowTemplate.FromEntityID, DEEPLINK_THIS_TIMERANGE); + break; - if ((bool)snapshotToken["fullCallgraph"] == true) - { - snapshot.CallGraphType = "FULL"; + case ENTITY_TYPE_BACKEND: + activityFlowRowTemplate.FromType = "Backend"; + activityFlowRowTemplate.FromLink = String.Format(DEEPLINK_BACKEND, activityFlowRowTemplate.Controller, activityFlowRowTemplate.ApplicationID, activityFlowRowTemplate.FromEntityID, DEEPLINK_THIS_TIMERANGE); + break; + + case ENTITY_TYPE_APPLICATION: + deepLinkMetricTemplateInMetricBrowser = DEEPLINK_METRIC_TIER_TARGET_METRIC_ID; + activityFlowRowTemplate.FromType = "Application"; + activityFlowRowTemplate.FromLink = String.Format(DEEPLINK_APPLICATION, activityFlowRowTemplate.Controller, activityFlowRowTemplate.FromEntityID, DEEPLINK_THIS_TIMERANGE); + break; + + default: + activityFlowRowTemplate.FromName = entityConnection["sourceNode"].ToString(); + activityFlowRowTemplate.FromType = entityConnection["sourceNodeDefinition"]["entityType"].ToString(); + break; } - else if ((bool)snapshotToken["delayedCallGraph"] == true) + + activityFlowRowTemplate.ToEntityID = (long)entityConnection["targetNodeDefinition"]["entityId"]; + entity = (JObject)flowmapEntities.Where(e => (long)e["idNum"] == activityFlowRowTemplate.ToEntityID && e["entityType"].ToString() == entityConnection["targetNodeDefinition"]["entityType"].ToString()).FirstOrDefault(); + if (entity != null) { - snapshot.CallGraphType = "PARTIAL"; + activityFlowRowTemplate.ToName = entity["name"].ToString(); } - else + switch (entityConnection["targetNodeDefinition"]["entityType"].ToString()) { - snapshot.CallGraphType = "NONE"; - } + case ENTITY_TYPE_TIER: + activityFlowRowTemplate.ToType = "Tier"; + activityFlowRowTemplate.ToLink = String.Format(DEEPLINK_TIER, activityFlowRowTemplate.Controller, activityFlowRowTemplate.ApplicationID, activityFlowRowTemplate.ToEntityID, DEEPLINK_THIS_TIMERANGE); + break; - snapshot.HasErrors = (bool)snapshotToken["errorOccurred"]; - snapshot.IsArchived = (bool)snapshotToken["archived"]; + case ENTITY_TYPE_BACKEND: + activityFlowRowTemplate.ToType = "Backend"; + activityFlowRowTemplate.ToLink = String.Format(DEEPLINK_BACKEND, activityFlowRowTemplate.Controller, activityFlowRowTemplate.ApplicationID, activityFlowRowTemplate.ToEntityID, DEEPLINK_THIS_TIMERANGE); + break; + + case ENTITY_TYPE_APPLICATION: + activityFlowRowTemplate.ToType = "Application"; + activityFlowRowTemplate.ToLink = String.Format(DEEPLINK_APPLICATION, activityFlowRowTemplate.Controller, activityFlowRowTemplate.ToEntityID, DEEPLINK_THIS_TIMERANGE); + break; + + default: + activityFlowRowTemplate.ToName = entityConnection["targetNode"].ToString(); + activityFlowRowTemplate.ToType = entityConnection["targetNodeDefinition"]["entityType"].ToString(); + break; + } + + // Haven't seen the incoming calls on the flowmap for Nodes. But maybe? + if (startTier != null) + { + if (activityFlowRowTemplate.FromEntityID == (long)startTier["idNum"]) + { + activityFlowRowTemplate.CallDirection = "FirstHop"; + } + else + { + activityFlowRowTemplate.CallDirection = "SubsequentHop"; + } + } + + // Process each of the stats nodes, duplicating things as we need them + foreach (JToken entityConnectionStat in entityConnection["stats"]) + { + ActivityFlow activityFlowRow = activityFlowRowTemplate.Clone(); + + activityFlowRow.CallType = entityConnectionStat["exitPointCall"]["exitPointType"].ToString(); + if (((bool)entityConnectionStat["exitPointCall"]["synchronous"]) == false) + { + activityFlowRow.CallType = String.Format("{0} async", activityFlowRow.CallType); + } + + if (entityConnectionStat["averageResponseTime"].HasValues == true) + { + activityFlowRow.ART = (long)entityConnectionStat["averageResponseTime"]["metricValue"]; + activityFlowRow.MetricsIDs.Add((long)entityConnectionStat["averageResponseTime"]["metricId"]); + } + if (entityConnectionStat["callsPerMinute"].HasValues == true) + { + activityFlowRow.CPM = (long)entityConnectionStat["callsPerMinute"]["metricValue"]; + activityFlowRow.MetricsIDs.Add((long)entityConnectionStat["callsPerMinute"]["metricId"]); + } + if (entityConnectionStat["errorsPerMinute"].HasValues == true) + { + activityFlowRow.EPM = (long)entityConnectionStat["errorsPerMinute"]["metricValue"]; + activityFlowRow.MetricsIDs.Add((long)entityConnectionStat["errorsPerMinute"]["metricId"]); + } + if (entityConnectionStat["numberOfCalls"].HasValues == true) { activityFlowRow.Calls = (long)entityConnectionStat["numberOfCalls"]["metricValue"]; } + if (entityConnectionStat["numberOfErrors"].HasValues == true) { activityFlowRow.Errors = (long)entityConnectionStat["numberOfErrors"]["metricValue"]; } + + if (activityFlowRow.ART < 0) { activityFlowRow.ART = 0; } + if (activityFlowRow.CPM < 0) { activityFlowRow.ART = 0; } + if (activityFlowRow.EPM < 0) { activityFlowRow.EPM = 0; } + if (activityFlowRow.Calls < 0) { activityFlowRow.Calls = 0; } + if (activityFlowRow.Errors < 0) { activityFlowRow.Errors = 0; } + + activityFlowRow.ErrorsPercentage = Math.Round((double)(double)activityFlowRow.Errors / (double)activityFlowRow.Calls * 100, 2); + if (Double.IsNaN(activityFlowRow.ErrorsPercentage) == true) activityFlowRow.ErrorsPercentage = 0; + + activityFlowRow.MetricsIDs.RemoveAll(m => m == -1); + + if (activityFlowRow.MetricsIDs != null && activityFlowRow.MetricsIDs.Count > 0) + { + StringBuilder sb = new StringBuilder(128); + foreach (int metricID in activityFlowRow.MetricsIDs) + { + sb.Append(String.Format(deepLinkMetricTemplateInMetricBrowser, entityIdForMetricBrowser, metricID)); + sb.Append(","); + } + sb.Remove(sb.Length - 1, 1); + activityFlowRow.MetricLink = String.Format(DEEPLINK_METRIC, activityFlowRow.Controller, activityFlowRow.ApplicationID, sb.ToString(), DEEPLINK_THIS_TIMERANGE); + } + activityFlowsList.Add(activityFlowRow); + } + } + } + + // Sort them + activityFlowsList = activityFlowsList.OrderBy(a => a.CallDirection).ThenBy(a => a.FromType).ThenBy(a => a.FromName).ThenBy(a => a.ToType).ThenBy(a => a.ToName).ThenBy(a => a.CallType).ThenBy(a => a.CPM).ToList(); + + string activityGridReportFileName = Path.Combine( + metricsEntityFolderPath, + CONVERT_ACTIVITY_GRID_FILE_NAME); + + FileIOHelper.writeListToCSVFile(activityFlowsList, new ActivityFlowReportMap(), activityGridReportFileName); + } + + private static void convertFlowmapBackend(ProgramOptions programOptions, JobConfiguration jobConfiguration, JobTarget jobTarget, EntityBackend backendRow, string metricsFolderPath) + { + string metricsEntityFolderPath = Path.Combine( + metricsFolderPath, + BACKENDS_TYPE_SHORT, + getShortenedEntityNameForFileSystem(backendRow.BackendName, backendRow.BackendID)); + + string flowmapDataFilePath = Path.Combine( + metricsEntityFolderPath, + String.Format(EXTRACT_ENTITY_FLOWMAP_FILE_NAME, jobConfiguration.Input.ExpandedTimeRange.From, jobConfiguration.Input.ExpandedTimeRange.To)); + + JObject flowmapData = FileIOHelper.loadJObjectFromFile(flowmapDataFilePath); + if (flowmapData == null) + { + return; + } + + long fromTimeUnix = convertToUnixTimestamp(jobConfiguration.Input.ExpandedTimeRange.From); + long toTimeUnix = convertToUnixTimestamp(jobConfiguration.Input.ExpandedTimeRange.To); + long differenceInMinutes = (toTimeUnix - fromTimeUnix) / (60000); + string DEEPLINK_THIS_TIMERANGE = String.Format(DEEPLINK_TIMERANGE_BETWEEN_TIMES, toTimeUnix, fromTimeUnix, differenceInMinutes); + + List activityFlowsList = null; + JArray flowmapEntities = (JArray)flowmapData["nodes"]; + JArray flowmapEntityConnections = (JArray)flowmapData["edges"]; + if (flowmapEntities != null && flowmapEntityConnections != null) + { + activityFlowsList = new List(flowmapEntityConnections.Count); + + // We don't display grid for Backends. But it is quite similar to Tier view + // For Backends, not going to process individual entities, but only connecting lines + + // Process each call between Tiers, Tiers and Backends + foreach (JToken entityConnection in flowmapEntityConnections) + { + ActivityFlow activityFlowRowTemplate = new ActivityFlow(); + + // Prepare the row + activityFlowRowTemplate.MetricsIDs = new List(3); + + activityFlowRowTemplate.Controller = backendRow.Controller; + activityFlowRowTemplate.ApplicationName = backendRow.ApplicationName; + activityFlowRowTemplate.ApplicationID = backendRow.ApplicationID; + + activityFlowRowTemplate.ControllerLink = String.Format(DEEPLINK_CONTROLLER, activityFlowRowTemplate.Controller, DEEPLINK_THIS_TIMERANGE); + activityFlowRowTemplate.ApplicationLink = String.Format(DEEPLINK_APPLICATION, activityFlowRowTemplate.Controller, activityFlowRowTemplate.ApplicationID, DEEPLINK_THIS_TIMERANGE); + + activityFlowRowTemplate.Duration = (int)(jobConfiguration.Input.ExpandedTimeRange.To - jobConfiguration.Input.ExpandedTimeRange.From).Duration().TotalMinutes; + activityFlowRowTemplate.From = jobConfiguration.Input.ExpandedTimeRange.From.ToLocalTime(); + activityFlowRowTemplate.To = jobConfiguration.Input.ExpandedTimeRange.To.ToLocalTime(); + activityFlowRowTemplate.FromUtc = jobConfiguration.Input.ExpandedTimeRange.From; + activityFlowRowTemplate.ToUtc = jobConfiguration.Input.ExpandedTimeRange.To; + + activityFlowRowTemplate.FromEntityID = (long)entityConnection["sourceNodeDefinition"]["entityId"]; + JObject entity = (JObject)flowmapEntities.Where(e => (long)e["idNum"] == activityFlowRowTemplate.FromEntityID && e["entityType"].ToString() == entityConnection["sourceNodeDefinition"]["entityType"].ToString()).FirstOrDefault(); + if (entity != null) + { + activityFlowRowTemplate.FromName = entity["name"].ToString(); + } + string deepLinkMetricTemplateInMetricBrowser = DEEPLINK_METRIC_APPLICATION_TARGET_METRIC_ID; + long entityIdForMetricBrowser = activityFlowRowTemplate.ApplicationID; + switch (entityConnection["sourceNodeDefinition"]["entityType"].ToString()) + { + case ENTITY_TYPE_TIER: + deepLinkMetricTemplateInMetricBrowser = DEEPLINK_METRIC_TIER_TARGET_METRIC_ID; + entityIdForMetricBrowser = activityFlowRowTemplate.FromEntityID; + activityFlowRowTemplate.FromType = "Tier"; + activityFlowRowTemplate.FromLink = String.Format(DEEPLINK_TIER, activityFlowRowTemplate.Controller, activityFlowRowTemplate.ApplicationID, activityFlowRowTemplate.FromEntityID, DEEPLINK_THIS_TIMERANGE); + break; + + case ENTITY_TYPE_BACKEND: + activityFlowRowTemplate.FromType = "Backend"; + activityFlowRowTemplate.FromLink = String.Format(DEEPLINK_BACKEND, activityFlowRowTemplate.Controller, activityFlowRowTemplate.ApplicationID, activityFlowRowTemplate.FromEntityID, DEEPLINK_THIS_TIMERANGE); + break; + + case ENTITY_TYPE_APPLICATION: + deepLinkMetricTemplateInMetricBrowser = DEEPLINK_METRIC_TIER_TARGET_METRIC_ID; + activityFlowRowTemplate.FromType = "Application"; + activityFlowRowTemplate.FromLink = String.Format(DEEPLINK_APPLICATION, activityFlowRowTemplate.Controller, activityFlowRowTemplate.FromEntityID, DEEPLINK_THIS_TIMERANGE); + break; + + default: + activityFlowRowTemplate.FromName = entityConnection["sourceNode"].ToString(); + activityFlowRowTemplate.FromType = entityConnection["sourceNodeDefinition"]["entityType"].ToString(); + break; + } + + activityFlowRowTemplate.ToEntityID = (long)entityConnection["targetNodeDefinition"]["entityId"]; + entity = (JObject)flowmapEntities.Where(e => (long)e["idNum"] == activityFlowRowTemplate.ToEntityID && e["entityType"].ToString() == entityConnection["targetNodeDefinition"]["entityType"].ToString()).FirstOrDefault(); + if (entity != null) + { + activityFlowRowTemplate.ToName = entity["name"].ToString(); + } + switch (entityConnection["targetNodeDefinition"]["entityType"].ToString()) + { + case ENTITY_TYPE_TIER: + activityFlowRowTemplate.ToType = "Tier"; + activityFlowRowTemplate.ToLink = String.Format(DEEPLINK_TIER, activityFlowRowTemplate.Controller, activityFlowRowTemplate.ApplicationID, activityFlowRowTemplate.ToEntityID, DEEPLINK_THIS_TIMERANGE); + break; + + case ENTITY_TYPE_BACKEND: + activityFlowRowTemplate.ToType = "Backend"; + activityFlowRowTemplate.ToLink = String.Format(DEEPLINK_BACKEND, activityFlowRowTemplate.Controller, activityFlowRowTemplate.ApplicationID, activityFlowRowTemplate.ToEntityID, DEEPLINK_THIS_TIMERANGE); + break; + + case ENTITY_TYPE_APPLICATION: + activityFlowRowTemplate.ToType = "Application"; + activityFlowRowTemplate.ToLink = String.Format(DEEPLINK_APPLICATION, activityFlowRowTemplate.Controller, activityFlowRowTemplate.ToEntityID, DEEPLINK_THIS_TIMERANGE); + break; + + default: + activityFlowRowTemplate.ToName = entityConnection["targetNode"].ToString(); + activityFlowRowTemplate.ToType = entityConnection["targetNodeDefinition"]["entityType"].ToString(); + break; + } + + if (activityFlowRowTemplate.FromEntityID == backendRow.BackendID) + { + activityFlowRowTemplate.CallDirection = "Outgoing"; + } + else + { + activityFlowRowTemplate.CallDirection = "Incoming"; + } + + // Process each of the stats nodes, duplicating things as we need them + foreach (JToken entityConnectionStat in entityConnection["stats"]) + { + ActivityFlow activityFlowRow = activityFlowRowTemplate.Clone(); + + activityFlowRow.CallType = entityConnectionStat["exitPointCall"]["exitPointType"].ToString(); + if (((bool)entityConnectionStat["exitPointCall"]["synchronous"]) == false) + { + activityFlowRow.CallType = String.Format("{0} async", activityFlowRow.CallType); + } + + if (entityConnectionStat["averageResponseTime"].HasValues == true) + { + activityFlowRow.ART = (long)entityConnectionStat["averageResponseTime"]["metricValue"]; + activityFlowRow.MetricsIDs.Add((long)entityConnectionStat["averageResponseTime"]["metricId"]); + } + if (entityConnectionStat["callsPerMinute"].HasValues == true) + { + activityFlowRow.CPM = (long)entityConnectionStat["callsPerMinute"]["metricValue"]; + activityFlowRow.MetricsIDs.Add((long)entityConnectionStat["callsPerMinute"]["metricId"]); + } + if (entityConnectionStat["errorsPerMinute"].HasValues == true) + { + activityFlowRow.EPM = (long)entityConnectionStat["errorsPerMinute"]["metricValue"]; + activityFlowRow.MetricsIDs.Add((long)entityConnectionStat["errorsPerMinute"]["metricId"]); + } + if (entityConnectionStat["numberOfCalls"].HasValues == true) { activityFlowRow.Calls = (long)entityConnectionStat["numberOfCalls"]["metricValue"]; } + if (entityConnectionStat["numberOfErrors"].HasValues == true) { activityFlowRow.Errors = (long)entityConnectionStat["numberOfErrors"]["metricValue"]; } + + if (activityFlowRow.ART < 0) { activityFlowRow.ART = 0; } + if (activityFlowRow.CPM < 0) { activityFlowRow.ART = 0; } + if (activityFlowRow.EPM < 0) { activityFlowRow.EPM = 0; } + if (activityFlowRow.Calls < 0) { activityFlowRow.Calls = 0; } + if (activityFlowRow.Errors < 0) { activityFlowRow.Errors = 0; } + + activityFlowRow.ErrorsPercentage = Math.Round((double)(double)activityFlowRow.Errors / (double)activityFlowRow.Calls * 100, 2); + if (Double.IsNaN(activityFlowRow.ErrorsPercentage) == true) activityFlowRow.ErrorsPercentage = 0; + + activityFlowRow.MetricsIDs.RemoveAll(m => m == -1); + + if (activityFlowRow.MetricsIDs != null && activityFlowRow.MetricsIDs.Count > 0) + { + StringBuilder sb = new StringBuilder(128); + foreach (int metricID in activityFlowRow.MetricsIDs) + { + sb.Append(String.Format(deepLinkMetricTemplateInMetricBrowser, entityIdForMetricBrowser, metricID)); + sb.Append(","); + } + sb.Remove(sb.Length - 1, 1); + activityFlowRow.MetricLink = String.Format(DEEPLINK_METRIC, activityFlowRow.Controller, activityFlowRow.ApplicationID, sb.ToString(), DEEPLINK_THIS_TIMERANGE); + } + activityFlowsList.Add(activityFlowRow); + } + } + } + + // Sort them + activityFlowsList = activityFlowsList.OrderBy(a => a.CallDirection).ThenBy(a => a.FromType).ThenBy(a => a.FromName).ThenBy(a => a.ToType).ThenBy(a => a.ToName).ThenBy(a => a.CallType).ThenBy(a => a.CPM).ToList(); + + string activityGridReportFileName = Path.Combine( + metricsEntityFolderPath, + CONVERT_ACTIVITY_GRID_FILE_NAME); + + FileIOHelper.writeListToCSVFile(activityFlowsList, new ActivityFlowReportMap(), activityGridReportFileName); + } + + #endregion + + #region Snapshot conversion functions + + private static int indexSnapshots( + ProgramOptions programOptions, + JobConfiguration jobConfiguration, + JobTarget jobTarget, + JobTimeRange jobTimeRange, + List entityList, + List tiersList, + List backendsList, + List serviceEndpointsList, + List errorsList, + List methodInvocationDataCollectorsList, + Dictionary> methodCallLineClassToFrameworkTypeMappingDictionary, + bool progressToConsole) + { + int j = 0; + + #region Target step variables + + string controllerFolderPath = Path.Combine(programOptions.OutputJobFolderPath, getFileSystemSafeString(new Uri(jobTarget.Controller).Host)); + string applicationFolderPath = Path.Combine(controllerFolderPath, getShortenedEntityNameForFileSystem(jobTarget.Application, jobTarget.ApplicationID)); + string snapshotsFolderPath = Path.Combine(applicationFolderPath, SNAPSHOTS_FOLDER_NAME); + string reportsFolderPath = Path.Combine(programOptions.OutputJobFolderPath, REPORTS_FOLDER_NAME); + + #endregion + + foreach (JToken snapshotToken in entityList) + { + // Only do first in chain + if ((bool)snapshotToken["firstInChain"] == false) + { + continue; + } + + logger.Info("Indexing snapshot for Application {0}, Tier {1}, Business Transaction {2}, RequestGUID {3}", jobTarget.Application, snapshotToken["applicationComponentName"], snapshotToken["businessTransactionName"], snapshotToken["requestGUID"]); + + #region Target step variables + + DateTime snapshotTime = convertFromUnixTimestamp((long)snapshotToken["serverStartTime"]); + + string snapshotFolderPath = Path.Combine( + snapshotsFolderPath, + getShortenedEntityNameForFileSystem(snapshotToken["applicationComponentName"].ToString(), (long)snapshotToken["applicationComponentId"]), + getShortenedEntityNameForFileSystem(snapshotToken["businessTransactionName"].ToString(), (long)snapshotToken["businessTransactionId"]), + String.Format("{0:yyyyMMddHH}", snapshotTime), + userExperienceFolderNameMapping[snapshotToken["userExperience"].ToString()], + String.Format(SNAPSHOT_FOLDER_NAME, snapshotToken["requestGUID"], snapshotTime)); + + string snapshotSegmentsDataFilePath = Path.Combine(snapshotFolderPath, EXTRACT_SNAPSHOT_SEGMENT_FILE_NAME); + + string snapshotsFileName = Path.Combine(snapshotFolderPath, CONVERT_SNAPSHOT_FILE_NAME); + string segmentsFileName = Path.Combine(snapshotFolderPath, CONVERT_SNAPSHOT_SEGMENTS_FILE_NAME); + string exitCallsFileName = Path.Combine(snapshotFolderPath, CONVERT_SNAPSHOT_SEGMENTS_EXIT_CALLS_FILE_NAME); + string serviceEndpointCallsFileName = Path.Combine(snapshotFolderPath, CONVERT_SNAPSHOT_SEGMENTS_SERVICE_ENDPOINT_CALLS_FILE_NAME); + string detectedErrorsFileName = Path.Combine(snapshotFolderPath, CONVERT_SNAPSHOT_SEGMENTS_DETECTED_ERRORS_FILE_NAME); + string businessDataFileName = Path.Combine(snapshotFolderPath, CONVERT_SNAPSHOT_SEGMENTS_BUSINESS_DATA_FILE_NAME); + string methodCallLinesFileName = Path.Combine(snapshotFolderPath, CONVERT_SNAPSHOT_SEGMENTS_METHOD_CALL_LINES_FILE_NAME); + string methodCallLinesOccurrencesFileName = Path.Combine(snapshotFolderPath, CONVERT_SNAPSHOT_SEGMENTS_METHOD_CALL_LINES_OCCURRENCES_FILE_NAME); + + + #endregion + + if (File.Exists(snapshotsFileName) == false || + File.Exists(segmentsFileName) == false || + File.Exists(exitCallsFileName) == false || + File.Exists(serviceEndpointCallsFileName) == false || + File.Exists(detectedErrorsFileName) == false || + File.Exists(businessDataFileName) == false || + File.Exists(methodCallLinesFileName) == false || + File.Exists(methodCallLinesOccurrencesFileName) == false) + { + #region Fill in Snapshot data + + Snapshot snapshot = new Snapshot(); + snapshot.Controller = jobTarget.Controller; + snapshot.ApplicationName = jobTarget.Application; + snapshot.ApplicationID = jobTarget.ApplicationID; + snapshot.TierID = (long)snapshotToken["applicationComponentId"]; + snapshot.TierName = snapshotToken["applicationComponentName"].ToString(); + snapshot.BTID = (long)snapshotToken["businessTransactionId"]; + snapshot.BTName = snapshotToken["businessTransactionName"].ToString(); + snapshot.NodeID = (long)snapshotToken["applicationComponentNodeId"]; + snapshot.NodeName = snapshotToken["applicationComponentNodeName"].ToString(); + + snapshot.OccuredUtc = convertFromUnixTimestamp((long)snapshotToken["serverStartTime"]); + snapshot.Occured = snapshot.OccuredUtc.ToLocalTime(); + + snapshot.RequestID = snapshotToken["requestGUID"].ToString(); + snapshot.UserExperience = snapshotToken["userExperience"].ToString(); + snapshot.Duration = (long)snapshotToken["timeTakenInMilliSecs"]; + snapshot.DurationRange = getDurationRangeAsString(snapshot.Duration); + snapshot.DiagSessionID = snapshotToken["diagnosticSessionGUID"].ToString(); + if (snapshotToken["url"] != null) { snapshot.URL = snapshotToken["url"].ToString(); } + + snapshot.TakenSummary = snapshotToken["summary"].ToString(); + if (snapshot.TakenSummary.Contains("Scheduled Snapshots:") == true) + { + snapshot.TakenReason = "Scheduled"; + } + else if (snapshot.TakenSummary.Contains("[Manual Diagnostic Session]") == true) + { + snapshot.TakenReason = "Diagnostic Session"; + } + else if (snapshot.TakenSummary.Contains("[Error]") == true) + { + snapshot.TakenReason = "Error"; + } + else if (snapshot.TakenSummary.Contains("Request was slower than the Standard Deviation threshold") == true) + { + snapshot.TakenReason = "Slower than StDev"; + } + else if (snapshot.TakenSummary.Contains("of requests were slow in the last minute starting") == true) + { + snapshot.TakenReason = "Slow Rate in Minute"; + } + else if (snapshot.TakenSummary.Contains("of requests had errors in the last minute starting") == true) + { + snapshot.TakenReason = "Error Rate in Minute"; + } + else + { + snapshot.TakenReason = ""; + } + + if ((bool)snapshotToken["fullCallgraph"] == true) + { + snapshot.CallGraphType = "FULL"; + } + else if ((bool)snapshotToken["delayedCallGraph"] == true) + { + snapshot.CallGraphType = "PARTIAL"; + } + else + { + snapshot.CallGraphType = "NONE"; + } + + snapshot.HasErrors = (bool)snapshotToken["errorOccurred"]; + snapshot.IsArchived = (bool)snapshotToken["archived"]; + + #region Fill in the deeplinks for the snapshot + + // Decide what kind of timerange + long fromTimeUnix = convertToUnixTimestamp(jobTimeRange.From); + long toTimeUnix = convertToUnixTimestamp(jobTimeRange.To); + long differenceInMinutes = (toTimeUnix - fromTimeUnix) / (60000); + string DEEPLINK_THIS_TIMERANGE = String.Format(DEEPLINK_TIMERANGE_BETWEEN_TIMES, toTimeUnix, fromTimeUnix, differenceInMinutes); + + snapshot.ControllerLink = String.Format(DEEPLINK_CONTROLLER, snapshot.Controller, DEEPLINK_THIS_TIMERANGE); + snapshot.ApplicationLink = String.Format(DEEPLINK_APPLICATION, snapshot.Controller, snapshot.ApplicationID, DEEPLINK_THIS_TIMERANGE); + snapshot.TierLink = String.Format(DEEPLINK_TIER, snapshot.Controller, snapshot.ApplicationID, snapshot.TierID, DEEPLINK_THIS_TIMERANGE); + snapshot.NodeLink = String.Format(DEEPLINK_NODE, snapshot.Controller, snapshot.ApplicationID, snapshot.NodeID, DEEPLINK_THIS_TIMERANGE); + snapshot.BTLink = String.Format(DEEPLINK_BUSINESS_TRANSACTION, snapshot.Controller, snapshot.ApplicationID, snapshot.BTID, DEEPLINK_THIS_TIMERANGE); + + // The snapshot link requires to have the time range is -30 < occuredtime < +30 minutes + long fromTimeUnixSnapshot = convertToUnixTimestamp(snapshot.OccuredUtc.AddMinutes(-30)); + long toTimeUnixSnapshot = convertToUnixTimestamp(snapshot.OccuredUtc.AddMinutes(+30)); + long differenceInMinutesSnapshot = (toTimeUnixSnapshot - fromTimeUnixSnapshot) / (60000); + string DEEPLINK_THIS_TIMERANGE_SNAPSHOT = String.Format(DEEPLINK_TIMERANGE_BETWEEN_TIMES, toTimeUnixSnapshot, fromTimeUnixSnapshot, differenceInMinutesSnapshot); + snapshot.SnapshotLink = String.Format(DEEPLINK_SNAPSHOT_OVERVIEW, snapshot.Controller, snapshot.ApplicationID, snapshot.RequestID, DEEPLINK_THIS_TIMERANGE_SNAPSHOT); + + // This is the snapshot report link + string reportFileName = String.Format( + REPORT_SNAPSHOT_DETAILS_FILE_NAME, + programOptions.JobName, + jobConfiguration.Input.ExpandedTimeRange.From, + jobConfiguration.Input.ExpandedTimeRange.To, + getFileSystemSafeString(new Uri(snapshot.Controller).Host), + getShortenedEntityNameForFileSystem(snapshot.ApplicationName, snapshot.ApplicationID), + getShortenedEntityNameForFileSystem(snapshot.BTName, snapshot.BTID), + userExperienceFolderNameMapping[snapshot.UserExperience], + snapshot.Occured, + snapshot.RequestID); + string reportFilePath = Path.Combine( + reportsFolderPath, + SNAPSHOTS_FOLDER_NAME, + reportFileName); + + reportFilePath = reportFilePath.Substring(reportsFolderPath.Length + 1); + snapshot.DetailLink = String.Format(@"=HYPERLINK(""{0}"", """")", reportFilePath); + + #endregion + + #endregion + + #region Process segments + + List segmentsList = null; + List exitCallsList = null; + List serviceEndpointCallsList = null; + List detectedErrorsList = null; + List businessDataList = null; + List methodCallLinesList = null; + List methodCallLinesOccurrencesList = null; + + JArray snapshotSegmentsList = FileIOHelper.loadJArrayFromFile(snapshotSegmentsDataFilePath); + if (snapshotSegmentsList != null) + { + #region Prepare elements for storage of indexed data from segments + + // Number of segments is known + segmentsList = new List(snapshotSegmentsList.Count); + + // Eyeball each segment to have 3 exits on average + exitCallsList = new List(snapshotSegmentsList.Count * 3); + + // Let's assume that each segment has a SEP + serviceEndpointCallsList = new List(snapshotSegmentsList.Count); + + // Don't know how long this is going to be + detectedErrorsList = new List(); + + // Don't know how long this one is going to be either + businessDataList = new List(); + + // Assume each call graph is 250 items long + methodCallLinesList = new List(snapshotSegmentsList.Count * 250); + + // Some methods repeat though + methodCallLinesOccurrencesList = new List(snapshotSegmentsList.Count * 50); + + SortedDictionary callChainsSnapshot = new SortedDictionary(); + + #endregion + + foreach (JToken snapshotSegmentToken in snapshotSegmentsList) + { + string snapshotSegmentDataFilePath = Path.Combine(snapshotFolderPath, String.Format(EXTRACT_SNAPSHOT_SEGMENT_DATA_FILE_NAME, snapshotSegmentToken["id"])); + JObject snapshotSegmentDetail = FileIOHelper.loadJObjectFromFile(snapshotSegmentDataFilePath); + if (snapshotSegmentDetail != null) + { + #region Fill in Segment data + + Segment segment = new Segment(); + + segment.Controller = snapshot.Controller; + segment.ApplicationName = snapshot.ApplicationName; + segment.ApplicationID = snapshot.ApplicationID; + segment.TierID = (long)snapshotSegmentToken["applicationComponentId"]; + segment.TierName = snapshotSegmentToken["applicationComponentName"].ToString(); + segment.BTID = snapshot.BTID; + segment.BTName = snapshot.BTName; + segment.NodeID = (long)snapshotSegmentToken["applicationComponentNodeId"]; + segment.NodeName = snapshotSegmentToken["applicationComponentNodeName"].ToString(); + + segment.OccuredUtc = convertFromUnixTimestamp((long)snapshotSegmentDetail["serverStartTime"]); + segment.Occured = segment.OccuredUtc.ToLocalTime(); + + segment.RequestID = snapshotSegmentDetail["requestGUID"].ToString(); + segment.SegmentID = (long)snapshotSegmentDetail["id"]; + segment.UserExperience = snapshotSegmentDetail["userExperience"].ToString(); + segment.Duration = (long)snapshotSegmentDetail["timeTakenInMilliSecs"]; + segment.DurationRange = getDurationRangeAsString(segment.Duration); + // The value here is not in milliseconds, contrary to the name + segment.CPUDuration = Math.Round((double)snapshotSegmentDetail["cpuTimeTakenInMilliSecs"] / 1000000, 2); + segment.E2ELatency = (long)snapshotSegmentDetail["endToEndLatency"]; + if (segment.E2ELatency == -1) { segment.E2ELatency = 0; } + if (snapshotSegmentDetail["totalWaitTime"] != null) segment.WaitDuration = (long)snapshotSegmentDetail["totalWaitTime"]; + if (snapshotSegmentDetail["totalBlockTime"] != null) segment.BlockDuration = (long)snapshotSegmentDetail["totalBlockTime"]; + segment.DiagSessionID = snapshotSegmentDetail["diagnosticSessionGUID"].ToString(); + if (snapshotSegmentDetail["url"] != null) segment.URL = snapshotSegmentDetail["url"].ToString(); + if (snapshotSegmentDetail["securityID"] != null) { segment.UserPrincipal = snapshotSegmentDetail["securityID"].ToString(); } + if (snapshotSegmentDetail["httpSessionID"] != null) { segment.HTTPSessionID = snapshotSegmentDetail["httpSessionID"].ToString(); } + + segment.TakenSummary = snapshotSegmentDetail["summary"].ToString(); + if (segment.TakenSummary.Contains("Scheduled Snapshots:") == true) + { + segment.TakenReason = "Scheduled"; + } + else if (segment.TakenSummary.Contains("[Manual Diagnostic Session]") == true) + { + segment.TakenReason = "Diagnostic Session"; + } + else if (segment.TakenSummary.Contains("[Error]") == true) + { + segment.TakenReason = "Error"; + } + else if (segment.TakenSummary.Contains("Request was slower than the Standard Deviation threshold") == true) + { + segment.TakenReason = "Slower than StDev"; + } + else if (segment.TakenSummary.Contains("of requests were slow in the last minute starting") == true) + { + segment.TakenReason = "Slow Rate in Minute"; + } + else if (segment.TakenSummary.Contains("of requests had errors in the last minute starting") == true) + { + segment.TakenReason = "Error Rate in Minute"; + } + else if (segment.TakenSummary.Contains("[Continuing]") == true) + { + segment.TakenReason = "Continuing"; + } + else + { + segment.TakenReason = ""; + } + segment.TakenPolicy = snapshotSegmentDetail["deepDivePolicy"].ToString(); + + segment.ThreadID = snapshotSegmentDetail["threadID"].ToString(); + segment.ThreadName = snapshotSegmentDetail["threadName"].ToString(); + + segment.WarningThreshold = snapshotSegmentDetail["warningThreshold"].ToString(); + segment.CriticalThreshold = snapshotSegmentDetail["criticalThreshold"].ToString(); + + if ((bool)snapshotSegmentToken["fullCallgraph"] == true) + { + segment.CallGraphType = "FULL"; + } + else if ((bool)snapshotSegmentToken["delayedCallGraph"] == true) + { + segment.CallGraphType = "PARTIAL"; + } + else + { + segment.CallGraphType = "NONE"; + } + + segment.HasErrors = (bool)snapshotSegmentDetail["errorOccured"]; + segment.IsArchived = (bool)snapshotSegmentDetail["archived"]; + segment.IsAsync = (bool)snapshotSegmentDetail["async"]; + segment.IsFirstInChain = (bool)snapshotSegmentDetail["firstInChain"]; + + // What is the relationship to the root segment + segment.FromSegmentID = 0; + if (segment.IsFirstInChain == false) + { + if (snapshotSegmentDetail["snapshotExitSequence"] != null) + { + // Parent exit has snapshotSequenceCounter in exitCalls array + // Child exit has snapshotExitSequence value that binds the child snapshot to the parent + List possibleParentSegments = snapshotSegmentsList.Where(s => s["exitCalls"].Count() > 0).ToList(); + foreach (JToken possibleParentSegment in possibleParentSegments) + { + List possibleExits = possibleParentSegment["exitCalls"].Where(e => e["snapshotSequenceCounter"].ToString() == snapshotSegmentDetail["snapshotExitSequence"].ToString()).ToList(); + if (possibleExits.Count > 0) + { + segment.FromSegmentID = (long)possibleParentSegment["id"]; + break; + } + } + } + if (segment.FromSegmentID == 0) + { + // Some async snapshots can have no initiating parent + // Do nothing + // OR! + // This can happen when the parent snapshot got an exception calling downstream tier, both producing snapshot, but parent snapshot doesn't have a call graph + // But sometimes non-async ones have funny parenting + } + } + segment.FromTierName = snapshotSegmentToken["callingComponent"].ToString(); + + #endregion + + #region Fill in the deeplinks for the segment + + segment.ControllerLink = snapshot.ControllerLink; + segment.ApplicationLink = snapshot.ApplicationLink; + segment.TierLink = String.Format(DEEPLINK_TIER, segment.Controller, segment.ApplicationID, segment.TierID, DEEPLINK_THIS_TIMERANGE); + segment.NodeLink = String.Format(DEEPLINK_NODE, segment.Controller, segment.ApplicationID, segment.NodeID, DEEPLINK_THIS_TIMERANGE); + segment.BTLink = snapshot.BTLink; + + // The snapshot link requires to have the time range is -30 < occuredtime < +30 minutes + fromTimeUnixSnapshot = convertToUnixTimestamp(snapshot.OccuredUtc.AddMinutes(-30)); + toTimeUnixSnapshot = convertToUnixTimestamp(snapshot.OccuredUtc.AddMinutes(+30)); + differenceInMinutesSnapshot = (toTimeUnixSnapshot - fromTimeUnixSnapshot) / (60000); + DEEPLINK_THIS_TIMERANGE_SNAPSHOT = String.Format(DEEPLINK_TIMERANGE_BETWEEN_TIMES, toTimeUnixSnapshot, fromTimeUnixSnapshot, differenceInMinutesSnapshot); + segment.SegmentLink = String.Format(DEEPLINK_SNAPSHOT_SEGMENT, segment.Controller, segment.ApplicationID, segment.RequestID, segment.SegmentID, DEEPLINK_THIS_TIMERANGE_SNAPSHOT); + + #endregion + + #region Get segment's call chain and make it pretty + + // Convert call chain to something readable + // This is raw: + //Component:108|Exit Call:JMS|To:{[UNRESOLVED][115]}|Component:{[UNRESOLVED][115]}|Exit Call:JMS|To:115|Component:115 + //^^^^^^^^^^^^^ ECommerce-Services + // ^^^^^^^^^^^^^ JMS + // ^^^^^^^^^^^^^^^^^^^^^^ Active MQ-OrderQueue + // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ JMS + // ^^^^^^^^^^^^^^ + // ^^^^^^^ Order-Processing-Services + // ^^^^^^^^^^^^ Order-Processing-Services + // This is what I want it to look like: + // ECommerce-Services->[JMS]->Active MQ-OrderQueue->[JMS]->Order-Processing-Services + // + // This is raw: + //Component:108|Exit Call:WEB_SERVICE|To:111|Component:111 + //^^^^^^^^^^^^^ ECommerce-Services + // ^^^^^^^^^^^^^^^^^^^^^ WEB_SERVICE + // ^^^^^^ Inventory-Services + // ^^^^^^ Inventory-Services + // This is what I want it to look like: + // ECommerce-Services->[WEB_SERVICE]->Inventory-Services + string callChainForThisSegment = snapshotSegmentDetail["callChain"].ToString(); + string[] callChainTokens = callChainForThisSegment.Split('|'); + StringBuilder sbCallChain = new StringBuilder(); + foreach (string callChainToken in callChainTokens) + { + if (callChainToken.StartsWith("Component") == true) + { + long tierID = -1; + if (long.TryParse(callChainToken.Substring(10), out tierID) == true) + { + if (tiersList != null) + { + EntityTier tier = tiersList.Where(t => t.TierID == tierID).FirstOrDefault(); + if (tier != null) + { + sbCallChain.AppendFormat("({0})->", tier.TierName); + } + } + } + } + else if (callChainToken.StartsWith("Exit Call") == true) + { + sbCallChain.AppendFormat("[{0}]->", callChainToken.Substring(10)); + } + else if (callChainToken.StartsWith("To:{[UNRESOLVED]") == true) + { + long backendID = -1; + if (long.TryParse(callChainToken.Substring(17).TrimEnd(']', '}'), out backendID) == true) + { + if (backendsList != null) + { + EntityBackend backend = backendsList.Where(b => b.BackendID == backendID).FirstOrDefault(); + if (backend != null) + { + //sbCallChain.AppendFormat("<{0}><{1}>>->", backendRow.BackendName, backendRow.BackendType); + sbCallChain.AppendFormat("<{0}>->", backend.BackendName); + } + } + } + } + } + if (sbCallChain.Length > 2) + { + sbCallChain.Remove(sbCallChain.Length - 2, 2); + } + callChainForThisSegment = sbCallChain.ToString(); + + #endregion + + #region Process Exits in Segment + + SortedDictionary callChainsSegment = new SortedDictionary(); + + List exitCallsListInThisSegment = new List(); + foreach (JToken exitCallToken in snapshotSegmentDetail["snapshotExitCalls"]) + { + #region Parse the exit call into correct exit + + ExitCall exitCall = new ExitCall(); + + exitCall.Controller = segment.Controller; + exitCall.ApplicationName = segment.ApplicationName; + exitCall.ApplicationID = segment.ApplicationID; + exitCall.TierID = segment.TierID; + exitCall.TierName = segment.TierName; + exitCall.BTID = segment.BTID; + exitCall.BTName = segment.BTName; + exitCall.NodeID = segment.NodeID; + exitCall.NodeName = segment.NodeName; + + exitCall.RequestID = segment.RequestID; + exitCall.SegmentID = segment.SegmentID; + + exitCall.OccuredUtc = segment.OccuredUtc; + exitCall.Occured = segment.Occured; + + exitCall.ExitType = exitCallToken["exitPointName"].ToString(); + + exitCall.SequenceNumber = exitCallToken["snapshotSequenceCounter"].ToString(); + + exitCall.Duration = (long)exitCallToken["timeTakenInMillis"]; + exitCall.DurationRange = getDurationRangeAsString(exitCall.Duration); + + exitCall.IsAsync = ((bool)exitCallToken["exitPointCall"]["synchronous"] == false); + + // Create pretty call chain + // Where are we going, Tier or Backend + if (exitCallToken["toComponentId"].ToString().StartsWith("{[UNRESOLVED]") == true) + { + // Backend + exitCall.ToEntityType = "Backend"; + JToken goingToProperty = exitCallToken["properties"].Where(p => p["name"].ToString() == "backendId").FirstOrDefault(); + if (goingToProperty != null) + { + exitCall.ToEntityID = (long)goingToProperty["value"]; ; + } + goingToProperty = exitCallToken["properties"].Where(p => p["name"].ToString() == "to").FirstOrDefault(); + if (goingToProperty != null) + { + exitCall.ToEntityName = goingToProperty["value"].ToString(); + } + if (exitCall.IsAsync == false) + { + exitCall.CallChain = String.Format("{0}->[{1}]:[{3} ms]-><{2}>", callChainForThisSegment, exitCall.ExitType, exitCall.ToEntityName, exitCall.Duration); + } + else + { + exitCall.CallChain = String.Format("{0}->[{1}]:[{3} ms async]-><{2}>", callChainForThisSegment, exitCall.ExitType, exitCall.ToEntityName, exitCall.Duration); + } + } + else if (exitCallToken["toComponentId"].ToString().StartsWith("App:") == true) + { + //Application + exitCall.ToEntityType = "Application"; + JToken goingToProperty = exitCallToken["properties"].Where(p => p["name"].ToString() == "appId").FirstOrDefault(); + if (goingToProperty != null) + { + exitCall.ToEntityID = (long)goingToProperty["value"]; ; + } + goingToProperty = exitCallToken["properties"].Where(p => p["name"].ToString() == "to").FirstOrDefault(); + if (goingToProperty != null) + { + exitCall.ToEntityName = goingToProperty["value"].ToString(); + } + if (exitCall.IsAsync == false) + { + exitCall.CallChain = String.Format("{0}->[{1}]:[{3} ms]->{{{2}}}", callChainForThisSegment, exitCall.ExitType, exitCall.ToEntityName, exitCall.Duration); + } + else + { + exitCall.CallChain = String.Format("{0}->[{1}]:[{3} ms async]->{{{2}}}", callChainForThisSegment, exitCall.ExitType, exitCall.ToEntityName, exitCall.Duration); + } + } + else + { + // Tier + exitCall.ToEntityType = "Tier"; + exitCall.ToEntityID = (long)exitCallToken["toComponentId"]; + JToken goingToProperty = exitCallToken["properties"].Where(p => p["name"].ToString() == "to").FirstOrDefault(); + if (goingToProperty != null) + { + exitCall.ToEntityName = goingToProperty["value"].ToString(); + } + if (exitCall.IsAsync == false) + { + exitCall.CallChain = String.Format("{0}->[{1}]:[{3} ms]->({2})", callChainForThisSegment, exitCall.ExitType, exitCall.ToEntityName, exitCall.Duration); + } + else + { + exitCall.CallChain = String.Format("{0}->[{1}]:[{3} ms async]->({2})", callChainForThisSegment, exitCall.ExitType, exitCall.ToEntityName, exitCall.Duration); + } + } + + // Add the exit call to the overall list for tracking + string exitCCCKey = String.Format("{0}_{1}_{2}", callChainForThisSegment, exitCall.ExitType, exitCall.ToEntityName); + CallChainContainer cccSeg = null; + if (callChainsSegment.ContainsKey(exitCCCKey) == false) + { + cccSeg = new CallChainContainer { From = callChainForThisSegment, ExitType = exitCall.ExitType, ToEntityName = exitCall.ToEntityName, ToEntityType = exitCall.ToEntityType }; + callChainsSegment.Add(exitCCCKey, cccSeg); + } + else + { + cccSeg = callChainsSegment[exitCCCKey]; + } + cccSeg.CallTimings.Add(new CallTiming { Async = exitCall.IsAsync, Duration = exitCall.Duration }); + + CallChainContainer cccSnap = null; + if (callChainsSnapshot.ContainsKey(exitCCCKey) == false) + { + cccSnap = new CallChainContainer { From = callChainForThisSegment, ExitType = exitCall.ExitType, ToEntityName = exitCall.ToEntityName, ToEntityType = exitCall.ToEntityType }; + callChainsSnapshot.Add(exitCCCKey, cccSnap); + } + else + { + cccSnap = callChainsSnapshot[exitCCCKey]; + } + cccSnap.CallTimings.Add(new CallTiming { Async = exitCall.IsAsync, Duration = exitCall.Duration }); - #region Fill in the deeplinks for the snapshot + exitCall.Detail = exitCallToken["detailString"].ToString(); + exitCall.ErrorDetail = exitCallToken["errorDetails"].ToString(); + if (exitCall.ErrorDetail == "\\N") { exitCall.ErrorDetail = String.Empty; } + exitCall.Method = exitCallToken["callingMethod"].ToString(); - // Decide what kind of timerange - long fromTimeUnix = convertToUnixTimestamp(jobTimeRange.From); - long toTimeUnix = convertToUnixTimestamp(jobTimeRange.To); - long differenceInMinutes = (toTimeUnix - fromTimeUnix) / (60000); - string DEEPLINK_THIS_TIMERANGE = String.Format(DEEPLINK_TIMERANGE_BETWEEN_TIMES, toTimeUnix, fromTimeUnix, differenceInMinutes); + // Parse Properties + exitCall.PropsAll = exitCallToken["propertiesAsString"].ToString(); + int i = 0; + foreach (JToken customExitPropertyToken in exitCallToken["properties"]) + { + exitCall.NumProps++; + string propertyName = customExitPropertyToken["name"].ToString(); + string propertyValue = customExitPropertyToken["value"].ToString(); + switch (propertyName) + { + case "component": + case "to": + case "from": + case "backendId": + // Ignore those, already mapped elsewhere + exitCall.NumProps--; + break; + case "Query Type": + exitCall.PropQueryType = propertyValue; + break; + case "Statement Type": + exitCall.PropStatementType = propertyValue; + break; + case "URL": + exitCall.PropURL = propertyValue; + break; + case "Service": + exitCall.PropServiceName = propertyValue; + break; + case "Operation": + exitCall.PropOperationName = propertyValue; + break; + case "Name": + exitCall.PropName = propertyValue; + break; + case "Asynchronous": + exitCall.PropAsync = propertyValue; + break; + case "Continuation": + exitCall.PropContinuation = propertyValue; + break; + default: + i++; + // Have 5 overflow buckets for those, hope it is enough + if (i == 1) + { + exitCall.Prop1Name = propertyName; + exitCall.Prop1Value = propertyValue; + } + else if (i == 2) + { + exitCall.Prop2Name = propertyName; + exitCall.Prop2Value = propertyValue; + } + else if (i == 3) + { + exitCall.Prop3Name = propertyName; + exitCall.Prop3Value = propertyValue; + } + else if (i == 4) + { + exitCall.Prop4Name = propertyName; + exitCall.Prop4Value = propertyValue; + } + else if (i == 5) + { + exitCall.Prop5Name = propertyName; + exitCall.Prop5Value = propertyValue; + } + break; + } + } - snapshot.ControllerLink = String.Format(DEEPLINK_CONTROLLER, snapshot.Controller, DEEPLINK_THIS_TIMERANGE); - snapshot.ApplicationLink = String.Format(DEEPLINK_APPLICATION, snapshot.Controller, snapshot.ApplicationID, DEEPLINK_THIS_TIMERANGE); - snapshot.TierLink = String.Format(DEEPLINK_TIER, snapshot.Controller, snapshot.ApplicationID, snapshot.TierID, DEEPLINK_THIS_TIMERANGE); - snapshot.NodeLink = String.Format(DEEPLINK_NODE, snapshot.Controller, snapshot.ApplicationID, snapshot.NodeID, DEEPLINK_THIS_TIMERANGE); - snapshot.BTLink = String.Format(DEEPLINK_BUSINESS_TRANSACTION, snapshot.Controller, snapshot.ApplicationID, snapshot.BTID, DEEPLINK_THIS_TIMERANGE); + exitCall.NumCalls = (int)exitCallToken["count"]; + exitCall.NumErrors = (int)exitCallToken["errorCount"]; + exitCall.HasErrors = exitCall.NumErrors != 0; - // The snapshot link requires to have the time range is -30 < occuredtime < +30 minutes - long fromTimeUnixSnapshot = convertToUnixTimestamp(snapshot.OccuredUtc.AddMinutes(-30)); - long toTimeUnixSnapshot = convertToUnixTimestamp(snapshot.OccuredUtc.AddMinutes(+30)); - long differenceInMinutesSnapshot = (toTimeUnixSnapshot - fromTimeUnixSnapshot) / (60000); - string DEEPLINK_THIS_TIMERANGE_SNAPSHOT = String.Format(DEEPLINK_TIMERANGE_BETWEEN_TIMES, toTimeUnixSnapshot, fromTimeUnixSnapshot, differenceInMinutesSnapshot); - snapshot.SnapshotLink = String.Format(DEEPLINK_SNAPSHOT_OVERVIEW, snapshot.Controller, snapshot.ApplicationID, snapshot.RequestID, DEEPLINK_THIS_TIMERANGE_SNAPSHOT); + // Which Segment are we going to + exitCall.ToSegmentID = 0; + if (exitCallToken["snapshotSequenceCounter"] != null) + { + // Parent segment has snapshotSequenceCounter in exitCalls array + // Child snapshot has snapshotExitSequence value that binds the child snapshot to the parent + JToken childSegment = snapshotSegmentsList.Where(s => s["triggerCall"].HasValues == true && s["triggerCall"]["snapshotSequenceCounter"].ToString() == exitCallToken["snapshotSequenceCounter"].ToString()).FirstOrDefault(); + if (childSegment != null) + { + exitCall.ToSegmentID = (long)childSegment["id"]; + } + } - // This is the snapshot report link - string reportFileName = String.Format( - REPORT_SNAPSHOT_DETAILS_FILE_NAME, - programOptions.JobName, - jobConfiguration.Input.ExpandedTimeRange.From, - jobConfiguration.Input.ExpandedTimeRange.To, - getFileSystemSafeString(new Uri(snapshot.Controller).Host), - getShortenedEntityNameForFileSystem(snapshot.ApplicationName, snapshot.ApplicationID), - getShortenedEntityNameForFileSystem(snapshot.BTName, snapshot.BTID), - userExperienceFolderNameMapping[snapshot.UserExperience], - snapshot.Occured, - snapshot.RequestID); - string reportFilePath = Path.Combine( - reportsFolderPath, - SNAPSHOTS_FOLDER_NAME, - reportFileName); + #endregion - reportFilePath = reportFilePath.Substring(reportsFolderPath.Length + 1); - snapshot.DetailLink = String.Format(@"=HYPERLINK(""{0}"", """")", reportFilePath); + #region Fill in the deeplinks for the exit - #endregion + exitCall.ControllerLink = segment.Controller; + exitCall.ApplicationLink = segment.ApplicationLink; + exitCall.TierLink = segment.TierLink; + exitCall.NodeLink = segment.NodeLink; + exitCall.BTLink = segment.BTLink; - #endregion + switch (exitCall.ToEntityType) + { + case "Backend": + exitCall.ToLink = String.Format(DEEPLINK_BACKEND, exitCall.Controller, exitCall.ApplicationID, exitCall.ToEntityID, DEEPLINK_THIS_TIMERANGE); + break; - #region Process segments + case "Tier": + exitCall.ToLink = String.Format(DEEPLINK_TIER, exitCall.Controller, exitCall.ApplicationID, exitCall.ToEntityID, DEEPLINK_THIS_TIMERANGE); + break; - List segmentsList = null; - List exitCallsList = null; - List serviceEndpointCallsList = null; - List detectedErrorsList = null; - List businessDataList = null; + case "Application": + exitCall.ToLink = String.Format(DEEPLINK_APPLICATION, exitCall.Controller, exitCall.ToEntityID, DEEPLINK_THIS_TIMERANGE); + break; - JArray snapshotSegmentsList = FileIOHelper.loadJArrayFromFile(snapshotSegmentsDataFilePath); - if (snapshotSegmentsList != null) - { - // Prepare elements for storage - segmentsList = new List(snapshotSegmentsList.Count); - // Eyeball each segment to have 3 exits on average - exitCallsList = new List(snapshotSegmentsList.Count * 3); - serviceEndpointCallsList = new List(snapshotSegmentsList.Count); - // Don't know how long this is going to be, so let's just do it - detectedErrorsList = new List(); - // Don't know how long this one is going to be either - businessDataList = new List(); + default: + break; + } - SortedDictionary callChainsSnapshot = new SortedDictionary(); + #endregion - foreach (JToken snapshotSegmentToken in snapshotSegmentsList) - { - string snapshotSegmentDataFilePath = Path.Combine(snapshotFolderPath, String.Format(EXTRACT_SNAPSHOT_SEGMENT_DATA_FILE_NAME, snapshotSegmentToken["id"])); - string snapshotSegmentErrorFilePath = Path.Combine(snapshotFolderPath, String.Format(EXTRACT_SNAPSHOT_SEGMENT_ERROR_FILE_NAME, snapshotSegmentToken["id"])); + exitCallsListInThisSegment.Add(exitCall); + } - JObject snapshotSegmentDetail = FileIOHelper.loadJObjectFromFile(snapshotSegmentDataFilePath); - if (snapshotSegmentDetail != null) - { - #region Fill in Segment data + #endregion - Segment segment = new Segment(); - segment.Controller = snapshot.Controller; - segment.ApplicationName = snapshot.ApplicationName; - segment.ApplicationID = snapshot.ApplicationID; - segment.TierID = (long)snapshotSegmentToken["applicationComponentId"]; - segment.TierName = snapshotSegmentToken["applicationComponentName"].ToString(); - segment.BTID = snapshot.BTID; - segment.BTName = snapshot.BTName; - segment.NodeID = (long)snapshotSegmentToken["applicationComponentNodeId"]; - segment.NodeName = snapshotSegmentToken["applicationComponentNodeName"].ToString(); + #region Process Service Endpoints in Segment - segment.OccuredUtc = convertFromUnixTimestamp((long)snapshotSegmentDetail["serverStartTime"]); - segment.Occured = segment.OccuredUtc.ToLocalTime(); + List serviceEndpointCallsListInThisSegment = new List(); + foreach (JToken serviceEndpointToken in snapshotSegmentDetail["serviceEndPointIds"]) + { + long serviceEndpointID = (long)((JValue)serviceEndpointToken).Value; + if (serviceEndpointsList != null) + { + EntityServiceEndpoint serviceEndpoint = serviceEndpointsList.Where(s => s.SEPID == serviceEndpointID).FirstOrDefault(); + if (serviceEndpoint != null) + { + #region Fill Service Endpoint stuff - segment.RequestID = snapshotSegmentDetail["requestGUID"].ToString(); - segment.SegmentID = (long)snapshotSegmentDetail["id"]; - segment.UserExperience = snapshotSegmentDetail["userExperience"].ToString(); - segment.Duration = (long)snapshotSegmentDetail["timeTakenInMilliSecs"]; - // The value here is not in milliseconds, contrary to the name - segment.CPUDuration = Math.Round((double)snapshotSegmentDetail["cpuTimeTakenInMilliSecs"] / 1000000, 2); - segment.E2ELatency = (long)snapshotSegmentDetail["endToEndLatency"]; - if (segment.E2ELatency == -1) { segment.E2ELatency = 0; } - if (snapshotSegmentDetail["totalWaitTime"] != null) segment.WaitDuration = (long)snapshotSegmentDetail["totalWaitTime"]; - if (snapshotSegmentDetail["totalBlockTime"] != null) segment.BlockDuration = (long)snapshotSegmentDetail["totalBlockTime"]; - segment.DiagSessionID = snapshotSegmentDetail["diagnosticSessionGUID"].ToString(); - if (snapshotSegmentDetail["url"] != null) segment.URL = snapshotSegmentDetail["url"].ToString(); - if (snapshotSegmentDetail["securityID"] != null) { segment.UserPrincipal = snapshotSegmentDetail["securityID"].ToString(); } - if (snapshotSegmentDetail["httpSessionID"] != null) { segment.HTTPSessionID = snapshotSegmentDetail["httpSessionID"].ToString(); } + ServiceEndpointCall serviceEndpointCall = new ServiceEndpointCall(); - segment.TakenSummary = snapshotSegmentDetail["summary"].ToString(); - if (segment.TakenSummary.Contains("Scheduled Snapshots:") == true) - { - segment.TakenReason = "Scheduled"; - } - else if (segment.TakenSummary.Contains("[Manual Diagnostic Session]") == true) - { - segment.TakenReason = "Diagnostic Session"; - } - else if (segment.TakenSummary.Contains("[Error]") == true) - { - segment.TakenReason = "Error"; - } - else if (segment.TakenSummary.Contains("Request was slower than the Standard Deviation threshold") == true) - { - segment.TakenReason = "Slower than StDev"; - } - else if (segment.TakenSummary.Contains("of requests were slow in the last minute starting") == true) - { - segment.TakenReason = "Slow Rate in Minute"; - } - else if (segment.TakenSummary.Contains("of requests had errors in the last minute starting") == true) - { - segment.TakenReason = "Error Rate in Minute"; - } - else if (segment.TakenSummary.Contains("[Continuing]") == true) - { - segment.TakenReason = "Continuing"; - } - else - { - segment.TakenReason = ""; - } - segment.TakenPolicy = snapshotSegmentDetail["deepDivePolicy"].ToString(); + serviceEndpointCall.Controller = segment.Controller; + serviceEndpointCall.ApplicationName = segment.ApplicationName; + serviceEndpointCall.ApplicationID = segment.ApplicationID; + serviceEndpointCall.TierID = segment.TierID; + serviceEndpointCall.TierName = segment.TierName; + serviceEndpointCall.BTID = segment.BTID; + serviceEndpointCall.BTName = segment.BTName; + serviceEndpointCall.NodeID = segment.NodeID; + serviceEndpointCall.NodeName = segment.NodeName; - segment.ThreadID = snapshotSegmentDetail["threadID"].ToString(); - segment.ThreadName = snapshotSegmentDetail["threadName"].ToString(); + serviceEndpointCall.RequestID = segment.RequestID; + serviceEndpointCall.SegmentID = segment.SegmentID; - segment.WarningThreshold = snapshotSegmentDetail["warningThreshold"].ToString(); - segment.CriticalThreshold = snapshotSegmentDetail["criticalThreshold"].ToString(); + serviceEndpointCall.SEPID = serviceEndpoint.SEPID; + serviceEndpointCall.SEPName = serviceEndpoint.SEPName; + serviceEndpointCall.SEPType = serviceEndpoint.SEPType; - if ((bool)snapshotSegmentToken["fullCallgraph"] == true) - { - segment.CallGraphType = "FULL"; - } - else if ((bool)snapshotSegmentToken["delayedCallGraph"] == true) - { - segment.CallGraphType = "PARTIAL"; - } - else - { - segment.CallGraphType = "NONE"; + #endregion + + #region Fill in the deeplinks for the Service Endpoint + + serviceEndpointCall.ControllerLink = segment.Controller; + serviceEndpointCall.ApplicationLink = segment.ApplicationLink; + serviceEndpointCall.TierLink = segment.TierLink; + serviceEndpointCall.NodeLink = segment.NodeLink; + serviceEndpointCall.BTLink = segment.BTLink; + serviceEndpointCall.SEPLink = String.Format(DEEPLINK_SERVICE_ENDPOINT, serviceEndpointCall.Controller, serviceEndpointCall.ApplicationID, serviceEndpointCall.TierID, serviceEndpointCall.SEPID, DEEPLINK_THIS_TIMERANGE); + + #endregion + + serviceEndpointCallsListInThisSegment.Add(serviceEndpointCall); + } + } } - segment.HasErrors = (bool)snapshotSegmentDetail["errorOccured"]; - segment.IsArchived = (bool)snapshotSegmentDetail["archived"]; - segment.IsAsync = (bool)snapshotSegmentDetail["async"]; - segment.IsFirstInChain = (bool)snapshotSegmentDetail["firstInChain"]; + #endregion - // What is the relationship to the root segment - segment.ParentSegmentID = 0; - if (segment.IsFirstInChain == false) + #region Process Errors in Segment + + segment.NumErrors = snapshotSegmentDetail["errorIDs"].Count(); + List detectedErrorsListInThisSegment = new List(); + if (segment.NumErrors > 0) { - if (snapshotSegmentDetail["snapshotExitSequence"] != null) + // First, populate the list of errors from the reported error numbers + List detectedErrorsFromErrorIDs = new List(segment.NumErrors); + foreach (JToken errorToken in snapshotSegmentDetail["errorIDs"]) { - // Parent snapshot has snapshotSequenceCounter in exitCalls array - // Child snapshot has snapshotExitSequence value that binds the child snapshot to the parent - //JToken parentSegment = snapshotSegmentsList.Where(s => s["exitCalls"]["snapshotSequenceCounter"].ToString() == snapshotSegmentDetail["snapshotExitSequence"].ToString()).FirstOrDefault(); - List possibleParentSegments = snapshotSegmentsList.Where(s => s["exitCalls"].Count() > 0).ToList(); - foreach (JToken possibleParentSegment in possibleParentSegments) + long errorID = (long)((JValue)errorToken).Value; + if (errorsList != null) { - List possibleExits = possibleParentSegment["exitCalls"].Where(e => e["snapshotSequenceCounter"].ToString() == snapshotSegmentDetail["snapshotExitSequence"].ToString()).ToList(); - if (possibleExits.Count > 0) + EntityError error = errorsList.Where(e => e.ErrorID == errorID).FirstOrDefault(); + if (error != null) { - segment.ParentSegmentID = (long)possibleParentSegment["id"]; - break; + DetectedError detectedError = new DetectedError(); + + detectedError.Controller = segment.Controller; + detectedError.ApplicationName = segment.ApplicationName; + detectedError.ApplicationID = segment.ApplicationID; + detectedError.TierID = segment.TierID; + detectedError.TierName = segment.TierName; + detectedError.BTID = segment.BTID; + detectedError.BTName = segment.BTName; + detectedError.NodeID = segment.NodeID; + detectedError.NodeName = segment.NodeName; + + detectedError.RequestID = segment.RequestID; + detectedError.SegmentID = segment.SegmentID; + + detectedError.ErrorID = error.ErrorID; + detectedError.ErrorName = error.ErrorName; + detectedError.ErrorType = error.ErrorType; + + detectedError.ErrorIDMatchedToMessage = false; + + detectedError.ErrorMessage = ""; + detectedError.ErrorDetail = ""; + + detectedErrorsFromErrorIDs.Add(detectedError); } } } - if (segment.ParentSegmentID == 0) + + // Second, populate the list of the details of errors + string snapshotSegmentErrorFilePath = Path.Combine(snapshotFolderPath, String.Format(EXTRACT_SNAPSHOT_SEGMENT_ERROR_FILE_NAME, snapshotSegmentToken["id"])); + JArray snapshotSegmentErrorDetail = FileIOHelper.loadJArrayFromFile(snapshotSegmentErrorFilePath); + if (snapshotSegmentErrorDetail != null) { - // Some async snapshots can have no initiating parent - // Do nothing - // OR! - // This can happen when the parent snapshot got an exception calling downstream tier, both producing snapshot, but parent snapshot doesn't have a call graph - // But sometimes non-async ones have funny parenting - } - } - segment.ParentTierName = snapshotSegmentToken["callingComponent"].ToString(); + detectedErrorsListInThisSegment = new List(snapshotSegmentErrorDetail.Count); - #endregion + foreach (JToken errorToken in snapshotSegmentErrorDetail) + { + DetectedError detectedError = new DetectedError(); - #region Fill in the deeplinks for the segment + detectedError.Controller = segment.Controller; + detectedError.ApplicationName = segment.ApplicationName; + detectedError.ApplicationID = segment.ApplicationID; + detectedError.TierID = segment.TierID; + detectedError.TierName = segment.TierName; + detectedError.BTID = segment.BTID; + detectedError.BTName = segment.BTName; + detectedError.NodeID = segment.NodeID; + detectedError.NodeName = segment.NodeName; - segment.ControllerLink = snapshot.ControllerLink; - segment.ApplicationLink = snapshot.ApplicationLink; - segment.TierLink = String.Format(DEEPLINK_TIER, segment.Controller, segment.ApplicationID, segment.TierID, DEEPLINK_THIS_TIMERANGE); - segment.NodeLink = String.Format(DEEPLINK_NODE, segment.Controller, segment.ApplicationID, segment.NodeID, DEEPLINK_THIS_TIMERANGE); - segment.BTLink = snapshot.BTLink; + detectedError.RequestID = segment.RequestID; + detectedError.SegmentID = segment.SegmentID; - // The snapshot link requires to have the time range is -30 < occuredtime < +30 minutes - fromTimeUnixSnapshot = convertToUnixTimestamp(snapshot.OccuredUtc.AddMinutes(-30)); - toTimeUnixSnapshot = convertToUnixTimestamp(snapshot.OccuredUtc.AddMinutes(+30)); - differenceInMinutesSnapshot = (toTimeUnixSnapshot - fromTimeUnixSnapshot) / (60000); - DEEPLINK_THIS_TIMERANGE_SNAPSHOT = String.Format(DEEPLINK_TIMERANGE_BETWEEN_TIMES, toTimeUnixSnapshot, fromTimeUnixSnapshot, differenceInMinutesSnapshot); - segment.SegmentLink = String.Format(DEEPLINK_SNAPSHOT_SEGMENT, segment.Controller, segment.ApplicationID, segment.RequestID, segment.SegmentID, DEEPLINK_THIS_TIMERANGE_SNAPSHOT); + detectedError.ErrorID = -1; + detectedError.ErrorName = "?"; + detectedError.ErrorType = "?"; - #endregion + detectedError.ErrorMessage = errorToken["name"].ToString(); + detectedError.ErrorDetail = errorToken["value"].ToString().Replace("AD_STACK_TRACE:", "\n").Replace("__AD_CMSG__", "\n"); - #region Get segment's call chain and make it pretty + detectedErrorsListInThisSegment.Add(detectedError); + } + } - // Convert call chain to something readable - // This is raw: - //Component:108|Exit Call:JMS|To:{[UNRESOLVED][115]}|Component:{[UNRESOLVED][115]}|Exit Call:JMS|To:115|Component:115 - //^^^^^^^^^^^^^ ECommerce-Services - // ^^^^^^^^^^^^^ JMS - // ^^^^^^^^^^^^^^^^^^^^^^ Active MQ-OrderQueue - // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ JMS - // ^^^^^^^^^^^^^^ - // ^^^^^^^ Order-Processing-Services - // ^^^^^^^^^^^^ Order-Processing-Services - // This is what I want it to look like: - // ECommerce-Services->[JMS]->Active MQ-OrderQueue->[JMS]->Order-Processing-Services - // - // This is raw: - //Component:108|Exit Call:WEB_SERVICE|To:111|Component:111 - //^^^^^^^^^^^^^ ECommerce-Services - // ^^^^^^^^^^^^^^^^^^^^^ WEB_SERVICE - // ^^^^^^ Inventory-Services - // ^^^^^^ Inventory-Services - // This is what I want it to look like: - // ECommerce-Services->[WEB_SERVICE]->Inventory-Services - string callChainForThisSegment = snapshotSegmentDetail["callChain"].ToString(); - string[] callChainTokens = callChainForThisSegment.Split('|'); - StringBuilder sbCallChain = new StringBuilder(); - foreach (string callChainToken in callChainTokens) - { - if (callChainToken.StartsWith("Component") == true) + // Now reconcile them both + #region Explanation of all of this nonsense to parse the errors + + // The IDs of the errors give us what errors occured + // But the segment JSON does not include all the errors + // The JSON in segment error detailsdoesn't include error number + // However, we get multipe error instances for each of the errors + // Here we have to do some serious gymnastics to match the detected error with what is in JSON + // + // Segment may say: + //"errorIDs" : [ 4532 ], + //"errorDetails" : [ { + // "id" : 0, + // "version" : 0, + // "name" : "Internal Server Error : 500", + // "value" : "HTTP error code : 500" + //} + // Error detail says: + //{ + // "id" : 286452959, + // "version" : 0, + // "name" : "Internal Server Error : 500", + // "value" : "HTTP error code : 500" + //} + // ------------------------------- + // Sometimes segment has no details: + //"errorIDs" : [ 66976 ], + //"errorDetails" : [ ], + // Where: + // 66976 TRBException : COMException + // But the details are there: + //[ { + // "id" : 171771942, + // "version" : 0, + // "name" : "Corillian.Voyager.ExecutionServices.Client.TRBException:Corillian.Voyager.ExecutionServices.Client.TRBException", + // "value" : "Unknown Voyager Connectivity Error: C0000FA5__AD_CMSG__System.Runtime.InteropServices.COMException (0xC0000FA5): Execute: Session doesn't exist or has timed out in TP TP41-SVAKSA69901MXK\r\n at Corillian.Platform.Router.VoyagerLoadBalancer.Execute(String sKey, String sRequest, String& sResponse)\r\n at Corillian.Voyager.VoyagerInterface.Client.VlbConnector.Execute(String voyagerCommandString, String sessionId, String userId, String FI)AD_STACK_TRACE:Corillian.Voyager.ExecutionServices.Client.TRBException: at Corillian.Voyager.VoyagerInterface.Client.VlbConnector.Void HandleCOMException(System.Runtime.InteropServices.COMException)() at Corillian.Voyager.VoyagerInterface.Client.VlbConnector.System.String Execute(System.String, System.String, System.String, System.String)() at Corillian.Voyager.ExecutionServices.Client.VoyagerService.System.String Execute(Corillian.Voyager.Common.IRequest, System.String, System.String, System.String)() at Corillian.Voyager.ExecutionServices.Client.VoyagerService.System.String Execute(Corillian.Voyager.Common.IRequest)() at USB.Banking.Operations.BankingServiceProxy.USB.Banking.Messages.USBGetAccountsResponse GetAccounts(USB.Banking.Messages.USBGetAccountsRequest)() at Corillian.AppsUI.Web.Models.Accounts.AccountServiceProxy.USB.Banking.Messages.USBGetAccountsResponse Corillian.AppsUI.Web.Models.Accounts.IAccountServiceProxy.GetAllAccounts(Boolean, Boolean, Boolean, Boolean)() at Corillian.AppsUI.Web.Models.Accounts.AccountServiceProxy.USB.Banking.Messages.USBGetAccountsResponse Corillian.AppsUI.Web.Models.Accounts.IAccountServiceProxy.GetAllAccounts(Boolean)() at Castle.Proxies.Invocations.IAccountServiceProxy_GetAllAccounts.Void InvokeMethodOnTarget()() at Castle.DynamicProxy.AbstractInvocation.Void Proceed()() at USB.DigitalChannel.DigitalUI.Helpers.Logging.LoggingInterceptor.Void Intercept(Castle.DynamicProxy.IInvocation)() at Castle.DynamicProxy.AbstractInvocation.Void Proceed()() at Castle.Proxies.IAccountServiceProxyProxy.USB.Banking.Messages.USBGetAccountsResponse GetAllAccounts(Boolean)() at Corillian.AppsUI.Web.Models.PaymentCentral.PaymentCentralService.Corillian.AppsUI.Web.Models.PaymentCentral.AccountBalancesResponseContainer GetAccountBalances(Corillian.AppsUI.Web.Models.PaymentCentral.AccountBalancesRequest)() at Corillian.AppsUI.Web.Models.PaymentCentral.PaymentCentralService.Corillian.AppsUI.Web.Models.PaymentCentral.UserAndAccountsResponse GetUserAndAccounts(Corillian.AppsUI.Web.Models.PaymentCentral.AccountBalancesRequest)() at Castle.Proxies.Invocations.IPaymentCentralService_GetUserAndAccounts.Void InvokeMethodOnTarget()() at Castle.DynamicProxy.AbstractInvocation.Void Proceed()() at USB.DigitalChannel.DigitalUI.Helpers.Logging.LoggingInterceptor.Void Intercept(Castle.DynamicProxy.IInvocation)() at Castle.DynamicProxy.AbstractInvocation.Void Proceed()() at Castle.Proxies.IPaymentCentralServiceProxy.Corillian.AppsUI.Web.Models.PaymentCentral.UserAndAccountsResponse GetUserAndAccounts(Corillian.AppsUI.Web.Models.PaymentCentral.AccountBalancesRequest)() at Corillian.AppsUI.Web.AsyncGetUserAndAccounts.System.String GetUserAndAccounts()() at Corillian.AppsUI.Web.AsyncGetUserAndAccounts.System.String get_TaskResult()() at USB.DigitalChannel.CommonUI.Controllers.BaseController.Void GetAsyncData(USB.DigitalChannel.CommonUI.Models.shared.BaseModel)() at Corillian.AppsUI.Web.Controllers.BaseDashboardController.Void GetWebAsyncData(Corillian.AppsUI.Web.Models.Shared.DashboardBaseModel)() at Corillian.AppsUI.Web.Controllers.CustomerDashboardController.System.Web.Mvc.ActionResult Index()() at .System.Object lambda_method(System.Runtime.CompilerServices.ExecutionScope, System.Web.Mvc.ControllerBase, System.Object[])() at System.Web.Mvc.ReflectedActionDescriptor.System.Object Execute(System.Web.Mvc.ControllerContext, System.Collections.Generic.IDictionary`2[System.String,System.Object])() at System.Web.Mvc.ControllerActionInvoker.System.Web.Mvc.ActionResult InvokeActionMethod(System.Web.Mvc.ControllerContext, System.Web.Mvc.ActionDescriptor, System.Collections.Generic.IDictionary`2[System.String,System.Object])() at System.Web.Mvc.ControllerActionInvoker+<>c__DisplayClassd.System.Web.Mvc.ActionExecutedContext b__a()() at System.Web.Mvc.ControllerActionInvoker.System.Web.Mvc.ActionExecutedContext InvokeActionMethodFilter(System.Web.Mvc.IActionFilter, System.Web.Mvc.ActionExecutingContext, System.Func`1[System.Web.Mvc.ActionExecutedContext])() at System.Web.Mvc.ControllerActionInvoker.System.Web.Mvc.ActionExecutedContext InvokeActionMethodFilter(System.Web.Mvc.IActionFilter, System.Web.Mvc.ActionExecutingContext, System.Func`1[System.Web.Mvc.ActionExecutedContext])() at System.Web.Mvc.ControllerActionInvoker.System.Web.Mvc.ActionExecutedContext InvokeActionMethodFilter(System.Web.Mvc.IActionFilter, System.Web.Mvc.ActionExecutingContext, System.Func`1[System.Web.Mvc.ActionExecutedContext])() at System.Web.Mvc.ControllerActionInvoker.System.Web.Mvc.ActionExecutedContext InvokeActionMethodFilter(System.Web.Mvc.IActionFilter, System.Web.Mvc.ActionExecutingContext, System.Func`1[System.Web.Mvc.ActionExecutedContext])() at System.Web.Mvc.ControllerActionInvoker.System.Web.Mvc.ActionExecutedContext InvokeActionMethodWithFilters(System.Web.Mvc.ControllerContext, System.Collections.Generic.IList`1[System.Web.Mvc.IActionFilter], System.Web.Mvc.ActionDescriptor, System.Collections.Generic.IDictionary`2[System.String,System.Object])() at System.Web.Mvc.ControllerActionInvoker.Boolean InvokeAction(System.Web.Mvc.ControllerContext, System.String)() at System.Web.Mvc.Controller.Void ExecuteCore()() at System.Web.Mvc.ControllerBase.Execute() at System.Web.Mvc.MvcHandler+<>c__DisplayClass8.b__4() at System.Web.Mvc.Async.AsyncResultWrapper+<>c__DisplayClass1.b__0() at System.Web.Mvc.Async.AsyncResultWrapper+<>c__DisplayClass8`1.b__7() at System.Web.Mvc.Async.AsyncResultWrapper+WrappedAsyncResult`1.End() at System.Web.Mvc.Async.AsyncResultWrapper.End() at System.Web.Mvc.Async.AsyncResultWrapper.End() at Microsoft.Web.Mvc.MvcDynamicSessionHandler.EndProcessRequest() at System.Web.HttpApplication+CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() at System.Web.HttpApplication.ExecuteStep() at System.Web.HttpApplication+PipelineStepManager.ResumeSteps() at System.Web.HttpApplication.BeginProcessRequestNotification() at System.Web.HttpRuntime.ProcessRequestNotificationPrivate() at System.Web.Hosting.PipelineRuntime.ProcessRequestNotificationHelper() at System.Web.Hosting.PipelineRuntime.ProcessRequestNotification() at System.Web.Hosting.PipelineRuntime.ProcessRequestNotificationHelper() at System.Web.Hosting.PipelineRuntime.ProcessRequestNotification() Caused by: Corillian.Voyager.ExecutionServices.Client.TRBException at Corillian.Platform.Router.VoyagerLoadBalancer.Void Execute(System.String, System.String, System.String ByRef)() ... 17 more " + //} ] + // ------------------------------- + // Sometimes segment says: + //"errorIDs" : [ 131789, 3002 ], + //"errorDetails" : [ { + // "id" : 0, + // "version" : 0, + // "name" : "1. USB.OLBService.Handlers.TransactionUtilities", + // "value" : "USB.OLBService.Handlers.TransactionUtilities : Error occurred in MapHostTransactions: System.NullReferenceException: Object reference not set to an instance of an object.\r\n at USB.OLBService.Handlers.TransactionUtilities.MapCheckCardHostResponseTransactions(GetOutStandingAuthRequest requestFromUI, List`1 transactions, USBAccount actualAcct)" + //} ], + // Where: + // 131789 MessageQueueException + // 3002 .NET Logger Error Messages + // But the list of errors looks like that: + //[ { + // "id" : 171889775, + // "version" : 0, + // "name" : "System.Messaging.MessageQueueException", + // "value" : "Insufficient resources to perform operation.AD_STACK_TRACE:System.Messaging.MessageQueueException: at System.Messaging.MessageQueue.SendInternal() at Corillian.Platform.Messaging.Sender.Send() at Corillian.Platform.Messaging.Sender.Send() at Corillian.Platform.Audit.AuditTrxSender.Audit() at USB.DigitalServices.Audit.MessageReceiver.Process() at USB.OLBService.Handlers.Utilities.Audit() at USB.OLBService.Handlers.GetTransactionTypes.Execute() at USB.OLBService.Handlers.TransactionUtilities.MapHostResponseTransactions() at USB.OLBService.Handlers.TransactionUtilities.GetMonitoryListExecutor() at USB.OLBService.Handlers.TransactionUtilities.GetHostHistory() at USB.OLBService.Handlers.GetPagedTransactionsV2.Execute() at USB.DCISService.Accounts.V1.Handlers.GetAccountTransactionsV4.Execute() at Fiserv.AppService.Core.HandlerBase`1.Execute() at Fiserv.AppService.Core.ServiceProcessor.Process() at USB.DCIS.Server.DCISServiceServer.Execute() at .SyncInvokeExecute() at System.ServiceModel.Dispatcher.SyncMethodInvoker.Invoke() at System.ServiceModel.Dispatcher.DispatchOperationRuntime.InvokeBegin() at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage5() at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage4() at System.ServiceModel.Dispatcher.MessageRpc.Process() at System.ServiceModel.Dispatcher.ChannelHandler.DispatchAndReleasePump() at System.ServiceModel.Dispatcher.ChannelHandler.HandleRequest() at System.ServiceModel.Dispatcher.ChannelHandler.AsyncMessagePump() at System.ServiceModel.Diagnostics.Utility+AsyncThunk.UnhandledExceptionFrame() at System.ServiceModel.AsyncResult.Complete() at System.ServiceModel.Channels.InputQueue`1+AsyncQueueReader.Set() at System.ServiceModel.Channels.InputQueue`1.EnqueueAndDispatch() at System.ServiceModel.Channels.InputQueue`1.EnqueueAndDispatch() at System.ServiceModel.Channels.InputQueueChannel`1.EnqueueAndDispatch() at System.ServiceModel.Channels.SingletonChannelAcceptor`3.Enqueue() at System.ServiceModel.Channels.SingletonChannelAcceptor`3.Enqueue() at System.ServiceModel.Channels.HttpChannelListener.HttpContextReceived() at System.ServiceModel.Activation.HostedHttpTransportManager.HttpContextReceived() at System.ServiceModel.Activation.HostedHttpRequestAsyncResult.BeginRequest() at System.ServiceModel.Activation.HostedHttpRequestAsyncResult.OnBeginRequest() at System.ServiceModel.PartialTrustHelpers.PartialTrustInvoke() at System.ServiceModel.Activation.HostedHttpRequestAsyncResult.OnBeginRequestWithFlow() at System.ServiceModel.Channels.IOThreadScheduler+CriticalHelper+WorkItem.Invoke2() at System.ServiceModel.Channels.IOThreadScheduler+CriticalHelper+WorkItem.Invoke() at System.ServiceModel.Channels.IOThreadScheduler+CriticalHelper.ProcessCallbacks() at System.ServiceModel.Channels.IOThreadScheduler+CriticalHelper.CompletionCallback() at System.ServiceModel.Channels.IOThreadScheduler+CriticalHelper+ScheduledOverlapped.IOCallback() at System.ServiceModel.Diagnostics.Utility+IOCompletionThunk.UnhandledExceptionFrame() at System.Threading._IOCompletionCallback.PerformIOCompletionCallback() " + //}, { + // "id" : 171889775, + // "version" : 0, + // "name" : "System.Messaging.MessageQueueException", + // "value" : "Insufficient resources to perform operation.AD_STACK_TRACE:System.Messaging.MessageQueueException: at System.Messaging.MessageQueue.SendInternal() at Corillian.Platform.Messaging.Sender.Send() at Corillian.Platform.Messaging.Sender.Send() at Corillian.Platform.Audit.AuditTrxSender.Audit() at USB.DigitalServices.Audit.MessageReceiver.Process() at USB.OLBService.Handlers.Utilities.Audit() at USB.OLBService.Handlers.GetTransactionTypes.Execute() at USB.OLBService.Handlers.TransactionUtilities.MapCheckCardHostResponseTransactions() at USB.OLBService.Handlers.TransactionUtilities.GetCheckCardAuthorizationsFromHost() at USB.OLBService.Handlers.GetPagedTransactionsV2.GetDebitCardAuthorizationTransactions() at USB.OLBService.Handlers.GetPagedTransactionsV2.Execute() at USB.DCISService.Accounts.V1.Handlers.GetAccountTransactionsV4.Execute() at Fiserv.AppService.Core.HandlerBase`1.Execute() at Fiserv.AppService.Core.ServiceProcessor.Process() at USB.DCIS.Server.DCISServiceServer.Execute() at .SyncInvokeExecute() at System.ServiceModel.Dispatcher.SyncMethodInvoker.Invoke() at System.ServiceModel.Dispatcher.DispatchOperationRuntime.InvokeBegin() at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage5() at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage4() at System.ServiceModel.Dispatcher.MessageRpc.Process() at System.ServiceModel.Dispatcher.ChannelHandler.DispatchAndReleasePump() at System.ServiceModel.Dispatcher.ChannelHandler.HandleRequest() at System.ServiceModel.Dispatcher.ChannelHandler.AsyncMessagePump() at System.ServiceModel.Diagnostics.Utility+AsyncThunk.UnhandledExceptionFrame() at System.ServiceModel.AsyncResult.Complete() at System.ServiceModel.Channels.InputQueue`1+AsyncQueueReader.Set() at System.ServiceModel.Channels.InputQueue`1.EnqueueAndDispatch() at System.ServiceModel.Channels.InputQueue`1.EnqueueAndDispatch() at System.ServiceModel.Channels.InputQueueChannel`1.EnqueueAndDispatch() at System.ServiceModel.Channels.SingletonChannelAcceptor`3.Enqueue() at System.ServiceModel.Channels.SingletonChannelAcceptor`3.Enqueue() at System.ServiceModel.Channels.HttpChannelListener.HttpContextReceived() at System.ServiceModel.Activation.HostedHttpTransportManager.HttpContextReceived() at System.ServiceModel.Activation.HostedHttpRequestAsyncResult.BeginRequest() at System.ServiceModel.Activation.HostedHttpRequestAsyncResult.OnBeginRequest() at System.ServiceModel.PartialTrustHelpers.PartialTrustInvoke() at System.ServiceModel.Activation.HostedHttpRequestAsyncResult.OnBeginRequestWithFlow() at System.ServiceModel.Channels.IOThreadScheduler+CriticalHelper+WorkItem.Invoke2() at System.ServiceModel.Channels.IOThreadScheduler+CriticalHelper+WorkItem.Invoke() at System.ServiceModel.Channels.IOThreadScheduler+CriticalHelper.ProcessCallbacks() at System.ServiceModel.Channels.IOThreadScheduler+CriticalHelper.CompletionCallback() at System.ServiceModel.Channels.IOThreadScheduler+CriticalHelper+ScheduledOverlapped.IOCallback() at System.ServiceModel.Diagnostics.Utility+IOCompletionThunk.UnhandledExceptionFrame() at System.Threading._IOCompletionCallback.PerformIOCompletionCallback() " + //}, { + // "id" : 171889775, + // "version" : 0, + // "name" : "System.Messaging.MessageQueueException", + // "value" : "Insufficient resources to perform operation.AD_STACK_TRACE:System.Messaging.MessageQueueException: at System.Messaging.MessageQueue.SendInternal() at Corillian.Platform.Messaging.Sender.Send() at Corillian.Platform.Messaging.Sender.Send() at Corillian.Platform.Audit.AuditTrxSender.Audit() at USB.DigitalServices.Audit.MessageReceiver.Process() at USB.OLBService.Handlers.Utilities.Audit() at USB.OLBService.Handlers.GetPagedTransactionsV2.GetDebitCardAuthorizationTransactions() at USB.OLBService.Handlers.GetPagedTransactionsV2.Execute() at USB.DCISService.Accounts.V1.Handlers.GetAccountTransactionsV4.Execute() at Fiserv.AppService.Core.HandlerBase`1.Execute() at Fiserv.AppService.Core.ServiceProcessor.Process() at USB.DCIS.Server.DCISServiceServer.Execute() at .SyncInvokeExecute() at System.ServiceModel.Dispatcher.SyncMethodInvoker.Invoke() at System.ServiceModel.Dispatcher.DispatchOperationRuntime.InvokeBegin() at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage5() at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage4() at System.ServiceModel.Dispatcher.MessageRpc.Process() at System.ServiceModel.Dispatcher.ChannelHandler.DispatchAndReleasePump() at System.ServiceModel.Dispatcher.ChannelHandler.HandleRequest() at System.ServiceModel.Dispatcher.ChannelHandler.AsyncMessagePump() at System.ServiceModel.Diagnostics.Utility+AsyncThunk.UnhandledExceptionFrame() at System.ServiceModel.AsyncResult.Complete() at System.ServiceModel.Channels.InputQueue`1+AsyncQueueReader.Set() at System.ServiceModel.Channels.InputQueue`1.EnqueueAndDispatch() at System.ServiceModel.Channels.InputQueue`1.EnqueueAndDispatch() at System.ServiceModel.Channels.InputQueueChannel`1.EnqueueAndDispatch() at System.ServiceModel.Channels.SingletonChannelAcceptor`3.Enqueue() at System.ServiceModel.Channels.SingletonChannelAcceptor`3.Enqueue() at System.ServiceModel.Channels.HttpChannelListener.HttpContextReceived() at System.ServiceModel.Activation.HostedHttpTransportManager.HttpContextReceived() at System.ServiceModel.Activation.HostedHttpRequestAsyncResult.BeginRequest() at System.ServiceModel.Activation.HostedHttpRequestAsyncResult.OnBeginRequest() at System.ServiceModel.PartialTrustHelpers.PartialTrustInvoke() at System.ServiceModel.Activation.HostedHttpRequestAsyncResult.OnBeginRequestWithFlow() at System.ServiceModel.Channels.IOThreadScheduler+CriticalHelper+WorkItem.Invoke2() at System.ServiceModel.Channels.IOThreadScheduler+CriticalHelper+WorkItem.Invoke() at System.ServiceModel.Channels.IOThreadScheduler+CriticalHelper.ProcessCallbacks() at System.ServiceModel.Channels.IOThreadScheduler+CriticalHelper.CompletionCallback() at System.ServiceModel.Channels.IOThreadScheduler+CriticalHelper+ScheduledOverlapped.IOCallback() at System.ServiceModel.Diagnostics.Utility+IOCompletionThunk.UnhandledExceptionFrame() at System.Threading._IOCompletionCallback.PerformIOCompletionCallback() " + //}, { + // "id" : 171889775, + // "version" : 0, + // "name" : "System.Messaging.MessageQueueException", + // "value" : "Insufficient resources to perform operation.AD_STACK_TRACE:System.Messaging.MessageQueueException: at System.Messaging.MessageQueue.SendInternal() at Corillian.Platform.Messaging.Sender.Send() at Corillian.Platform.Messaging.Sender.Send() at Corillian.Platform.Audit.AuditTrxSender.Audit() at USB.DigitalServices.Audit.MessageReceiver.Process() at USB.OLBService.Handlers.Utilities.Audit() at USB.OLBService.Handlers.GetPagedTransactionsV2.Execute() at USB.DCISService.Accounts.V1.Handlers.GetAccountTransactionsV4.Execute() at Fiserv.AppService.Core.HandlerBase`1.Execute() at Fiserv.AppService.Core.ServiceProcessor.Process() at USB.DCIS.Server.DCISServiceServer.Execute() at .SyncInvokeExecute() at System.ServiceModel.Dispatcher.SyncMethodInvoker.Invoke() at System.ServiceModel.Dispatcher.DispatchOperationRuntime.InvokeBegin() at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage5() at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage4() at System.ServiceModel.Dispatcher.MessageRpc.Process() at System.ServiceModel.Dispatcher.ChannelHandler.DispatchAndReleasePump() at System.ServiceModel.Dispatcher.ChannelHandler.HandleRequest() at System.ServiceModel.Dispatcher.ChannelHandler.AsyncMessagePump() at System.ServiceModel.Diagnostics.Utility+AsyncThunk.UnhandledExceptionFrame() at System.ServiceModel.AsyncResult.Complete() at System.ServiceModel.Channels.InputQueue`1+AsyncQueueReader.Set() at System.ServiceModel.Channels.InputQueue`1.EnqueueAndDispatch() at System.ServiceModel.Channels.InputQueue`1.EnqueueAndDispatch() at System.ServiceModel.Channels.InputQueueChannel`1.EnqueueAndDispatch() at System.ServiceModel.Channels.SingletonChannelAcceptor`3.Enqueue() at System.ServiceModel.Channels.SingletonChannelAcceptor`3.Enqueue() at System.ServiceModel.Channels.HttpChannelListener.HttpContextReceived() at System.ServiceModel.Activation.HostedHttpTransportManager.HttpContextReceived() at System.ServiceModel.Activation.HostedHttpRequestAsyncResult.BeginRequest() at System.ServiceModel.Activation.HostedHttpRequestAsyncResult.OnBeginRequest() at System.ServiceModel.PartialTrustHelpers.PartialTrustInvoke() at System.ServiceModel.Activation.HostedHttpRequestAsyncResult.OnBeginRequestWithFlow() at System.ServiceModel.Channels.IOThreadScheduler+CriticalHelper+WorkItem.Invoke2() at System.ServiceModel.Channels.IOThreadScheduler+CriticalHelper+WorkItem.Invoke() at System.ServiceModel.Channels.IOThreadScheduler+CriticalHelper.ProcessCallbacks() at System.ServiceModel.Channels.IOThreadScheduler+CriticalHelper.CompletionCallback() at System.ServiceModel.Channels.IOThreadScheduler+CriticalHelper+ScheduledOverlapped.IOCallback() at System.ServiceModel.Diagnostics.Utility+IOCompletionThunk.UnhandledExceptionFrame() at System.Threading._IOCompletionCallback.PerformIOCompletionCallback() " + //}, { + // "id" : 171889775, + // "version" : 0, + // "name" : "System.Messaging.MessageQueueException", + // "value" : "Insufficient resources to perform operation.AD_STACK_TRACE:System.Messaging.MessageQueueException: at System.Messaging.MessageQueue.SendInternal() at Corillian.Platform.Messaging.Sender.Send() at Corillian.Platform.Messaging.Sender.Send() at Corillian.Platform.Audit.AuditTrxSender.Audit() at USB.DigitalServices.Audit.MessageReceiver.Process() at USB.DigitalServices.HandlerCore.ContextSafeHandler`1.Audit() at USB.DCISService.Accounts.V1.Handlers.GetAccountTransactionsV4.Execute() at Fiserv.AppService.Core.HandlerBase`1.Execute() at Fiserv.AppService.Core.ServiceProcessor.Process() at USB.DCIS.Server.DCISServiceServer.Execute() at .SyncInvokeExecute() at System.ServiceModel.Dispatcher.SyncMethodInvoker.Invoke() at System.ServiceModel.Dispatcher.DispatchOperationRuntime.InvokeBegin() at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage5() at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage4() at System.ServiceModel.Dispatcher.MessageRpc.Process() at System.ServiceModel.Dispatcher.ChannelHandler.DispatchAndReleasePump() at System.ServiceModel.Dispatcher.ChannelHandler.HandleRequest() at System.ServiceModel.Dispatcher.ChannelHandler.AsyncMessagePump() at System.ServiceModel.Diagnostics.Utility+AsyncThunk.UnhandledExceptionFrame() at System.ServiceModel.AsyncResult.Complete() at System.ServiceModel.Channels.InputQueue`1+AsyncQueueReader.Set() at System.ServiceModel.Channels.InputQueue`1.EnqueueAndDispatch() at System.ServiceModel.Channels.InputQueue`1.EnqueueAndDispatch() at System.ServiceModel.Channels.InputQueueChannel`1.EnqueueAndDispatch() at System.ServiceModel.Channels.SingletonChannelAcceptor`3.Enqueue() at System.ServiceModel.Channels.SingletonChannelAcceptor`3.Enqueue() at System.ServiceModel.Channels.HttpChannelListener.HttpContextReceived() at System.ServiceModel.Activation.HostedHttpTransportManager.HttpContextReceived() at System.ServiceModel.Activation.HostedHttpRequestAsyncResult.BeginRequest() at System.ServiceModel.Activation.HostedHttpRequestAsyncResult.OnBeginRequest() at System.ServiceModel.PartialTrustHelpers.PartialTrustInvoke() at System.ServiceModel.Activation.HostedHttpRequestAsyncResult.OnBeginRequestWithFlow() at System.ServiceModel.Channels.IOThreadScheduler+CriticalHelper+WorkItem.Invoke2() at System.ServiceModel.Channels.IOThreadScheduler+CriticalHelper+WorkItem.Invoke() at System.ServiceModel.Channels.IOThreadScheduler+CriticalHelper.ProcessCallbacks() at System.ServiceModel.Channels.IOThreadScheduler+CriticalHelper.CompletionCallback() at System.ServiceModel.Channels.IOThreadScheduler+CriticalHelper+ScheduledOverlapped.IOCallback() at System.ServiceModel.Diagnostics.Utility+IOCompletionThunk.UnhandledExceptionFrame() at System.Threading._IOCompletionCallback.PerformIOCompletionCallback() " + //}, { + // "id" : 171889775, + // "version" : 0, + // "name" : "1. USB.OLBService.Handlers.TransactionUtilities", + // "value" : "USB.OLBService.Handlers.TransactionUtilities : Error occurred in MapHostTransactions: System.NullReferenceException: Object reference not set to an instance of an object.\r\n at USB.OLBService.Handlers.TransactionUtilities.MapCheckCardHostResponseTransactions(GetOutStandingAuthRequest requestFromUI, List`1 transactions, USBAccount actualAcct)" + //} ] + + #endregion + + foreach (DetectedError detectedError in detectedErrorsListInThisSegment) { - long tierID = -1; - if (long.TryParse(callChainToken.Substring(10), out tierID) == true) + // Try by exact message match + DetectedError detectedErrorWithErrorID = detectedErrorsFromErrorIDs.Where(e => e.ErrorName == detectedError.ErrorMessage).FirstOrDefault(); + + // Try starting with the message + if (detectedErrorWithErrorID == null) { - if (tiersList != null) + detectedErrorWithErrorID = detectedErrorsFromErrorIDs.Where(e => e.ErrorName.StartsWith(detectedError.ErrorMessage)).FirstOrDefault(); + } + + // Try containing the message + if (detectedErrorWithErrorID == null) + { + detectedErrorWithErrorID = detectedErrorsFromErrorIDs.Where(e => e.ErrorName.Contains(detectedError.ErrorMessage)).FirstOrDefault(); + } + + // Try by partial name match second + if (detectedErrorWithErrorID == null) + { + // Split by . and : + // java.io.IOException + // -> java, io, IOException + // Detected as IOException + // Corillian.Voyager.ExecutionServices.Client.TRBException:Corillian.Voyager.ExecutionServices.Client.TRBException + // -> Corillian, Voyager, ExecutionServices, Client, TRBException, Corillian, Voyager, ExecutionServices, Client, TRBException + // Detected as TRBException + string[] errorMessageTokens = detectedError.ErrorMessage.Split('.', ':'); + + // Go backwards because exception type is at the end + for (int i = errorMessageTokens.Length - 1; i >= 0; i--) { - EntityTier tier = tiersList.Where(t => t.TierID == tierID).FirstOrDefault(); - if (tier != null) + detectedErrorWithErrorID = detectedErrorsFromErrorIDs.Where(e => e.ErrorName.Contains(errorMessageTokens[i])).FirstOrDefault(); + if (detectedErrorWithErrorID != null) { - sbCallChain.AppendFormat("({0})->", tier.TierName); + break; } } } + + // Did we find it? + if (detectedErrorWithErrorID != null) + { + // Yay, we did, mark this error by ID off as matched and copy the values to the final + detectedErrorWithErrorID.ErrorIDMatchedToMessage = true; + + detectedError.ErrorID = detectedErrorWithErrorID.ErrorID; + detectedError.ErrorName = detectedErrorWithErrorID.ErrorName; + detectedError.ErrorType = detectedErrorWithErrorID.ErrorType; + + #region Fill in the deeplinks for the Error + + detectedError.ControllerLink = segment.Controller; + detectedError.ApplicationLink = segment.ApplicationLink; + detectedError.TierLink = segment.TierLink; + detectedError.NodeLink = segment.NodeLink; + detectedError.BTLink = segment.BTLink; + detectedError.ErrorLink = String.Format(DEEPLINK_ERROR, detectedError.Controller, detectedError.ApplicationID, detectedError.ErrorID, DEEPLINK_THIS_TIMERANGE); + + #endregion + + } } - else if (callChainToken.StartsWith("Exit Call") == true) + + // At this point, we matched what we could. + // A little cleanup - what if we have 1 by error ID and 1 message without Error ID left? If yes, those obviously match + List detectedErrorsFromErrorIDsUnmatched = detectedErrorsFromErrorIDs.Where(e => e.ErrorIDMatchedToMessage == false).ToList(); + List detectedErrorsListInThisSegmentUnmatched = detectedErrorsListInThisSegment.Where(e => e.ErrorID == -1).ToList(); + if (detectedErrorsFromErrorIDsUnmatched.Count == 1 && detectedErrorsListInThisSegmentUnmatched.Count == 1) { - sbCallChain.AppendFormat("[{0}]->", callChainToken.Substring(10)); + DetectedError detectedError = detectedErrorsListInThisSegmentUnmatched[0]; + DetectedError detectedErrorWithErrorID = detectedErrorsFromErrorIDsUnmatched[0]; + detectedErrorWithErrorID.ErrorIDMatchedToMessage = true; + + detectedError.ErrorID = detectedErrorWithErrorID.ErrorID; + detectedError.ErrorName = detectedErrorWithErrorID.ErrorName; + detectedError.ErrorType = detectedErrorWithErrorID.ErrorType; + + #region Fill in the deeplinks for the Error + + detectedError.ControllerLink = segment.Controller; + detectedError.ApplicationLink = segment.ApplicationLink; + detectedError.TierLink = segment.TierLink; + detectedError.NodeLink = segment.NodeLink; + detectedError.BTLink = segment.BTLink; + detectedError.ErrorLink = String.Format(DEEPLINK_ERROR, detectedError.Controller, detectedError.ApplicationID, detectedError.ErrorID, DEEPLINK_THIS_TIMERANGE); + + #endregion } - else if (callChainToken.StartsWith("To:{[UNRESOLVED]") == true) + else if (detectedErrorsFromErrorIDsUnmatched.Count > 1) { - long backendID = -1; - if (long.TryParse(callChainToken.Substring(17).TrimEnd(']', '}'), out backendID) == true) - { - if (backendsList != null) - { - EntityBackend backend = backendsList.Where(b => b.BackendID == backendID).FirstOrDefault(); - if (backend != null) - { - //sbCallChain.AppendFormat("<{0}><{1}>>->", backendRow.BackendName, backendRow.BackendType); - sbCallChain.AppendFormat("<{0}>->", backend.BackendName); - } - } - } + // Don't know how to match those. Let's just append them to the list + detectedErrorsListInThisSegment.AddRange(detectedErrorsFromErrorIDsUnmatched); } } - if (sbCallChain.Length > 2) - { - sbCallChain.Remove(sbCallChain.Length - 2, 2); - } - callChainForThisSegment = sbCallChain.ToString(); #endregion - #region Process Exits in Segment + #region Process Data Collectors in Segment - SortedDictionary callChainsSegment = new SortedDictionary(); + List businessDataListInThisSegment = new List(); - List exitCallsListInThisSegment = new List(); - foreach (JToken exitCallToken in snapshotSegmentDetail["snapshotExitCalls"]) + // Transaction properties + foreach (JToken transactionPropertyToken in snapshotSegmentDetail["transactionProperties"]) { - #region Parse the exit call into correct exit + BusinessData businessData = new BusinessData(); - ExitCall exitCall = new ExitCall(); + businessData.Controller = segment.Controller; + businessData.ApplicationName = segment.ApplicationName; + businessData.ApplicationID = segment.ApplicationID; + businessData.TierID = segment.TierID; + businessData.TierName = segment.TierName; + businessData.BTID = segment.BTID; + businessData.BTName = segment.BTName; + businessData.NodeID = segment.NodeID; + businessData.NodeName = segment.NodeName; - exitCall.Controller = segment.Controller; - exitCall.ApplicationName = segment.ApplicationName; - exitCall.ApplicationID = segment.ApplicationID; - exitCall.TierID = segment.TierID; - exitCall.TierName = segment.TierName; - exitCall.BTID = segment.BTID; - exitCall.BTName = segment.BTName; - exitCall.NodeID = segment.NodeID; - exitCall.NodeName = segment.NodeName; + businessData.RequestID = segment.RequestID; + businessData.SegmentID = segment.SegmentID; - exitCall.RequestID = segment.RequestID; - exitCall.SegmentID = segment.SegmentID; + businessData.DataType = "Transaction"; - exitCall.OccuredUtc = segment.OccuredUtc; - exitCall.Occured = segment.Occured; + businessData.DataName = transactionPropertyToken["name"].ToString(); + businessData.DataValue = transactionPropertyToken["value"].ToString(); - exitCall.ExitType = exitCallToken["exitPointName"].ToString(); + #region Fill in the deeplinks for the Business Data - exitCall.Duration = (long)exitCallToken["timeTakenInMillis"]; - exitCall.IsAsync = ((bool)exitCallToken["exitPointCall"]["synchronous"] == false); + businessData.ControllerLink = segment.Controller; + businessData.ApplicationLink = segment.ApplicationLink; + businessData.TierLink = segment.TierLink; + businessData.NodeLink = segment.NodeLink; + businessData.BTLink = segment.BTLink; - // Create pretty call chain - // Where are we going, Tier or Backend - if (exitCallToken["toComponentId"].ToString().StartsWith("{[UNRESOLVED]") == true) - { - // Backend - exitCall.ToEntityType = "Backend"; - JToken goingToProperty = exitCallToken["properties"].Where(p => p["name"].ToString() == "backendId").FirstOrDefault(); - if (goingToProperty != null) - { - exitCall.ToEntityID = (long)goingToProperty["value"]; ; - } - goingToProperty = exitCallToken["properties"].Where(p => p["name"].ToString() == "to").FirstOrDefault(); - if (goingToProperty != null) - { - exitCall.ToEntityName = goingToProperty["value"].ToString(); - } - if (exitCall.IsAsync == false) - { - exitCall.CallChain = String.Format("{0}->[{1}]:[{3} ms]-><{2}>", callChainForThisSegment, exitCall.ExitType, exitCall.ToEntityName, exitCall.Duration); - } - else - { - exitCall.CallChain = String.Format("{0}->[{1}]:[{3} ms async]-><{2}>", callChainForThisSegment, exitCall.ExitType, exitCall.ToEntityName, exitCall.Duration); - } - } - else if (exitCallToken["toComponentId"].ToString().StartsWith("App:") == true) - { - //Application - exitCall.ToEntityType = "Application"; - JToken goingToProperty = exitCallToken["properties"].Where(p => p["name"].ToString() == "appId").FirstOrDefault(); - if (goingToProperty != null) - { - exitCall.ToEntityID = (long)goingToProperty["value"]; ; - } - goingToProperty = exitCallToken["properties"].Where(p => p["name"].ToString() == "to").FirstOrDefault(); - if (goingToProperty != null) - { - exitCall.ToEntityName = goingToProperty["value"].ToString(); - } - if (exitCall.IsAsync == false) - { - exitCall.CallChain = String.Format("{0}->[{1}]:[{3} ms]->{{{2}}}", callChainForThisSegment, exitCall.ExitType, exitCall.ToEntityName, exitCall.Duration); - } - else - { - exitCall.CallChain = String.Format("{0}->[{1}]:[{3} ms async]->{{{2}}}", callChainForThisSegment, exitCall.ExitType, exitCall.ToEntityName, exitCall.Duration); - } - } - else - { - // Tier - exitCall.ToEntityType = "Tier"; - exitCall.ToEntityID = (long)exitCallToken["toComponentId"]; - JToken goingToProperty = exitCallToken["properties"].Where(p => p["name"].ToString() == "to").FirstOrDefault(); - if (goingToProperty != null) - { - exitCall.ToEntityName = goingToProperty["value"].ToString(); - } - if (exitCall.IsAsync == false) - { - exitCall.CallChain = String.Format("{0}->[{1}]:[{3} ms]->({2})", callChainForThisSegment, exitCall.ExitType, exitCall.ToEntityName, exitCall.Duration); - } - else - { - exitCall.CallChain = String.Format("{0}->[{1}]:[{3} ms async]->({2})", callChainForThisSegment, exitCall.ExitType, exitCall.ToEntityName, exitCall.Duration); - } - } + #endregion - // Add the exit call to the overall list for tracking - string exitCCCKey = String.Format("{0}_{1}_{2}", callChainForThisSegment, exitCall.ExitType, exitCall.ToEntityName); - CallChainContainer cccSeg = null; - if (callChainsSegment.ContainsKey(exitCCCKey) == false) - { - cccSeg = new CallChainContainer { From = callChainForThisSegment, ExitType = exitCall.ExitType, ToEntityName = exitCall.ToEntityName, ToEntityType = exitCall.ToEntityType }; - callChainsSegment.Add(exitCCCKey, cccSeg); - } - else - { - cccSeg = callChainsSegment[exitCCCKey]; - } - cccSeg.CallTimings.Add(new CallTiming { Async = exitCall.IsAsync, Duration = exitCall.Duration }); + businessDataListInThisSegment.Add(businessData); + } - CallChainContainer cccSnap = null; - if (callChainsSnapshot.ContainsKey(exitCCCKey) == false) - { - cccSnap = new CallChainContainer { From = callChainForThisSegment, ExitType = exitCall.ExitType, ToEntityName = exitCall.ToEntityName, ToEntityType = exitCall.ToEntityType }; - callChainsSnapshot.Add(exitCCCKey, cccSnap); - } - else - { - cccSnap = callChainsSnapshot[exitCCCKey]; - } - cccSnap.CallTimings.Add(new CallTiming { Async = exitCall.IsAsync, Duration = exitCall.Duration }); + // HTTP data collectors + foreach (JToken transactionPropertyToken in snapshotSegmentDetail["httpParameters"]) + { + BusinessData businessData = new BusinessData(); + + businessData.Controller = segment.Controller; + businessData.ApplicationName = segment.ApplicationName; + businessData.ApplicationID = segment.ApplicationID; + businessData.TierID = segment.TierID; + businessData.TierName = segment.TierName; + businessData.BTID = segment.BTID; + businessData.BTName = segment.BTName; + businessData.NodeID = segment.NodeID; + businessData.NodeName = segment.NodeName; - exitCall.Detail = exitCallToken["detailString"].ToString(); - exitCall.ErrorDetail = exitCallToken["errorDetails"].ToString(); - if (exitCall.ErrorDetail == "\\N") { exitCall.ErrorDetail = String.Empty; } - exitCall.Method = exitCallToken["callingMethod"].ToString(); + businessData.RequestID = segment.RequestID; + businessData.SegmentID = segment.SegmentID; - // Parse Properties - exitCall.PropsAll = exitCallToken["propertiesAsString"].ToString(); - int i = 0; - foreach (JToken customExitPropertyToken in exitCallToken["properties"]) - { - exitCall.NumProps++; - string propertyName = customExitPropertyToken["name"].ToString(); - string propertyValue = customExitPropertyToken["value"].ToString(); - switch (propertyName) - { - case "component": - case "to": - case "from": - case "backendId": - // Ignore those, already mapped elsewhere - exitCall.NumProps--; - break; - case "Query Type": - exitCall.PropQueryType = propertyValue; - break; - case "Statement Type": - exitCall.PropStatementType = propertyValue; - break; - case "URL": - exitCall.PropURL = propertyValue; - break; - case "Service": - exitCall.PropServiceName = propertyValue; - break; - case "Operation": - exitCall.PropOperationName = propertyValue; - break; - case "Name": - exitCall.PropName = propertyValue; - break; - case "Asynchronous": - exitCall.PropAsync = propertyValue; - break; - case "Continuation": - exitCall.PropContinuation = propertyValue; - break; - default: - i++; - // Have 5 overflow buckets for those, hope it is enough - if (i == 1) - { - exitCall.Prop1Name = propertyName; - exitCall.Prop1Value = propertyValue; - } - else if (i == 2) - { - exitCall.Prop2Name = propertyName; - exitCall.Prop2Value = propertyValue; - } - else if (i == 3) - { - exitCall.Prop3Name = propertyName; - exitCall.Prop3Value = propertyValue; - } - else if (i == 4) - { - exitCall.Prop4Name = propertyName; - exitCall.Prop4Value = propertyValue; - } - else if (i == 5) - { - exitCall.Prop5Name = propertyName; - exitCall.Prop5Value = propertyValue; - } - break; - } - } + businessData.DataType = "HTTP"; - exitCall.NumCalls = (int)exitCallToken["count"]; - exitCall.NumErrors = (int)exitCallToken["errorCount"]; - exitCall.HasErrors = exitCall.NumErrors != 0; + businessData.DataName = transactionPropertyToken["name"].ToString(); + businessData.DataValue = transactionPropertyToken["value"].ToString(); + + #region Fill in the deeplinks for the Business Data + + businessData.ControllerLink = segment.Controller; + businessData.ApplicationLink = segment.ApplicationLink; + businessData.TierLink = segment.TierLink; + businessData.NodeLink = segment.NodeLink; + businessData.BTLink = segment.BTLink; #endregion - #region Fill in the deeplinks for the exit + businessDataListInThisSegment.Add(businessData); + } - exitCall.ControllerLink = segment.Controller; - exitCall.ApplicationLink = segment.ApplicationLink; - exitCall.TierLink = segment.TierLink; - exitCall.NodeLink = segment.NodeLink; - exitCall.BTLink = segment.BTLink; + // MIDCs + foreach (JToken transactionPropertyToken in snapshotSegmentDetail["businessData"]) + { + BusinessData businessData = new BusinessData(); - switch (exitCall.ToEntityType) - { - case "Backend": - exitCall.ToLink = String.Format(DEEPLINK_BACKEND, exitCall.Controller, exitCall.ApplicationID, exitCall.ToEntityID, DEEPLINK_THIS_TIMERANGE); - break; + businessData.Controller = segment.Controller; + businessData.ApplicationName = segment.ApplicationName; + businessData.ApplicationID = segment.ApplicationID; + businessData.TierID = segment.TierID; + businessData.TierName = segment.TierName; + businessData.BTID = segment.BTID; + businessData.BTName = segment.BTName; + businessData.NodeID = segment.NodeID; + businessData.NodeName = segment.NodeName; - case "Tier": - exitCall.ToLink = String.Format(DEEPLINK_TIER, exitCall.Controller, exitCall.ApplicationID, exitCall.ToEntityID, DEEPLINK_THIS_TIMERANGE); - break; + businessData.RequestID = segment.RequestID; + businessData.SegmentID = segment.SegmentID; - case "Application": - exitCall.ToLink = String.Format(DEEPLINK_APPLICATION, exitCall.Controller, exitCall.ToEntityID, DEEPLINK_THIS_TIMERANGE); - break; + businessData.DataType = "Code"; - default: - break; - } + businessData.DataName = transactionPropertyToken["name"].ToString(); + businessData.DataValue = transactionPropertyToken["value"].ToString().Trim('[', ']'); + + #region Fill in the deeplinks for the Business Data + + businessData.ControllerLink = segment.Controller; + businessData.ApplicationLink = segment.ApplicationLink; + businessData.TierLink = segment.TierLink; + businessData.NodeLink = segment.NodeLink; + businessData.BTLink = segment.BTLink; #endregion - exitCallsListInThisSegment.Add(exitCall); + businessDataListInThisSegment.Add(businessData); } #endregion - #region Process Service Endpoints in Segment + #region Process Call Graphs in Segment - List serviceEndpointCallsListInThisSegment = new List(); - foreach (JToken serviceEndpointToken in snapshotSegmentDetail["serviceEndPointIds"]) + string snapshotSegmentCallGraphFilePath = Path.Combine(snapshotFolderPath, String.Format(EXTRACT_SNAPSHOT_SEGMENT_CALLGRAPH_FILE_NAME, snapshotSegmentToken["id"])); + JArray snapshotSegmentCallGraphs = FileIOHelper.loadJArrayFromFile(snapshotSegmentCallGraphFilePath); + + // Can't use recursion for some of the snapshots because of StackOverflowException + // We run out of stack when we go 400+ deep into call stack, which apparently happens + //List methodCallLinesInSegmentList = new List(250); + //if (snapshotSegmentCallGraphs != null && snapshotSegmentCallGraphs.HasValues == true) + //{ + // int methodLineCallSequenceNumber = 0; + // // Make a copy of this list because we are going to slowly strip it down and we don't want the parent list modified + // List exitCallsListInThisSegmentCopy = new List(exitCallsListInThisSegment.Count); + // exitCallsListInThisSegmentCopy.AddRange(exitCallsListInThisSegment); + // convertCallGraphChildren_Recursion(snapshotSegmentCallGraphs[0], 0, ref methodLineCallSequenceNumber, methodCallLinesInSegmentList, serviceEndpointCallsListInThisSegment, exitCallsListInThisSegmentCopy); + //} + + // Instead, let's call it using stack-based algorithm + + // Make a copy of this list because we are going to slowly strip it down and we don't want the parent list modified + List methodCallLinesInSegmentList = null; + if (snapshotSegmentCallGraphs != null && snapshotSegmentCallGraphs.HasValues == true) { - long serviceEndpointID = (long)((JValue)serviceEndpointToken).Value; - if (serviceEndpointsList != null) + List exitCallsListInThisSegmentCopy = new List(exitCallsListInThisSegment.Count); + exitCallsListInThisSegmentCopy.AddRange(exitCallsListInThisSegment); + methodCallLinesInSegmentList = convertCallGraphChildren_Stack(snapshotSegmentCallGraphs[0], serviceEndpointCallsListInThisSegment, exitCallsListInThisSegmentCopy); + } + if (methodCallLinesInSegmentList == null) + { + methodCallLinesInSegmentList = new List(0); + } + + // Fill in common values and look up framework + foreach (MethodCallLine methodCallLine in methodCallLinesInSegmentList) + { + methodCallLine.Controller = snapshot.Controller; + methodCallLine.ApplicationName = snapshot.ApplicationName; + methodCallLine.ApplicationID = snapshot.ApplicationID; + methodCallLine.TierID = (long)snapshotSegmentToken["applicationComponentId"]; + methodCallLine.TierName = snapshotSegmentToken["applicationComponentName"].ToString(); + methodCallLine.BTID = snapshot.BTID; + methodCallLine.BTName = snapshot.BTName; + methodCallLine.NodeID = (long)snapshotSegmentToken["applicationComponentNodeId"]; + methodCallLine.NodeName = snapshotSegmentToken["applicationComponentNodeName"].ToString(); + + methodCallLine.RequestID = snapshotSegmentToken["requestGUID"].ToString(); + methodCallLine.SegmentID = (long)snapshotSegmentToken["id"]; + + // Index Method->Framework type + if (methodCallLine.Class.Length == 0) { - EntityServiceEndpoint serviceEndpoint = serviceEndpointsList.Where(s => s.SEPID == serviceEndpointID).FirstOrDefault(); - if (serviceEndpoint != null) + methodCallLine.Framework = "Empty class name"; + } + else + { + string keyLetterOfMappingList = methodCallLine.Class.Substring(0, 1).ToLower(); + if (methodCallLineClassToFrameworkTypeMappingDictionary.ContainsKey(keyLetterOfMappingList) == false) { - #region Fill Service Endpoint stuff + methodCallLine.Framework = String.Format("No mapping for {0}", keyLetterOfMappingList); + } + else + { + List methodCallLineClassToFrameworkTypeMappingList = methodCallLineClassToFrameworkTypeMappingDictionary[keyLetterOfMappingList]; - ServiceEndpointCall serviceEndpointCall = new ServiceEndpointCall(); + bool frameworkMappingFound = false; + foreach (MethodCallLineClassTypeMapping mapping in methodCallLineClassToFrameworkTypeMappingList) + { + if (methodCallLine.Class.StartsWith(mapping.ClassPrefix, StringComparison.Ordinal) == true) + { + methodCallLine.Framework = String.Format("{0} ({1})", mapping.ClassPrefix, mapping.FrameworkType); + frameworkMappingFound = true; + break; + } + } + if (frameworkMappingFound == false) + { + // Grab just the namespace of the class + int indexOfPeriodBeforeClassName = methodCallLine.Class.LastIndexOf('.'); + if (indexOfPeriodBeforeClassName > 0) + { + methodCallLine.Framework = methodCallLine.Class.Substring(0, indexOfPeriodBeforeClassName); + } + else + { + methodCallLine.Framework = "No class name determined"; + } + } + } + } - serviceEndpointCall.Controller = segment.Controller; - serviceEndpointCall.ApplicationName = segment.ApplicationName; - serviceEndpointCall.ApplicationID = segment.ApplicationID; - serviceEndpointCall.TierID = segment.TierID; - serviceEndpointCall.TierName = segment.TierName; - serviceEndpointCall.BTID = segment.BTID; - serviceEndpointCall.BTName = segment.BTName; - serviceEndpointCall.NodeID = segment.NodeID; - serviceEndpointCall.NodeName = segment.NodeName; + // Calculate the duration range + methodCallLine.ExecRange = getDurationRangeAsString(methodCallLine.Exec); + } - serviceEndpointCall.RequestID = segment.RequestID; - serviceEndpointCall.SegmentID = segment.SegmentID; + // Fill in data collectors + // Choose only the MIDC data collectors + List businessDataCodeListInThisSegment = businessDataListInThisSegment.Where(b => b.DataType == "Code").ToList(); + // Only fill in MIDCs if there are rules in places and values + if (businessDataCodeListInThisSegment.Count > 0 && methodInvocationDataCollectorsList != null && methodInvocationDataCollectorsList.Count > 0) + { + var midcSettingGroups = methodInvocationDataCollectorsList.GroupBy(m => new { m.MatchClass, m.MatchMethod }); - serviceEndpointCall.SEPID = serviceEndpoint.SEPID; - serviceEndpointCall.SEPName = serviceEndpoint.SEPName; - serviceEndpointCall.SEPType = serviceEndpoint.SEPType; + foreach (var midcSettingGroup in midcSettingGroups) + { + List methodInvocationDataCollectors = midcSettingGroup.ToList(); + MethodInvocationDataCollector methodInvocationDataCollector = methodInvocationDataCollectors[0]; + // Find the methods matching this data collector setting + List methodCallLinesMatchingMIDC = methodCallLinesInSegmentList.Where(m => m.Class == methodInvocationDataCollector.MatchClass && m.Method == methodInvocationDataCollector.MatchMethod).ToList(); + if (methodCallLinesMatchingMIDC.Count > 0) + { + // Found some lines, let's enumerate data collectors that were actually collected and match them + List businessDataReferenceList = new List(methodInvocationDataCollectors.Count); + foreach (BusinessData businessData in businessDataCodeListInThisSegment) + { + if (methodInvocationDataCollectors.Count(m => m.DataGathererName == businessData.DataName) > 0) + { + businessDataReferenceList.Add(String.Format("{0}={1} ({2})", businessData.DataName, businessData.DataValue, methodInvocationDataCollector.CollectorName)); + } + } - #endregion + // Now that we have the list of those data collectors, put them into the method line + foreach (MethodCallLine methodCallLine in methodCallLinesMatchingMIDC) + { + methodCallLine.NumMIDCs = businessDataReferenceList.Count; - #region Fill in the deeplinks for the Service Endpoint + if (methodCallLine.NumMIDCs == 1) + { + methodCallLine.MIDCs = businessDataReferenceList[0]; + } + else + { + if (businessDataReferenceList.Count > 0) + { + StringBuilder sb = new StringBuilder(64 * methodCallLine.NumMIDCs); + foreach (string businessDataReference in businessDataReferenceList) + { + sb.AppendFormat("{0};\n", businessDataReference); + } + sb.Remove(sb.Length - 1, 1); + methodCallLine.MIDCs = sb.ToString(); + } + } + } + } + } + } - serviceEndpointCall.ControllerLink = segment.Controller; - serviceEndpointCall.ApplicationLink = segment.ApplicationLink; - serviceEndpointCall.TierLink = segment.TierLink; - serviceEndpointCall.NodeLink = segment.NodeLink; - serviceEndpointCall.BTLink = segment.BTLink; - serviceEndpointCall.SEPLink = String.Format(DEEPLINK_SERVICE_ENDPOINT, serviceEndpointCall.Controller, serviceEndpointCall.ApplicationID, serviceEndpointCall.TierID, serviceEndpointCall.SEPID, DEEPLINK_THIS_TIMERANGE); + // Process all method call lines to generate Occurrences list, finding and counting all the unique values + Dictionary methodCallLinesOccurrencesInSegmentDictionary = new Dictionary(methodCallLinesInSegmentList.Count); + foreach (MethodCallLine methodCallLine in methodCallLinesInSegmentList) + { + if (methodCallLinesOccurrencesInSegmentDictionary.ContainsKey(methodCallLine.FullName) == false) + { + // Add new + MethodCallLine methodCallLineOccurrence = methodCallLine.Clone(); + methodCallLineOccurrence.NumCalls = 1; + methodCallLinesOccurrencesInSegmentDictionary.Add(methodCallLine.FullName, methodCallLineOccurrence); + } + else + { + // Adjust existing + MethodCallLine methodCallLineOccurrence = methodCallLinesOccurrencesInSegmentDictionary[methodCallLine.FullName]; - #endregion + methodCallLineOccurrence.NumCalls++; - serviceEndpointCallsListInThisSegment.Add(serviceEndpointCall); - } + methodCallLineOccurrence.Exec = methodCallLineOccurrence.Exec + methodCallLine.Exec; + methodCallLineOccurrence.Wait = methodCallLineOccurrence.Wait + methodCallLine.Wait; + methodCallLineOccurrence.Block = methodCallLineOccurrence.Block + methodCallLine.Block; + methodCallLineOccurrence.CPU = methodCallLineOccurrence.CPU + methodCallLine.CPU; + + methodCallLineOccurrence.NumExits = methodCallLineOccurrence.NumExits + methodCallLine.NumExits; + methodCallLineOccurrence.NumSEPs = methodCallLineOccurrence.NumSEPs + methodCallLine.NumSEPs; + methodCallLineOccurrence.NumMIDCs = methodCallLineOccurrence.NumMIDCs + methodCallLine.NumMIDCs; + methodCallLineOccurrence.NumChildren = methodCallLineOccurrence.NumChildren + methodCallLine.NumChildren; } } + List methodCallLinesOccurrencesInSegmentList = new List(methodCallLinesOccurrencesInSegmentDictionary.Count); + methodCallLinesOccurrencesInSegmentList = methodCallLinesOccurrencesInSegmentDictionary.Values.ToList(); + methodCallLinesOccurrencesInSegmentList = methodCallLinesOccurrencesInSegmentList.OrderBy(m => m.FullName).ToList(); + foreach (MethodCallLine methodCallLine in methodCallLinesOccurrencesInSegmentList) + { + methodCallLine.ExecRange = getDurationRangeAsString(methodCallLine.Exec); + } #endregion - #region Process Errors in Segment + #region Update call chains and call types from exits into segment - segment.NumErrors = snapshotSegmentDetail["errorIDs"].Count(); - List detectedErrorsListInThisSegment = new List(); - if (segment.NumErrors > 0) + SortedDictionary exitTypesSegment = new SortedDictionary(); + + StringBuilder sbCallChainsSegment = new StringBuilder(128 * callChainsSegment.Count); + foreach (var callChain in callChainsSegment) { - // First, populate the list of errors from the reported error numbers - List detectedErrorsFromErrorIDs = new List(segment.NumErrors); - foreach (JToken errorToken in snapshotSegmentDetail["errorIDs"]) + sbCallChainsSegment.AppendFormat("{0}\n", callChain.Value); + if (exitTypesSegment.ContainsKey(callChain.Value.ExitType) == false) { - long errorID = (long)((JValue)errorToken).Value; - if (errorsList != null) - { - EntityError error = errorsList.Where(e => e.ErrorID == errorID).FirstOrDefault(); - if (error != null) - { - DetectedError detectedError = new DetectedError(); + exitTypesSegment.Add(callChain.Value.ExitType, 0); + } + exitTypesSegment[callChain.Value.ExitType] = exitTypesSegment[callChain.Value.ExitType] + callChain.Value.CallTimings.Count; + } + if (sbCallChainsSegment.Length > 1) { sbCallChainsSegment.Remove(sbCallChainsSegment.Length - 1, 1); } + segment.CallChains = sbCallChainsSegment.ToString(); - detectedError.Controller = segment.Controller; - detectedError.ApplicationName = segment.ApplicationName; - detectedError.ApplicationID = segment.ApplicationID; - detectedError.TierID = segment.TierID; - detectedError.TierName = segment.TierName; - detectedError.BTID = segment.BTID; - detectedError.BTName = segment.BTName; - detectedError.NodeID = segment.NodeID; - detectedError.NodeName = segment.NodeName; + StringBuilder sbExitTypesSegment = new StringBuilder(10 * exitTypesSegment.Count); + foreach (var exitType in exitTypesSegment) + { + sbExitTypesSegment.AppendFormat("{0}={1}\n", exitType.Key, exitType.Value); + } - detectedError.RequestID = segment.RequestID; - detectedError.SegmentID = segment.SegmentID; + if (sbExitTypesSegment.Length > 1) { sbExitTypesSegment.Remove(sbExitTypesSegment.Length - 1, 1); } + segment.ExitTypes = sbExitTypesSegment.ToString(); - detectedError.ErrorID = error.ErrorID; - detectedError.ErrorName = error.ErrorName; - detectedError.ErrorType = error.ErrorType; + #endregion - detectedError.ErrorIDMatchedToMessage = false; + #region Update counts of calls and types of destinations for Segment - detectedError.ErrorMessage = ""; - detectedError.ErrorDetail = ""; + segment.NumCallsToTiers = exitCallsListInThisSegment.Where(e => e.ToEntityType == "Tier").Sum(e => e.NumCalls); + segment.NumCallsToBackends = exitCallsListInThisSegment.Where(e => e.ToEntityType == "Backend").Sum(e => e.NumCalls); + segment.NumCallsToApplications = exitCallsListInThisSegment.Where(e => e.ToEntityType == "Application").Sum(e => e.NumCalls); - detectedErrorsFromErrorIDs.Add(detectedError); - } - } - } + segment.NumCalledTiers = exitCallsListInThisSegment.Where(e => e.ToEntityType == "Tier").GroupBy(e => e.ToEntityName).Count(); + segment.NumCalledBackends = exitCallsListInThisSegment.Where(e => e.ToEntityType == "Backend").GroupBy(e => e.ToEntityName).Count(); + segment.NumCalledApplications = exitCallsListInThisSegment.Where(e => e.ToEntityType == "Application").GroupBy(e => e.ToEntityName).Count(); - // Second, populate the list of the details of errors - JArray snapshotSegmentErrorDetail = FileIOHelper.loadJArrayFromFile(snapshotSegmentErrorFilePath); - if (snapshotSegmentErrorDetail != null) - { - detectedErrorsListInThisSegment = new List(snapshotSegmentErrorDetail.Count); + segment.NumSEPs = serviceEndpointCallsListInThisSegment.Count(); - foreach (JToken errorToken in snapshotSegmentErrorDetail) - { - DetectedError detectedError = new DetectedError(); + segment.NumHTTPDCs = businessDataListInThisSegment.Where(d => d.DataType == "HTTP").Count(); + segment.NumMIDCs = businessDataListInThisSegment.Where(d => d.DataType == "Code").Count(); - detectedError.Controller = segment.Controller; - detectedError.ApplicationName = segment.ApplicationName; - detectedError.ApplicationID = segment.ApplicationID; - detectedError.TierID = segment.TierID; - detectedError.TierName = segment.TierName; - detectedError.BTID = segment.BTID; - detectedError.BTName = segment.BTName; - detectedError.NodeID = segment.NodeID; - detectedError.NodeName = segment.NodeName; + #endregion - detectedError.RequestID = segment.RequestID; - detectedError.SegmentID = segment.SegmentID; + // Add the created entities + segmentsList.Add(segment); + exitCallsList.AddRange(exitCallsListInThisSegment); + serviceEndpointCallsList.AddRange(serviceEndpointCallsListInThisSegment); + detectedErrorsList.AddRange(detectedErrorsListInThisSegment); + businessDataList.AddRange(businessDataListInThisSegment); + methodCallLinesList.AddRange(methodCallLinesInSegmentList); + methodCallLinesOccurrencesList.AddRange(methodCallLinesOccurrencesInSegmentList); + } + } - detectedError.ErrorID = -1; - detectedError.ErrorName = "?"; - detectedError.ErrorType = "?"; + // Sort things prettily + segmentsList = segmentsList.OrderByDescending(s => s.IsFirstInChain).ThenBy(s => s.Occured).ThenBy(s => s.UserExperience).ToList(); + exitCallsList = exitCallsList.OrderBy(c => c.RequestID).ThenBy(c => c.SegmentID).ThenBy(c => c.ExitType).ToList(); + serviceEndpointCallsList = serviceEndpointCallsList.OrderBy(s => s.RequestID).ThenBy(s => s.SegmentID).ThenBy(s => s.SEPName).ToList(); + detectedErrorsList = detectedErrorsList.OrderBy(e => e.RequestID).ThenBy(e => e.SegmentID).ThenBy(e => e.ErrorName).ToList(); + businessDataList = businessDataList.OrderBy(b => b.DataType).ThenBy(b => b.DataName).ToList(); - detectedError.ErrorMessage = errorToken["name"].ToString(); - detectedError.ErrorDetail = errorToken["value"].ToString().Replace("AD_STACK_TRACE:", "\n").Replace("__AD_CMSG__", "\n"); + #region Update call chains from segments into snapshot - detectedErrorsListInThisSegment.Add(detectedError); - } - } + SortedDictionary exitTypesSnapshot = new SortedDictionary(); - // Now reconcile them both - #region Explanation of all of this nonsense to parse the errors + StringBuilder sbCallChainsSnapshot = new StringBuilder(128 * callChainsSnapshot.Count); + foreach (var callChain in callChainsSnapshot) + { + sbCallChainsSnapshot.AppendFormat("{0};\n", callChain.Value); + if (exitTypesSnapshot.ContainsKey(callChain.Value.ExitType) == false) + { + exitTypesSnapshot.Add(callChain.Value.ExitType, 0); + } + exitTypesSnapshot[callChain.Value.ExitType] = exitTypesSnapshot[callChain.Value.ExitType] + callChain.Value.CallTimings.Count; + } + if (sbCallChainsSnapshot.Length > 1) { sbCallChainsSnapshot.Remove(sbCallChainsSnapshot.Length - 1, 1); } + snapshot.CallChains = sbCallChainsSnapshot.ToString(); - // The IDs of the errors give us what errors occured - // But the segment JSON does not include all the errors - // The JSON in segment error detailsdoesn't include error number - // However, we get multipe error instances for each of the errors - // Here we have to do some serious gymnastics to match the detected error with what is in JSON - // - // Segment may say: - //"errorIDs" : [ 4532 ], - //"errorDetails" : [ { - // "id" : 0, - // "version" : 0, - // "name" : "Internal Server Error : 500", - // "value" : "HTTP error code : 500" - //} - // Error detail says: - //{ - // "id" : 286452959, - // "version" : 0, - // "name" : "Internal Server Error : 500", - // "value" : "HTTP error code : 500" - //} - // ------------------------------- - // Sometimes segment has no details: - //"errorIDs" : [ 66976 ], - //"errorDetails" : [ ], - // Where: - // 66976 TRBException : COMException - // But the details are there: - //[ { - // "id" : 171771942, - // "version" : 0, - // "name" : "Corillian.Voyager.ExecutionServices.Client.TRBException:Corillian.Voyager.ExecutionServices.Client.TRBException", - // "value" : "Unknown Voyager Connectivity Error: C0000FA5__AD_CMSG__System.Runtime.InteropServices.COMException (0xC0000FA5): Execute: Session doesn't exist or has timed out in TP TP41-SVAKSA69901MXK\r\n at Corillian.Platform.Router.VoyagerLoadBalancer.Execute(String sKey, String sRequest, String& sResponse)\r\n at Corillian.Voyager.VoyagerInterface.Client.VlbConnector.Execute(String voyagerCommandString, String sessionId, String userId, String FI)AD_STACK_TRACE:Corillian.Voyager.ExecutionServices.Client.TRBException: at Corillian.Voyager.VoyagerInterface.Client.VlbConnector.Void HandleCOMException(System.Runtime.InteropServices.COMException)() at Corillian.Voyager.VoyagerInterface.Client.VlbConnector.System.String Execute(System.String, System.String, System.String, System.String)() at Corillian.Voyager.ExecutionServices.Client.VoyagerService.System.String Execute(Corillian.Voyager.Common.IRequest, System.String, System.String, System.String)() at Corillian.Voyager.ExecutionServices.Client.VoyagerService.System.String Execute(Corillian.Voyager.Common.IRequest)() at USB.Banking.Operations.BankingServiceProxy.USB.Banking.Messages.USBGetAccountsResponse GetAccounts(USB.Banking.Messages.USBGetAccountsRequest)() at Corillian.AppsUI.Web.Models.Accounts.AccountServiceProxy.USB.Banking.Messages.USBGetAccountsResponse Corillian.AppsUI.Web.Models.Accounts.IAccountServiceProxy.GetAllAccounts(Boolean, Boolean, Boolean, Boolean)() at Corillian.AppsUI.Web.Models.Accounts.AccountServiceProxy.USB.Banking.Messages.USBGetAccountsResponse Corillian.AppsUI.Web.Models.Accounts.IAccountServiceProxy.GetAllAccounts(Boolean)() at Castle.Proxies.Invocations.IAccountServiceProxy_GetAllAccounts.Void InvokeMethodOnTarget()() at Castle.DynamicProxy.AbstractInvocation.Void Proceed()() at USB.DigitalChannel.DigitalUI.Helpers.Logging.LoggingInterceptor.Void Intercept(Castle.DynamicProxy.IInvocation)() at Castle.DynamicProxy.AbstractInvocation.Void Proceed()() at Castle.Proxies.IAccountServiceProxyProxy.USB.Banking.Messages.USBGetAccountsResponse GetAllAccounts(Boolean)() at Corillian.AppsUI.Web.Models.PaymentCentral.PaymentCentralService.Corillian.AppsUI.Web.Models.PaymentCentral.AccountBalancesResponseContainer GetAccountBalances(Corillian.AppsUI.Web.Models.PaymentCentral.AccountBalancesRequest)() at Corillian.AppsUI.Web.Models.PaymentCentral.PaymentCentralService.Corillian.AppsUI.Web.Models.PaymentCentral.UserAndAccountsResponse GetUserAndAccounts(Corillian.AppsUI.Web.Models.PaymentCentral.AccountBalancesRequest)() at Castle.Proxies.Invocations.IPaymentCentralService_GetUserAndAccounts.Void InvokeMethodOnTarget()() at Castle.DynamicProxy.AbstractInvocation.Void Proceed()() at USB.DigitalChannel.DigitalUI.Helpers.Logging.LoggingInterceptor.Void Intercept(Castle.DynamicProxy.IInvocation)() at Castle.DynamicProxy.AbstractInvocation.Void Proceed()() at Castle.Proxies.IPaymentCentralServiceProxy.Corillian.AppsUI.Web.Models.PaymentCentral.UserAndAccountsResponse GetUserAndAccounts(Corillian.AppsUI.Web.Models.PaymentCentral.AccountBalancesRequest)() at Corillian.AppsUI.Web.AsyncGetUserAndAccounts.System.String GetUserAndAccounts()() at Corillian.AppsUI.Web.AsyncGetUserAndAccounts.System.String get_TaskResult()() at USB.DigitalChannel.CommonUI.Controllers.BaseController.Void GetAsyncData(USB.DigitalChannel.CommonUI.Models.shared.BaseModel)() at Corillian.AppsUI.Web.Controllers.BaseDashboardController.Void GetWebAsyncData(Corillian.AppsUI.Web.Models.Shared.DashboardBaseModel)() at Corillian.AppsUI.Web.Controllers.CustomerDashboardController.System.Web.Mvc.ActionResult Index()() at .System.Object lambda_method(System.Runtime.CompilerServices.ExecutionScope, System.Web.Mvc.ControllerBase, System.Object[])() at System.Web.Mvc.ReflectedActionDescriptor.System.Object Execute(System.Web.Mvc.ControllerContext, System.Collections.Generic.IDictionary`2[System.String,System.Object])() at System.Web.Mvc.ControllerActionInvoker.System.Web.Mvc.ActionResult InvokeActionMethod(System.Web.Mvc.ControllerContext, System.Web.Mvc.ActionDescriptor, System.Collections.Generic.IDictionary`2[System.String,System.Object])() at System.Web.Mvc.ControllerActionInvoker+<>c__DisplayClassd.System.Web.Mvc.ActionExecutedContext b__a()() at System.Web.Mvc.ControllerActionInvoker.System.Web.Mvc.ActionExecutedContext InvokeActionMethodFilter(System.Web.Mvc.IActionFilter, System.Web.Mvc.ActionExecutingContext, System.Func`1[System.Web.Mvc.ActionExecutedContext])() at System.Web.Mvc.ControllerActionInvoker.System.Web.Mvc.ActionExecutedContext InvokeActionMethodFilter(System.Web.Mvc.IActionFilter, System.Web.Mvc.ActionExecutingContext, System.Func`1[System.Web.Mvc.ActionExecutedContext])() at System.Web.Mvc.ControllerActionInvoker.System.Web.Mvc.ActionExecutedContext InvokeActionMethodFilter(System.Web.Mvc.IActionFilter, System.Web.Mvc.ActionExecutingContext, System.Func`1[System.Web.Mvc.ActionExecutedContext])() at System.Web.Mvc.ControllerActionInvoker.System.Web.Mvc.ActionExecutedContext InvokeActionMethodFilter(System.Web.Mvc.IActionFilter, System.Web.Mvc.ActionExecutingContext, System.Func`1[System.Web.Mvc.ActionExecutedContext])() at System.Web.Mvc.ControllerActionInvoker.System.Web.Mvc.ActionExecutedContext InvokeActionMethodWithFilters(System.Web.Mvc.ControllerContext, System.Collections.Generic.IList`1[System.Web.Mvc.IActionFilter], System.Web.Mvc.ActionDescriptor, System.Collections.Generic.IDictionary`2[System.String,System.Object])() at System.Web.Mvc.ControllerActionInvoker.Boolean InvokeAction(System.Web.Mvc.ControllerContext, System.String)() at System.Web.Mvc.Controller.Void ExecuteCore()() at System.Web.Mvc.ControllerBase.Execute() at System.Web.Mvc.MvcHandler+<>c__DisplayClass8.b__4() at System.Web.Mvc.Async.AsyncResultWrapper+<>c__DisplayClass1.b__0() at System.Web.Mvc.Async.AsyncResultWrapper+<>c__DisplayClass8`1.b__7() at System.Web.Mvc.Async.AsyncResultWrapper+WrappedAsyncResult`1.End() at System.Web.Mvc.Async.AsyncResultWrapper.End() at System.Web.Mvc.Async.AsyncResultWrapper.End() at Microsoft.Web.Mvc.MvcDynamicSessionHandler.EndProcessRequest() at System.Web.HttpApplication+CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() at System.Web.HttpApplication.ExecuteStep() at System.Web.HttpApplication+PipelineStepManager.ResumeSteps() at System.Web.HttpApplication.BeginProcessRequestNotification() at System.Web.HttpRuntime.ProcessRequestNotificationPrivate() at System.Web.Hosting.PipelineRuntime.ProcessRequestNotificationHelper() at System.Web.Hosting.PipelineRuntime.ProcessRequestNotification() at System.Web.Hosting.PipelineRuntime.ProcessRequestNotificationHelper() at System.Web.Hosting.PipelineRuntime.ProcessRequestNotification() Caused by: Corillian.Voyager.ExecutionServices.Client.TRBException at Corillian.Platform.Router.VoyagerLoadBalancer.Void Execute(System.String, System.String, System.String ByRef)() ... 17 more " - //} ] - // ------------------------------- - // Sometimes segment says: - //"errorIDs" : [ 131789, 3002 ], - //"errorDetails" : [ { - // "id" : 0, - // "version" : 0, - // "name" : "1. USB.OLBService.Handlers.TransactionUtilities", - // "value" : "USB.OLBService.Handlers.TransactionUtilities : Error occurred in MapHostTransactions: System.NullReferenceException: Object reference not set to an instance of an object.\r\n at USB.OLBService.Handlers.TransactionUtilities.MapCheckCardHostResponseTransactions(GetOutStandingAuthRequest requestFromUI, List`1 transactions, USBAccount actualAcct)" - //} ], - // Where: - // 131789 MessageQueueException - // 3002 .NET Logger Error Messages - // But the list of errors looks like that: - //[ { - // "id" : 171889775, - // "version" : 0, - // "name" : "System.Messaging.MessageQueueException", - // "value" : "Insufficient resources to perform operation.AD_STACK_TRACE:System.Messaging.MessageQueueException: at System.Messaging.MessageQueue.SendInternal() at Corillian.Platform.Messaging.Sender.Send() at Corillian.Platform.Messaging.Sender.Send() at Corillian.Platform.Audit.AuditTrxSender.Audit() at USB.DigitalServices.Audit.MessageReceiver.Process() at USB.OLBService.Handlers.Utilities.Audit() at USB.OLBService.Handlers.GetTransactionTypes.Execute() at USB.OLBService.Handlers.TransactionUtilities.MapHostResponseTransactions() at USB.OLBService.Handlers.TransactionUtilities.GetMonitoryListExecutor() at USB.OLBService.Handlers.TransactionUtilities.GetHostHistory() at USB.OLBService.Handlers.GetPagedTransactionsV2.Execute() at USB.DCISService.Accounts.V1.Handlers.GetAccountTransactionsV4.Execute() at Fiserv.AppService.Core.HandlerBase`1.Execute() at Fiserv.AppService.Core.ServiceProcessor.Process() at USB.DCIS.Server.DCISServiceServer.Execute() at .SyncInvokeExecute() at System.ServiceModel.Dispatcher.SyncMethodInvoker.Invoke() at System.ServiceModel.Dispatcher.DispatchOperationRuntime.InvokeBegin() at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage5() at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage4() at System.ServiceModel.Dispatcher.MessageRpc.Process() at System.ServiceModel.Dispatcher.ChannelHandler.DispatchAndReleasePump() at System.ServiceModel.Dispatcher.ChannelHandler.HandleRequest() at System.ServiceModel.Dispatcher.ChannelHandler.AsyncMessagePump() at System.ServiceModel.Diagnostics.Utility+AsyncThunk.UnhandledExceptionFrame() at System.ServiceModel.AsyncResult.Complete() at System.ServiceModel.Channels.InputQueue`1+AsyncQueueReader.Set() at System.ServiceModel.Channels.InputQueue`1.EnqueueAndDispatch() at System.ServiceModel.Channels.InputQueue`1.EnqueueAndDispatch() at System.ServiceModel.Channels.InputQueueChannel`1.EnqueueAndDispatch() at System.ServiceModel.Channels.SingletonChannelAcceptor`3.Enqueue() at System.ServiceModel.Channels.SingletonChannelAcceptor`3.Enqueue() at System.ServiceModel.Channels.HttpChannelListener.HttpContextReceived() at System.ServiceModel.Activation.HostedHttpTransportManager.HttpContextReceived() at System.ServiceModel.Activation.HostedHttpRequestAsyncResult.BeginRequest() at System.ServiceModel.Activation.HostedHttpRequestAsyncResult.OnBeginRequest() at System.ServiceModel.PartialTrustHelpers.PartialTrustInvoke() at System.ServiceModel.Activation.HostedHttpRequestAsyncResult.OnBeginRequestWithFlow() at System.ServiceModel.Channels.IOThreadScheduler+CriticalHelper+WorkItem.Invoke2() at System.ServiceModel.Channels.IOThreadScheduler+CriticalHelper+WorkItem.Invoke() at System.ServiceModel.Channels.IOThreadScheduler+CriticalHelper.ProcessCallbacks() at System.ServiceModel.Channels.IOThreadScheduler+CriticalHelper.CompletionCallback() at System.ServiceModel.Channels.IOThreadScheduler+CriticalHelper+ScheduledOverlapped.IOCallback() at System.ServiceModel.Diagnostics.Utility+IOCompletionThunk.UnhandledExceptionFrame() at System.Threading._IOCompletionCallback.PerformIOCompletionCallback() " - //}, { - // "id" : 171889775, - // "version" : 0, - // "name" : "System.Messaging.MessageQueueException", - // "value" : "Insufficient resources to perform operation.AD_STACK_TRACE:System.Messaging.MessageQueueException: at System.Messaging.MessageQueue.SendInternal() at Corillian.Platform.Messaging.Sender.Send() at Corillian.Platform.Messaging.Sender.Send() at Corillian.Platform.Audit.AuditTrxSender.Audit() at USB.DigitalServices.Audit.MessageReceiver.Process() at USB.OLBService.Handlers.Utilities.Audit() at USB.OLBService.Handlers.GetTransactionTypes.Execute() at USB.OLBService.Handlers.TransactionUtilities.MapCheckCardHostResponseTransactions() at USB.OLBService.Handlers.TransactionUtilities.GetCheckCardAuthorizationsFromHost() at USB.OLBService.Handlers.GetPagedTransactionsV2.GetDebitCardAuthorizationTransactions() at USB.OLBService.Handlers.GetPagedTransactionsV2.Execute() at USB.DCISService.Accounts.V1.Handlers.GetAccountTransactionsV4.Execute() at Fiserv.AppService.Core.HandlerBase`1.Execute() at Fiserv.AppService.Core.ServiceProcessor.Process() at USB.DCIS.Server.DCISServiceServer.Execute() at .SyncInvokeExecute() at System.ServiceModel.Dispatcher.SyncMethodInvoker.Invoke() at System.ServiceModel.Dispatcher.DispatchOperationRuntime.InvokeBegin() at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage5() at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage4() at System.ServiceModel.Dispatcher.MessageRpc.Process() at System.ServiceModel.Dispatcher.ChannelHandler.DispatchAndReleasePump() at System.ServiceModel.Dispatcher.ChannelHandler.HandleRequest() at System.ServiceModel.Dispatcher.ChannelHandler.AsyncMessagePump() at System.ServiceModel.Diagnostics.Utility+AsyncThunk.UnhandledExceptionFrame() at System.ServiceModel.AsyncResult.Complete() at System.ServiceModel.Channels.InputQueue`1+AsyncQueueReader.Set() at System.ServiceModel.Channels.InputQueue`1.EnqueueAndDispatch() at System.ServiceModel.Channels.InputQueue`1.EnqueueAndDispatch() at System.ServiceModel.Channels.InputQueueChannel`1.EnqueueAndDispatch() at System.ServiceModel.Channels.SingletonChannelAcceptor`3.Enqueue() at System.ServiceModel.Channels.SingletonChannelAcceptor`3.Enqueue() at System.ServiceModel.Channels.HttpChannelListener.HttpContextReceived() at System.ServiceModel.Activation.HostedHttpTransportManager.HttpContextReceived() at System.ServiceModel.Activation.HostedHttpRequestAsyncResult.BeginRequest() at System.ServiceModel.Activation.HostedHttpRequestAsyncResult.OnBeginRequest() at System.ServiceModel.PartialTrustHelpers.PartialTrustInvoke() at System.ServiceModel.Activation.HostedHttpRequestAsyncResult.OnBeginRequestWithFlow() at System.ServiceModel.Channels.IOThreadScheduler+CriticalHelper+WorkItem.Invoke2() at System.ServiceModel.Channels.IOThreadScheduler+CriticalHelper+WorkItem.Invoke() at System.ServiceModel.Channels.IOThreadScheduler+CriticalHelper.ProcessCallbacks() at System.ServiceModel.Channels.IOThreadScheduler+CriticalHelper.CompletionCallback() at System.ServiceModel.Channels.IOThreadScheduler+CriticalHelper+ScheduledOverlapped.IOCallback() at System.ServiceModel.Diagnostics.Utility+IOCompletionThunk.UnhandledExceptionFrame() at System.Threading._IOCompletionCallback.PerformIOCompletionCallback() " - //}, { - // "id" : 171889775, - // "version" : 0, - // "name" : "System.Messaging.MessageQueueException", - // "value" : "Insufficient resources to perform operation.AD_STACK_TRACE:System.Messaging.MessageQueueException: at System.Messaging.MessageQueue.SendInternal() at Corillian.Platform.Messaging.Sender.Send() at Corillian.Platform.Messaging.Sender.Send() at Corillian.Platform.Audit.AuditTrxSender.Audit() at USB.DigitalServices.Audit.MessageReceiver.Process() at USB.OLBService.Handlers.Utilities.Audit() at USB.OLBService.Handlers.GetPagedTransactionsV2.GetDebitCardAuthorizationTransactions() at USB.OLBService.Handlers.GetPagedTransactionsV2.Execute() at USB.DCISService.Accounts.V1.Handlers.GetAccountTransactionsV4.Execute() at Fiserv.AppService.Core.HandlerBase`1.Execute() at Fiserv.AppService.Core.ServiceProcessor.Process() at USB.DCIS.Server.DCISServiceServer.Execute() at .SyncInvokeExecute() at System.ServiceModel.Dispatcher.SyncMethodInvoker.Invoke() at System.ServiceModel.Dispatcher.DispatchOperationRuntime.InvokeBegin() at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage5() at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage4() at System.ServiceModel.Dispatcher.MessageRpc.Process() at System.ServiceModel.Dispatcher.ChannelHandler.DispatchAndReleasePump() at System.ServiceModel.Dispatcher.ChannelHandler.HandleRequest() at System.ServiceModel.Dispatcher.ChannelHandler.AsyncMessagePump() at System.ServiceModel.Diagnostics.Utility+AsyncThunk.UnhandledExceptionFrame() at System.ServiceModel.AsyncResult.Complete() at System.ServiceModel.Channels.InputQueue`1+AsyncQueueReader.Set() at System.ServiceModel.Channels.InputQueue`1.EnqueueAndDispatch() at System.ServiceModel.Channels.InputQueue`1.EnqueueAndDispatch() at System.ServiceModel.Channels.InputQueueChannel`1.EnqueueAndDispatch() at System.ServiceModel.Channels.SingletonChannelAcceptor`3.Enqueue() at System.ServiceModel.Channels.SingletonChannelAcceptor`3.Enqueue() at System.ServiceModel.Channels.HttpChannelListener.HttpContextReceived() at System.ServiceModel.Activation.HostedHttpTransportManager.HttpContextReceived() at System.ServiceModel.Activation.HostedHttpRequestAsyncResult.BeginRequest() at System.ServiceModel.Activation.HostedHttpRequestAsyncResult.OnBeginRequest() at System.ServiceModel.PartialTrustHelpers.PartialTrustInvoke() at System.ServiceModel.Activation.HostedHttpRequestAsyncResult.OnBeginRequestWithFlow() at System.ServiceModel.Channels.IOThreadScheduler+CriticalHelper+WorkItem.Invoke2() at System.ServiceModel.Channels.IOThreadScheduler+CriticalHelper+WorkItem.Invoke() at System.ServiceModel.Channels.IOThreadScheduler+CriticalHelper.ProcessCallbacks() at System.ServiceModel.Channels.IOThreadScheduler+CriticalHelper.CompletionCallback() at System.ServiceModel.Channels.IOThreadScheduler+CriticalHelper+ScheduledOverlapped.IOCallback() at System.ServiceModel.Diagnostics.Utility+IOCompletionThunk.UnhandledExceptionFrame() at System.Threading._IOCompletionCallback.PerformIOCompletionCallback() " - //}, { - // "id" : 171889775, - // "version" : 0, - // "name" : "System.Messaging.MessageQueueException", - // "value" : "Insufficient resources to perform operation.AD_STACK_TRACE:System.Messaging.MessageQueueException: at System.Messaging.MessageQueue.SendInternal() at Corillian.Platform.Messaging.Sender.Send() at Corillian.Platform.Messaging.Sender.Send() at Corillian.Platform.Audit.AuditTrxSender.Audit() at USB.DigitalServices.Audit.MessageReceiver.Process() at USB.OLBService.Handlers.Utilities.Audit() at USB.OLBService.Handlers.GetPagedTransactionsV2.Execute() at USB.DCISService.Accounts.V1.Handlers.GetAccountTransactionsV4.Execute() at Fiserv.AppService.Core.HandlerBase`1.Execute() at Fiserv.AppService.Core.ServiceProcessor.Process() at USB.DCIS.Server.DCISServiceServer.Execute() at .SyncInvokeExecute() at System.ServiceModel.Dispatcher.SyncMethodInvoker.Invoke() at System.ServiceModel.Dispatcher.DispatchOperationRuntime.InvokeBegin() at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage5() at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage4() at System.ServiceModel.Dispatcher.MessageRpc.Process() at System.ServiceModel.Dispatcher.ChannelHandler.DispatchAndReleasePump() at System.ServiceModel.Dispatcher.ChannelHandler.HandleRequest() at System.ServiceModel.Dispatcher.ChannelHandler.AsyncMessagePump() at System.ServiceModel.Diagnostics.Utility+AsyncThunk.UnhandledExceptionFrame() at System.ServiceModel.AsyncResult.Complete() at System.ServiceModel.Channels.InputQueue`1+AsyncQueueReader.Set() at System.ServiceModel.Channels.InputQueue`1.EnqueueAndDispatch() at System.ServiceModel.Channels.InputQueue`1.EnqueueAndDispatch() at System.ServiceModel.Channels.InputQueueChannel`1.EnqueueAndDispatch() at System.ServiceModel.Channels.SingletonChannelAcceptor`3.Enqueue() at System.ServiceModel.Channels.SingletonChannelAcceptor`3.Enqueue() at System.ServiceModel.Channels.HttpChannelListener.HttpContextReceived() at System.ServiceModel.Activation.HostedHttpTransportManager.HttpContextReceived() at System.ServiceModel.Activation.HostedHttpRequestAsyncResult.BeginRequest() at System.ServiceModel.Activation.HostedHttpRequestAsyncResult.OnBeginRequest() at System.ServiceModel.PartialTrustHelpers.PartialTrustInvoke() at System.ServiceModel.Activation.HostedHttpRequestAsyncResult.OnBeginRequestWithFlow() at System.ServiceModel.Channels.IOThreadScheduler+CriticalHelper+WorkItem.Invoke2() at System.ServiceModel.Channels.IOThreadScheduler+CriticalHelper+WorkItem.Invoke() at System.ServiceModel.Channels.IOThreadScheduler+CriticalHelper.ProcessCallbacks() at System.ServiceModel.Channels.IOThreadScheduler+CriticalHelper.CompletionCallback() at System.ServiceModel.Channels.IOThreadScheduler+CriticalHelper+ScheduledOverlapped.IOCallback() at System.ServiceModel.Diagnostics.Utility+IOCompletionThunk.UnhandledExceptionFrame() at System.Threading._IOCompletionCallback.PerformIOCompletionCallback() " - //}, { - // "id" : 171889775, - // "version" : 0, - // "name" : "System.Messaging.MessageQueueException", - // "value" : "Insufficient resources to perform operation.AD_STACK_TRACE:System.Messaging.MessageQueueException: at System.Messaging.MessageQueue.SendInternal() at Corillian.Platform.Messaging.Sender.Send() at Corillian.Platform.Messaging.Sender.Send() at Corillian.Platform.Audit.AuditTrxSender.Audit() at USB.DigitalServices.Audit.MessageReceiver.Process() at USB.DigitalServices.HandlerCore.ContextSafeHandler`1.Audit() at USB.DCISService.Accounts.V1.Handlers.GetAccountTransactionsV4.Execute() at Fiserv.AppService.Core.HandlerBase`1.Execute() at Fiserv.AppService.Core.ServiceProcessor.Process() at USB.DCIS.Server.DCISServiceServer.Execute() at .SyncInvokeExecute() at System.ServiceModel.Dispatcher.SyncMethodInvoker.Invoke() at System.ServiceModel.Dispatcher.DispatchOperationRuntime.InvokeBegin() at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage5() at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage4() at System.ServiceModel.Dispatcher.MessageRpc.Process() at System.ServiceModel.Dispatcher.ChannelHandler.DispatchAndReleasePump() at System.ServiceModel.Dispatcher.ChannelHandler.HandleRequest() at System.ServiceModel.Dispatcher.ChannelHandler.AsyncMessagePump() at System.ServiceModel.Diagnostics.Utility+AsyncThunk.UnhandledExceptionFrame() at System.ServiceModel.AsyncResult.Complete() at System.ServiceModel.Channels.InputQueue`1+AsyncQueueReader.Set() at System.ServiceModel.Channels.InputQueue`1.EnqueueAndDispatch() at System.ServiceModel.Channels.InputQueue`1.EnqueueAndDispatch() at System.ServiceModel.Channels.InputQueueChannel`1.EnqueueAndDispatch() at System.ServiceModel.Channels.SingletonChannelAcceptor`3.Enqueue() at System.ServiceModel.Channels.SingletonChannelAcceptor`3.Enqueue() at System.ServiceModel.Channels.HttpChannelListener.HttpContextReceived() at System.ServiceModel.Activation.HostedHttpTransportManager.HttpContextReceived() at System.ServiceModel.Activation.HostedHttpRequestAsyncResult.BeginRequest() at System.ServiceModel.Activation.HostedHttpRequestAsyncResult.OnBeginRequest() at System.ServiceModel.PartialTrustHelpers.PartialTrustInvoke() at System.ServiceModel.Activation.HostedHttpRequestAsyncResult.OnBeginRequestWithFlow() at System.ServiceModel.Channels.IOThreadScheduler+CriticalHelper+WorkItem.Invoke2() at System.ServiceModel.Channels.IOThreadScheduler+CriticalHelper+WorkItem.Invoke() at System.ServiceModel.Channels.IOThreadScheduler+CriticalHelper.ProcessCallbacks() at System.ServiceModel.Channels.IOThreadScheduler+CriticalHelper.CompletionCallback() at System.ServiceModel.Channels.IOThreadScheduler+CriticalHelper+ScheduledOverlapped.IOCallback() at System.ServiceModel.Diagnostics.Utility+IOCompletionThunk.UnhandledExceptionFrame() at System.Threading._IOCompletionCallback.PerformIOCompletionCallback() " - //}, { - // "id" : 171889775, - // "version" : 0, - // "name" : "1. USB.OLBService.Handlers.TransactionUtilities", - // "value" : "USB.OLBService.Handlers.TransactionUtilities : Error occurred in MapHostTransactions: System.NullReferenceException: Object reference not set to an instance of an object.\r\n at USB.OLBService.Handlers.TransactionUtilities.MapCheckCardHostResponseTransactions(GetOutStandingAuthRequest requestFromUI, List`1 transactions, USBAccount actualAcct)" - //} ] + StringBuilder sbExitTypesSnapshot = new StringBuilder(10 * exitTypesSnapshot.Count); + foreach (var exitType in exitTypesSnapshot) + { + sbExitTypesSnapshot.AppendFormat("{0}={1}\n", exitType.Key, exitType.Value); + } - #endregion + if (sbExitTypesSnapshot.Length > 1) { sbExitTypesSnapshot.Remove(sbExitTypesSnapshot.Length - 1, 1); } + snapshot.ExitTypes = sbExitTypesSnapshot.ToString(); - foreach (DetectedError detectedError in detectedErrorsListInThisSegment) - { - // Try by exact message match - DetectedError detectedErrorWithErrorID = detectedErrorsFromErrorIDs.Where(e => e.ErrorName == detectedError.ErrorMessage).FirstOrDefault(); + #endregion - // Try starting with the message - if (detectedErrorWithErrorID == null) - { - detectedErrorWithErrorID = detectedErrorsFromErrorIDs.Where(e => e.ErrorName.StartsWith(detectedError.ErrorMessage)).FirstOrDefault(); - } + #region Update various counts for Snapshot columns - // Try containing the message - if (detectedErrorWithErrorID == null) - { - detectedErrorWithErrorID = detectedErrorsFromErrorIDs.Where(e => e.ErrorName.Contains(detectedError.ErrorMessage)).FirstOrDefault(); - } + snapshot.NumErrors = segmentsList.Sum(s => s.NumErrors); - // Try by partial name match second - if (detectedErrorWithErrorID == null) - { - // Split by . and : - // java.io.IOException - // -> java, io, IOException - // Detected as IOException - // Corillian.Voyager.ExecutionServices.Client.TRBException:Corillian.Voyager.ExecutionServices.Client.TRBException - // -> Corillian, Voyager, ExecutionServices, Client, TRBException, Corillian, Voyager, ExecutionServices, Client, TRBException - // Detected as TRBException - string[] errorMessageTokens = detectedError.ErrorMessage.Split('.', ':'); + snapshot.NumSegments = segmentsList.Count; + snapshot.NumCallGraphs = segmentsList.Count(s => s.CallGraphType != "NONE"); - // Go backwards because exception type is at the end - for (int i = errorMessageTokens.Length - 1; i >= 0; i--) - { - detectedErrorWithErrorID = detectedErrorsFromErrorIDs.Where(e => e.ErrorName.Contains(errorMessageTokens[i])).FirstOrDefault(); - if (detectedErrorWithErrorID != null) - { - break; - } - } - } + snapshot.NumCallsToTiers = segmentsList.Sum(s => s.NumCallsToTiers); + snapshot.NumCallsToBackends = segmentsList.Sum(s => s.NumCallsToBackends); + snapshot.NumCallsToApplications = segmentsList.Sum(s => s.NumCallsToApplications); - // Did we find it? - if (detectedErrorWithErrorID != null) - { - // Yay, we did, mark this error by ID off as matched and copy the values to the final - detectedErrorWithErrorID.ErrorIDMatchedToMessage = true; + snapshot.NumCalledTiers = segmentsList.Sum(s => s.NumCalledTiers); + snapshot.NumCalledBackends = segmentsList.Sum(s => s.NumCalledBackends); + snapshot.NumCalledApplications = segmentsList.Sum(s => s.NumCalledApplications); - detectedError.ErrorID = detectedErrorWithErrorID.ErrorID; - detectedError.ErrorName = detectedErrorWithErrorID.ErrorName; - detectedError.ErrorType = detectedErrorWithErrorID.ErrorType; + snapshot.NumSEPs = segmentsList.Sum(s => s.NumSEPs); - #region Fill in the deeplinks for the Error + snapshot.NumHTTPDCs = segmentsList.Sum(s => s.NumHTTPDCs); + snapshot.NumMIDCs = segmentsList.Sum(s => s.NumMIDCs); - detectedError.ControllerLink = segment.Controller; - detectedError.ApplicationLink = segment.ApplicationLink; - detectedError.TierLink = segment.TierLink; - detectedError.NodeLink = segment.NodeLink; - detectedError.BTLink = segment.BTLink; - detectedError.ErrorLink = String.Format(DEEPLINK_ERROR, detectedError.Controller, detectedError.ApplicationID, detectedError.ErrorID, DEEPLINK_THIS_TIMERANGE); + #endregion + } + + #endregion - #endregion + #region Save results - } - } + // Save results + if (segmentsList != null) + { + FileIOHelper.writeListToCSVFile(segmentsList, new SegmentReportMap(), segmentsFileName); + } - // At this point, we matched what we could. - // A little cleanup - what if we have 1 by error ID and 1 message without Error ID left? If yes, those obviously match - List detectedErrorsFromErrorIDsUnmatched = detectedErrorsFromErrorIDs.Where(e => e.ErrorIDMatchedToMessage == false).ToList(); - List detectedErrorsListInThisSegmentUnmatched = detectedErrorsListInThisSegment.Where(e => e.ErrorID == -1).ToList(); - if (detectedErrorsFromErrorIDsUnmatched.Count == 1 && detectedErrorsListInThisSegmentUnmatched.Count == 1) - { - DetectedError detectedError = detectedErrorsListInThisSegmentUnmatched[0]; - DetectedError detectedErrorWithErrorID = detectedErrorsFromErrorIDsUnmatched[0]; - detectedErrorWithErrorID.ErrorIDMatchedToMessage = true; + if (exitCallsList != null) + { + FileIOHelper.writeListToCSVFile(exitCallsList, new ExitCallReportMap(), exitCallsFileName); + } - detectedError.ErrorID = detectedErrorWithErrorID.ErrorID; - detectedError.ErrorName = detectedErrorWithErrorID.ErrorName; - detectedError.ErrorType = detectedErrorWithErrorID.ErrorType; + if (serviceEndpointCallsList != null) + { - #region Fill in the deeplinks for the Error + FileIOHelper.writeListToCSVFile(serviceEndpointCallsList, new ServiceEndpointCallReportMap(), serviceEndpointCallsFileName); + } - detectedError.ControllerLink = segment.Controller; - detectedError.ApplicationLink = segment.ApplicationLink; - detectedError.TierLink = segment.TierLink; - detectedError.NodeLink = segment.NodeLink; - detectedError.BTLink = segment.BTLink; - detectedError.ErrorLink = String.Format(DEEPLINK_ERROR, detectedError.Controller, detectedError.ApplicationID, detectedError.ErrorID, DEEPLINK_THIS_TIMERANGE); + if (detectedErrorsList != null) + { + FileIOHelper.writeListToCSVFile(detectedErrorsList, new DetectedErrorReportMap(), detectedErrorsFileName); + } - #endregion - } - else if (detectedErrorsFromErrorIDsUnmatched.Count > 1) - { - // Don't know how to match those. Let's just append them to the list - detectedErrorsListInThisSegment.AddRange(detectedErrorsFromErrorIDsUnmatched); - } - } + if (businessDataList != null) + { + FileIOHelper.writeListToCSVFile(businessDataList, new BusinessDataReportMap(), businessDataFileName); + } - #endregion + if (methodCallLinesList != null) + { + FileIOHelper.writeListToCSVFile(methodCallLinesList, new MethodCallLineReportMap(), methodCallLinesFileName); + } - #region Process Data Collectors in Segment + if (methodCallLinesOccurrencesList != null) + { + FileIOHelper.writeListToCSVFile(methodCallLinesOccurrencesList, new MethodCallLineOccurrenceReportMap(), methodCallLinesOccurrencesFileName); + } - List businessDataListInThisSegment = new List(); + List snapshotRows = new List(1); + snapshotRows.Add(snapshot); + FileIOHelper.writeListToCSVFile(snapshotRows, new SnapshotReportMap(), snapshotsFileName); - // Transaction properties - foreach (JToken transactionPropertyToken in snapshotSegmentDetail["transactionProperties"]) - { - BusinessData businessData = new BusinessData(); + #endregion + } - businessData.Controller = segment.Controller; - businessData.ApplicationName = segment.ApplicationName; - businessData.ApplicationID = segment.ApplicationID; - businessData.TierID = segment.TierID; - businessData.TierName = segment.TierName; - businessData.BTID = segment.BTID; - businessData.BTName = segment.BTName; - businessData.NodeID = segment.NodeID; - businessData.NodeName = segment.NodeName; + if (progressToConsole == true) + { + j++; + if (j % 100 == 0) + { + Console.Write("[{0}].", j); + } + } + } - businessData.RequestID = segment.RequestID; - businessData.SegmentID = segment.SegmentID; + return entityList.Count; + } - businessData.DataType = "Transaction"; + private static MethodCallLine convertCallGraphChildren_Recursion( + JToken methodCallLineJSON, + int currentDepth, + ref int methodLineCallSequenceNumber, + List methodCallLinesList, + List serviceEndpointCallsList, + List exitCallsList) + { + MethodCallLine methodCallLine = new MethodCallLine(); - businessData.DataName = transactionPropertyToken["name"].ToString(); - businessData.DataValue = transactionPropertyToken["value"].ToString(); + methodCallLine.SequenceNumber = methodLineCallSequenceNumber; + methodLineCallSequenceNumber++; - #region Fill in the deeplinks for the Business Data + // Populate current method call class, methods and types + methodCallLine.Type = methodCallLineJSON["type"].ToString(); + methodCallLine.PrettyName = methodCallLineJSON["name"].ToString(); + methodCallLine.Class = methodCallLineJSON["className"].ToString(); + methodCallLine.Method = methodCallLineJSON["methodName"].ToString(); + methodCallLine.LineNumber = (int)methodCallLineJSON["lineNumber"]; + if (methodCallLine.LineNumber > 0) + { + methodCallLine.FullName = String.Format("{0}:{1}:{2}", methodCallLine.Class, methodCallLine.Method, methodCallLine.LineNumber); + } + else + { + methodCallLine.FullName = String.Format("{0}:{1}", methodCallLine.Class, methodCallLine.Method); + } + methodCallLine.FullNameIndent = String.Format("{0}{1}", new string(' ', currentDepth), methodCallLine.FullName); - businessData.ControllerLink = segment.Controller; - businessData.ApplicationLink = segment.ApplicationLink; - businessData.TierLink = segment.TierLink; - businessData.NodeLink = segment.NodeLink; - businessData.BTLink = segment.BTLink; + // Fill in Service Endpoints + if (methodCallLineJSON["serviceEndPointIds"].HasValues == true && serviceEndpointCallsList.Count > 0) + { + methodCallLine.NumSEPs = methodCallLineJSON["serviceEndPointIds"].Count(); - #endregion + List serviceEndpointReferenceList = new List(methodCallLine.NumSEPs); + foreach (long sepID in methodCallLineJSON["serviceEndPointIds"]) + { + ServiceEndpointCall serviceEndpointCall = serviceEndpointCallsList.Where(s => s.SEPID == sepID).FirstOrDefault(); + if (serviceEndpointCall != null) + { + serviceEndpointReferenceList.Add(String.Format("{0} ({1})", serviceEndpointCall.SEPName, serviceEndpointCall.SEPType)); + } + } - businessDataListInThisSegment.Add(businessData); - } + if (methodCallLine.NumSEPs == 1) + { + methodCallLine.SEPs = serviceEndpointReferenceList[0]; + } + else + { + StringBuilder sb = new StringBuilder(32 * methodCallLine.NumSEPs); + foreach (string serviceEndpointReference in serviceEndpointReferenceList) + { + sb.AppendFormat("{0};\n", serviceEndpointReference); + } + sb.Remove(sb.Length - 1, 1); + methodCallLine.SEPs = sb.ToString(); + } + } - // HTTP data collectors - foreach (JToken transactionPropertyToken in snapshotSegmentDetail["httpParameters"]) - { - BusinessData businessData = new BusinessData(); + // Fill in Durations + // We first assume that duration is equal to duration with children. Then when adding children, recalculate, subtracting child's duration + methodCallLine.ExecTotal = (long)methodCallLineJSON["timeSpentInMilliSec"]; + methodCallLine.Exec = methodCallLine.ExecTotal; + methodCallLine.WaitTotal = (long)methodCallLineJSON["waitTime"]; + methodCallLine.Wait = methodCallLine.WaitTotal; + methodCallLine.BlockTotal = (long)methodCallLineJSON["blockTime"]; + methodCallLine.Block = methodCallLine.BlockTotal; + methodCallLine.CPUTotal = (long)methodCallLineJSON["cpuTime"]; + methodCallLine.CPU = methodCallLine.CPUTotal; + + // Count children + if (methodCallLineJSON["children"].HasValues == false) + { + methodCallLine.NumChildren = 0; + } + else + { + methodCallLine.NumChildren = methodCallLineJSON["children"].Count(); + } - businessData.Controller = segment.Controller; - businessData.ApplicationName = segment.ApplicationName; - businessData.ApplicationID = segment.ApplicationID; - businessData.TierID = segment.TierID; - businessData.TierName = segment.TierName; - businessData.BTID = segment.BTID; - businessData.BTName = segment.BTName; - businessData.NodeID = segment.NodeID; - businessData.NodeName = segment.NodeName; + // Specify depth + methodCallLine.Depth = currentDepth; - businessData.RequestID = segment.RequestID; - businessData.SegmentID = segment.SegmentID; + // Determine type of this element in the call graph tree + if (currentDepth == 0) + { + methodCallLine.ElementType = MethodCallLineElementType.Root; + } + else + { + if (methodCallLine.NumChildren == 0) + { + methodCallLine.ElementType = MethodCallLineElementType.Leaf; + } + else if (methodCallLine.NumChildren == 1) + { + methodCallLine.ElementType = MethodCallLineElementType.Stem; + } + else + { + methodCallLine.ElementType = MethodCallLineElementType.Branch; + } + } - businessData.DataType = "HTTP"; + // Fill in exits + // Frequently, the exits in the list from Segments (passed via exitCallsList parameter to the function), are ordered + // in the same sequence as the exits encountered during unrolling the call graph tree + // However, that is not always the case + // Exceptions appear to be + // a) .NET applications + // and + // b) the database connection acquisition backend calls that are grouped together into number of calls >1 and duration being the Sum(of all) + // So the logic is to find the Exit by the ordinal location, if that doesn't work, find it by SequenceNumber, and if that doesn't work, by the detail string + // The ExitCall.SequenceNumber can look like that: + // "snapshotSequenceCounter" : "1|6|5" + // Most of the time the sequence number from segment matches just great to that in the exit call + // But sometimes there can be an exit that is to the same query, and so its ExitCall.NumCalls will be > 1 + // For those, the UI displays the exit with total number of those, and the call graph has detail + // Typically these are the calls to database pooling + if (methodCallLineJSON["exitCalls"].HasValues == true && exitCallsList.Count > 0) + { + methodCallLine.NumExits = methodCallLineJSON["exitCalls"].Count(); - businessData.DataName = transactionPropertyToken["name"].ToString(); - businessData.DataValue = transactionPropertyToken["value"].ToString(); + List exitCallsReferenceList = new List(methodCallLine.NumExits); - #region Fill in the deeplinks for the Business Data + foreach (JToken exitCallToken in methodCallLineJSON["exitCalls"]) + { + ExitCall exitCallForThisExit = null; - businessData.ControllerLink = segment.Controller; - businessData.ApplicationLink = segment.ApplicationLink; - businessData.TierLink = segment.TierLink; - businessData.NodeLink = segment.NodeLink; - businessData.BTLink = segment.BTLink; + bool adjustCallDurationInCallChain = false; - #endregion + // First, try by the ordinal value + if (exitCallsList.Count > 0) + { + exitCallForThisExit = exitCallsList[0]; + if (exitCallForThisExit.SequenceNumber == exitCallToken["snapshotSequenceCounter"].ToString()) + { + if (exitCallForThisExit.NumCalls > 1) + { + // Found it and it is used more than once + adjustCallDurationInCallChain = true; + } + else + { + // Found it and it is a singular one + exitCallsList.Remove(exitCallForThisExit); + } + } + else + { + // Not the right one + exitCallForThisExit = null; + } + } - businessDataListInThisSegment.Add(businessData); - } + // Second, try looking it up by the sequence number + if (exitCallForThisExit == null) + { + exitCallForThisExit = exitCallsList.Where(e => e.SequenceNumber == exitCallToken["snapshotSequenceCounter"].ToString()).FirstOrDefault(); + if (exitCallForThisExit != null) + { + if (exitCallForThisExit.NumCalls > 1) + { + // Found it and it is used more than once + adjustCallDurationInCallChain = true; + } + else + { + // Found it and it is a singular one + exitCallsList.Remove(exitCallForThisExit); + } + } + } - // MIDCs - foreach (JToken transactionPropertyToken in snapshotSegmentDetail["businessData"]) - { - BusinessData businessData = new BusinessData(); + // Third, try looking up up by the exact properties + if (exitCallForThisExit == null) + { + adjustCallDurationInCallChain = true; + + // This must be one of those calls that has more then 1 call, and is grouped + // Make up the exit details using the values in the call graph information + exitCallForThisExit = exitCallsList.Where( + e => e.NumCalls > 1 && + e.Detail == exitCallToken["detailString"].ToString() && + e.PropsAll == exitCallToken["propertiesAsString"].ToString()).FirstOrDefault(); + } - businessData.Controller = segment.Controller; - businessData.ApplicationName = segment.ApplicationName; - businessData.ApplicationID = segment.ApplicationID; - businessData.TierID = segment.TierID; - businessData.TierName = segment.TierName; - businessData.BTID = segment.BTID; - businessData.BTName = segment.BTName; - businessData.NodeID = segment.NodeID; - businessData.NodeName = segment.NodeName; + // Fourth, still don't have an exit from segment data + // Manually create an exit from the Call Graph value + if (exitCallForThisExit == null) + { + adjustCallDurationInCallChain = false; - businessData.RequestID = segment.RequestID; - businessData.SegmentID = segment.SegmentID; + exitCallForThisExit = new ExitCall(); + exitCallForThisExit.Duration = (long)exitCallToken["timeTakenInMillis"]; + exitCallForThisExit.IsAsync = ((bool)exitCallToken["exitPointCall"]["synchronous"] == false); + exitCallForThisExit.ExitType = exitCallToken["type"].ToString(); + exitCallForThisExit.Detail = exitCallToken["detailString"].ToString(); - businessData.DataType = "Code"; + JToken goingToProperty = exitCallToken["properties"].Where(p => p["name"].ToString() == "to").FirstOrDefault(); + if (goingToProperty != null) + { + exitCallForThisExit.ToEntityName = goingToProperty["value"].ToString(); + } + goingToProperty = exitCallToken["properties"].Where(p => p["name"].ToString() == "from").FirstOrDefault(); + string callChainForThisSegment = "(Generated From Call Graph:Unknown)"; + if (goingToProperty != null) + { + callChainForThisSegment = String.Format("(Generated From Call Graph:{0})", goingToProperty["value"].ToString()); + } + if (exitCallForThisExit.IsAsync == false) + { + exitCallForThisExit.CallChain = String.Format("{0}->[{1}]:[{3} ms]-><{2}>", callChainForThisSegment, exitCallForThisExit.ExitType, exitCallForThisExit.ToEntityName, exitCallForThisExit.Duration); + } + else + { + exitCallForThisExit.CallChain = String.Format("{0}->[{1}]:[{3} ms async]-><{2}>", callChainForThisSegment, exitCallForThisExit.ExitType, exitCallForThisExit.ToEntityName, exitCallForThisExit.Duration); + } + } - businessData.DataName = transactionPropertyToken["name"].ToString(); - businessData.DataValue = transactionPropertyToken["value"].ToString().Trim('[', ']'); + // Finally, here we should have an exit from the segment data + string callChain = exitCallForThisExit.CallChain; + if (adjustCallDurationInCallChain == true) + { + // Call duration in the exit that has more then one call (typically database connection acquisition + // would have this call chain + // (ECommerce-Services)->[WEB_SERVICE]->(Inventory-Services)->[JDBC]:[20 ms]-> + // Here we replace this ^^, which is a sum of all the calls in the call graph + // with the value from the exit in the call graph + + Regex regexDuration = new Regex(@"(.*\[)(\d*)( ms.*\].*)", RegexOptions.IgnoreCase); + callChain = regexDuration.Replace(callChain, + m => String.Format( + "{0}{1}{2}", + m.Groups[1].Value, + exitCallToken["timeTakenInMillis"], + m.Groups[3].Value)); + } - #region Fill in the deeplinks for the Business Data + // Prepare the rendered value + if (exitCallForThisExit.HasErrors == false) + { + if (exitCallForThisExit.ToSegmentID != 0) + { + exitCallsReferenceList.Add(String.Format("{0}->/{1}/ {2}", callChain, exitCallForThisExit.ToSegmentID, exitCallForThisExit.Detail)); + } + else + { + exitCallsReferenceList.Add(String.Format("{0} {1}", callChain, exitCallForThisExit.Detail)); + } + } + else + { + exitCallsReferenceList.Add(String.Format("{0} {1} Error {2}", callChain, exitCallForThisExit.Detail, exitCallForThisExit.ErrorDetail)); + methodCallLine.HasErrors = true; + } + } - businessData.ControllerLink = segment.Controller; - businessData.ApplicationLink = segment.ApplicationLink; - businessData.TierLink = segment.TierLink; - businessData.NodeLink = segment.NodeLink; - businessData.BTLink = segment.BTLink; + // Finally, render the value out of all the exits in here + if (methodCallLine.NumExits == 1 && exitCallsReferenceList.Count > 0) + { + methodCallLine.ExitCalls = exitCallsReferenceList[0]; + } + else + { + StringBuilder sb = new StringBuilder(32 * methodCallLine.NumExits); + foreach (string exitCallsReference in exitCallsReferenceList) + { + sb.AppendFormat("{0};\n", exitCallsReference); + } + sb.Remove(sb.Length - 1, 1); + methodCallLine.ExitCalls = sb.ToString(); + } + } - #endregion + // Add to total list + methodCallLinesList.Add(methodCallLine); - businessDataListInThisSegment.Add(businessData); - } + // Go through the children, recursively. Love recursion + if (methodCallLine.NumChildren > 0) + { + List methodCallLinesAllChildren = new List(10); + foreach (JToken childMethodCallLineJSON in (JArray)methodCallLineJSON["children"]) + { + currentDepth++; + + MethodCallLine methodCallLineChild = convertCallGraphChildren_Recursion(childMethodCallLineJSON, currentDepth, ref methodLineCallSequenceNumber, methodCallLinesList, serviceEndpointCallsList, exitCallsList); - #endregion + // Now that we measured child, subtract its duration from the current node + methodCallLine.Exec = methodCallLine.Exec - methodCallLineChild.ExecTotal; + methodCallLine.Wait = methodCallLine.Wait - methodCallLineChild.WaitTotal; + methodCallLine.Block = methodCallLine.Block - methodCallLineChild.BlockTotal; + methodCallLine.CPU = methodCallLine.CPU - methodCallLineChild.CPUTotal; - #region Update call chains and call types from exits into segment + currentDepth--; + } + } + + // Calculate the duration range + methodCallLine.ExecRange = getDurationRangeAsString(methodCallLine.Exec); - SortedDictionary exitTypesSegment = new SortedDictionary(); + return methodCallLine; + } - StringBuilder sbCallChainsSegment = new StringBuilder(128 * callChainsSegment.Count); - foreach (var callChain in callChainsSegment) - { - sbCallChainsSegment.AppendFormat("{0}\n", callChain.Value); - if (exitTypesSegment.ContainsKey(callChain.Value.ExitType) == false) - { - exitTypesSegment.Add(callChain.Value.ExitType, 0); - } - exitTypesSegment[callChain.Value.ExitType] = exitTypesSegment[callChain.Value.ExitType] + callChain.Value.CallTimings.Count; - } - if (sbCallChainsSegment.Length > 1) { sbCallChainsSegment.Remove(sbCallChainsSegment.Length - 1, 1); } - segment.CallChains = sbCallChainsSegment.ToString(); + private static List convertCallGraphChildren_Stack( + JToken methodCallLineJSONRoot, + List serviceEndpointCallsList, + List exitCallsList) + { + List methodCallLinesList = new List(500); + List methodCallLinesLeafList = new List(10); - StringBuilder sbExitTypesSegment = new StringBuilder(10 * exitTypesSegment.Count); - foreach (var exitType in exitTypesSegment) - { - sbExitTypesSegment.AppendFormat("{0}={1}\n", exitType.Key, exitType.Value); - } + if (methodCallLineJSONRoot == null) + { + return methodCallLinesList; + } - if (sbExitTypesSegment.Length > 1) { sbExitTypesSegment.Remove(sbExitTypesSegment.Length - 1, 1); } - segment.ExitTypes = sbExitTypesSegment.ToString(); + // Assume depth of at least 100 + Stack stackOfMethodCallLineJSONs = new Stack(100); + Stack stackOfParentMethodCallLines = new Stack(100); - #endregion + // Add the first one + stackOfMethodCallLineJSONs.Push(methodCallLineJSONRoot); - #region Update counts of calls and types of destinations for Segment + int methodLineCallSequenceNumber = 0; - segment.NumCallsToTiers = exitCallsListInThisSegment.Where(e => e.ToEntityType == "Tier").Sum(e => e.NumCalls); - segment.NumCallsToBackends = exitCallsListInThisSegment.Where(e => e.ToEntityType == "Backend").Sum(e => e.NumCalls); - segment.NumCallsToApplications = exitCallsListInThisSegment.Where(e => e.ToEntityType == "Application").Sum(e => e.NumCalls); + // Let's scroll through, it is just like a binary tree, except with multiple children, meaning that it has left and right, and right again + while (stackOfMethodCallLineJSONs.Count > 0) + { + JToken methodCallLineJSON = stackOfMethodCallLineJSONs.Pop(); + MethodCallLine methodCallLineParent = null; + if (stackOfParentMethodCallLines.Count > 0) + { + methodCallLineParent = stackOfParentMethodCallLines.Pop(); + } - segment.NumCalledTiers = exitCallsListInThisSegment.Where(e => e.ToEntityType == "Tier").GroupBy(e => e.ToEntityName).Count(); - segment.NumCalledBackends = exitCallsListInThisSegment.Where(e => e.ToEntityType == "Backend").GroupBy(e => e.ToEntityName).Count(); - segment.NumCalledApplications = exitCallsListInThisSegment.Where(e => e.ToEntityType == "Application").GroupBy(e => e.ToEntityName).Count(); + #region Populate MethodCallLine - segment.NumSEPs = serviceEndpointCallsListInThisSegment.Count(); + MethodCallLine methodCallLine = new MethodCallLine(); - segment.NumHTTPDCs = businessDataListInThisSegment.Where(d => d.DataType == "HTTP").Count(); - segment.NumMIDCs = businessDataListInThisSegment.Where(d => d.DataType == "Code").Count(); + methodCallLine.Parent = methodCallLineParent; - #endregion + methodCallLine.SequenceNumber = methodLineCallSequenceNumber; + methodLineCallSequenceNumber++; - // Add the created entities - segmentsList.Add(segment); - exitCallsList.AddRange(exitCallsListInThisSegment); - serviceEndpointCallsList.AddRange(serviceEndpointCallsListInThisSegment); - detectedErrorsList.AddRange(detectedErrorsListInThisSegment); - businessDataList.AddRange(businessDataListInThisSegment); - } - } + // Populate current method call class, methods and types + methodCallLine.Type = methodCallLineJSON["type"].ToString(); + methodCallLine.PrettyName = methodCallLineJSON["name"].ToString(); + methodCallLine.Class = methodCallLineJSON["className"].ToString(); + methodCallLine.Method = methodCallLineJSON["methodName"].ToString(); + methodCallLine.LineNumber = (int)methodCallLineJSON["lineNumber"]; + if (methodCallLine.LineNumber > 0) + { + methodCallLine.FullName = String.Format("{0}:{1}:{2}", methodCallLine.Class, methodCallLine.Method, methodCallLine.LineNumber); + } + else + { + methodCallLine.FullName = String.Format("{0}:{1}", methodCallLine.Class, methodCallLine.Method); + } - // Sort things prettily - segmentsList = segmentsList.OrderByDescending(s => s.IsFirstInChain).ThenBy(s => s.Occured).ThenBy(s => s.UserExperience).ToList(); - exitCallsList = exitCallsList.OrderBy(c => c.RequestID).ThenBy(c => c.SegmentID).ThenBy(c => c.ExitType).ToList(); - serviceEndpointCallsList = serviceEndpointCallsList.OrderBy(s => s.RequestID).ThenBy(s => s.SegmentID).ThenBy(s => s.SEPName).ToList(); - detectedErrorsList = detectedErrorsList.OrderBy(e => e.RequestID).ThenBy(e => e.SegmentID).ThenBy(e => e.ErrorName).ToList(); - businessDataList = businessDataList.OrderBy(b => b.DataType).ThenBy(b => b.DataName).ToList(); + // Specify depth + if (methodCallLine.Parent == null) + { + methodCallLine.Depth = 0; + } + else + { + methodCallLine.Depth = methodCallLine.Parent.Depth + 1; + } - #region Update call chains from segments into snapshot + methodCallLine.FullNameIndent = String.Format("{0}{1}", new string(' ', methodCallLine.Depth), methodCallLine.FullName); - SortedDictionary exitTypesSnapshot = new SortedDictionary(); + // Fill in Service Endpoints + if (methodCallLineJSON["serviceEndPointIds"].HasValues == true && serviceEndpointCallsList.Count > 0) + { + methodCallLine.NumSEPs = methodCallLineJSON["serviceEndPointIds"].Count(); - StringBuilder sbCallChainsSnapshot = new StringBuilder(128 * callChainsSnapshot.Count); - foreach (var callChain in callChainsSnapshot) + List serviceEndpointReferenceList = new List(methodCallLine.NumSEPs); + foreach (long sepID in methodCallLineJSON["serviceEndPointIds"]) + { + ServiceEndpointCall serviceEndpointCall = serviceEndpointCallsList.Where(s => s.SEPID == sepID).FirstOrDefault(); + if (serviceEndpointCall != null) { - sbCallChainsSnapshot.AppendFormat("{0};\n", callChain.Value); - if (exitTypesSnapshot.ContainsKey(callChain.Value.ExitType) == false) - { - exitTypesSnapshot.Add(callChain.Value.ExitType, 0); - } - exitTypesSnapshot[callChain.Value.ExitType] = exitTypesSnapshot[callChain.Value.ExitType] + callChain.Value.CallTimings.Count; + serviceEndpointReferenceList.Add(String.Format("{0} ({1})", serviceEndpointCall.SEPName, serviceEndpointCall.SEPType)); } - if (sbCallChainsSnapshot.Length > 1) { sbCallChainsSnapshot.Remove(sbCallChainsSnapshot.Length - 1, 1); } - snapshot.CallChains = sbCallChainsSnapshot.ToString(); + } - StringBuilder sbExitTypesSnapshot = new StringBuilder(10 * exitTypesSnapshot.Count); - foreach (var exitType in exitTypesSnapshot) + if (methodCallLine.NumSEPs == 1) + { + methodCallLine.SEPs = serviceEndpointReferenceList[0]; + } + else + { + StringBuilder sb = new StringBuilder(32 * methodCallLine.NumSEPs); + foreach (string serviceEndpointReference in serviceEndpointReferenceList) { - sbExitTypesSnapshot.AppendFormat("{0}={1}\n", exitType.Key, exitType.Value); + sb.AppendFormat("{0};\n", serviceEndpointReference); } + sb.Remove(sb.Length - 1, 1); + methodCallLine.SEPs = sb.ToString(); + } + } - if (sbExitTypesSnapshot.Length > 1) { sbExitTypesSnapshot.Remove(sbExitTypesSnapshot.Length - 1, 1); } - snapshot.ExitTypes = sbExitTypesSnapshot.ToString(); + // Fill in Durations + // We first assume that duration is equal to duration with children. Then when adding children, recalculate, subtracting child's duration + methodCallLine.ExecTotal = (long)methodCallLineJSON["timeSpentInMilliSec"]; + methodCallLine.Exec = methodCallLine.ExecTotal; + methodCallLine.WaitTotal = (long)methodCallLineJSON["waitTime"]; + methodCallLine.Wait = methodCallLine.WaitTotal; + methodCallLine.BlockTotal = (long)methodCallLineJSON["blockTime"]; + methodCallLine.Block = methodCallLine.BlockTotal; + methodCallLine.CPUTotal = (long)methodCallLineJSON["cpuTime"]; + methodCallLine.CPU = methodCallLine.CPUTotal; - #endregion + if (methodCallLineParent != null) + { + methodCallLineParent.Exec = methodCallLineParent.Exec - methodCallLine.ExecTotal; + methodCallLineParent.Wait = methodCallLineParent.Wait - methodCallLine.WaitTotal; + methodCallLineParent.Block = methodCallLineParent.Block - methodCallLine.BlockTotal; + methodCallLineParent.CPU = methodCallLineParent.CPU - methodCallLine.CPUTotal; + } - #region Update various counts for Snapshot columns + // Count children + if (methodCallLineJSON["children"].HasValues == false) + { + methodCallLine.NumChildren = 0; + } + else + { + methodCallLine.NumChildren = methodCallLineJSON["children"].Count(); + } - snapshot.NumErrors = segmentsList.Sum(s => s.NumErrors); + // Determine type of this element in the call graph tree + if (methodCallLine.Depth == 0) + { + methodCallLine.ElementType = MethodCallLineElementType.Root; + } + else + { + if (methodCallLine.NumChildren == 0) + { + methodCallLine.ElementType = MethodCallLineElementType.Leaf; + // Remember this as the bottom of call graph so we can walk from up here calculating durations + methodCallLinesLeafList.Add(methodCallLine); + } + else if (methodCallLine.NumChildren == 1) + { + methodCallLine.ElementType = MethodCallLineElementType.Stem; + } + else + { + methodCallLine.ElementType = MethodCallLineElementType.Branch; + } + } - snapshot.NumSegments = segmentsList.Count; - snapshot.NumCallGraphs = segmentsList.Count(s => s.CallGraphType != "NONE"); + // Fill in exits + // Frequently, the exits in the list from Segments (passed via exitCallsList parameter to the function), are ordered + // in the same sequence as the exits encountered during unrolling the call graph tree + // However, that is not always the case + // Exceptions appear to be + // a) .NET applications + // and + // b) the database connection acquisition backend calls that are grouped together into number of calls >1 and duration being the Sum(of all) + // So the logic is to find the Exit by the ordinal location, if that doesn't work, find it by SequenceNumber, and if that doesn't work, by the detail string + // The ExitCall.SequenceNumber can look like that: + // "snapshotSequenceCounter" : "1|6|5" + // Most of the time the sequence number from segment matches just great to that in the exit call + // But sometimes there can be an exit that is to the same query, and so its ExitCall.NumCalls will be > 1 + // For those, the UI displays the exit with total number of those, and the call graph has detail + // Typically these are the calls to database pooling + if (methodCallLineJSON["exitCalls"].HasValues == true && exitCallsList.Count > 0) + { + methodCallLine.NumExits = methodCallLineJSON["exitCalls"].Count(); + + List exitCallsReferenceList = new List(methodCallLine.NumExits); + + foreach (JToken exitCallToken in methodCallLineJSON["exitCalls"]) + { + ExitCall exitCallForThisExit = null; - snapshot.NumCallsToTiers = segmentsList.Sum(s => s.NumCallsToTiers); - snapshot.NumCallsToBackends = segmentsList.Sum(s => s.NumCallsToBackends); - snapshot.NumCallsToApplications = segmentsList.Sum(s => s.NumCallsToApplications); + bool adjustCallDurationInCallChain = false; - snapshot.NumCalledTiers = segmentsList.Sum(s => s.NumCalledTiers); - snapshot.NumCalledBackends = segmentsList.Sum(s => s.NumCalledBackends); - snapshot.NumCalledApplications = segmentsList.Sum(s => s.NumCalledApplications); + // First, try by the ordinal value + if (exitCallsList.Count > 0) + { + exitCallForThisExit = exitCallsList[0]; + if (exitCallForThisExit.SequenceNumber == exitCallToken["snapshotSequenceCounter"].ToString()) + { + if (exitCallForThisExit.NumCalls > 1) + { + // Found it and it is used more than once + adjustCallDurationInCallChain = true; + } + else + { + // Found it and it is a singular one + exitCallsList.Remove(exitCallForThisExit); + } + } + else + { + // Not the right one + exitCallForThisExit = null; + } + } - snapshot.NumSEPs = segmentsList.Sum(s => s.NumSEPs); + // Second, try looking it up by the sequence number + if (exitCallForThisExit == null) + { + exitCallForThisExit = exitCallsList.Where(e => e.SequenceNumber == exitCallToken["snapshotSequenceCounter"].ToString()).FirstOrDefault(); + if (exitCallForThisExit != null) + { + if (exitCallForThisExit.NumCalls > 1) + { + // Found it and it is used more than once + adjustCallDurationInCallChain = true; + } + else + { + // Found it and it is a singular one + exitCallsList.Remove(exitCallForThisExit); + } + } + } - snapshot.NumHTTPDCs = segmentsList.Sum(s => s.NumHTTPDCs); - snapshot.NumMIDCs = segmentsList.Sum(s => s.NumMIDCs); + // Third, try looking up up by the exact properties + if (exitCallForThisExit == null) + { + adjustCallDurationInCallChain = true; + + // This must be one of those calls that has more then 1 call, and is grouped + // Make up the exit details using the values in the call graph information + exitCallForThisExit = exitCallsList.Where( + e => e.NumCalls > 1 && + e.Detail == exitCallToken["detailString"].ToString() && + e.PropsAll == exitCallToken["propertiesAsString"].ToString()).FirstOrDefault(); + } - #endregion - } + // Fourth, still don't have an exit from segment data + // Manually create an exit from the Call Graph value + if (exitCallForThisExit == null) + { + adjustCallDurationInCallChain = false; - #endregion + exitCallForThisExit = new ExitCall(); + exitCallForThisExit.Duration = (long)exitCallToken["timeTakenInMillis"]; + exitCallForThisExit.IsAsync = ((bool)exitCallToken["exitPointCall"]["synchronous"] == false); + exitCallForThisExit.ExitType = exitCallToken["type"].ToString(); + exitCallForThisExit.Detail = exitCallToken["detailString"].ToString(); - #region Save results + JToken goingToProperty = exitCallToken["properties"].Where(p => p["name"].ToString() == "to").FirstOrDefault(); + if (goingToProperty != null) + { + exitCallForThisExit.ToEntityName = goingToProperty["value"].ToString(); + } + goingToProperty = exitCallToken["properties"].Where(p => p["name"].ToString() == "from").FirstOrDefault(); + string callChainForThisSegment = "(Generated From Call Graph:Unknown)"; + if (goingToProperty != null) + { + callChainForThisSegment = String.Format("(Generated From Call Graph:{0})", goingToProperty["value"].ToString()); + } + if (exitCallForThisExit.IsAsync == false) + { + exitCallForThisExit.CallChain = String.Format("{0}->[{1}]:[{3} ms]-><{2}>", callChainForThisSegment, exitCallForThisExit.ExitType, exitCallForThisExit.ToEntityName, exitCallForThisExit.Duration); + } + else + { + exitCallForThisExit.CallChain = String.Format("{0}->[{1}]:[{3} ms async]-><{2}>", callChainForThisSegment, exitCallForThisExit.ExitType, exitCallForThisExit.ToEntityName, exitCallForThisExit.Duration); + } + } - // Save results - if (segmentsList != null) - { - FileIOHelper.writeListToCSVFile(segmentsList, new SegmentReportMap(), segmentsFileName); - } + // Finally, here we should have an exit from the segment data + string callChain = exitCallForThisExit.CallChain; + if (adjustCallDurationInCallChain == true) + { + // Call duration in the exit that has more then one call (typically database connection acquisition + // would have this call chain + // (ECommerce-Services)->[WEB_SERVICE]->(Inventory-Services)->[JDBC]:[20 ms]-> + // Here we replace this ^^, which is a sum of all the calls in the call graph + // with the value from the exit in the call graph + + Regex regexDuration = new Regex(@"(.*\[)(\d*)( ms.*\].*)", RegexOptions.IgnoreCase); + callChain = regexDuration.Replace(callChain, + m => String.Format( + "{0}{1}{2}", + m.Groups[1].Value, + exitCallToken["timeTakenInMillis"], + m.Groups[3].Value)); + } - if (exitCallsList != null) - { - FileIOHelper.writeListToCSVFile(exitCallsList, new ExitCallReportMap(), exitCallsFileName); + // Prepare the rendered value + if (exitCallForThisExit.HasErrors == false) + { + if (exitCallForThisExit.ToSegmentID != 0) + { + exitCallsReferenceList.Add(String.Format("{0}->/{1}/ {2}", callChain, exitCallForThisExit.ToSegmentID, exitCallForThisExit.Detail)); + } + else + { + exitCallsReferenceList.Add(String.Format("{0} {1}", callChain, exitCallForThisExit.Detail)); + } + } + else + { + exitCallsReferenceList.Add(String.Format("{0} {1} Error {2}", callChain, exitCallForThisExit.Detail, exitCallForThisExit.ErrorDetail)); + methodCallLine.HasErrors = true; + } } - if (serviceEndpointCallsList != null) + // Finally, render the value out of all the exits in here + if (methodCallLine.NumExits == 1 && exitCallsReferenceList.Count > 0) { - - FileIOHelper.writeListToCSVFile(serviceEndpointCallsList, new ServiceEndpointCallReportMap(), serviceEndpointCallsFileName); + methodCallLine.ExitCalls = exitCallsReferenceList[0]; } - - if (detectedErrorsList != null) + else { - FileIOHelper.writeListToCSVFile(detectedErrorsList, new DetectedErrorReportMap(), detectedErrorsFileName); + StringBuilder sb = new StringBuilder(32 * methodCallLine.NumExits); + foreach (string exitCallsReference in exitCallsReferenceList) + { + sb.AppendFormat("{0};\n", exitCallsReference); + } + sb.Remove(sb.Length - 1, 1); + methodCallLine.ExitCalls = sb.ToString(); } + } - if (businessDataList != null) - { - FileIOHelper.writeListToCSVFile(businessDataList, new BusinessDataReportMap(), businessDataFileName); - } + #endregion - List snapshotRows = new List(1); - snapshotRows.Add(snapshot); - FileIOHelper.writeListToCSVFile(snapshotRows, new SnapshotReportMap(), snapshotsFileName); + // Add to total list + methodCallLinesList.Add(methodCallLine); - #endregion + // Move to next sibling + if (methodCallLineJSON.Next != null) + { + JToken methodCallLineNextJSON = methodCallLineJSON.Next; + stackOfMethodCallLineJSONs.Push(methodCallLineNextJSON); + stackOfParentMethodCallLines.Push(methodCallLine.Parent); } - if (progressToConsole == true) + // Move to next child, if exists, will take precedence of the sibling + if (methodCallLine.NumChildren > 0) { - j++; - if (j % 100 == 0) + JToken methodCallLineNextJSON = methodCallLineJSON["children"]; + if (methodCallLineNextJSON.HasValues == true) { - Console.Write("[{0}].", j); + methodCallLineNextJSON = methodCallLineNextJSON[0]; + stackOfMethodCallLineJSONs.Push(methodCallLineNextJSON); + stackOfParentMethodCallLines.Push(methodCallLine); } } } - return entityList.Count; + // Now calculate durations by walking up from each of the leafs, which are the bottom-most entries in the call graph + // Actual duration of the parent is the value reported minus the value of its child(ren) + //foreach (MethodCallLine methodCallLine in methodCallLinesLeafList) + //{ + // MethodCallLine methodCallLineChild = methodCallLine; + // // Walk until we hit up + // while (methodCallLineChild.Parent != null) + // { + // MethodCallLine methodCallLineParent = methodCallLineChild.Parent; + + // if (methodCallLineParent.ExecAdjusted == false || methodCallLineParent.ElementType == MethodCallLineElementType.Branch) + // { + // methodCallLineParent.Exec = methodCallLineParent.Exec - methodCallLineChild.ExecTotal; + // methodCallLineParent.Wait = methodCallLineParent.Wait - methodCallLineChild.WaitTotal; + // methodCallLineParent.Block = methodCallLineParent.Block - methodCallLineChild.BlockTotal; + // methodCallLineParent.CPU = methodCallLineParent.CPU - methodCallLineChild.CPUTotal; + // methodCallLineParent.ExecAdjusted = true; + // } + + // methodCallLineChild = methodCallLineParent; + // } + //} + + return methodCallLinesList; + } + + private static string getDurationRangeAsString(long duration) + { + if (duration < 0) + { + return "-1: t<0"; + } + else if (duration == 0) + { + return "00: t=0"; + } + else if (duration > 0 && duration <= 10) + { + return "01: 0 10 && duration <= 50) + { + return "02: 10 50 && duration <= 100) + { + return "03: 50 100 && duration <= 200) + { + return "04: 100 200 && duration <= 500) + { + return "05: 200 500 && duration <= 1000) + { + return "06: 500 1000 && duration <= 2000) + { + return "07: 1000 2000 && duration <= 5000) + { + return "08: 2000 5000 && duration <= 10000) + { + return "09: 5000 10000 && duration <= 15000) + { + return "10: 10000 15000 && duration <= 20000) + { + return "11: 15000 20000 && duration <= 50000) + { + return "12: 20000 50000 && duration <= 100000) + { + return "13: 50000 100000 && duration <= 150000) + { + return "14: 100000 150000 && duration <= 200000) + { + return "15: 150000 200000 && duration <= 300000) + { + return "16: 200000300000"; ; } #endregion @@ -17482,7 +19210,7 @@ private static ExcelPackage createIndividualEntityMetricGraphsReportTemplate(Pro ApplicationID = jobTarget.ApplicationID, Status = jobTarget.Status.ToString() }, true); - ExcelTable table = sheet.Tables.Add(range, REPORT_METRICS_ALL_ENTITIES_TABLE_PARAMETERS_TARGETS); + ExcelTable table = sheet.Tables.Add(range, REPORT_METRICS_GRAPHS_TABLE_PARAMETERS_TARGETS); table.ShowHeader = true; table.TableStyle = TableStyles.Medium2; table.ShowFilter = true; @@ -17503,7 +19231,7 @@ private static ExcelPackage createIndividualEntityMetricGraphsReportTemplate(Pro #region Controller sheet - sheet = excelMetricGraphs.Workbook.Worksheets.Add(REPORT_ENTITY_DETAILS_SHEET_CONTROLLERS); + sheet = excelMetricGraphs.Workbook.Worksheets.Add(REPORT_METRICS_GRAPHS_SHEET_CONTROLLERS); sheet.Cells[1, 1].Value = "Table of Contents"; sheet.Cells[1, 2].Formula = String.Format(@"=HYPERLINK(""#'{0}'!A1"", """")", REPORT_SHEET_TOC); sheet.Cells[1, 2].StyleName = "HyperLinkStyle"; @@ -17512,7 +19240,7 @@ private static ExcelPackage createIndividualEntityMetricGraphsReportTemplate(Pro range = readCSVFileIntoExcelRange(controllersAllReportFilePath, 0, sheet, REPORT_METRICS_GRAPHS_LIST_SHEET_START_TABLE_AT, 1); if (range != null) { - table = sheet.Tables.Add(range, REPORT_ENTITY_DETAILS_TABLE_CONTROLLERS); + table = sheet.Tables.Add(range, REPORT_METRICS_GRAPHS_TABLE_CONTROLLERS); table.ShowHeader = true; table.TableStyle = TableStyles.Medium2; table.ShowFilter = true; @@ -17772,7 +19500,7 @@ private static void fillMetricDetailAndMetricValuesTablesForEntity( if (sheetMetrics.Dimension.Rows == 2) { - fromRow = REPORT_METRICS_ALL_ENTITIES_LIST_SHEET_START_TABLE_AT; + fromRow = REPORT_METRICS_GRAPHS_LIST_SHEET_START_TABLE_AT; } else { @@ -20935,7 +22663,7 @@ private static bool finalizeAndSaveIndividualEntityMetricReport(ExcelPackage exc sheet = excelEntityDetail.Workbook.Worksheets[REPORT_ENTITY_DETAILS_SHEET_SUMMARY]; - if (sheet.Dimension.Rows > REPORT_DETECTED_ENTITIES_LIST_SHEET_START_TABLE_AT) + if (sheet.Dimension.Rows > REPORT_ENTITY_DETAILS_LIST_SHEET_START_TABLE_AT) { table = sheet.Tables[REPORT_ENTITY_DETAILS_TABLE_ENTITY_HOURLY]; if (table != null) @@ -20980,9 +22708,9 @@ private static bool finalizeAndSaveIndividualEntityMetricReport(ExcelPackage exc sheet = excelEntityDetail.Workbook.Worksheets[REPORT_ENTITY_DETAILS_SHEET_ACTIVITYGRID]; - if (sheet.Dimension.Rows > REPORT_DETECTED_ENTITIES_LIST_SHEET_START_TABLE_AT) + if (sheet.Dimension.Rows > REPORT_ENTITY_DETAILS_LIST_SHEET_START_TABLE_AT) { - range = sheet.Cells[REPORT_DETECTED_ENTITIES_LIST_SHEET_START_TABLE_AT, 1, sheet.Dimension.Rows, sheet.Dimension.Columns]; + range = sheet.Cells[REPORT_ENTITY_DETAILS_LIST_SHEET_START_TABLE_AT, 1, sheet.Dimension.Rows, sheet.Dimension.Columns]; table = sheet.Tables.Add(range, REPORT_ENTITY_DETAILS_ACTIVITY_GRID); table.ShowHeader = true; table.TableStyle = TableStyles.Medium2; @@ -21006,7 +22734,7 @@ private static bool finalizeAndSaveIndividualEntityMetricReport(ExcelPackage exc sheet = excelEntityDetail.Workbook.Worksheets[REPORT_ENTITY_DETAILS_SHEET_EVENTS]; - if (sheet.Dimension.Rows > REPORT_DETECTED_ENTITIES_LIST_SHEET_START_TABLE_AT) + if (sheet.Dimension.Rows > REPORT_ENTITY_DETAILS_LIST_SHEET_START_TABLE_AT) { table = sheet.Tables[REPORT_ENTITY_DETAILS_TABLE_EVENTS]; if (table != null) @@ -21070,9 +22798,9 @@ private static bool finalizeAndSaveIndividualEntityMetricReport(ExcelPackage exc sheet = excelEntityDetail.Workbook.Worksheets[REPORT_ENTITY_DETAILS_SHEET_HEALTH_RULE_VIOLATIONS]; - if (sheet.Dimension.Rows > REPORT_DETECTED_ENTITIES_LIST_SHEET_START_TABLE_AT) + if (sheet.Dimension.Rows > REPORT_ENTITY_DETAILS_LIST_SHEET_START_TABLE_AT) { - range = sheet.Cells[REPORT_DETECTED_ENTITIES_LIST_SHEET_START_TABLE_AT, 1, sheet.Dimension.Rows, sheet.Dimension.Columns]; + range = sheet.Cells[REPORT_ENTITY_DETAILS_LIST_SHEET_START_TABLE_AT, 1, sheet.Dimension.Rows, sheet.Dimension.Columns]; table = sheet.Tables.Add(range, REPORT_ENTITY_DETAILS_TABLE_HEALTH_RULE_VIOLATION_EVENTS); table.ShowHeader = true; table.TableStyle = TableStyles.Medium2; @@ -21122,7 +22850,7 @@ private static bool finalizeAndSaveIndividualEntityMetricReport(ExcelPackage exc #region Snapshots sheet sheet = excelEntityDetail.Workbook.Worksheets[REPORT_ENTITY_DETAILS_SHEET_SNAPSHOTS]; - if (sheet.Dimension.Rows > REPORT_DETECTED_ENTITIES_LIST_SHEET_START_TABLE_AT) + if (sheet.Dimension.Rows > REPORT_ENTITY_DETAILS_LIST_SHEET_START_TABLE_AT) { table = sheet.Tables[REPORT_ENTITY_DETAILS_TABLE_SNAPSHOTS]; if (table != null) @@ -21143,7 +22871,7 @@ private static bool finalizeAndSaveIndividualEntityMetricReport(ExcelPackage exc sheet.Column(table.Columns["OccuredUtc"].Position + 1).Width = 20; sheet.Column(table.Columns["DetailLink"].Position + 1).Width = 25; - ExcelAddress cfAddressUserExperience = new ExcelAddress(REPORT_METRICS_ALL_ENTITIES_LIST_SHEET_START_TABLE_AT + 1, table.Columns["UserExperience"].Position + 1, sheet.Dimension.Rows, table.Columns["UserExperience"].Position + 1); + ExcelAddress cfAddressUserExperience = new ExcelAddress(REPORT_ENTITY_DETAILS_LIST_SHEET_START_TABLE_AT + 1, table.Columns["UserExperience"].Position + 1, sheet.Dimension.Rows, table.Columns["UserExperience"].Position + 1); var cfUserExperience = sheet.ConditionalFormatting.AddEqual(cfAddressUserExperience); cfUserExperience.Style.Font.Color.Color = Color.White; cfUserExperience.Style.Fill.BackgroundColor.Color = colorGreenForNormalSnapshots; @@ -21169,7 +22897,7 @@ private static bool finalizeAndSaveIndividualEntityMetricReport(ExcelPackage exc cfUserExperience.Style.Fill.BackgroundColor.Color = colorRedForErrorSnapshots; cfUserExperience.Formula = @"=""ERROR"""; - ExcelAddress cfAddressDuration = new ExcelAddress(REPORT_METRICS_ALL_ENTITIES_LIST_SHEET_START_TABLE_AT + 1, table.Columns["Duration"].Position + 1, sheet.Dimension.Rows, table.Columns["Duration"].Position + 1); + ExcelAddress cfAddressDuration = new ExcelAddress(REPORT_ENTITY_DETAILS_LIST_SHEET_START_TABLE_AT + 1, table.Columns["Duration"].Position + 1, sheet.Dimension.Rows, table.Columns["Duration"].Position + 1); var cfDuration = sheet.ConditionalFormatting.AddThreeColorScale(cfAddressDuration); cfDuration.LowValue.Color = colorGreenFor3ColorScales; cfDuration.MiddleValue.Type = eExcelConditionalFormattingValueObjectType.Percentile; @@ -21177,37 +22905,37 @@ private static bool finalizeAndSaveIndividualEntityMetricReport(ExcelPackage exc cfDuration.MiddleValue.Color = colorYellowFor3ColorScales; cfDuration.HighValue.Color = colorRedFor3ColorScales; - ExcelAddress cfAddressNum = new ExcelAddress(REPORT_METRICS_ALL_ENTITIES_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumErrors"].Position + 1, sheet.Dimension.Rows, table.Columns["NumErrors"].Position + 1); + ExcelAddress cfAddressNum = new ExcelAddress(REPORT_ENTITY_DETAILS_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumErrors"].Position + 1, sheet.Dimension.Rows, table.Columns["NumErrors"].Position + 1); var cfNum = sheet.ConditionalFormatting.AddDatabar(cfAddressNum, colorLightBlueForDatabars); - cfAddressNum = new ExcelAddress(REPORT_METRICS_ALL_ENTITIES_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumCallGraphs"].Position + 1, sheet.Dimension.Rows, table.Columns["NumCallGraphs"].Position + 1); + cfAddressNum = new ExcelAddress(REPORT_ENTITY_DETAILS_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumCallGraphs"].Position + 1, sheet.Dimension.Rows, table.Columns["NumCallGraphs"].Position + 1); cfNum = sheet.ConditionalFormatting.AddDatabar(cfAddressNum, colorLightBlueForDatabars); - cfAddressNum = new ExcelAddress(REPORT_METRICS_ALL_ENTITIES_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumCalledBackends"].Position + 1, sheet.Dimension.Rows, table.Columns["NumCalledBackends"].Position + 1); + cfAddressNum = new ExcelAddress(REPORT_ENTITY_DETAILS_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumCalledBackends"].Position + 1, sheet.Dimension.Rows, table.Columns["NumCalledBackends"].Position + 1); cfNum = sheet.ConditionalFormatting.AddDatabar(cfAddressNum, colorLightBlueForDatabars); - cfAddressNum = new ExcelAddress(REPORT_METRICS_ALL_ENTITIES_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumCalledTiers"].Position + 1, sheet.Dimension.Rows, table.Columns["NumCalledTiers"].Position + 1); + cfAddressNum = new ExcelAddress(REPORT_ENTITY_DETAILS_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumCalledTiers"].Position + 1, sheet.Dimension.Rows, table.Columns["NumCalledTiers"].Position + 1); cfNum = sheet.ConditionalFormatting.AddDatabar(cfAddressNum, colorLightBlueForDatabars); - cfAddressNum = new ExcelAddress(REPORT_METRICS_ALL_ENTITIES_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumCalledApplications"].Position + 1, sheet.Dimension.Rows, table.Columns["NumCalledApplications"].Position + 1); + cfAddressNum = new ExcelAddress(REPORT_ENTITY_DETAILS_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumCalledApplications"].Position + 1, sheet.Dimension.Rows, table.Columns["NumCalledApplications"].Position + 1); cfNum = sheet.ConditionalFormatting.AddDatabar(cfAddressNum, colorLightBlueForDatabars); - cfAddressNum = new ExcelAddress(REPORT_METRICS_ALL_ENTITIES_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumCallsToBackends"].Position + 1, sheet.Dimension.Rows, table.Columns["NumCallsToBackends"].Position + 1); + cfAddressNum = new ExcelAddress(REPORT_ENTITY_DETAILS_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumCallsToBackends"].Position + 1, sheet.Dimension.Rows, table.Columns["NumCallsToBackends"].Position + 1); cfNum = sheet.ConditionalFormatting.AddDatabar(cfAddressNum, colorLightBlueForDatabars); - cfAddressNum = new ExcelAddress(REPORT_METRICS_ALL_ENTITIES_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumCallsToTiers"].Position + 1, sheet.Dimension.Rows, table.Columns["NumCallsToTiers"].Position + 1); + cfAddressNum = new ExcelAddress(REPORT_ENTITY_DETAILS_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumCallsToTiers"].Position + 1, sheet.Dimension.Rows, table.Columns["NumCallsToTiers"].Position + 1); cfNum = sheet.ConditionalFormatting.AddDatabar(cfAddressNum, colorLightBlueForDatabars); - cfAddressNum = new ExcelAddress(REPORT_METRICS_ALL_ENTITIES_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumCallsToApplications"].Position + 1, sheet.Dimension.Rows, table.Columns["NumCallsToApplications"].Position + 1); + cfAddressNum = new ExcelAddress(REPORT_ENTITY_DETAILS_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumCallsToApplications"].Position + 1, sheet.Dimension.Rows, table.Columns["NumCallsToApplications"].Position + 1); cfNum = sheet.ConditionalFormatting.AddDatabar(cfAddressNum, colorLightBlueForDatabars); - cfAddressNum = new ExcelAddress(REPORT_METRICS_ALL_ENTITIES_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumSEPs"].Position + 1, sheet.Dimension.Rows, table.Columns["NumSEPs"].Position + 1); + cfAddressNum = new ExcelAddress(REPORT_ENTITY_DETAILS_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumSEPs"].Position + 1, sheet.Dimension.Rows, table.Columns["NumSEPs"].Position + 1); cfNum = sheet.ConditionalFormatting.AddDatabar(cfAddressNum, colorLightBlueForDatabars); - cfAddressNum = new ExcelAddress(REPORT_METRICS_ALL_ENTITIES_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumHTTPDCs"].Position + 1, sheet.Dimension.Rows, table.Columns["NumHTTPDCs"].Position + 1); + cfAddressNum = new ExcelAddress(REPORT_ENTITY_DETAILS_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumHTTPDCs"].Position + 1, sheet.Dimension.Rows, table.Columns["NumHTTPDCs"].Position + 1); cfNum = sheet.ConditionalFormatting.AddDatabar(cfAddressNum, colorLightBlueForDatabars); - cfAddressNum = new ExcelAddress(REPORT_METRICS_ALL_ENTITIES_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumMIDCs"].Position + 1, sheet.Dimension.Rows, table.Columns["NumMIDCs"].Position + 1); + cfAddressNum = new ExcelAddress(REPORT_ENTITY_DETAILS_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumMIDCs"].Position + 1, sheet.Dimension.Rows, table.Columns["NumMIDCs"].Position + 1); cfNum = sheet.ConditionalFormatting.AddDatabar(cfAddressNum, colorLightBlueForDatabars); sheet = excelEntityDetail.Workbook.Worksheets[REPORT_ENTITY_DETAILS_SHEET_SNAPSHOTS_PIVOT]; @@ -21241,9 +22969,9 @@ private static bool finalizeAndSaveIndividualEntityMetricReport(ExcelPackage exc #region Segments sheet sheet = excelEntityDetail.Workbook.Worksheets[REPORT_ENTITY_DETAILS_SHEET_SEGMENTS]; - if (sheet.Dimension.Rows > REPORT_DETECTED_ENTITIES_LIST_SHEET_START_TABLE_AT) + if (sheet.Dimension.Rows > REPORT_ENTITY_DETAILS_LIST_SHEET_START_TABLE_AT) { - range = sheet.Cells[REPORT_DETECTED_ENTITIES_LIST_SHEET_START_TABLE_AT, 1, sheet.Dimension.Rows, sheet.Dimension.Columns]; + range = sheet.Cells[REPORT_ENTITY_DETAILS_LIST_SHEET_START_TABLE_AT, 1, sheet.Dimension.Rows, sheet.Dimension.Columns]; table = sheet.Tables.Add(range, REPORT_ENTITY_DETAILS_TABLE_SEGMENTS); table.ShowHeader = true; table.TableStyle = TableStyles.Medium2; @@ -21257,13 +22985,13 @@ private static bool finalizeAndSaveIndividualEntityMetricReport(ExcelPackage exc sheet.Column(table.Columns["BTName"].Position + 1).Width = 20; sheet.Column(table.Columns["UserExperience"].Position + 1).Width = 10; sheet.Column(table.Columns["RequestID"].Position + 1).Width = 15; - sheet.Column(table.Columns["SegmentID"].Position + 1).Width = 15; - sheet.Column(table.Columns["ParentSegmentID"].Position + 1).Width = 15; - sheet.Column(table.Columns["ParentTierName"].Position + 1).Width = 20; + sheet.Column(table.Columns["SegmentID"].Position + 1).Width = 10; + sheet.Column(table.Columns["FromSegmentID"].Position + 1).Width = 15; + sheet.Column(table.Columns["FromTierName"].Position + 1).Width = 20; sheet.Column(table.Columns["Occured"].Position + 1).Width = 20; sheet.Column(table.Columns["OccuredUtc"].Position + 1).Width = 20; - ExcelAddress cfAddressUserExperience = new ExcelAddress(REPORT_METRICS_ALL_ENTITIES_LIST_SHEET_START_TABLE_AT + 1, table.Columns["UserExperience"].Position + 1, sheet.Dimension.Rows, table.Columns["UserExperience"].Position + 1); + ExcelAddress cfAddressUserExperience = new ExcelAddress(REPORT_ENTITY_DETAILS_LIST_SHEET_START_TABLE_AT + 1, table.Columns["UserExperience"].Position + 1, sheet.Dimension.Rows, table.Columns["UserExperience"].Position + 1); var cfUserExperience = sheet.ConditionalFormatting.AddEqual(cfAddressUserExperience); cfUserExperience.Style.Font.Color.Color = Color.White; cfUserExperience.Style.Fill.BackgroundColor.Color = colorGreenForNormalSnapshots; @@ -21289,7 +23017,7 @@ private static bool finalizeAndSaveIndividualEntityMetricReport(ExcelPackage exc cfUserExperience.Style.Fill.BackgroundColor.Color = colorRedForErrorSnapshots; cfUserExperience.Formula = @"=""ERROR"""; - ExcelAddress cfAddressDuration = new ExcelAddress(REPORT_METRICS_ALL_ENTITIES_LIST_SHEET_START_TABLE_AT + 1, table.Columns["Duration"].Position + 1, sheet.Dimension.Rows, table.Columns["Duration"].Position + 1); + ExcelAddress cfAddressDuration = new ExcelAddress(REPORT_ENTITY_DETAILS_LIST_SHEET_START_TABLE_AT + 1, table.Columns["Duration"].Position + 1, sheet.Dimension.Rows, table.Columns["Duration"].Position + 1); var cfDuration = sheet.ConditionalFormatting.AddThreeColorScale(cfAddressDuration); cfDuration.LowValue.Color = colorGreenFor3ColorScales; cfDuration.MiddleValue.Type = eExcelConditionalFormattingValueObjectType.Percentile; @@ -21297,34 +23025,34 @@ private static bool finalizeAndSaveIndividualEntityMetricReport(ExcelPackage exc cfDuration.MiddleValue.Color = colorYellowFor3ColorScales; cfDuration.HighValue.Color = colorRedFor3ColorScales; - ExcelAddress cfAddressNum = new ExcelAddress(REPORT_METRICS_ALL_ENTITIES_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumErrors"].Position + 1, sheet.Dimension.Rows, table.Columns["NumErrors"].Position + 1); + ExcelAddress cfAddressNum = new ExcelAddress(REPORT_ENTITY_DETAILS_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumErrors"].Position + 1, sheet.Dimension.Rows, table.Columns["NumErrors"].Position + 1); var cfNum = sheet.ConditionalFormatting.AddDatabar(cfAddressNum, colorLightBlueForDatabars); - cfAddressNum = new ExcelAddress(REPORT_METRICS_ALL_ENTITIES_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumCalledBackends"].Position + 1, sheet.Dimension.Rows, table.Columns["NumCalledBackends"].Position + 1); + cfAddressNum = new ExcelAddress(REPORT_ENTITY_DETAILS_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumCalledBackends"].Position + 1, sheet.Dimension.Rows, table.Columns["NumCalledBackends"].Position + 1); cfNum = sheet.ConditionalFormatting.AddDatabar(cfAddressNum, colorLightBlueForDatabars); - cfAddressNum = new ExcelAddress(REPORT_METRICS_ALL_ENTITIES_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumCalledTiers"].Position + 1, sheet.Dimension.Rows, table.Columns["NumCalledTiers"].Position + 1); + cfAddressNum = new ExcelAddress(REPORT_ENTITY_DETAILS_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumCalledTiers"].Position + 1, sheet.Dimension.Rows, table.Columns["NumCalledTiers"].Position + 1); cfNum = sheet.ConditionalFormatting.AddDatabar(cfAddressNum, colorLightBlueForDatabars); - cfAddressNum = new ExcelAddress(REPORT_METRICS_ALL_ENTITIES_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumCalledApplications"].Position + 1, sheet.Dimension.Rows, table.Columns["NumCalledApplications"].Position + 1); + cfAddressNum = new ExcelAddress(REPORT_ENTITY_DETAILS_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumCalledApplications"].Position + 1, sheet.Dimension.Rows, table.Columns["NumCalledApplications"].Position + 1); cfNum = sheet.ConditionalFormatting.AddDatabar(cfAddressNum, colorLightBlueForDatabars); - cfAddressNum = new ExcelAddress(REPORT_METRICS_ALL_ENTITIES_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumCallsToBackends"].Position + 1, sheet.Dimension.Rows, table.Columns["NumCallsToBackends"].Position + 1); + cfAddressNum = new ExcelAddress(REPORT_ENTITY_DETAILS_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumCallsToBackends"].Position + 1, sheet.Dimension.Rows, table.Columns["NumCallsToBackends"].Position + 1); cfNum = sheet.ConditionalFormatting.AddDatabar(cfAddressNum, colorLightBlueForDatabars); - cfAddressNum = new ExcelAddress(REPORT_METRICS_ALL_ENTITIES_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumCallsToTiers"].Position + 1, sheet.Dimension.Rows, table.Columns["NumCallsToTiers"].Position + 1); + cfAddressNum = new ExcelAddress(REPORT_ENTITY_DETAILS_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumCallsToTiers"].Position + 1, sheet.Dimension.Rows, table.Columns["NumCallsToTiers"].Position + 1); cfNum = sheet.ConditionalFormatting.AddDatabar(cfAddressNum, colorLightBlueForDatabars); - cfAddressNum = new ExcelAddress(REPORT_METRICS_ALL_ENTITIES_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumCallsToApplications"].Position + 1, sheet.Dimension.Rows, table.Columns["NumCallsToApplications"].Position + 1); + cfAddressNum = new ExcelAddress(REPORT_ENTITY_DETAILS_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumCallsToApplications"].Position + 1, sheet.Dimension.Rows, table.Columns["NumCallsToApplications"].Position + 1); cfNum = sheet.ConditionalFormatting.AddDatabar(cfAddressNum, colorLightBlueForDatabars); - cfAddressNum = new ExcelAddress(REPORT_METRICS_ALL_ENTITIES_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumSEPs"].Position + 1, sheet.Dimension.Rows, table.Columns["NumSEPs"].Position + 1); + cfAddressNum = new ExcelAddress(REPORT_ENTITY_DETAILS_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumSEPs"].Position + 1, sheet.Dimension.Rows, table.Columns["NumSEPs"].Position + 1); cfNum = sheet.ConditionalFormatting.AddDatabar(cfAddressNum, colorLightBlueForDatabars); - cfAddressNum = new ExcelAddress(REPORT_METRICS_ALL_ENTITIES_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumHTTPDCs"].Position + 1, sheet.Dimension.Rows, table.Columns["NumHTTPDCs"].Position + 1); + cfAddressNum = new ExcelAddress(REPORT_ENTITY_DETAILS_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumHTTPDCs"].Position + 1, sheet.Dimension.Rows, table.Columns["NumHTTPDCs"].Position + 1); cfNum = sheet.ConditionalFormatting.AddDatabar(cfAddressNum, colorLightBlueForDatabars); - cfAddressNum = new ExcelAddress(REPORT_METRICS_ALL_ENTITIES_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumMIDCs"].Position + 1, sheet.Dimension.Rows, table.Columns["NumMIDCs"].Position + 1); + cfAddressNum = new ExcelAddress(REPORT_ENTITY_DETAILS_LIST_SHEET_START_TABLE_AT + 1, table.Columns["NumMIDCs"].Position + 1, sheet.Dimension.Rows, table.Columns["NumMIDCs"].Position + 1); cfNum = sheet.ConditionalFormatting.AddDatabar(cfAddressNum, colorLightBlueForDatabars); sheet = excelEntityDetail.Workbook.Worksheets[REPORT_ENTITY_DETAILS_SHEET_SEGMENTS_PIVOT]; @@ -21355,9 +23083,9 @@ private static bool finalizeAndSaveIndividualEntityMetricReport(ExcelPackage exc sheet = excelEntityDetail.Workbook.Worksheets[REPORT_ENTITY_DETAILS_SHEET_EXIT_CALLS]; - if (sheet.Dimension.Rows > REPORT_DETECTED_ENTITIES_LIST_SHEET_START_TABLE_AT) + if (sheet.Dimension.Rows > REPORT_ENTITY_DETAILS_LIST_SHEET_START_TABLE_AT) { - range = sheet.Cells[REPORT_DETECTED_ENTITIES_LIST_SHEET_START_TABLE_AT, 1, sheet.Dimension.Rows, sheet.Dimension.Columns]; + range = sheet.Cells[REPORT_ENTITY_DETAILS_LIST_SHEET_START_TABLE_AT, 1, sheet.Dimension.Rows, sheet.Dimension.Columns]; table = sheet.Tables.Add(range, REPORT_ENTITY_DETAILS_TABLE_EXIT_CALLS); table.ShowHeader = true; table.TableStyle = TableStyles.Medium2; @@ -21370,13 +23098,16 @@ private static bool finalizeAndSaveIndividualEntityMetricReport(ExcelPackage exc sheet.Column(table.Columns["NodeName"].Position + 1).Width = 20; sheet.Column(table.Columns["BTName"].Position + 1).Width = 20; sheet.Column(table.Columns["RequestID"].Position + 1).Width = 15; - sheet.Column(table.Columns["SegmentID"].Position + 1).Width = 15; + sheet.Column(table.Columns["SegmentID"].Position + 1).Width = 10; sheet.Column(table.Columns["ToEntityName"].Position + 1).Width = 15; sheet.Column(table.Columns["ExitType"].Position + 1).Width = 10; sheet.Column(table.Columns["Detail"].Position + 1).Width = 20; sheet.Column(table.Columns["Method"].Position + 1).Width = 20; + sheet.Column(table.Columns["ToSegmentID"].Position + 1).Width = 15; + sheet.Column(table.Columns["Occured"].Position + 1).Width = 20; + sheet.Column(table.Columns["OccuredUtc"].Position + 1).Width = 20; - ExcelAddress cfAddressDuration = new ExcelAddress(REPORT_METRICS_ALL_ENTITIES_LIST_SHEET_START_TABLE_AT + 1, table.Columns["Duration"].Position + 1, sheet.Dimension.Rows, table.Columns["Duration"].Position + 1); + ExcelAddress cfAddressDuration = new ExcelAddress(REPORT_ENTITY_DETAILS_LIST_SHEET_START_TABLE_AT + 1, table.Columns["Duration"].Position + 1, sheet.Dimension.Rows, table.Columns["Duration"].Position + 1); var cfDuration = sheet.ConditionalFormatting.AddThreeColorScale(cfAddressDuration); cfDuration.LowValue.Color = colorGreenFor3ColorScales; cfDuration.MiddleValue.Type = eExcelConditionalFormattingValueObjectType.Percentile; @@ -21422,9 +23153,9 @@ private static bool finalizeAndSaveIndividualEntityMetricReport(ExcelPackage exc sheet = excelEntityDetail.Workbook.Worksheets[REPORT_ENTITY_DETAILS_SHEET_SERVICE_ENDPOINT_CALLS]; - if (sheet.Dimension.Rows > REPORT_DETECTED_ENTITIES_LIST_SHEET_START_TABLE_AT) + if (sheet.Dimension.Rows > REPORT_ENTITY_DETAILS_LIST_SHEET_START_TABLE_AT) { - range = sheet.Cells[REPORT_DETECTED_ENTITIES_LIST_SHEET_START_TABLE_AT, 1, sheet.Dimension.Rows, sheet.Dimension.Columns]; + range = sheet.Cells[REPORT_ENTITY_DETAILS_LIST_SHEET_START_TABLE_AT, 1, sheet.Dimension.Rows, sheet.Dimension.Columns]; table = sheet.Tables.Add(range, REPORT_ENTITY_DETAILS_TABLE_SERVICE_ENDPOINT_CALLS); table.ShowHeader = true; table.TableStyle = TableStyles.Medium2; @@ -21437,7 +23168,7 @@ private static bool finalizeAndSaveIndividualEntityMetricReport(ExcelPackage exc sheet.Column(table.Columns["NodeName"].Position + 1).Width = 20; sheet.Column(table.Columns["BTName"].Position + 1).Width = 20; sheet.Column(table.Columns["RequestID"].Position + 1).Width = 15; - sheet.Column(table.Columns["SegmentID"].Position + 1).Width = 15; + sheet.Column(table.Columns["SegmentID"].Position + 1).Width = 10; sheet.Column(table.Columns["SepName"].Position + 1).Width = 20; } @@ -21447,9 +23178,9 @@ private static bool finalizeAndSaveIndividualEntityMetricReport(ExcelPackage exc sheet = excelEntityDetail.Workbook.Worksheets[REPORT_ENTITY_DETAILS_SHEET_DETECTED_ERRORS]; - if (sheet.Dimension.Rows > REPORT_DETECTED_ENTITIES_LIST_SHEET_START_TABLE_AT) + if (sheet.Dimension.Rows > REPORT_ENTITY_DETAILS_LIST_SHEET_START_TABLE_AT) { - range = sheet.Cells[REPORT_DETECTED_ENTITIES_LIST_SHEET_START_TABLE_AT, 1, sheet.Dimension.Rows, sheet.Dimension.Columns]; + range = sheet.Cells[REPORT_ENTITY_DETAILS_LIST_SHEET_START_TABLE_AT, 1, sheet.Dimension.Rows, sheet.Dimension.Columns]; table = sheet.Tables.Add(range, REPORT_ENTITY_DETAILS_TABLE_DETECTED_ERRORS); table.ShowHeader = true; table.TableStyle = TableStyles.Medium2; @@ -21462,7 +23193,7 @@ private static bool finalizeAndSaveIndividualEntityMetricReport(ExcelPackage exc sheet.Column(table.Columns["NodeName"].Position + 1).Width = 20; sheet.Column(table.Columns["BTName"].Position + 1).Width = 20; sheet.Column(table.Columns["RequestID"].Position + 1).Width = 15; - sheet.Column(table.Columns["SegmentID"].Position + 1).Width = 15; + sheet.Column(table.Columns["SegmentID"].Position + 1).Width = 10; sheet.Column(table.Columns["ErrorName"].Position + 1).Width = 20; sheet.Column(table.Columns["ErrorMessage"].Position + 1).Width = 20; sheet.Column(table.Columns["ErrorDetail"].Position + 1).Width = 20; @@ -21495,9 +23226,9 @@ private static bool finalizeAndSaveIndividualEntityMetricReport(ExcelPackage exc sheet = excelEntityDetail.Workbook.Worksheets[REPORT_ENTITY_DETAILS_SHEET_BUSINESS_DATA]; - if (sheet.Dimension.Rows > REPORT_DETECTED_ENTITIES_LIST_SHEET_START_TABLE_AT) + if (sheet.Dimension.Rows > REPORT_ENTITY_DETAILS_LIST_SHEET_START_TABLE_AT) { - range = sheet.Cells[REPORT_DETECTED_ENTITIES_LIST_SHEET_START_TABLE_AT, 1, sheet.Dimension.Rows, sheet.Dimension.Columns]; + range = sheet.Cells[REPORT_ENTITY_DETAILS_LIST_SHEET_START_TABLE_AT, 1, sheet.Dimension.Rows, sheet.Dimension.Columns]; table = sheet.Tables.Add(range, REPORT_ENTITY_DETAILS_TABLE_BUSINESS_DATA); table.ShowHeader = true; table.TableStyle = TableStyles.Medium2; @@ -21510,7 +23241,7 @@ private static bool finalizeAndSaveIndividualEntityMetricReport(ExcelPackage exc sheet.Column(table.Columns["NodeName"].Position + 1).Width = 20; sheet.Column(table.Columns["BTName"].Position + 1).Width = 20; sheet.Column(table.Columns["RequestID"].Position + 1).Width = 15; - sheet.Column(table.Columns["SegmentID"].Position + 1).Width = 15; + sheet.Column(table.Columns["SegmentID"].Position + 1).Width = 10; sheet.Column(table.Columns["DataName"].Position + 1).Width = 20; sheet.Column(table.Columns["DataValue"].Position + 1).Width = 20; sheet.Column(table.Columns["DataType"].Position + 1).Width = 10; diff --git a/Program.cs b/Program.cs index ab1bee7..44583fa 100644 --- a/Program.cs +++ b/Program.cs @@ -48,7 +48,7 @@ public static void Main(string[] args) programOptions.JobName = Path.GetFileNameWithoutExtension(programOptions.InputJobFilePath); programOptions.OutputJobFolderPath = Path.Combine(programOptions.OutputFolderPath, programOptions.JobName); programOptions.OutputJobFilePath = Path.Combine(programOptions.OutputJobFolderPath, "jobparameters.json"); - + programOptions.ProgramLocationFolderPath = AppDomain.CurrentDomain.BaseDirectory; logger.Trace("Adjusted ProgramOptions are now:\r\n{0}", programOptions); loggerConsole.Trace("Adjusted ProgramOptions are now:\r\n{0}", programOptions); diff --git a/Properties/AssemblyInfo.cs b/Properties/AssemblyInfo.cs index 0799727..66f4694 100644 --- a/Properties/AssemblyInfo.cs +++ b/Properties/AssemblyInfo.cs @@ -31,5 +31,5 @@ // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.12")] -[assembly: AssemblyFileVersion("1.0.0.12")] +[assembly: AssemblyVersion("1.0.0.14")] +[assembly: AssemblyFileVersion("1.0.0.14")] diff --git a/ReportObjects/Metric/Maps/MetricValueMetricReportMap.cs b/ReportObjects/Metric/Maps/MetricValueMetricReportMap.cs index 261eb70..bc1f7c3 100644 --- a/ReportObjects/Metric/Maps/MetricValueMetricReportMap.cs +++ b/ReportObjects/Metric/Maps/MetricValueMetricReportMap.cs @@ -14,7 +14,7 @@ public MetricValueMetricReportMap() Map(m => m.Count).Index(i); i++; Map(m => m.Min).Index(i); i++; Map(m => m.Max).Index(i); i++; - Map(m => m.Occurences).Index(i); i++; + Map(m => m.Occurrences).Index(i); i++; Map(m => m.Sum).Index(i); i++; Map(m => m.MetricID).Index(i); i++; Map(m => m.MetricResolution); diff --git a/ReportObjects/Metric/MetricValue.cs b/ReportObjects/Metric/MetricValue.cs index 2e8738e..ebea544 100644 --- a/ReportObjects/Metric/MetricValue.cs +++ b/ReportObjects/Metric/MetricValue.cs @@ -14,7 +14,7 @@ public class MetricValue public long Count { get; set; } public long Min { get; set; } public long Max { get; set; } - public long Occurences { get; set; } + public long Occurrences { get; set; } public long Sum { get; set; } public long Value { get; set; } diff --git a/ReportObjects/Snapshot/CallChainContainer.cs b/ReportObjects/Snapshot/CallChainContainer.cs index da31e91..dfa02ea 100644 --- a/ReportObjects/Snapshot/CallChainContainer.cs +++ b/ReportObjects/Snapshot/CallChainContainer.cs @@ -1,8 +1,5 @@ -using System; -using System.Collections.Generic; -using System.Linq; +using System.Collections.Generic; using System.Text; -using System.Threading.Tasks; namespace AppDynamics.Dexter.DataObjects { diff --git a/ReportObjects/Snapshot/ExecTimeRange.cs b/ReportObjects/Snapshot/ExecTimeRange.cs new file mode 100644 index 0000000..89447a6 --- /dev/null +++ b/ReportObjects/Snapshot/ExecTimeRange.cs @@ -0,0 +1,13 @@ +using System; + +namespace AppDynamics.Dexter.DataObjects +{ + public enum ExecTimeRange + { + R_0, + R_0_10, + R_10_50, + R_50_100, + R_100_200 + } +} diff --git a/ReportObjects/Snapshot/ExitCall.cs b/ReportObjects/Snapshot/ExitCall.cs index 77067ca..742aab4 100644 --- a/ReportObjects/Snapshot/ExitCall.cs +++ b/ReportObjects/Snapshot/ExitCall.cs @@ -27,12 +27,14 @@ public class ExitCall public string ToLink { get; set; } public string ToEntityName { get; set; } public string ToEntityType { get; set; } + public long ToSegmentID { get; set; } public DateTime Occured { get; set; } public DateTime OccuredUtc { get; set; } public string RequestID { get; set; } public long SegmentID { get; set; } + public string SequenceNumber { get; set; } public string ExitType { get; set; } public string Detail { get; set; } @@ -40,6 +42,8 @@ public class ExitCall public bool IsAsync { get; set; } public long Duration { get; set; } + public string DurationRange { get; set; } + public string CallChain { get; set; } public bool HasErrors { get; set; } diff --git a/ReportObjects/Snapshot/Maps/BusinessDataReportMap.cs b/ReportObjects/Snapshot/Maps/BusinessDataReportMap.cs index 90b173e..c9423d0 100644 --- a/ReportObjects/Snapshot/Maps/BusinessDataReportMap.cs +++ b/ReportObjects/Snapshot/Maps/BusinessDataReportMap.cs @@ -23,12 +23,6 @@ public BusinessDataReportMap() Map(m => m.TierID).Index(i); i++; Map(m => m.NodeID).Index(i); i++; Map(m => m.BTID).Index(i); i++; - - //Map(m => m.ControllerLink).Index(i); i++; - //Map(m => m.ApplicationLink).Index(i); i++; - //Map(m => m.TierLink).Index(i); i++; - //Map(m => m.NodeLink).Index(i); i++; - //Map(m => m.BTLink).Index(i); i++; } } } \ No newline at end of file diff --git a/ReportObjects/Snapshot/Maps/DetectedErrorReportMap.cs b/ReportObjects/Snapshot/Maps/DetectedErrorReportMap.cs index d89e3b4..eac8dd1 100644 --- a/ReportObjects/Snapshot/Maps/DetectedErrorReportMap.cs +++ b/ReportObjects/Snapshot/Maps/DetectedErrorReportMap.cs @@ -26,11 +26,6 @@ public DetectedErrorReportMap() Map(m => m.BTID).Index(i); i++; Map(m => m.ErrorID).Index(i); i++; - //Map(m => m.ControllerLink).Index(i); i++; - //Map(m => m.ApplicationLink).Index(i); i++; - //Map(m => m.TierLink).Index(i); i++; - //Map(m => m.NodeLink).Index(i); i++; - //Map(m => m.BTLink).Index(i); i++; Map(m => m.ErrorLink).Index(i); i++; } } diff --git a/ReportObjects/Snapshot/Maps/ExitCallReportMap.cs b/ReportObjects/Snapshot/Maps/ExitCallReportMap.cs index b479354..4bacf0c 100644 --- a/ReportObjects/Snapshot/Maps/ExitCallReportMap.cs +++ b/ReportObjects/Snapshot/Maps/ExitCallReportMap.cs @@ -14,13 +14,17 @@ public ExitCallReportMap() Map(m => m.BTName).Index(i); i++; Map(m => m.RequestID).Index(i); i++; Map(m => m.SegmentID).Index(i); i++; + Map(m => m.SequenceNumber).Index(i); i++; Map(m => m.ToEntityName).Index(i); i++; Map(m => m.ToEntityType).Index(i); i++; + Map(m => m.ToSegmentID).Index(i); i++; Map(m => m.Occured).Index(i); i++; Map(m => m.OccuredUtc).Index(i); i++; Map(m => m.Duration).Index(i); i++; + Map(m => m.DurationRange).Index(i); i++; + Map(m => m.ExitType).Index(i); i++; Map(m => m.Detail).Index(i); i++; Map(m => m.Method).Index(i); i++; @@ -60,11 +64,6 @@ public ExitCallReportMap() Map(m => m.BTID).Index(i); i++; Map(m => m.ToEntityID).Index(i); i++; - //Map(m => m.ControllerLink).Index(i); i++; - //Map(m => m.ApplicationLink).Index(i); i++; - //Map(m => m.TierLink).Index(i); i++; - //Map(m => m.NodeLink).Index(i); i++; - //Map(m => m.BTLink).Index(i); i++; Map(m => m.ToLink).Index(i); i++; } } diff --git a/ReportObjects/Snapshot/Maps/MethodCallLineClassTypeMappingReportMap.cs b/ReportObjects/Snapshot/Maps/MethodCallLineClassTypeMappingReportMap.cs new file mode 100644 index 0000000..b52a732 --- /dev/null +++ b/ReportObjects/Snapshot/Maps/MethodCallLineClassTypeMappingReportMap.cs @@ -0,0 +1,14 @@ +using CsvHelper.Configuration; + +namespace AppDynamics.Dexter.DataObjects +{ + public class MethodCallLineClassTypeMappingReportMap : ClassMap + { + public MethodCallLineClassTypeMappingReportMap() + { + int i = 0; + Map(m => m.ClassPrefix).Index(i); i++; + Map(m => m.FrameworkType).Index(i); i++; + } + } +} \ No newline at end of file diff --git a/ReportObjects/Snapshot/Maps/MethodCallLineOccurrenceReportMap.cs b/ReportObjects/Snapshot/Maps/MethodCallLineOccurrenceReportMap.cs new file mode 100644 index 0000000..d82e293 --- /dev/null +++ b/ReportObjects/Snapshot/Maps/MethodCallLineOccurrenceReportMap.cs @@ -0,0 +1,45 @@ +using CsvHelper.Configuration; + +namespace AppDynamics.Dexter.DataObjects +{ + public class MethodCallLineOccurrenceReportMap : ClassMap + { + public MethodCallLineOccurrenceReportMap() + { + int i = 0; + Map(m => m.Controller).Index(i); i++; + Map(m => m.ApplicationName).Index(i); i++; + Map(m => m.TierName).Index(i); i++; + Map(m => m.NodeName).Index(i); i++; + Map(m => m.BTName).Index(i); i++; + Map(m => m.RequestID).Index(i); i++; + Map(m => m.SegmentID).Index(i); i++; + + Map(m => m.Type).Index(i); i++; + Map(m => m.Framework).Index(i); i++; + + Map(m => m.FullName).Index(i); i++; + Map(m => m.PrettyName).Index(i); i++; + Map(m => m.Class).Index(i); i++; + Map(m => m.Method).Index(i); i++; + Map(m => m.LineNumber).Index(i); i++; + Map(m => m.NumCalls).Index(i); i++; + + Map(m => m.Exec).Index(i); i++; + Map(m => m.Wait).Index(i); i++; + Map(m => m.Block).Index(i); i++; + Map(m => m.CPU).Index(i); i++; + Map(m => m.ExecRange).Index(i); i++; + + Map(m => m.NumExits).Index(i); i++; + Map(m => m.NumSEPs).Index(i); i++; + Map(m => m.NumMIDCs).Index(i); i++; + Map(m => m.NumChildren).Index(i); i++; + + Map(m => m.ApplicationID).Index(i); i++; + Map(m => m.TierID).Index(i); i++; + Map(m => m.NodeID).Index(i); i++; + Map(m => m.BTID).Index(i); i++; + } + } +} \ No newline at end of file diff --git a/ReportObjects/Snapshot/Maps/MethodCallLineReportMap.cs b/ReportObjects/Snapshot/Maps/MethodCallLineReportMap.cs new file mode 100644 index 0000000..e42b779 --- /dev/null +++ b/ReportObjects/Snapshot/Maps/MethodCallLineReportMap.cs @@ -0,0 +1,59 @@ +using CsvHelper.Configuration; + +namespace AppDynamics.Dexter.DataObjects +{ + public class MethodCallLineReportMap : ClassMap + { + public MethodCallLineReportMap() + { + int i = 0; + Map(m => m.Controller).Index(i); i++; + Map(m => m.ApplicationName).Index(i); i++; + Map(m => m.TierName).Index(i); i++; + Map(m => m.NodeName).Index(i); i++; + Map(m => m.BTName).Index(i); i++; + Map(m => m.RequestID).Index(i); i++; + Map(m => m.SegmentID).Index(i); i++; + + Map(m => m.Type).Index(i); i++; + Map(m => m.Framework).Index(i); i++; + Map(m => m.FullNameIndent).Index(i); i++; + + Map(m => m.Exec).Index(i); i++; + Map(m => m.ExecTotal).Index(i); i++; + Map(m => m.Wait).Index(i); i++; + Map(m => m.WaitTotal).Index(i); i++; + Map(m => m.Block).Index(i); i++; + Map(m => m.BlockTotal).Index(i); i++; + Map(m => m.CPU).Index(i); i++; + Map(m => m.CPUTotal).Index(i); i++; + Map(m => m.ExecRange).Index(i); i++; + + Map(m => m.ExitCalls).Index(i); i++; + Map(m => m.NumExits).Index(i); i++; + Map(m => m.HasErrors).Index(i); i++; + + Map(m => m.SEPs).Index(i); i++; + Map(m => m.NumSEPs).Index(i); i++; + + Map(m => m.MIDCs).Index(i); i++; + Map(m => m.NumMIDCs).Index(i); i++; + + Map(m => m.NumChildren).Index(i); i++; + Map(m => m.ElementType).Index(i); i++; + Map(m => m.SequenceNumber).Index(i); i++; + Map(m => m.Depth).Index(i); i++; + + Map(m => m.PrettyName).Index(i); i++; + Map(m => m.FullName).Index(i); i++; + Map(m => m.Class).Index(i); i++; + Map(m => m.Method).Index(i); i++; + Map(m => m.LineNumber).Index(i); i++; + + Map(m => m.ApplicationID).Index(i); i++; + Map(m => m.TierID).Index(i); i++; + Map(m => m.NodeID).Index(i); i++; + Map(m => m.BTID).Index(i); i++; + } + } +} \ No newline at end of file diff --git a/ReportObjects/Snapshot/Maps/SegmentReportMap.cs b/ReportObjects/Snapshot/Maps/SegmentReportMap.cs index 374766d..20a7489 100644 --- a/ReportObjects/Snapshot/Maps/SegmentReportMap.cs +++ b/ReportObjects/Snapshot/Maps/SegmentReportMap.cs @@ -15,8 +15,8 @@ public SegmentReportMap() Map(m => m.UserExperience).Index(i); i++; Map(m => m.RequestID).Index(i); i++; Map(m => m.SegmentID).Index(i); i++; - Map(m => m.ParentSegmentID).Index(i); i++; - Map(m => m.ParentTierName).Index(i); i++; + Map(m => m.FromSegmentID).Index(i); i++; + Map(m => m.FromTierName).Index(i); i++; Map(m => m.Occured).Index(i); i++; Map(m => m.OccuredUtc).Index(i); i++; @@ -25,6 +25,7 @@ public SegmentReportMap() Map(m => m.ThreadName).Index(i); i++; Map(m => m.Duration).Index(i); i++; + Map(m => m.DurationRange).Index(i); i++; Map(m => m.CPUDuration).Index(i); i++; Map(m => m.WaitDuration).Index(i); i++; Map(m => m.BlockDuration).Index(i); i++; diff --git a/ReportObjects/Snapshot/Maps/ServiceEndpointCallReportMap.cs b/ReportObjects/Snapshot/Maps/ServiceEndpointCallReportMap.cs index c315f7a..7ea64c9 100644 --- a/ReportObjects/Snapshot/Maps/ServiceEndpointCallReportMap.cs +++ b/ReportObjects/Snapshot/Maps/ServiceEndpointCallReportMap.cs @@ -23,11 +23,6 @@ public ServiceEndpointCallReportMap() Map(m => m.BTID).Index(i); i++; Map(m => m.SEPID).Index(i); i++; - //Map(m => m.ControllerLink).Index(i); i++; - //Map(m => m.ApplicationLink).Index(i); i++; - //Map(m => m.TierLink).Index(i); i++; - //Map(m => m.NodeLink).Index(i); i++; - //Map(m => m.BTLink).Index(i); i++; Map(m => m.SEPLink).Index(i); i++; } } diff --git a/ReportObjects/Snapshot/Maps/SnapshotReportMap.cs b/ReportObjects/Snapshot/Maps/SnapshotReportMap.cs index fdd835d..dba3859 100644 --- a/ReportObjects/Snapshot/Maps/SnapshotReportMap.cs +++ b/ReportObjects/Snapshot/Maps/SnapshotReportMap.cs @@ -19,6 +19,7 @@ public SnapshotReportMap() Map(m => m.OccuredUtc).Index(i); i++; Map(m => m.Duration).Index(i); i++; + Map(m => m.DurationRange).Index(i); i++; Map(m => m.URL).Index(i); i++; Map(m => m.CallChains).Index(i); i++; diff --git a/ReportObjects/Snapshot/MethodCallLine.cs b/ReportObjects/Snapshot/MethodCallLine.cs new file mode 100644 index 0000000..573c0e8 --- /dev/null +++ b/ReportObjects/Snapshot/MethodCallLine.cs @@ -0,0 +1,79 @@ +using System; + +namespace AppDynamics.Dexter.DataObjects +{ + public class MethodCallLine + { + public string Controller { get; set; } + + public long ApplicationID { get; set; } + public string ApplicationName { get; set; } + + public long TierID { get; set; } + public string TierName { get; set; } + + public long NodeID { get; set; } + public string NodeName { get; set; } + + public long BTID { get; set; } + public string BTName { get; set; } + + public string RequestID { get; set; } + public long SegmentID { get; set; } + + public string Type { get; set; } + public string Framework { get; set; } + public string FullNameIndent { get; set; } + public string FullName { get; set; } + public string PrettyName { get; set; } + public string Class { get; set; } + public string Method { get; set; } + public int LineNumber { get; set; } + + public long Exec { get; set; } + public long ExecTotal { get; set; } + public long Wait { get; set; } + public long WaitTotal { get; set; } + public long Block { get; set; } + public long BlockTotal { get; set; } + public long CPU { get; set; } + public long CPUTotal { get; set; } + public bool ExecAdjusted { get; set; } + + public string ExecRange { get; set; } + + public int Depth { get; set; } + public MethodCallLineElementType ElementType { get; set; } + public int NumChildren { get; set; } + + public string SEPs { get; set; } + public int NumSEPs { get; set; } + + public string ExitCalls { get; set; } + public int NumExits { get; set; } + public bool HasErrors { get; set; } + + public string MIDCs { get; set; } + public int NumMIDCs { get; set; } + + public int SequenceNumber { get; set; } + public int NumCalls { get; set; } + + public MethodCallLine Parent { get; set; } + + public MethodCallLine Clone() + { + return (MethodCallLine)this.MemberwiseClone(); + } + + public override String ToString() + { + return String.Format( + "MethodCallLine: {0}, {1} ms, {2} deep, #{3}", + this.FullName, + this.Exec, + this.Depth, + this.SequenceNumber); + } + } +} diff --git a/ReportObjects/Snapshot/MethodCallLineClassTypeMapping.cs b/ReportObjects/Snapshot/MethodCallLineClassTypeMapping.cs new file mode 100644 index 0000000..e232ae4 --- /dev/null +++ b/ReportObjects/Snapshot/MethodCallLineClassTypeMapping.cs @@ -0,0 +1,18 @@ +using System; + +namespace AppDynamics.Dexter.DataObjects +{ + public class MethodCallLineClassTypeMapping + { + public string ClassPrefix { get; set; } + public string FrameworkType { get; set; } + + public override String ToString() + { + return String.Format( + "MethodCallLineClassTypeMapping: {0}->{1}", + this.ClassPrefix, + this.FrameworkType); + } + } +} diff --git a/ReportObjects/Snapshot/MethodCallLineElementType.cs b/ReportObjects/Snapshot/MethodCallLineElementType.cs new file mode 100644 index 0000000..7ec1fb2 --- /dev/null +++ b/ReportObjects/Snapshot/MethodCallLineElementType.cs @@ -0,0 +1,12 @@ +using System; + +namespace AppDynamics.Dexter.DataObjects +{ + public enum MethodCallLineElementType + { + Root, + Stem, + Branch, + Leaf + } +} diff --git a/ReportObjects/Snapshot/Segment.cs b/ReportObjects/Snapshot/Segment.cs index 4155cc4..d3945c1 100644 --- a/ReportObjects/Snapshot/Segment.cs +++ b/ReportObjects/Snapshot/Segment.cs @@ -1,6 +1,4 @@ using System; -using System.Collections.Generic; -using System.Text; namespace AppDynamics.Dexter.DataObjects { @@ -32,10 +30,12 @@ public class Segment public long SegmentID { get; set; } public string UserExperience { get; set; } public long Duration { get; set; } + public string DurationRange { get; set; } + public long E2ELatency { get; set; } public double CPUDuration { get; set; } - public double WaitDuration { get; set; } - public double BlockDuration { get; set; } + public long WaitDuration { get; set; } + public long BlockDuration { get; set; } public string DiagSessionID { get; set; } public string URL { get; set; } public string ThreadID { get; set; } @@ -50,8 +50,8 @@ public class Segment public string WarningThreshold { get; set; } public string CriticalThreshold { get; set; } - public long ParentSegmentID { get; set; } - public string ParentTierName { get; set; } + public long FromSegmentID { get; set; } + public string FromTierName { get; set; } public string CallGraphType { get; set; } public bool IsArchived { get; set; } diff --git a/ReportObjects/Snapshot/Snapshot.cs b/ReportObjects/Snapshot/Snapshot.cs index a1473bb..cee7e96 100644 --- a/ReportObjects/Snapshot/Snapshot.cs +++ b/ReportObjects/Snapshot/Snapshot.cs @@ -1,6 +1,4 @@ using System; -using System.Collections.Generic; -using System.Text; namespace AppDynamics.Dexter.DataObjects { @@ -31,6 +29,7 @@ public class Snapshot public string RequestID { get; set; } public string UserExperience { get; set; } public long Duration { get; set; } + public string DurationRange { get; set; } public string DiagSessionID { get; set; } public string URL { get; set; }