diff --git a/AppDynamics.Dexter.Core.csproj b/AppDynamics.Dexter.Core.csproj index aaaa7d2..00fbd5f 100644 --- a/AppDynamics.Dexter.Core.csproj +++ b/AppDynamics.Dexter.Core.csproj @@ -52,18 +52,18 @@ - + - - - - + + + + - + @@ -72,6 +72,30 @@ + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + Always + + + Always + Always diff --git a/ChromeDriver/78/linux64/chromedriver b/ChromeDriver/78/linux64/chromedriver index 95965a8..eeecd35 100644 Binary files a/ChromeDriver/78/linux64/chromedriver and b/ChromeDriver/78/linux64/chromedriver differ diff --git a/ChromeDriver/78/mac64/chromedriver b/ChromeDriver/78/mac64/chromedriver index 0840731..4ff3bcc 100644 Binary files a/ChromeDriver/78/mac64/chromedriver and b/ChromeDriver/78/mac64/chromedriver differ diff --git a/ChromeDriver/78/win32/chromedriver.exe b/ChromeDriver/78/win32/chromedriver.exe index 7b97f31..ec9ce29 100644 Binary files a/ChromeDriver/78/win32/chromedriver.exe and b/ChromeDriver/78/win32/chromedriver.exe differ diff --git a/ChromeDriver/77/linux64/chromedriver b/ChromeDriver/79/linux64/chromedriver similarity index 57% rename from ChromeDriver/77/linux64/chromedriver rename to ChromeDriver/79/linux64/chromedriver index e21c03d..6942445 100644 Binary files a/ChromeDriver/77/linux64/chromedriver and b/ChromeDriver/79/linux64/chromedriver differ diff --git a/ChromeDriver/77/mac64/chromedriver b/ChromeDriver/79/mac64/chromedriver similarity index 64% rename from ChromeDriver/77/mac64/chromedriver rename to ChromeDriver/79/mac64/chromedriver index 543ed9f..d9bff50 100644 Binary files a/ChromeDriver/77/mac64/chromedriver and b/ChromeDriver/79/mac64/chromedriver differ diff --git a/ChromeDriver/76/win32/chromedriver.exe b/ChromeDriver/79/win32/chromedriver.exe similarity index 53% rename from ChromeDriver/76/win32/chromedriver.exe rename to ChromeDriver/79/win32/chromedriver.exe index 0eedbe0..244efd4 100644 Binary files a/ChromeDriver/76/win32/chromedriver.exe and b/ChromeDriver/79/win32/chromedriver.exe differ diff --git a/ChromeDriver/76/linux64/chromedriver b/ChromeDriver/80/linux64/chromedriver similarity index 57% rename from ChromeDriver/76/linux64/chromedriver rename to ChromeDriver/80/linux64/chromedriver index a087573..b362f8f 100644 Binary files a/ChromeDriver/76/linux64/chromedriver and b/ChromeDriver/80/linux64/chromedriver differ diff --git a/ChromeDriver/76/mac64/chromedriver b/ChromeDriver/80/mac64/chromedriver similarity index 63% rename from ChromeDriver/76/mac64/chromedriver rename to ChromeDriver/80/mac64/chromedriver index 135416c..df7565d 100644 Binary files a/ChromeDriver/76/mac64/chromedriver and b/ChromeDriver/80/mac64/chromedriver differ diff --git a/ChromeDriver/77/win32/chromedriver.exe b/ChromeDriver/80/win32/chromedriver.exe similarity index 54% rename from ChromeDriver/77/win32/chromedriver.exe rename to ChromeDriver/80/win32/chromedriver.exe index ae80772..d419a51 100644 Binary files a/ChromeDriver/77/win32/chromedriver.exe and b/ChromeDriver/80/win32/chromedriver.exe differ diff --git a/ControllerApi/ControllerApi.cs b/ControllerApi/ControllerApi.cs index 7b307a9..9da64ad 100644 --- a/ControllerApi/ControllerApi.cs +++ b/ControllerApi/ControllerApi.cs @@ -222,9 +222,75 @@ public string GetAPMConfigurationExportXML(long applicationID) return this.apiGET(String.Format("controller/ConfigObjectImportExportServlet?applicationId={0}", applicationID), "text/xml", false); } - public string GetAPMSEPConfiguration(long accountID, long applicationID) + public string GetAPMSEPAutodetectionConfiguration(long applicationID) { - return this.apiGET(String.Format("api/accounts/{0}/applications/{1}/sep", accountID, applicationID), "application/vnd.appd.cntrl+json", false); + string requestJSONTemplate = +@"{{ + ""agentType"": ""APP_AGENT"", + ""attachedEntity"": {{ + ""entityId"": {0}, + ""entityType"": ""APPLICATION"" + }} +}}"; + + string requestBody = String.Format(requestJSONTemplate, + applicationID); + + return this.apiPOST("controller/restui/serviceEndpoint/getServiceEndpointMatchConfigs", "application/json", requestBody, "application/json", true); + } + + public string GetAPMSEPTierConfigurationOverride(long tierID, string agentType) + { + string requestJSONTemplate = +@"{{ + ""agentType"": ""{1}"", + ""attachedEntity"": {{ + ""entityId"": {0}, + ""entityType"": ""APPLICATION_COMPONENT"" + }} +}}"; + + string requestBody = String.Format(requestJSONTemplate, + tierID, + agentType); + + return this.apiPOST("controller/restui/serviceEndpoint/getServiceEndpointDefContainer", "application/json", requestBody, "application/json", true); + } + + public string GetAPMSEPTierAutodetectionConfiguration(long tierID, string agentType) + { + string requestJSONTemplate = +@"{{ + ""agentType"": ""{1}"", + ""attachedEntity"": {{ + ""entityId"": {0}, + ""entityType"": ""APPLICATION_COMPONENT"" + }} +}}"; + + string requestBody = String.Format(requestJSONTemplate, + tierID, + agentType); + + return this.apiPOST("controller/restui/serviceEndpoint/getServiceEndpointMatchConfigs", "application/json", requestBody, "application/json", true); + } + + public string GetAPMSEPTierRules(long tierID, string agentType) + { + string requestJSONTemplate = +@"{{ + ""agentType"": ""{1}"", + ""attachedEntity"": {{ + ""entityId"": {0}, + ""entityType"": ""APPLICATION_COMPONENT"" + }} +}}"; + + string requestBody = String.Format(requestJSONTemplate, + tierID, + agentType); + + return this.apiPOST("controller/restui/serviceEndpoint/getAll", "application/json", requestBody, "application/json", true); } public string GetAPMDeveloperModeConfiguration(long applicationID) diff --git a/DataObjects/JobConfiguration/JobOutput.cs b/DataObjects/JobConfiguration/JobOutput.cs index 0400c2b..da840f3 100644 --- a/DataObjects/JobConfiguration/JobOutput.cs +++ b/DataObjects/JobConfiguration/JobOutput.cs @@ -14,6 +14,7 @@ public class JobOutput public bool UsersGroupsRolesPermissions { get; set; } public bool Dashboards { get; set; } public bool Licenses { get; set; } + public bool HealthCheck { get; set; } public bool ApplicationSummary { get; set; } } } diff --git a/DataObjects/JobConfiguration/JobStatus.cs b/DataObjects/JobConfiguration/JobStatus.cs index a23c7ba..f8952a0 100644 --- a/DataObjects/JobConfiguration/JobStatus.cs +++ b/DataObjects/JobConfiguration/JobStatus.cs @@ -61,6 +61,8 @@ public enum JobStatus IndexAPMMetrics = 80, IndexAPMFlowmaps = 81, IndexAPMSnapshots = 82, + + IndexAPMHealthCheck = 90, // Report steps ReportControllerAndApplicationConfiguration = 100, @@ -86,9 +88,11 @@ public enum JobStatus ReportAPMFlameGraphs = 132, ReportAPMEntityDetails = 133, - ReportAPMApplicationSummary = 134, + + ReportHealthCheck = 140, + ReportAPMApplicationSummary = 141, - ReportAPMEntityDashboardScreenshots = 140, + ReportAPMEntityDashboardScreenshots = 150, // The rest Done = 500, diff --git a/DefaultJob.json b/DefaultJob.json index b88b147..b4ae939 100644 --- a/DefaultJob.json +++ b/DefaultJob.json @@ -51,8 +51,8 @@ ], "Input": { "TimeRange": { - "From": "2019-11-191T09:00:00", - "To": "2019-11-19T10:00:00" + "From": "2019-12-17T09:00:00", + "To": "2019-12-17T10:00:00" }, "UsersGroupsRolesPermissions": true, "Dashboards": true, @@ -72,99 +72,30 @@ "Tiers": [], "TierType": { "All": true, - "APP_AGENT": false, - "DOT_NET_APP_AGENT": false, - "NATIVE_APP_AGENT": false, - "NATIVE_DYNAMIC": false, - "NATIVE_SDK": false, - "NATIVE_WEB_SERVER": false, - "NODEJS_APP_AGENT": false, - "PHP_APP_AGENT": false, - "PYTHON_APP_AGENT": false, - "RUBY_APP_AGENT": false + "APP_AGENT": false, "DOT_NET_APP_AGENT": false, "NATIVE_APP_AGENT": false, "NATIVE_DYNAMIC": false, "NATIVE_SDK": false, + "NATIVE_WEB_SERVER": false, "NODEJS_APP_AGENT": false, "PHP_APP_AGENT": false, "PYTHON_APP_AGENT": false, "RUBY_APP_AGENT": false }, "BusinessTransactions": [], "BusinessTransactionType": { "All": true, - "SERVLET": false, - "HTTP": false, - "WEB_SERVICE": false, - "POJO": false, - "JMS": false, - "EJB": false, - "SPRING_BEAN": false, - "STRUTS_ACTION": false, - "ASP_DOTNET": false, - "ASP_DOTNET_WEB_SERVICE": false, - "DOTNET_REMOTING": false, - "WCF": false, - "DOTNET_JMS": false, - "POCO": false, - "PHP_WEB": false, - "PHP_MVC": false, - "PHP_DRUPAL": false, - "PHP_WORDPRESS": false, - "PHP_CLI": false, - "PHP_WEB_SERVICE": false, - "NODEJS_WEB": false, - "NATIVE": false, - "WEB": false, - "PYTHON_WEB": false, - "RUBY_WEB": false, - "RUBY_RAILS": false, - "BINARY_REMOTING": false + "SERVLET": false, "HTTP": false, "WEB_SERVICE": false, "POJO": false, "JMS": false, "EJB": false, "SPRING_BEAN": false, "STRUTS_ACTION": false, + "ASP_DOTNET": false, "ASP_DOTNET_WEB_SERVICE": false, "DOTNET_REMOTING": false, "WCF": false, + "DOTNET_JMS": false, "POCO": false, "PHP_WEB": false, "PHP_MVC": false, "PHP_DRUPAL": false,"PHP_WORDPRESS": false, + "PHP_CLI": false, "PHP_WEB_SERVICE": false, "NODEJS_WEB": false, "NATIVE": false, "WEB": false, "PYTHON_WEB": false, "RUBY_WEB": false, "RUBY_RAILS": false, "BINARY_REMOTING": false }, "Nodes": [], "NodeType": { "All": true, - "APP_AGENT": false, - "DOT_NET_APP_AGENT": false, - "NATIVE_APP_AGENT": false, - "NATIVE_DYNAMIC": false, - "NATIVE_SDK": false, - "NATIVE_WEB_SERVER": false, - "NODEJS_APP_AGENT": false, - "PHP_APP_AGENT": false, - "PYTHON_APP_AGENT": false, - "RUBY_APP_AGENT": false + "APP_AGENT": false, "DOT_NET_APP_AGENT": false, "NATIVE_APP_AGENT": false, "NATIVE_DYNAMIC": false, "NATIVE_SDK": false, + "NATIVE_WEB_SERVER": false, "NODEJS_APP_AGENT": false, "PHP_APP_AGENT": false, "PYTHON_APP_AGENT": false, "RUBY_APP_AGENT": false }, "Backends": [], "BackendType": { "All": true, - "SOCKET": false, - "HTTP": false, - "CUSTOM": false, - "CUSTOM_ASYNC": false, - "FILE_SERVER": false, - "MAIL_SERVER": false, - "WEB_SERVICE": false, - "ERP": false, - "CACHE": false, - "WEBSPHERE_MQ": false, - "MAINFRAME": false, - "TIBCO_ASYNC": false, - "TIBCO": false, - "ESB": false, - "SAP": false, - "AVRO": false, - "THRIFT": false, - "CASSANDRA": false, - "MQ": false, - "JMS": false, - "WEBSOCKET": false, - "JDBC": false, - "RMI": false, - "LDAP": false, - "CORBA": false, - "RABBITMQ": false, - "ADODOTNET": false, - "DOTNETDirectoryServices": false, - "DOTNETRemoting": false, - "DOTNETMessaging": false, - "WCF": false, - "MSMQ": false, - "DB": false, - "NETWORK": false + "SOCKET": false, "HTTP": false, "CUSTOM": false, "CUSTOM_ASYNC": false, "FILE_SERVER": false, "MAIL_SERVER": false, "WEB_SERVICE": false, "ERP": false, + "CACHE": false, "WEBSPHERE_MQ": false, "MAINFRAME": false, "TIBCO_ASYNC": false, "TIBCO": false, "ESB": false, "SAP": false, "AVRO": false, + "THRIFT": false, "CASSANDRA": false, "MQ": false, "JMS": false, "WEBSOCKET": false, "JDBC": false, "RMI": false, "LDAP": false, "CORBA": false, + "RABBITMQ": false, "ADODOTNET": false, "DOTNETDirectoryServices": false, "DOTNETRemoting": false, "DOTNETMessaging": false, "WCF": false, "MSMQ": false, "DB": false, "NETWORK": false } }, "Snapshots": true, @@ -172,47 +103,16 @@ "Tiers": [], "TierType": { "All": true, - "APP_AGENT": false, - "DOT_NET_APP_AGENT": false, - "NATIVE_APP_AGENT": false, - "NATIVE_DYNAMIC": false, - "NATIVE_SDK": false, - "NATIVE_WEB_SERVER": false, - "NODEJS_APP_AGENT": false, - "PHP_APP_AGENT": false, - "PYTHON_APP_AGENT": false, - "RUBY_APP_AGENT": false + "APP_AGENT": false, "DOT_NET_APP_AGENT": false, "NATIVE_APP_AGENT": false, "NATIVE_DYNAMIC": false, "NATIVE_SDK": false, + "NATIVE_WEB_SERVER": false, "NODEJS_APP_AGENT": false, "PHP_APP_AGENT": false, "PYTHON_APP_AGENT": false, "RUBY_APP_AGENT": false }, "BusinessTransactions": [], "BusinessTransactionType": { "All": true, - "SERVLET": false, - "HTTP": false, - "WEB_SERVICE": false, - "POJO": false, - "JMS": false, - "EJB": false, - "SPRING_BEAN": false, - "STRUTS_ACTION": false, - "ASP_DOTNET": false, - "ASP_DOTNET_WEB_SERVICE": false, - "DOTNET_REMOTING": false, - "WCF": false, - "DOTNET_JMS": false, - "POCO": false, - "PHP_WEB": false, - "PHP_MVC": false, - "PHP_DRUPAL": false, - "PHP_WORDPRESS": false, - "PHP_CLI": false, - "PHP_WEB_SERVICE": false, - "NODEJS_WEB": false, - "NATIVE": false, - "WEB": false, - "PYTHON_WEB": false, - "RUBY_WEB": false, - "RUBY_RAILS": false, - "BINARY_REMOTING": false + "SERVLET": false, "HTTP": false, "WEB_SERVICE": false, "POJO": false, "JMS": false, "EJB": false, "SPRING_BEAN": false, "STRUTS_ACTION": false, + "ASP_DOTNET": false, "ASP_DOTNET_WEB_SERVICE": false, "DOTNET_REMOTING": false, "WCF": false, + "DOTNET_JMS": false, "POCO": false, "PHP_WEB": false, "PHP_MVC": false, "PHP_DRUPAL": false,"PHP_WORDPRESS": false, + "PHP_CLI": false, "PHP_WEB_SERVICE": false, "NODEJS_WEB": false, "NATIVE": false, "WEB": false, "PYTHON_WEB": false, "RUBY_WEB": false, "RUBY_RAILS": false, "BINARY_REMOTING": false }, "UserExperience": { "Normal": true, @@ -240,6 +140,7 @@ "EntityDetails": true, "Snapshots": true, "FlameGraphs": true, - "ApplicationSummary": true + "HealthCheck": false, + "ApplicationSummary": false } } \ No newline at end of file diff --git a/EmptyConfig/reference.controller/EmptyAPM.0/CFG/seps.detection.json b/EmptyConfig/reference.controller/EmptyAPM.0/CFG/seps.detection.json new file mode 100644 index 0000000..ddf1ae5 --- /dev/null +++ b/EmptyConfig/reference.controller/EmptyAPM.0/CFG/seps.detection.json @@ -0,0 +1,158 @@ +[ { + "id" : 43, + "version" : 0, + "name" : "SERVLET", + "nameUnique" : true, + "applicationComponentId" : 0, + "enabled" : true, + "discoveryConfig" : { + "namingSchemeType" : "URI", + "properties" : [ { + "id" : 0, + "version" : 0, + "name" : "uri-length", + "value" : "first-n-segments" + }, { + "id" : 0, + "version" : 0, + "name" : "segment-length", + "value" : "2" + } ] + }, + "entryPointType" : "SERVLET", + "entryPointTypeString" : "SERVLET", + "attachedEntity" : { + "id" : 0, + "version" : 0, + "entityType" : "APPLICATION", + "entityId" : 7, + "prettyToString" : null + }, + "agentType" : "APP_AGENT" +}, { + "id" : 44, + "version" : 0, + "name" : "STRUTS_ACTION", + "nameUnique" : true, + "applicationComponentId" : 0, + "enabled" : true, + "discoveryConfig" : { + "namingSchemeType" : "ACTION_NAME_AND_METHOD_NAME", + "properties" : [ ] + }, + "entryPointType" : "STRUTS_ACTION", + "entryPointTypeString" : "STRUTS_ACTION", + "attachedEntity" : { + "id" : 0, + "version" : 0, + "entityType" : "APPLICATION", + "entityId" : 7, + "prettyToString" : null + }, + "agentType" : "APP_AGENT" +}, { + "id" : 46, + "version" : 0, + "name" : "WEB_SERVICE", + "nameUnique" : true, + "applicationComponentId" : 0, + "enabled" : true, + "discoveryConfig" : { + "namingSchemeType" : "SERVICE_NAME_AND_OPERATION_NAME", + "properties" : [ ] + }, + "entryPointType" : "WEB_SERVICE", + "entryPointTypeString" : "WEB_SERVICE", + "attachedEntity" : { + "id" : 0, + "version" : 0, + "entityType" : "APPLICATION", + "entityId" : 7, + "prettyToString" : null + }, + "agentType" : "APP_AGENT" +}, { + "id" : 48, + "version" : 0, + "name" : "POJO", + "nameUnique" : true, + "applicationComponentId" : 0, + "enabled" : true, + "discoveryConfig" : { + "namingSchemeType" : "FULLY_QUALIFIED_CLASS_NAME", + "properties" : [ ] + }, + "entryPointType" : "POJO", + "entryPointTypeString" : "POJO", + "attachedEntity" : { + "id" : 0, + "version" : 0, + "entityType" : "APPLICATION", + "entityId" : 7, + "prettyToString" : null + }, + "agentType" : "APP_AGENT" +}, { + "id" : 47, + "version" : 0, + "name" : "SPRING_BEAN", + "nameUnique" : true, + "applicationComponentId" : 0, + "enabled" : false, + "discoveryConfig" : { + "namingSchemeType" : "BEAN_ID_AND_METHOD_NAME", + "properties" : [ ] + }, + "entryPointType" : "SPRING_BEAN", + "entryPointTypeString" : "SPRING_BEAN", + "attachedEntity" : { + "id" : 0, + "version" : 0, + "entityType" : "APPLICATION", + "entityId" : 7, + "prettyToString" : null + }, + "agentType" : "APP_AGENT" +}, { + "id" : 49, + "version" : 0, + "name" : "EJB", + "nameUnique" : true, + "applicationComponentId" : 0, + "enabled" : false, + "discoveryConfig" : { + "namingSchemeType" : "EJB_NAME_AND_METHOD_NAME", + "properties" : [ ] + }, + "entryPointType" : "EJB", + "entryPointTypeString" : "EJB", + "attachedEntity" : { + "id" : 0, + "version" : 0, + "entityType" : "APPLICATION", + "entityId" : 7, + "prettyToString" : null + }, + "agentType" : "APP_AGENT" +}, { + "id" : 45, + "version" : 0, + "name" : "JMS", + "nameUnique" : true, + "applicationComponentId" : 0, + "enabled" : true, + "discoveryConfig" : { + "namingSchemeType" : "DESTINATION_NAME", + "properties" : [ ] + }, + "entryPointType" : "JMS", + "entryPointTypeString" : "JMS", + "attachedEntity" : { + "id" : 0, + "version" : 0, + "entityType" : "APPLICATION", + "entityId" : 7, + "prettyToString" : null + }, + "agentType" : "APP_AGENT" +} ] \ No newline at end of file diff --git a/EmptyConfig/reference.controller/EmptyAPM.0/CFG/seps.json b/EmptyConfig/reference.controller/EmptyAPM.0/CFG/seps.json deleted file mode 100644 index 2af631b..0000000 --- a/EmptyConfig/reference.controller/EmptyAPM.0/CFG/seps.json +++ /dev/null @@ -1 +0,0 @@ -{"applicationId": "1754","applicationName": "endor-app","sepContainer": [{"entityType": "APPLICATION","entityId": "1754","agentType": "DOT_NET_APP_AGENT","override": true},{"entityType": "APPLICATION","entityId": "1754","agentType": "NODEJS_APP_AGENT","override": true},{"entityType": "APPLICATION","entityId": "1754","agentType": "APP_AGENT","override": true,"sEPMatchPointConfigs": [{"id": "10492","name": "EJB","enabled": false,"entryPointType": "EJB","namingSchemeType": "EJB_NAME_AND_METHOD_NAME"},{"id": "10488","name": "JMS","enabled": true,"entryPointType": "JMS","namingSchemeType": "DESTINATION_NAME"},{"id": "10489","name": "POJO","enabled": true,"entryPointType": "POJO","namingSchemeType": "FULLY_QUALIFIED_CLASS_NAME"},{"id": "10491","name": "SERVLET","enabled": true,"entryPointType": "SERVLET","namingSchemeType": "URI","namingSchemeProperties": "uri-length;first-n-segments;segment-length;2;"},{"id": "10487","name": "SPRING_BEAN","enabled": false,"entryPointType": "SPRING_BEAN","namingSchemeType": "BEAN_ID_AND_METHOD_NAME"},{"id": "10490","name": "STRUTS_ACTION","enabled": true,"entryPointType": "STRUTS_ACTION","namingSchemeType": "ACTION_NAME_AND_METHOD_NAME"},{"id": "10493","name": "WEB_SERVICE","enabled": true,"entryPointType": "WEB_SERVICE","namingSchemeType": "SERVICE_NAME_AND_OPERATION_NAME"}]},{"entityType": "APPLICATION","entityId": "1754","agentType": "PHP_APP_AGENT","override": true}],"actions": [{"href": "http://arb.saas.appdynamics.com/api/accounts/105/applications/1754/sep","method": ["POST"],"name": "SEP_CREATE_UPDATE"}],"links": [{"href": "http://arb.saas.appdynamics.com/api/accounts/105/applications/1754/sep/{tier.id}","name": "sep"}]} \ No newline at end of file diff --git a/HealthCheckSettingMapping.csv b/HealthCheckSettingMapping.csv new file mode 100644 index 0000000..6a4fde1 --- /dev/null +++ b/HealthCheckSettingMapping.csv @@ -0,0 +1,21 @@ +Name,Value,DataType +LatestControllerVersion,4.5.16,Version +LatestAppAgentVersion,4.5.10,Version +LatestMachineAgentVersion,4.5.10,Version +ApplicationErrorPercentageCritical,80,Decimal +ApplicationErrorPercentageWarning,50,Decimal +TierErrorPercentageCritical,80,Decimal +TierErrorPercentageWarning,50,Decimal +NodeErrorPercentageCritical,80,Decimal +NodeErrorPercentageWarning,50,Decimal +BusinessTransactionErrorPercentageCritical,80,Decimal +BusinessTransactionErrorPercentageWarning,50,Decimal +TierAvailabilityPercentageCritical,10,Decimal +TierAvailabilityPercentageWarning,30,Decimal +NodeAvailabilityPercentageCritical,25,Decimal +NodeAvailabilityPercentageWarning,50,Decimal +APMApplicationNameLengthGrade5,30,Integer +APMApplicationNameLengthGrade4,40,Integer +APMApplicationNameLengthGrade3,50,Integer +APMApplicationNameLengthGrade2,60,Integer +APMApplicationNameEnvironmentRegex,(production|prod|qa|test|tst|nonprod|perf|performance|sit|clt|dev|uat|poc|pov|demo|stage|stg),String diff --git a/ProcessingSteps/Extract/ExtractAPMConfiguration.cs b/ProcessingSteps/Extract/ExtractAPMConfiguration.cs index be70f4f..27a9e0f 100644 --- a/ProcessingSteps/Extract/ExtractAPMConfiguration.cs +++ b/ProcessingSteps/Extract/ExtractAPMConfiguration.cs @@ -1,5 +1,7 @@ -using AppDynamics.Dexter.ReportObjectMaps; +using AppDynamics.Dexter.DataObjects; +using AppDynamics.Dexter.ReportObjectMaps; using AppDynamics.Dexter.ReportObjects; +using Newtonsoft.Json; using Newtonsoft.Json.Linq; using System; using System.Collections.Generic; @@ -93,26 +95,62 @@ public override bool Execute(ProgramOptions programOptions, JobConfiguration job #region Service Endpoints // SEPs are not included in the extracted XML - // There is Flash/Flex API but I am not going to call it - // Otherwise there is accounts API https://docs.appdynamics.com/display/PRO45/Access+Swagger+and+Accounts+API - // This includes this one: - // GET /accounts/{acctId}/applications/{appId}/sep Get all ServiceEndPointConfigs for application - // It requires pretty high admin level access but hey, it's not Flash - - loggerConsole.Info("Service Endpoint Configuration"); + // 2018: + // There is Flash/Flex API but I am not going to call it + // Otherwise there is accounts API https://docs.appdynamics.com/display/PRO45/Access+Swagger+and+Accounts+API + // This includes this one: + // GET /accounts/{acctId}/applications/{appId}/sep Get all ServiceEndPointConfigs for application + // It requires pretty high admin level access but hey, it's not Flash + // 12/19/2019: + // Previous API is removed, so we're going to call the RESTUI API + + loggerConsole.Info("Service Endpoint Detection"); + + if (File.Exists(FilePathMap.APMApplicationConfigurationSEPDetectionRulesDataFilePath(jobTarget)) == false) + { + string applicationConfigSEPJSON = controllerApi.GetAPMSEPAutodetectionConfiguration(jobTarget.ApplicationID); + if (applicationConfigSEPJSON != String.Empty) FileIOHelper.SaveFileToPath(applicationConfigSEPJSON, FilePathMap.APMApplicationConfigurationSEPDetectionRulesDataFilePath(jobTarget)); + } - if (File.Exists(FilePathMap.APMApplicationConfigurationSEPDataFilePath(jobTarget)) == false) + string tiersJSON = controllerApi.GetAPMTiers(jobTarget.ApplicationID); + if (tiersJSON != String.Empty) { - string myAccountJSON = controllerApi.GetAccountsMyAccount(); - if (myAccountJSON != String.Empty) + List tiersRESTList = JsonConvert.DeserializeObject>(tiersJSON); + if (tiersRESTList != null) { - JObject myAccount = JObject.Parse(myAccountJSON); - if (myAccount != null) + loggerConsole.Info("Service Endpoint Detection for Tiers"); + foreach (AppDRESTTier tier in tiersRESTList) + { + string tierConfigOverrideJSON = controllerApi.GetAPMSEPTierConfigurationOverride(tier.id, tier.agentType); + if (tierConfigOverrideJSON != String.Empty) + { + JObject tierOverrideObject = JObject.Parse(tierConfigOverrideJSON); + if (tierOverrideObject != null) + { + if (getBoolValueFromJToken(tierOverrideObject, "override") == true) + { + loggerConsole.Info("Service Endpoint Detection for Tier {0}", tier.name); + + string tierConfigSEPJSON = controllerApi.GetAPMSEPTierAutodetectionConfiguration(tier.id, tier.agentType); + if (tierConfigSEPJSON != String.Empty && tierConfigSEPJSON != "[]" && tierConfigSEPJSON != "[ ]") + { + FileIOHelper.SaveFileToPath(tierConfigSEPJSON, FilePathMap.APMApplicationConfigurationSEPTierDetectionRulesDataFilePath(jobTarget, tier)); + } + } + } + } + } + + loggerConsole.Info("Explicit Service Endpoint Rules for Tiers"); + foreach (AppDRESTTier tier in tiersRESTList) { - long accountID = getLongValueFromJToken(myAccount, "id"); + string tierConfigSEPJSON = controllerApi.GetAPMSEPTierRules(tier.id, tier.agentType); + if (tierConfigSEPJSON != String.Empty && tierConfigSEPJSON != "[]" && tierConfigSEPJSON != "[ ]") + { + loggerConsole.Info("Service Endpoint Rule for Tier {0}", tier.name); - string applicationConfigSEPJSON = controllerApi.GetAPMSEPConfiguration(accountID, jobTarget.ApplicationID); - if (applicationConfigSEPJSON != String.Empty) FileIOHelper.SaveFileToPath(applicationConfigSEPJSON, FilePathMap.APMApplicationConfigurationSEPDataFilePath(jobTarget)); + FileIOHelper.SaveFileToPath(tierConfigSEPJSON, FilePathMap.APMApplicationConfigurationSEPTierExplicitRulesDataFilePath(jobTarget, tier)); + } } } } diff --git a/ProcessingSteps/Extract/ExtractAPMEntityDashboardScreenshots.cs b/ProcessingSteps/Extract/ExtractAPMEntityDashboardScreenshots.cs index 0559d7e..924e444 100644 --- a/ProcessingSteps/Extract/ExtractAPMEntityDashboardScreenshots.cs +++ b/ProcessingSteps/Extract/ExtractAPMEntityDashboardScreenshots.cs @@ -122,7 +122,7 @@ public override bool Execute(ProgramOptions programOptions, JobConfiguration job ChromeOptions options = new ChromeOptions(); options.AcceptInsecureCertificates = true; - //options.AddArgument("--headless"); + options.AddArgument("--headless"); options.AddArgument("--guest"); options.AddArgument("--disable-extensions"); diff --git a/ProcessingSteps/Extract/ExtractAPMSnapshots.cs b/ProcessingSteps/Extract/ExtractAPMSnapshots.cs index ef4e9fc..501ec22 100644 --- a/ProcessingSteps/Extract/ExtractAPMSnapshots.cs +++ b/ProcessingSteps/Extract/ExtractAPMSnapshots.cs @@ -215,7 +215,7 @@ public override bool Execute(ProgramOptions programOptions, JobConfiguration job } else { - logger.Warn("Snapshot list retrival call unexpectedly did not have any evidence of continuation CursorId"); + logger.Warn("Snapshot list retrieval call unexpectedly did not have any evidence of continuation CursorId"); } logger.Info("Retrieved snapshots from Controller {0}, Application {1}, From {2:o}, To {3:o}', number of snapshots {4}, continuation type {5}, continuation CursorId {6}", jobTarget.Controller, jobTarget.Application, jobTimeRange.From, jobTimeRange.To, retrievedSnapshotsArray.Count, serverCursorIdType, serverCursorId); diff --git a/ProcessingSteps/FilePathMap.cs b/ProcessingSteps/FilePathMap.cs index 3448461..4abc028 100644 --- a/ProcessingSteps/FilePathMap.cs +++ b/ProcessingSteps/FilePathMap.cs @@ -49,6 +49,9 @@ public class FilePathMap private const string CONTROLLER_RBAC_FOLDER_NAME = "RBAC"; + private const string HEALTHCHECK_FOLDER_NAME = "HEALTH"; + private const string HEALTHCHECK_APM_FOLDER_NAME = "HEALTHAPM"; + #endregion #region Constants for the folder and file names of data extract @@ -60,7 +63,9 @@ public class FilePathMap // Controller wide settings file names private const string EXTRACT_CONFIGURATION_APPLICATION_FILE_NAME = "configuration.xml"; private const string EXTRACT_CONFIGURATION_APPLICATION_DETAILS_FILE_NAME = "configuration.json"; - private const string EXTRACT_CONFIGURATION_APPLICATION_SEP_FILE_NAME = "seps.json"; + private const string EXTRACT_CONFIGURATION_APPLICATION_SEP_DETECTION_FILE_NAME = "seps.detection.json"; + private const string EXTRACT_CONFIGURATION_APPLICATION_TIER_SEP_DETECTION_FILE_NAME = "seps.detection.{0}.json"; + private const string EXTRACT_CONFIGURATION_APPLICATION_TIER_SEP_EXPLICIT_FILE_NAME = "seps.rules.{0}.json"; private const string EXTRACT_CONTROLLER_VERSION_FILE_NAME = "controllerversion.xml"; private const string EXTRACT_HTTP_TEMPLATES_FILE_NAME = "templateshttp.json"; @@ -314,7 +319,8 @@ public class FilePathMap private const string CONVERT_CONFIG_BUSINESS_TRANSACTION_ENTRY_RULES_FILE_NAME = "btentry.rules.csv"; private const string CONVERT_CONFIG_BUSINESS_TRANSACTION_ENTRY_RULES_2_0_FILE_NAME = "btentry.rules.2.0.csv"; private const string CONVERT_CONFIG_BUSINESS_TRANSACTION_ENTRY_SCOPES_FILE_NAME = "btentry.scopes.csv"; - private const string CONVERT_CONFIG_SERVICE_ENDPOINT_ENTRY_RULES_FILE_NAME = "sep.rules.csv"; + private const string CONVERT_CONFIG_SERVICE_ENDPOINT_DISCOVERY_RULES_FILE_NAME = "sep.discovery.csv"; + private const string CONVERT_CONFIG_SERVICE_ENDPOINT_ENTRY_RULES_FILE_NAME = "sep.entry.csv"; private const string CONVERT_CONFIG_BACKEND_DISCOVERY_RULES_FILE_NAME = "backend.rules.csv"; private const string CONVERT_CONFIG_CUSTOM_EXIT_RULES_FILE_NAME = "customexit.rules.csv"; private const string CONVERT_CONFIG_INFORMATION_POINT_RULES_FILE_NAME = "infopoints.csv"; @@ -415,6 +421,9 @@ public class FilePathMap private const string CONVERT_ACTIVITY_GRIDS_PERMINUTE_FILE_NAME = "activitygrids.perminute.full.csv"; private const string CONVERT_ALL_ACTIVITY_GRIDS_PERMINUTE_FILE_NAME = "{0}.activitygrids.perminute.full.csv"; + // Health check conversion file names + private const string CONVERT_HEALTH_CHECK_RULE_RESULTS_FILE_NAME = "healthcheck.rule.results.csv"; + #endregion #region Constants for the folder and file names of data reports @@ -439,6 +448,7 @@ public class FilePathMap private const string REPORT_LICENSES_FILE_NAME = "Licenses.{0}.{1:yyyyMMddHHmm}-{2:yyyyMMddHHmm}.xlsx"; private const string REPORT_APPLICATIONS_DASHBOARDS_FILE_NAME = "ApplicationsDashboards.{0}.{1:yyyyMMddHHmm}-{2:yyyyMMddHHmm}.html"; private const string REPORT_APPLICATION_DASHBOARDS_FILE_NAME = "ApplicationDashboards.html"; + private const string REPORT_HEALTH_CHECK_RESULTS_APM_FILE_NAME = "HealthCheck.APM.{0}.{1:yyyyMMddHHmm}-{2:yyyyMMddHHmm}.xlsx"; // Per entity report names private const string REPORT_ENTITY_DETAILS_APPLICATION_FILE_NAME = "EntityDetails.{0}.{1}.{2:yyyyMMddHHmm}-{3:yyyyMMddHHmm}.xlsx"; @@ -476,6 +486,9 @@ public class FilePathMap // Settings for the metric extracts private const string ENTITY_METRICS_EXTRACT_MAPPING_FILE_NAME = "EntityMetricsExtractMapping.csv"; + // Settings for the metric extracts + private const string HEALTH_CHECK_SETTING_MAPPING_FILE_NAME = "HealthCheckSettingMapping.csv"; + // Flame graph template SVG XML file private const string FLAME_GRAPH_TEMPLATE_FILE_NAME = "FlameGraphTemplate.svg"; @@ -3723,15 +3736,75 @@ public string APMApplicationConfigurationDetailsDataFilePath(JobTarget jobTarget } - public string APMApplicationConfigurationSEPDataFilePath(JobTarget jobTarget) + public string APMApplicationConfigurationSEPDetectionRulesDataFilePath(JobTarget jobTarget) + { + return Path.Combine( + this.ProgramOptions.OutputJobFolderPath, + DATA_FOLDER_NAME, + getFileSystemSafeString(getControllerNameForFileSystem(jobTarget.Controller)), + getShortenedEntityNameForFileSystem(jobTarget.Application, jobTarget.ApplicationID), + CONFIGURATION_FOLDER_NAME, + EXTRACT_CONFIGURATION_APPLICATION_SEP_DETECTION_FILE_NAME); + } + + public string APMApplicationConfigurationSEPTierDetectionRulesDataFilePath(JobTarget jobTarget, AppDRESTTier tier) + { + string reportFileName = String.Format( + EXTRACT_CONFIGURATION_APPLICATION_TIER_SEP_DETECTION_FILE_NAME, + getShortenedEntityNameForFileSystem(tier.name, tier.id)); + + return Path.Combine( + this.ProgramOptions.OutputJobFolderPath, + DATA_FOLDER_NAME, + getFileSystemSafeString(getControllerNameForFileSystem(jobTarget.Controller)), + getShortenedEntityNameForFileSystem(jobTarget.Application, jobTarget.ApplicationID), + CONFIGURATION_FOLDER_NAME, + reportFileName); + } + + public string APMApplicationConfigurationSEPTierDetectionRulesDataFilePath(JobTarget jobTarget, APMTier tier) + { + string reportFileName = String.Format( + EXTRACT_CONFIGURATION_APPLICATION_TIER_SEP_DETECTION_FILE_NAME, + getShortenedEntityNameForFileSystem(tier.TierName, tier.TierID)); + + return Path.Combine( + this.ProgramOptions.OutputJobFolderPath, + DATA_FOLDER_NAME, + getFileSystemSafeString(getControllerNameForFileSystem(jobTarget.Controller)), + getShortenedEntityNameForFileSystem(jobTarget.Application, jobTarget.ApplicationID), + CONFIGURATION_FOLDER_NAME, + reportFileName); + } + + public string APMApplicationConfigurationSEPTierExplicitRulesDataFilePath(JobTarget jobTarget, AppDRESTTier tier) + { + string reportFileName = String.Format( + EXTRACT_CONFIGURATION_APPLICATION_TIER_SEP_EXPLICIT_FILE_NAME, + getShortenedEntityNameForFileSystem(tier.name, tier.id)); + + return Path.Combine( + this.ProgramOptions.OutputJobFolderPath, + DATA_FOLDER_NAME, + getFileSystemSafeString(getControllerNameForFileSystem(jobTarget.Controller)), + getShortenedEntityNameForFileSystem(jobTarget.Application, jobTarget.ApplicationID), + CONFIGURATION_FOLDER_NAME, + reportFileName); + } + + public string APMApplicationConfigurationSEPTierExplicitRulesDataFilePath(JobTarget jobTarget, APMTier tier) { + string reportFileName = String.Format( + EXTRACT_CONFIGURATION_APPLICATION_TIER_SEP_EXPLICIT_FILE_NAME, + getShortenedEntityNameForFileSystem(tier.TierName, tier.TierID)); + return Path.Combine( this.ProgramOptions.OutputJobFolderPath, DATA_FOLDER_NAME, getFileSystemSafeString(getControllerNameForFileSystem(jobTarget.Controller)), getShortenedEntityNameForFileSystem(jobTarget.Application, jobTarget.ApplicationID), CONFIGURATION_FOLDER_NAME, - EXTRACT_CONFIGURATION_APPLICATION_SEP_FILE_NAME); + reportFileName); } public string APMApplicationDeveloperModeNodesDataFilePath(JobTarget jobTarget) @@ -3782,6 +3855,17 @@ public string APMBusinessTransactionEntryRulesIndexFilePath(JobTarget jobTarget) CONVERT_CONFIG_BUSINESS_TRANSACTION_ENTRY_RULES_FILE_NAME); } + public string APMServiceEndpointDiscoveryRulesIndexFilePath(JobTarget jobTarget) + { + return Path.Combine( + this.ProgramOptions.OutputJobFolderPath, + INDEX_FOLDER_NAME, + getFileSystemSafeString(getControllerNameForFileSystem(jobTarget.Controller)), + getShortenedEntityNameForFileSystem(jobTarget.Application, jobTarget.ApplicationID), + CONFIGURATION_FOLDER_NAME, + CONVERT_CONFIG_SERVICE_ENDPOINT_DISCOVERY_RULES_FILE_NAME); + } + public string APMServiceEndpointEntryRulesIndexFilePath(JobTarget jobTarget) { return Path.Combine( @@ -4041,6 +4125,15 @@ public string APMBusinessTransactionEntryRulesReportFilePath() CONVERT_CONFIG_BUSINESS_TRANSACTION_ENTRY_RULES_FILE_NAME); } + public string APMServiceEndpointDiscoveryRulesReportFilePath() + { + return Path.Combine( + this.ProgramOptions.OutputJobFolderPath, + REPORT_FOLDER_NAME, + CONFIGURATION_APM_FOLDER_NAME, + CONVERT_CONFIG_SERVICE_ENDPOINT_DISCOVERY_RULES_FILE_NAME); + } + public string APMServiceEndpointEntryRulesReportFilePath() { return Path.Combine( @@ -4305,6 +4398,63 @@ public string ConfigurationComparisonReportFilePath() #endregion + #region APM Health Check Index + + public string APMHealthCheckRuleResultsIndexFilePath(JobTarget jobTarget) + { + return Path.Combine( + this.ProgramOptions.OutputJobFolderPath, + INDEX_FOLDER_NAME, + getFileSystemSafeString(getControllerNameForFileSystem(jobTarget.Controller)), + getShortenedEntityNameForFileSystem(jobTarget.Application, jobTarget.ApplicationID), + HEALTHCHECK_FOLDER_NAME, + CONVERT_HEALTH_CHECK_RULE_RESULTS_FILE_NAME); + } + + #endregion + + #region APM Health Check Report + + public string HealthCheckSettingMappingFilePath() + { + return Path.Combine( + this.ProgramOptions.ProgramLocationFolderPath, + HEALTH_CHECK_SETTING_MAPPING_FILE_NAME); + } + + public string APMHealthCheckReportFolderPath() + { + return Path.Combine( + this.ProgramOptions.OutputJobFolderPath, + REPORT_FOLDER_NAME, + HEALTHCHECK_APM_FOLDER_NAME); + } + + public string APMHealthCheckRuleResultsReportFilePath() + { + return Path.Combine( + this.ProgramOptions.OutputJobFolderPath, + REPORT_FOLDER_NAME, + HEALTHCHECK_APM_FOLDER_NAME, + CONVERT_HEALTH_CHECK_RULE_RESULTS_FILE_NAME); + } + + public string APMHealthCheckResultsExcelReportFilePath(JobTimeRange jobTimeRange) + { + string reportFileName = String.Format( + REPORT_HEALTH_CHECK_RESULTS_APM_FILE_NAME, + this.ProgramOptions.JobName, + jobTimeRange.From, + jobTimeRange.To); + return Path.Combine( + this.ProgramOptions.OutputJobFolderPath, + REPORT_FOLDER_NAME, + reportFileName); + } + + #endregion + + #region RBAC Data public string UsersDataFilePath(JobTarget jobTarget) @@ -6679,6 +6829,8 @@ public string ApplicationSummaryWordReportFilePath(JobTarget jobTarget, JobTimeR public static string getFileSystemSafeString(string fileOrFolderNameToClear) { + if (fileOrFolderNameToClear == null) fileOrFolderNameToClear = String.Empty; + foreach (var c in Path.GetInvalidFileNameChars()) { fileOrFolderNameToClear = fileOrFolderNameToClear.Replace(c, '-'); diff --git a/ProcessingSteps/Index/IndexAPMConfiguration.cs b/ProcessingSteps/Index/IndexAPMConfiguration.cs index 26e1b03..a3555fd 100644 --- a/ProcessingSteps/Index/IndexAPMConfiguration.cs +++ b/ProcessingSteps/Index/IndexAPMConfiguration.cs @@ -128,6 +128,7 @@ public override bool Execute(ProgramOptions programOptions, JobConfiguration job if (configXml == null) { logger.Warn("No application configuration in {0} file", FilePathMap.APMApplicationConfigurationXMLDataFilePath(jobTarget)); + loggerConsole.Warn("No application configuration in {0} file", FilePathMap.APMApplicationConfigurationXMLDataFilePath(jobTarget)); continue; } @@ -377,118 +378,69 @@ public override bool Execute(ProgramOptions programOptions, JobConfiguration job #endregion - #region Service Endpoint Rules + #region Service Endpoint Discovery and Entry Rules - loggerConsole.Info("Service Endpoint Rules"); + loggerConsole.Info("Service Endpoint Discovery Rules"); - List serviceEndpointEntryRulesList = new List(); + List serviceEndpointDiscoveryRulesList = new List(); - JObject serviceEndpointsContainer = FileIOHelper.LoadJObjectFromFile(FilePathMap.APMApplicationConfigurationSEPDataFilePath(jobTarget)); - if (serviceEndpointsContainer != null && isTokenPropertyNull(serviceEndpointsContainer, "sepContainer") == false) + // SEP Autodetection Rules for App + JArray serviceEndpointsArray = FileIOHelper.LoadJArrayFromFile(FilePathMap.APMApplicationConfigurationSEPDetectionRulesDataFilePath(jobTarget)); + if (serviceEndpointsArray != null) { - foreach (JObject serviceEndpointContainer in serviceEndpointsContainer["sepContainer"]) + foreach (JObject serviceEndpointObject in serviceEndpointsArray) { - // SEP Autodetection Rules - if (getStringValueFromJToken(serviceEndpointContainer, "entityType") == "APPLICATION") + ServiceEndpointDiscoveryRule serviceEndpointDiscoveryRule = fillServiceEnpointDiscoveryRule(serviceEndpointObject, null, applicationConfiguration); + serviceEndpointDiscoveryRulesList.Add(serviceEndpointDiscoveryRule); + } + } + + // SEP Autodetection Rules for Tiers overrides + if (tiersThisAppList != null) + { + foreach (APMTier tier in tiersThisAppList) + { + JArray serviceEndpointsTierArray = FileIOHelper.LoadJArrayFromFile(FilePathMap.APMApplicationConfigurationSEPTierDetectionRulesDataFilePath(jobTarget, tier)); + if (serviceEndpointsTierArray != null) { - if (isTokenPropertyNull(serviceEndpointContainer, "sEPMatchPointConfigs") == false) + foreach (JObject serviceEndpointRuleObject in serviceEndpointsTierArray) { - foreach (JObject serviceEndpoint in serviceEndpointContainer["sEPMatchPointConfigs"]) - { - ServiceEndpointEntryRule serviceEndpointEntryRule = new ServiceEndpointEntryRule(); + ServiceEndpointDiscoveryRule serviceEndpointDiscoveryRule = fillServiceEnpointDiscoveryRule(serviceEndpointRuleObject, tier, applicationConfiguration); + serviceEndpointDiscoveryRulesList.Add(serviceEndpointDiscoveryRule); + } + } + } + } - serviceEndpointEntryRule.Controller = applicationConfiguration.Controller; - serviceEndpointEntryRule.ControllerLink = applicationConfiguration.ControllerLink; - serviceEndpointEntryRule.ApplicationName = applicationConfiguration.ApplicationName; - serviceEndpointEntryRule.ApplicationID = applicationConfiguration.ApplicationID; - serviceEndpointEntryRule.ApplicationLink = applicationConfiguration.ApplicationLink; + applicationConfiguration.NumSEPDiscoveryRules = serviceEndpointDiscoveryRulesList.Count; - serviceEndpointEntryRule.AgentType = getStringValueFromJToken(serviceEndpointContainer, "agentType"); - serviceEndpointEntryRule.RuleName = getStringValueFromJToken(serviceEndpoint, "name"); - serviceEndpointEntryRule.EntryPointType = getStringValueFromJToken(serviceEndpoint, "entryPointType"); - serviceEndpointEntryRule.IsOverride = getBoolValueFromJToken(serviceEndpointContainer, "override"); - serviceEndpointEntryRule.IsMonitoringEnabled = getBoolValueFromJToken(serviceEndpoint, "enabled"); - serviceEndpointEntryRule.NamingConfigType = getStringValueFromJToken(serviceEndpoint, "namingSchemeType"); + serviceEndpointDiscoveryRulesList = serviceEndpointDiscoveryRulesList.OrderBy(b => b.TierName).ThenBy(b => b.AgentType).ThenBy(b => b.EntryPointType).ToList(); + FileIOHelper.WriteListToCSVFile(serviceEndpointDiscoveryRulesList, new ServiceEndpointDiscoveryRuleReportMap(), FilePathMap.APMServiceEndpointDiscoveryRulesIndexFilePath(jobTarget)); - serviceEndpointEntryRule.DiscoveryType = getStringValueFromJToken(serviceEndpoint, "namingSchemeProperties"); + stepTimingTarget.NumEntities = stepTimingTarget.NumEntities + serviceEndpointDiscoveryRulesList.Count; - serviceEndpointEntryRulesList.Add(serviceEndpointEntryRule); - } - } - } - } - foreach (JObject serviceEndpointContainer in serviceEndpointsContainer["sepContainer"]) + loggerConsole.Info("Custom Service Endpoint Entry Rules"); + + List serviceEndpointEntryRulesList = new List(); + + if (tiersThisAppList != null) + { + foreach (APMTier tier in tiersThisAppList) { - // Explicit SEP rule - if (getStringValueFromJToken(serviceEndpointContainer, "entityType") == "APPLICATION_COMPONENT") + JArray serviceEndpointRulesInTierArray = FileIOHelper.LoadJArrayFromFile(FilePathMap.APMApplicationConfigurationSEPTierExplicitRulesDataFilePath(jobTarget, tier)); + if (serviceEndpointRulesInTierArray != null) { - if (isTokenPropertyNull(serviceEndpointContainer, "sEPDefinitions") == false) + foreach (JObject serviceEndpointRuleObject in serviceEndpointRulesInTierArray) { - foreach (JObject serviceEndpointObject in serviceEndpointContainer["sEPDefinitions"]) - { - ServiceEndpointEntryRule serviceEndpointEntryRule = new ServiceEndpointEntryRule(); - - serviceEndpointEntryRule.Controller = applicationConfiguration.Controller; - serviceEndpointEntryRule.ControllerLink = applicationConfiguration.ControllerLink; - serviceEndpointEntryRule.ApplicationName = applicationConfiguration.ApplicationName; - serviceEndpointEntryRule.ApplicationID = applicationConfiguration.ApplicationID; - serviceEndpointEntryRule.ApplicationLink = applicationConfiguration.ApplicationLink; - - if (tiersThisAppList != null) - { - APMTier tier = tiersThisAppList.Where(t => t.EntityID == getLongValueFromJToken(serviceEndpointContainer, "entityId")).FirstOrDefault(); - if (tier != null) - { - serviceEndpointEntryRule.TierName = tier.TierName; - } - } - - serviceEndpointEntryRule.AgentType = getStringValueFromJToken(serviceEndpointContainer, "agentType"); - serviceEndpointEntryRule.RuleName = getStringValueFromJToken(serviceEndpointObject, "definitionName"); - serviceEndpointEntryRule.EntryPointType = getStringValueFromJToken(serviceEndpointObject, "entryPointType"); - serviceEndpointEntryRule.IsOverride = getBoolValueFromJToken(serviceEndpointContainer, "override"); - serviceEndpointEntryRule.IsMonitoringEnabled = true; - - serviceEndpointEntryRule.RuleRawValue = makeXMLFormattedAndIndented(serviceEndpointObject["MatchPointRuleXml"].ToString()); - - if (serviceEndpointsThisAppList != null) - { - List serviceEndpointsForThisRule = new List(); - - serviceEndpointsForThisRule.AddRange(serviceEndpointsThisAppList.Where(s => s.SEPName == serviceEndpointEntryRule.RuleName).ToList()); - serviceEndpointsForThisRule.AddRange(serviceEndpointsThisAppList.Where(s => s.SEPName.StartsWith(String.Format("{0}.", serviceEndpointEntryRule.RuleName))).ToList()); - serviceEndpointsForThisRule = serviceEndpointsForThisRule.Distinct().ToList(); - serviceEndpointEntryRule.NumDetectedSEPs = serviceEndpointsForThisRule.Count; - if (serviceEndpointsForThisRule.Count > 0) - { - StringBuilder sb = new StringBuilder(32 * serviceEndpointsForThisRule.Count); - foreach (APMServiceEndpoint sep in serviceEndpointsForThisRule) - { - sb.AppendFormat("{0}/{1};\n", sep.TierName, sep.SEPName); - } - sb.Remove(sb.Length - 1, 1); - - serviceEndpointEntryRule.DetectedSEPs = sb.ToString(); - - // Now update the list of Entities to map which rule we are in - foreach (APMServiceEndpoint serviceEndpoint in serviceEndpointsForThisRule) - { - serviceEndpoint.IsExplicitRule = true; - serviceEndpoint.RuleName = String.Format("{0}/{1} [{2}]", serviceEndpointEntryRule.TierName, serviceEndpointEntryRule.RuleName, serviceEndpointEntryRule.EntryPointType); - serviceEndpoint.RuleName = serviceEndpoint.RuleName.TrimStart('/'); - } - } - } - - serviceEndpointEntryRulesList.Add(serviceEndpointEntryRule); - } + ServiceEndpointEntryRule serviceEndpointEntryRule = fillServiceEnpointEntryRule(serviceEndpointRuleObject, tier, applicationConfiguration, serviceEndpointsThisAppList); + serviceEndpointEntryRulesList.Add(serviceEndpointEntryRule); } } } } - applicationConfiguration.NumSEPRules = serviceEndpointEntryRulesList.Count; + applicationConfiguration.NumSEPEntryRules = serviceEndpointEntryRulesList.Count; serviceEndpointEntryRulesList = serviceEndpointEntryRulesList.OrderBy(b => b.TierName).ThenBy(b => b.AgentType).ThenBy(b => b.EntryPointType).ToList(); FileIOHelper.WriteListToCSVFile(serviceEndpointEntryRulesList, new ServiceEndpointEntryRuleReportMap(), FilePathMap.APMServiceEndpointEntryRulesIndexFilePath(jobTarget)); @@ -1386,8 +1338,11 @@ public override bool Execute(ProgramOptions programOptions, JobConfiguration job #region Save the updated Backends, Business Transactions and Service Endpoints FileIOHelper.WriteListToCSVFile(backendsList, new APMBackendReportMap(), FilePathMap.APMBackendsReportFilePath()); + FileIOHelper.WriteListToCSVFile(backendsThisAppList, new APMBackendReportMap(), FilePathMap.APMBackendsIndexFilePath(jobTarget)); FileIOHelper.WriteListToCSVFile(businessTransactionsList, new APMBusinessTransactionReportMap(), FilePathMap.APMBusinessTransactionsReportFilePath()); + FileIOHelper.WriteListToCSVFile(businessTransactionsThisAppList, new APMBusinessTransactionReportMap(), FilePathMap.APMBusinessTransactionsIndexFilePath(jobTarget)); FileIOHelper.WriteListToCSVFile(serviceEndpointsList, new APMServiceEndpointReportMap(), FilePathMap.APMServiceEndpointsReportFilePath()); + FileIOHelper.WriteListToCSVFile(serviceEndpointsThisAppList, new APMServiceEndpointReportMap(), FilePathMap.APMServiceEndpointsIndexFilePath(jobTarget)); #endregion @@ -1415,6 +1370,10 @@ public override bool Execute(ProgramOptions programOptions, JobConfiguration job { FileIOHelper.AppendTwoCSVFiles(FilePathMap.APMBusinessTransactionEntryRulesReportFilePath(), FilePathMap.APMBusinessTransactionEntryRulesIndexFilePath(jobTarget)); } + if (File.Exists(FilePathMap.APMServiceEndpointDiscoveryRulesIndexFilePath(jobTarget)) == true && new FileInfo(FilePathMap.APMServiceEndpointDiscoveryRulesIndexFilePath(jobTarget)).Length > 0) + { + FileIOHelper.AppendTwoCSVFiles(FilePathMap.APMServiceEndpointDiscoveryRulesReportFilePath(), FilePathMap.APMServiceEndpointDiscoveryRulesIndexFilePath(jobTarget)); + } if (File.Exists(FilePathMap.APMServiceEndpointEntryRulesIndexFilePath(jobTarget)) == true && new FileInfo(FilePathMap.APMServiceEndpointEntryRulesIndexFilePath(jobTarget)).Length > 0) { FileIOHelper.AppendTwoCSVFiles(FilePathMap.APMServiceEndpointEntryRulesReportFilePath(), FilePathMap.APMServiceEndpointEntryRulesIndexFilePath(jobTarget)); @@ -2022,6 +1981,105 @@ private static BackendDiscoveryRule fillBackendDiscoveryRule(XmlNode backendDisc return backendDiscoveryRule; } + private static ServiceEndpointDiscoveryRule fillServiceEnpointDiscoveryRule(JObject serviceEndpointRuleObject, APMTier tier, APMApplicationConfiguration applicationConfiguration) + { + ServiceEndpointDiscoveryRule serviceEndpointDiscoveryRule = new ServiceEndpointDiscoveryRule(); + + serviceEndpointDiscoveryRule.Controller = applicationConfiguration.Controller; + serviceEndpointDiscoveryRule.ControllerLink = applicationConfiguration.ControllerLink; + serviceEndpointDiscoveryRule.ApplicationName = applicationConfiguration.ApplicationName; + serviceEndpointDiscoveryRule.ApplicationID = applicationConfiguration.ApplicationID; + serviceEndpointDiscoveryRule.ApplicationLink = applicationConfiguration.ApplicationLink; + + serviceEndpointDiscoveryRule.AgentType = getStringValueFromJToken(serviceEndpointRuleObject, "agentType"); + serviceEndpointDiscoveryRule.RuleName = getStringValueFromJToken(serviceEndpointRuleObject, "name"); + serviceEndpointDiscoveryRule.EntryPointType = getStringValueFromJToken(serviceEndpointRuleObject, "entryPointType"); + serviceEndpointDiscoveryRule.Version = getIntValueFromJToken(serviceEndpointRuleObject, "version"); + serviceEndpointDiscoveryRule.IsEnabled = getBoolValueFromJToken(serviceEndpointRuleObject, "enabled"); + if (isTokenPropertyNull(serviceEndpointRuleObject, "discoveryConfig") == false) + { + JObject discoveryConfigObject = (JObject)serviceEndpointRuleObject["discoveryConfig"]; + serviceEndpointDiscoveryRule.NamingConfigType = getStringValueFromJToken(discoveryConfigObject, "namingSchemeType"); + + if (isTokenPropertyNull(discoveryConfigObject, "properties") == false) + { + string[] nameValues = discoveryConfigObject["properties"].Select(s => String.Format("{0}={1}", getStringValueFromJToken(s, "name"), getStringValueFromJToken(s, "value"))).ToArray(); + serviceEndpointDiscoveryRule.DiscoveryType = String.Join(";", nameValues); + } + } + + if (tier != null) serviceEndpointDiscoveryRule.TierName = tier.TierName; + + return serviceEndpointDiscoveryRule; + } + + private static ServiceEndpointEntryRule fillServiceEnpointEntryRule(JObject serviceEndpointRuleObject, APMTier tier, APMApplicationConfiguration applicationConfiguration, List serviceEndpointsList) + { + ServiceEndpointEntryRule serviceEndpointEntryRule = new ServiceEndpointEntryRule(); + + serviceEndpointEntryRule.Controller = applicationConfiguration.Controller; + serviceEndpointEntryRule.ControllerLink = applicationConfiguration.ControllerLink; + serviceEndpointEntryRule.ApplicationName = applicationConfiguration.ApplicationName; + serviceEndpointEntryRule.ApplicationID = applicationConfiguration.ApplicationID; + serviceEndpointEntryRule.ApplicationLink = applicationConfiguration.ApplicationLink; + + serviceEndpointEntryRule.AgentType = getStringValueFromJToken(serviceEndpointRuleObject, "agentType"); + serviceEndpointEntryRule.RuleName = getStringValueFromJToken(serviceEndpointRuleObject, "name"); + serviceEndpointEntryRule.EntryPointType = getStringValueFromJToken(serviceEndpointRuleObject, "entryPointType"); + serviceEndpointEntryRule.Version = getIntValueFromJToken(serviceEndpointRuleObject, "version"); + if (isTokenPropertyNull(serviceEndpointRuleObject, "matchPointRule") == false) + { + JObject discoveryConfigObject = (JObject)serviceEndpointRuleObject["matchPointRule"]; + + serviceEndpointEntryRule.Priority = getIntValueFromJToken(discoveryConfigObject, "priority"); + serviceEndpointEntryRule.IsEnabled = getBoolValueFromJToken(discoveryConfigObject, "enabled"); + serviceEndpointEntryRule.IsExclusion = getBoolValueFromJToken(discoveryConfigObject, "excluded"); + + serviceEndpointEntryRule.MatchConditions = getStringValueOfObjectFromJToken(serviceEndpointRuleObject, "matchPointRule", false); + + // This is for POCO/POJOs + serviceEndpointEntryRule.Actions = getStringValueOfObjectFromJToken(discoveryConfigObject, "splitConfig", false); + + // This is for ASP.NET/Servlet + if (serviceEndpointEntryRule.Actions.Length == 0) + { + serviceEndpointEntryRule.Actions = getStringValueOfObjectFromJToken(discoveryConfigObject, "ruleProperties", false); + } + } + + serviceEndpointEntryRule.TierName = tier.TierName; + + if (serviceEndpointsList != null) + { + List serviceEndpointsForThisRule = new List(); + + serviceEndpointsForThisRule.AddRange(serviceEndpointsList.Where(s => s.SEPName == serviceEndpointEntryRule.RuleName).ToList()); + serviceEndpointsForThisRule.AddRange(serviceEndpointsList.Where(s => s.SEPName.StartsWith(String.Format("{0}.", serviceEndpointEntryRule.RuleName))).ToList()); + serviceEndpointsForThisRule = serviceEndpointsForThisRule.Distinct().ToList(); + serviceEndpointEntryRule.NumDetectedSEPs = serviceEndpointsForThisRule.Count; + if (serviceEndpointsForThisRule.Count > 0) + { + StringBuilder sb = new StringBuilder(32 * serviceEndpointsForThisRule.Count); + foreach (APMServiceEndpoint sep in serviceEndpointsForThisRule) + { + sb.AppendFormat("{0}/{1};\n", sep.TierName, sep.SEPName); + } + sb.Remove(sb.Length - 1, 1); + + serviceEndpointEntryRule.DetectedSEPs = sb.ToString(); + + // Now update the list of Entities to map which rule we are in + foreach (APMServiceEndpoint serviceEndpoint in serviceEndpointsForThisRule) + { + serviceEndpoint.IsExplicitRule = true; + serviceEndpoint.RuleName = String.Format("{0}/{1} [{2}]", serviceEndpointEntryRule.TierName, serviceEndpointEntryRule.RuleName, serviceEndpointEntryRule.EntryPointType); + serviceEndpoint.RuleName = serviceEndpoint.RuleName.TrimStart('/'); + } + } + } + return serviceEndpointEntryRule; + } + private static CustomExitRule fillCustomExitRule(XmlNode backendDiscoveryMatchPointConfigurationNode, XmlNode customExitConfigurationNode, APMApplicationConfiguration applicationConfiguration, XmlNode applicationComponentNode, List backendsList) { CustomExitRule customExitRule = new CustomExitRule(); @@ -2173,6 +2231,8 @@ private static AgentConfigurationProperty fillAgentConfigurationProperty(XmlNode agentConfigurationProperty.TierName = getStringValueFromXmlNode(applicationComponentNode.SelectSingleNode("name")); } + agentConfigurationProperty.IsBuiltIn = AGENT_PROPERTIES_BUILTIN.Contains(agentConfigurationProperty.PropertyName); + return agentConfigurationProperty; } diff --git a/ProcessingSteps/Index/IndexAPMEntities.cs b/ProcessingSteps/Index/IndexAPMEntities.cs index d4f1126..cb02e1e 100644 --- a/ProcessingSteps/Index/IndexAPMEntities.cs +++ b/ProcessingSteps/Index/IndexAPMEntities.cs @@ -770,7 +770,6 @@ public override bool Execute(ProgramOptions programOptions, JobConfiguration job { loggerConsole.Info("Index List of Tiers ({0} entities)", tiersRESTList.Count); - tiersList = new List(tiersRESTList.Count); resolvedBackendsList = new List(tiersRESTList.Count * 10); diff --git a/ProcessingSteps/Index/IndexAPMHealthCheck.cs b/ProcessingSteps/Index/IndexAPMHealthCheck.cs new file mode 100644 index 0000000..2bf9bf7 --- /dev/null +++ b/ProcessingSteps/Index/IndexAPMHealthCheck.cs @@ -0,0 +1,1197 @@ +using AppDynamics.Dexter.DataObjects; +using AppDynamics.Dexter.ReportObjectMaps; +using AppDynamics.Dexter.ReportObjects; +using Newtonsoft.Json.Linq; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Text.RegularExpressions; +using System.Threading; + +namespace AppDynamics.Dexter.ProcessingSteps +{ + public class IndexAPMHealthCheck : JobStepIndexBase + { + public override bool Execute(ProgramOptions programOptions, JobConfiguration jobConfiguration) + { + Stopwatch stopWatch = new Stopwatch(); + stopWatch.Start(); + + StepTiming stepTimingFunction = new StepTiming(); + stepTimingFunction.JobFileName = programOptions.OutputJobFilePath; + stepTimingFunction.StepName = jobConfiguration.Status.ToString(); + stepTimingFunction.StepID = (int)jobConfiguration.Status; + stepTimingFunction.StartTime = DateTime.Now; + stepTimingFunction.NumEntities = jobConfiguration.Target.Count; + + this.DisplayJobStepStartingStatus(jobConfiguration); + + FilePathMap = new FilePathMap(programOptions, jobConfiguration); + + try + { + if (this.ShouldExecute(jobConfiguration) == false) + { + return true; + } + + if (jobConfiguration.Target.Count(t => t.Type == APPLICATION_TYPE_APM) == 0) + { + return true; + } + + bool reportFolderCleaned = false; + + // Process each target + for (int i = 0; i < jobConfiguration.Target.Count; i++) + { + Stopwatch stopWatchTarget = new Stopwatch(); + stopWatchTarget.Start(); + + JobTarget jobTarget = jobConfiguration.Target[i]; + + if (jobTarget.Type != null && jobTarget.Type.Length > 0 && jobTarget.Type != APPLICATION_TYPE_APM) continue; + + StepTiming stepTimingTarget = new StepTiming(); + stepTimingTarget.Controller = jobTarget.Controller; + stepTimingTarget.ApplicationName = jobTarget.Application; + stepTimingTarget.ApplicationID = jobTarget.ApplicationID; + stepTimingTarget.JobFileName = programOptions.OutputJobFilePath; + stepTimingTarget.StepName = jobConfiguration.Status.ToString(); + stepTimingTarget.StepID = (int)jobConfiguration.Status; + stepTimingTarget.StartTime = DateTime.Now; + + try + { + this.DisplayJobTargetStartingStatus(jobConfiguration, jobTarget, i + 1); + + #region Target step variables + + List healthCheckRuleResults = new List(); + + #endregion + + #region Preload all the reports that will be filtered by the subsequent entities + + loggerConsole.Info("Entity Details Data Preloading"); + + // This file will always be there? + List healthCheckSettingsList = FileIOHelper.ReadListFromCSVFile(FilePathMap.HealthCheckSettingMappingFilePath(), new HealthCheckSettingMappingMap()); + if (healthCheckSettingsList == null || healthCheckSettingsList.Count == 0) + { + loggerConsole.Warn("Health check settings file did not load. Exiting the health checks"); + + return false; + } + Dictionary healthCheckSettingsDictionary = healthCheckSettingsList.ToDictionary(h => h.Name, h => h); + + List controllerSummariesList = FileIOHelper.ReadListFromCSVFile(FilePathMap.ControllerSummaryIndexFilePath(jobTarget), new ControllerSummaryReportMap()); + List applicationsList = FileIOHelper.ReadListFromCSVFile(FilePathMap.APMApplicationsIndexFilePath(jobTarget), new APMApplicationReportMap()); + List applicationsMetricsList = FileIOHelper.ReadListFromCSVFile(FilePathMap.EntitiesFullIndexFilePath(jobTarget, APMApplication.ENTITY_FOLDER), new ApplicationMetricReportMap()); + + List tiersList = FileIOHelper.ReadListFromCSVFile(FilePathMap.APMTiersIndexFilePath(jobTarget), new APMTierReportMap()); + List tiersMetricsList = FileIOHelper.ReadListFromCSVFile(FilePathMap.EntitiesFullIndexFilePath(jobTarget, APMTier.ENTITY_FOLDER), new TierMetricReportMap()); + + List nodesList = FileIOHelper.ReadListFromCSVFile(FilePathMap.APMNodesIndexFilePath(jobTarget), new APMNodeReportMap()); + List nodesMetricsList = FileIOHelper.ReadListFromCSVFile(FilePathMap.EntitiesFullIndexFilePath(jobTarget, APMNode.ENTITY_FOLDER), new NodeMetricReportMap()); + + List businessTransactionsList = FileIOHelper.ReadListFromCSVFile(FilePathMap.APMBusinessTransactionsIndexFilePath(jobTarget), new APMBusinessTransactionReportMap()); + List businessTransactionsMetricsList = FileIOHelper.ReadListFromCSVFile(FilePathMap.EntitiesFullIndexFilePath(jobTarget, APMBusinessTransaction.ENTITY_FOLDER), new BusinessTransactionMetricReportMap()); + + List backendsList = FileIOHelper.ReadListFromCSVFile(FilePathMap.APMBackendsIndexFilePath(jobTarget), new APMBackendReportMap()); + List backendsMetricsList = FileIOHelper.ReadListFromCSVFile(FilePathMap.EntitiesFullIndexFilePath(jobTarget, APMBackend.ENTITY_FOLDER), new BackendMetricReportMap()); + + List serviceEndpointsList = FileIOHelper.ReadListFromCSVFile(FilePathMap.APMServiceEndpointsIndexFilePath(jobTarget), new APMServiceEndpointReportMap()); + List serviceEndpointsMetricsList = FileIOHelper.ReadListFromCSVFile(FilePathMap.EntitiesFullIndexFilePath(jobTarget, APMServiceEndpoint.ENTITY_FOLDER), new ServiceEndpointMetricReportMap()); + + List errorsList = FileIOHelper.ReadListFromCSVFile(FilePathMap.APMErrorsIndexFilePath(jobTarget), new APMErrorReportMap()); + List errorsMetricsList = FileIOHelper.ReadListFromCSVFile(FilePathMap.EntitiesFullIndexFilePath(jobTarget, APMError.ENTITY_FOLDER), new ErrorMetricReportMap()); + + List informationPointsList = FileIOHelper.ReadListFromCSVFile(FilePathMap.APMInformationPointsIndexFilePath(jobTarget), new APMInformationPointReportMap()); + List informationPointsMetricsList = FileIOHelper.ReadListFromCSVFile(FilePathMap.EntitiesFullIndexFilePath(jobTarget, APMInformationPoint.ENTITY_FOLDER), new InformationPointMetricReportMap()); + + List resolvedBackendsList = FileIOHelper.ReadListFromCSVFile(FilePathMap.APMMappedBackendsIndexFilePath(jobTarget), new APMResolvedBackendReportMap()); + + //List eventsAllList = FileIOHelper.ReadListFromCSVFile(FilePathMap.ApplicationEventsIndexFilePath(jobTarget), new EventReportMap()); + //List healthRuleViolationEventsAllList = FileIOHelper.ReadListFromCSVFile(FilePathMap.ApplicationHealthRuleViolationsIndexFilePath(jobTarget), new HealthRuleViolationEventReportMap()); + //List snapshotsAllList = FileIOHelper.ReadListFromCSVFile(FilePathMap.SnapshotsIndexFilePath(jobTarget), new SnapshotReportMap()); + //List segmentsAllList = FileIOHelper.ReadListFromCSVFile(FilePathMap.SnapshotsSegmentsIndexFilePath(jobTarget), new SegmentReportMap()); + //List exitCallsAllList = FileIOHelper.ReadListFromCSVFile(FilePathMap.SnapshotsExitCallsIndexFilePath(jobTarget), new ExitCallReportMap()); + //List serviceEndpointCallsAllList = FileIOHelper.ReadListFromCSVFile(FilePathMap.SnapshotsServiceEndpointCallsIndexFilePath(jobTarget), new ServiceEndpointCallReportMap()); + //List detectedErrorsAllList = FileIOHelper.ReadListFromCSVFile(FilePathMap.SnapshotsDetectedErrorsIndexFilePath(jobTarget), new DetectedErrorReportMap()); + //List businessDataAllList = FileIOHelper.ReadListFromCSVFile(FilePathMap.SnapshotsBusinessDataIndexFilePath(jobTarget), new BusinessDataReportMap()); + + List agentPropertiesList = FileIOHelper.ReadListFromCSVFile(FilePathMap.APMAgentConfigurationPropertiesIndexFilePath(jobTarget), new AgentConfigurationPropertyReportMap()); + + #endregion + + #region Controller + + healthCheckRuleResults.Add( + evaluate_Controller_Version( + jobTarget, + healthCheckSettingsDictionary, + controllerSummariesList)); + + healthCheckRuleResults.Add( + evaluate_Controller_SaaS_OnPrem( + jobTarget, + healthCheckSettingsDictionary)); + + #endregion + + #region Application Naming + + healthCheckRuleResults.Add( + evaluate_APMApplication_Name_Length( + jobTarget, + healthCheckSettingsDictionary, + jobConfiguration)); + + healthCheckRuleResults.Add( + evaluate_APMApplication_Name_Environment( + jobTarget, + healthCheckSettingsDictionary, + jobConfiguration)); + + #endregion + + #region Application Agent Properties + + healthCheckRuleResults.AddRange( + evaluate_APMApplication_Properties_BuiltIn_Modified( + jobTarget, + healthCheckSettingsDictionary, + jobConfiguration, + agentPropertiesList)); + + healthCheckRuleResults.AddRange( + evaluate_APMApplication_Properties_New_Added( + jobTarget, + healthCheckSettingsDictionary, + jobConfiguration, + agentPropertiesList)); + + healthCheckRuleResults.AddRange( + evaluate_APMApplication_Properties_WellKnown_analytics_dynamic_service_enabled( + jobTarget, + healthCheckSettingsDictionary, + jobConfiguration, + agentPropertiesList)); + + healthCheckRuleResults.AddRange( + evaluate_APMApplication_Properties_WellKnown_find_entry_points( + jobTarget, + healthCheckSettingsDictionary, + jobConfiguration, + agentPropertiesList)); + + healthCheckRuleResults.AddRange( + evaluate_APMApplication_Properties_WellKnown_use_old_servlet_split_for_get_parm_value_rule( + jobTarget, + healthCheckSettingsDictionary, + jobConfiguration, + agentPropertiesList)); + + healthCheckRuleResults.AddRange( + evaluate_APMApplication_Properties_WellKnown_use_max_business_transactions( + jobTarget, + healthCheckSettingsDictionary, + jobConfiguration, + agentPropertiesList)); + + #endregion + + #region Tier Agent Property Overrides + + healthCheckRuleResults.AddRange( + evaluate_APMApplication_Tier_Properties_Overriden( + jobTarget, + healthCheckSettingsDictionary, + jobConfiguration, + agentPropertiesList, + tiersList)); + + //#region Tier Property Overrides on + + //healthCheckRuleResult = createHealthCheckRuleResult(jobTarget, "APMTier", "Tier1", -123, "Agent Property Configuration", "APM-005-TIER-PROPERTIES-OVERRIDE", "Tier Agent Properties Override"); + //healthCheckRuleResult.Grade = 3; + //healthCheckRuleResult.Description = "Tiers {0} in Application {1} overridden App-level Agent Properties"; + //healthCheckRuleResult.Code = "APM-0005"; + //healthCheckRuleResult.RuleLink = String.Format(@"=HYPERLINK(""{0}"", """")", String.Format("{0}#{1}", FilePathMap.ApplicationSummaryWordReportFilePath(jobTarget, jobConfiguration.Input.TimeRange, false), "Application_Properties")); + //healthCheckRuleResults.Add(healthCheckRuleResult); + + //#endregion + + //#region Built-in properties modified from their default values + + //healthCheckRuleResult = createHealthCheckRuleResult(jobTarget, "APMTier", "Tier1", -123, "Agent Property Configuration", "APM-006-TIER-PROPERTIES-MODIFIED", "Tier Agent Properties Modified"); + //healthCheckRuleResult.Grade = 3; + //healthCheckRuleResult.Description = "Built-in Agent Properties {0} modified from their default values in Application {1} Tier {2}"; + //healthCheckRuleResult.RuleLink = String.Format(@"=HYPERLINK(""{0}"", """")", String.Format("{0}#{1}", FilePathMap.ApplicationSummaryWordReportFilePath(jobTarget, jobConfiguration.Input.TimeRange, false), "Application_Properties")); + //healthCheckRuleResults.Add(healthCheckRuleResult); + + //#endregion + + //#region New properties added + + //healthCheckRuleResult = createHealthCheckRuleResult(jobTarget, "APMTier", "Tier1", -123, "Agent Property Configuration", "APM-007-TIER-PROPERTIES-ADDED", "Tier Agent Properties Added"); + //healthCheckRuleResult.Grade = 3; + //healthCheckRuleResult.Description = "Non-default Agent Properties {0} added to Application {1} Tier {2}"; + //healthCheckRuleResult.RuleLink = String.Format(@"=HYPERLINK(""{0}"", """")", String.Format("{0}#{1}", FilePathMap.ApplicationSummaryWordReportFilePath(jobTarget, jobConfiguration.Input.TimeRange, false), "Application_Properties")); + //healthCheckRuleResults.Add(healthCheckRuleResult); + + //#endregion + + #endregion + + // Sort them + healthCheckRuleResults = healthCheckRuleResults.OrderBy(h => h.EntityType).ThenBy(h => h.EntityName).ThenBy(h => h.Category).ThenBy(h => h.Name).ToList(); + + // Set version + string versionOfDEXTER = Assembly.GetEntryAssembly().GetName().Version.ToString(); + foreach (HealthCheckRuleResult healthCheckRuleResult in healthCheckRuleResults) + { + healthCheckRuleResult.Version = versionOfDEXTER; + } + + FileIOHelper.WriteListToCSVFile(healthCheckRuleResults, new HealthCheckRuleResultReportMap(), FilePathMap.APMHealthCheckRuleResultsIndexFilePath(jobTarget)); + + stepTimingTarget.NumEntities = healthCheckRuleResults.Count; + + #region Combine All for Report CSV + + // If it is the first one, clear out the combined folder + if (reportFolderCleaned == false) + { + FileIOHelper.DeleteFolder(FilePathMap.APMHealthCheckReportFolderPath()); + Thread.Sleep(1000); + FileIOHelper.CreateFolder(FilePathMap.APMHealthCheckReportFolderPath()); + reportFolderCleaned = true; + } + + // Append all the individual report files into one + if (File.Exists(FilePathMap.APMHealthCheckRuleResultsIndexFilePath(jobTarget)) == true && new FileInfo(FilePathMap.APMHealthCheckRuleResultsIndexFilePath(jobTarget)).Length > 0) + { + FileIOHelper.AppendTwoCSVFiles(FilePathMap.APMHealthCheckRuleResultsReportFilePath(), FilePathMap.APMHealthCheckRuleResultsIndexFilePath(jobTarget)); + } + //if (File.Exists(FilePathMap.APMTiersIndexFilePath(jobTarget)) == true && new FileInfo(FilePathMap.APMTiersIndexFilePath(jobTarget)).Length > 0) + //{ + // FileIOHelper.AppendTwoCSVFiles(FilePathMap.APMTiersReportFilePath(), FilePathMap.APMTiersIndexFilePath(jobTarget)); + //} + //if (File.Exists(FilePathMap.APMNodesIndexFilePath(jobTarget)) == true && new FileInfo(FilePathMap.APMNodesIndexFilePath(jobTarget)).Length > 0) + //{ + // FileIOHelper.AppendTwoCSVFiles(FilePathMap.APMNodesReportFilePath(), FilePathMap.APMNodesIndexFilePath(jobTarget)); + //} + //if (File.Exists(FilePathMap.APMNodeStartupOptionsIndexFilePath(jobTarget)) == true && new FileInfo(FilePathMap.APMNodeStartupOptionsIndexFilePath(jobTarget)).Length > 0) + //{ + // FileIOHelper.AppendTwoCSVFiles(FilePathMap.APMNodeStartupOptionsReportFilePath(), FilePathMap.APMNodeStartupOptionsIndexFilePath(jobTarget)); + //} + //if (File.Exists(FilePathMap.APMNodePropertiesIndexFilePath(jobTarget)) == true && new FileInfo(FilePathMap.APMNodePropertiesIndexFilePath(jobTarget)).Length > 0) + //{ + // FileIOHelper.AppendTwoCSVFiles(FilePathMap.APMNodePropertiesReportFilePath(), FilePathMap.APMNodePropertiesIndexFilePath(jobTarget)); + //} + //if (File.Exists(FilePathMap.APMNodeEnvironmentVariablesIndexFilePath(jobTarget)) == true && new FileInfo(FilePathMap.APMNodeEnvironmentVariablesIndexFilePath(jobTarget)).Length > 0) + //{ + // FileIOHelper.AppendTwoCSVFiles(FilePathMap.APMNodeEnvironmentVariablesReportFilePath(), FilePathMap.APMNodeEnvironmentVariablesIndexFilePath(jobTarget)); + //} + //if (File.Exists(FilePathMap.APMBackendsIndexFilePath(jobTarget)) == true && new FileInfo(FilePathMap.APMBackendsIndexFilePath(jobTarget)).Length > 0) + //{ + // FileIOHelper.AppendTwoCSVFiles(FilePathMap.APMBackendsReportFilePath(), FilePathMap.APMBackendsIndexFilePath(jobTarget)); + //} + //if (File.Exists(FilePathMap.APMMappedBackendsIndexFilePath(jobTarget)) == true && new FileInfo(FilePathMap.APMMappedBackendsIndexFilePath(jobTarget)).Length > 0) + //{ + // FileIOHelper.AppendTwoCSVFiles(FilePathMap.APMMappedBackendsReportFilePath(), FilePathMap.APMMappedBackendsIndexFilePath(jobTarget)); + //} + //if (File.Exists(FilePathMap.APMBusinessTransactionsIndexFilePath(jobTarget)) == true && new FileInfo(FilePathMap.APMBusinessTransactionsIndexFilePath(jobTarget)).Length > 0) + //{ + // FileIOHelper.AppendTwoCSVFiles(FilePathMap.APMBusinessTransactionsReportFilePath(), FilePathMap.APMBusinessTransactionsIndexFilePath(jobTarget)); + //} + //if (File.Exists(FilePathMap.APMOverflowBusinessTransactionsIndexFilePath(jobTarget)) == true && new FileInfo(FilePathMap.APMOverflowBusinessTransactionsIndexFilePath(jobTarget)).Length > 0) + //{ + // FileIOHelper.AppendTwoCSVFiles(FilePathMap.APMOverflowBusinessTransactionsReportFilePath(), FilePathMap.APMOverflowBusinessTransactionsIndexFilePath(jobTarget)); + //} + //if (File.Exists(FilePathMap.APMServiceEndpointsIndexFilePath(jobTarget)) == true && new FileInfo(FilePathMap.APMServiceEndpointsIndexFilePath(jobTarget)).Length > 0) + //{ + // FileIOHelper.AppendTwoCSVFiles(FilePathMap.APMServiceEndpointsReportFilePath(), FilePathMap.APMServiceEndpointsIndexFilePath(jobTarget)); + //} + //if (File.Exists(FilePathMap.APMErrorsIndexFilePath(jobTarget)) == true && new FileInfo(FilePathMap.APMErrorsIndexFilePath(jobTarget)).Length > 0) + //{ + // FileIOHelper.AppendTwoCSVFiles(FilePathMap.APMErrorsReportFilePath(), FilePathMap.APMErrorsIndexFilePath(jobTarget)); + //} + //if (File.Exists(FilePathMap.APMInformationPointsIndexFilePath(jobTarget)) == true && new FileInfo(FilePathMap.APMInformationPointsIndexFilePath(jobTarget)).Length > 0) + //{ + // FileIOHelper.AppendTwoCSVFiles(FilePathMap.APMInformationPointsReportFilePath(), FilePathMap.APMInformationPointsIndexFilePath(jobTarget)); + //} + + #endregion + } + catch (Exception ex) + { + logger.Warn(ex); + loggerConsole.Warn(ex); + + return false; + } + finally + { + stopWatchTarget.Stop(); + + this.DisplayJobTargetEndedStatus(jobConfiguration, jobTarget, i + 1, stopWatchTarget); + + 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(), FilePathMap.StepTimingReportFilePath(), true); + } + } + + return true; + } + catch (Exception ex) + { + logger.Error(ex); + loggerConsole.Error(ex); + + return false; + } + finally + { + stopWatch.Stop(); + + this.DisplayJobStepEndedStatus(jobConfiguration, stopWatch); + + stepTimingFunction.EndTime = DateTime.Now; + stepTimingFunction.Duration = stopWatch.Elapsed; + stepTimingFunction.DurationMS = stopWatch.ElapsedMilliseconds; + + List stepTimings = new List(1); + stepTimings.Add(stepTimingFunction); + FileIOHelper.WriteListToCSVFile(stepTimings, new StepTimingReportMap(), FilePathMap.StepTimingReportFilePath(), true); + } + } + + public override bool ShouldExecute(JobConfiguration jobConfiguration) + { + logger.Trace("Output.HealthCheck={0}", jobConfiguration.Output.HealthCheck); + loggerConsole.Trace("Output.HealthCheck={0}", jobConfiguration.Output.HealthCheck); + if (jobConfiguration.Output.HealthCheck == false) + { + loggerConsole.Trace("Skipping index of health check"); + } + return (jobConfiguration.Output.HealthCheck == true); + } + + #region Settings helper methods + + private Version getVersionSetting(Dictionary healthCheckSettingsDictionary, string settingName, string valueIfNotThere) + { + if (healthCheckSettingsDictionary.ContainsKey(settingName) == true) + { + string versionString = healthCheckSettingsDictionary[settingName].Value; + Version version = new Version(); + if (Version.TryParse(versionString, out version) == true) + { + return version; + } + else + { + return new Version(valueIfNotThere); + } + } + else + { + return new Version(valueIfNotThere); + } + } + + private int getIntegerSetting(Dictionary healthCheckSettingsDictionary, string settingName, int valueIfNotThere) + { + if (healthCheckSettingsDictionary.ContainsKey(settingName) == true) + { + string numberString = healthCheckSettingsDictionary[settingName].Value; + int number = 0; + if (Int32.TryParse(numberString, out number) == true) + { + return number; + } + else + { + return valueIfNotThere; + } + } + else + { + return valueIfNotThere; + } + } + + private string getStringSetting(Dictionary healthCheckSettingsDictionary, string settingName, string valueIfNotThere) + { + if (healthCheckSettingsDictionary.ContainsKey(settingName) == true) + { + return healthCheckSettingsDictionary[settingName].Value; + } + else + { + return valueIfNotThere; + } + } + + #endregion + + private HealthCheckRuleResult createHealthCheckRuleResult( + JobTarget jobTarget, + string entityType, + string entityName, + long entityID, + string ruleCategory, + string ruleCode, + string ruleName) + { + HealthCheckRuleResult healthCheckRuleResult = new HealthCheckRuleResult(); + healthCheckRuleResult.Controller = jobTarget.Controller; + healthCheckRuleResult.Application = jobTarget.Application; + healthCheckRuleResult.ApplicationID = jobTarget.ApplicationID; + + healthCheckRuleResult.EntityType = entityType; + healthCheckRuleResult.EntityName = entityName; + healthCheckRuleResult.EntityID = entityID; + + healthCheckRuleResult.Category = ruleCategory; + healthCheckRuleResult.Code = ruleCode; + healthCheckRuleResult.Name = ruleName; + healthCheckRuleResult.Grade = 0; + + healthCheckRuleResult.EvaluationTime = DateTime.Now; + + return healthCheckRuleResult; + } + + #region Controller + + /// + /// Version of Controller should be reasonably latest + /// + /// + /// + /// + /// + private HealthCheckRuleResult evaluate_Controller_Version( + JobTarget jobTarget, + Dictionary healthCheckSettingsDictionary, + List controllerSummariesList) + { + string thisHealthRuleCode = "PLAT-001-PLATFORM-VERSION"; + loggerConsole.Info("Evaluating Controller Version ({0})", thisHealthRuleCode); + + HealthCheckRuleResult healthCheckRuleResult = createHealthCheckRuleResult(jobTarget, "Controller", jobTarget.Controller, 0, "Platform", thisHealthRuleCode, "Controller Version"); + if (controllerSummariesList != null && controllerSummariesList.Count > 0) + { + ControllerSummary controllerSummary = controllerSummariesList[0]; + Version versionThisController = new Version(jobTarget.ControllerVersion); + + Version versionLatest = getVersionSetting(healthCheckSettingsDictionary, "LatestControllerVersion", "4.5.13"); + Version versionLatestFirstRelease = new Version(versionLatest.Major, versionLatest.Minor); + Version versionLatestMinus1 = new Version(versionLatest.Major, versionLatest.Minor - 1); + Version versionLatestMinus2 = new Version(versionLatest.Major, versionLatest.Minor - 2); + Version versionLatestMinus3 = new Version(versionLatest.Major, versionLatest.Minor - 3); + Version versionLatestMinus4 = new Version(versionLatest.Major, versionLatest.Minor - 4); + Version versionLatestMinus5 = new Version(versionLatest.Major, versionLatest.Minor - 5); + if (versionThisController >= versionLatest) + { + healthCheckRuleResult.Grade = 5; + healthCheckRuleResult.Description = String.Format("The Controller version '{0}' is greater or equal to latest '{1}'", jobTarget.ControllerVersion, versionLatest); + } + else if (versionThisController >= versionLatestFirstRelease) + { + healthCheckRuleResult.Grade = 4; + healthCheckRuleResult.Description = String.Format("The Controller version '{0}' is in '{1}' branch, old", jobTarget.ControllerVersion, versionLatestFirstRelease); + } + else if (versionThisController >= versionLatestMinus1) + { + healthCheckRuleResult.Grade = 4; + healthCheckRuleResult.Description = String.Format("The Controller version '{0}' is in '{1}' branch, really old", jobTarget.ControllerVersion, versionLatestMinus1); + } + else if (versionThisController >= versionLatestMinus2) + { + healthCheckRuleResult.Grade = 3; + healthCheckRuleResult.Description = String.Format("The Controller version '{0}' is in '{1}' branch, really, really old", jobTarget.ControllerVersion, versionLatestMinus2); + } + else if (versionThisController >= versionLatestMinus3) + { + healthCheckRuleResult.Grade = 3; + healthCheckRuleResult.Description = String.Format("The Controller version '{0}' is in '{1}' branch, really, really, really old", jobTarget.ControllerVersion, versionLatestMinus3); + } + else if (versionThisController >= versionLatestMinus4) + { + healthCheckRuleResult.Grade = 2; + healthCheckRuleResult.Description = String.Format("The Controller version '{0}' is in '{1}' branch, really, really, really, really old", jobTarget.ControllerVersion, versionLatestMinus4); + } + else if (versionThisController >= versionLatestMinus5) + { + healthCheckRuleResult.Grade = 2; + healthCheckRuleResult.Description = String.Format("The Controller version '{0}' is in '{1}' branch, really, really, really, really, really old", jobTarget.ControllerVersion, versionLatestMinus5); + } + else + { + healthCheckRuleResult.Grade = 1; + healthCheckRuleResult.Description = String.Format("The Controller version '{0}' is < '{1}' branch. Ancient", jobTarget.ControllerVersion, versionLatestMinus5); + } + } + else + { + healthCheckRuleResult.Grade = 1; + healthCheckRuleResult.Description = "No information about Controller version available"; + } + + return healthCheckRuleResult; + } + + /// + /// We like SaaS controllers more than on premises + /// + /// + /// + /// + private HealthCheckRuleResult evaluate_Controller_SaaS_OnPrem( + JobTarget jobTarget, + Dictionary healthCheckSettingsDictionary) + { + string thisHealthRuleCode = "PLAT-002-PLATFORM-SAAS"; + loggerConsole.Info("Evaluating Controller SaaS or OnPremises ({0})", thisHealthRuleCode); + + HealthCheckRuleResult healthCheckRuleResult = createHealthCheckRuleResult(jobTarget, "Controller", jobTarget.Controller, 0, "Platform", thisHealthRuleCode, "Controller SaaS or OnPrem"); + if (jobTarget.Controller.ToLower().Contains("saas.appdynamics") == true) + { + healthCheckRuleResult.Grade = 5; + healthCheckRuleResult.Description = "Controller is running in AppDynamics SaaS cloud"; + } + else + { + healthCheckRuleResult.Grade = 3; + healthCheckRuleResult.Description = "Controller is running in OnPremises configuration"; + } + return healthCheckRuleResult; + } + + #endregion + + #region APM Application Naming + + /// + /// Length of the APM Application Name + /// + /// + /// + /// + private HealthCheckRuleResult evaluate_APMApplication_Name_Length( + JobTarget jobTarget, + Dictionary healthCheckSettingsDictionary, + JobConfiguration jobConfiguration) + { + string thisHealthRuleCode = "APM-001-APP-NAME-LENGTH"; + loggerConsole.Info("Evaluating Application name length ({0})", thisHealthRuleCode); + + HealthCheckRuleResult healthCheckRuleResult = createHealthCheckRuleResult(jobTarget, "APMApp", jobTarget.Application, jobTarget.ApplicationID, "Logical Model Naming", thisHealthRuleCode, "App Name Length"); + healthCheckRuleResult.RuleLink = String.Format(@"=HYPERLINK(""{0}"", """")", String.Format("{0}#{1}", FilePathMap.ApplicationSummaryWordReportFilePath(jobTarget, jobConfiguration.Input.TimeRange, false), "Application")); + + if (jobTarget.Application.Length > getIntegerSetting(healthCheckSettingsDictionary, "APMApplicationNameLengthGrade2", 60)) + { + healthCheckRuleResult.Grade = 1; + healthCheckRuleResult.Description = String.Format("The Application Name '{0}' is very, very, very long (>{1} characters)", jobTarget.Application, getIntegerSetting(healthCheckSettingsDictionary, "APMApplicationNameLengthGrade2", 60)); + } + else if (jobTarget.Application.Length > getIntegerSetting(healthCheckSettingsDictionary, "APMApplicationNameLengthGrade3", 50)) + { + healthCheckRuleResult.Grade = 2; + healthCheckRuleResult.Description = String.Format("The Application Name '{0}' is very, very long (>{1} characters)", jobTarget.Application, getIntegerSetting(healthCheckSettingsDictionary, "APMApplicationNameLengthGrade3", 50)); + } + else if (jobTarget.Application.Length > getIntegerSetting(healthCheckSettingsDictionary, "APMApplicationNameLengthGrade4", 40)) + { + healthCheckRuleResult.Grade = 3; + healthCheckRuleResult.Description = String.Format("The Application Name '{0}' is very long (>{1} characters)", jobTarget.Application, getIntegerSetting(healthCheckSettingsDictionary, "APMApplicationNameLengthGrade2", 40)); + } + else if (jobTarget.Application.Length > getIntegerSetting(healthCheckSettingsDictionary, "APMApplicationNameLengthGrade5", 30)) + { + healthCheckRuleResult.Grade = 4; + healthCheckRuleResult.Description = String.Format("The Application Name '{0}' is long (>{1} characters)", jobTarget.Application, getIntegerSetting(healthCheckSettingsDictionary, "APMApplicationNameLengthGrade5", 30)); + } + else + { + healthCheckRuleResult.Grade = 5; + healthCheckRuleResult.Description = String.Format("The Application Name '{0}' is within recommended length (<={1} characters)", jobTarget.Application, getIntegerSetting(healthCheckSettingsDictionary, "APMApplicationNameLengthGrade5", 30)); + } + + return healthCheckRuleResult; + } + + /// + /// APM Application name should contain environment designation + /// + /// + /// + /// + private HealthCheckRuleResult evaluate_APMApplication_Name_Environment( + JobTarget jobTarget, + Dictionary healthCheckSettingsDictionary, + JobConfiguration jobConfiguration) + { + string thisHealthRuleCode = "APM-002-APP-NAME-INC-ENV-DESIGNATION"; + loggerConsole.Info(thisHealthRuleCode); + + HealthCheckRuleResult healthCheckRuleResult = createHealthCheckRuleResult(jobTarget, "APMApp", jobTarget.Application, jobTarget.ApplicationID, "Logical Model Naming", thisHealthRuleCode, "App Name Includes Environment Designation"); + healthCheckRuleResult.RuleLink = String.Format(@"=HYPERLINK(""{0}"", """")", String.Format("{0}#{1}", FilePathMap.ApplicationSummaryWordReportFilePath(jobTarget, jobConfiguration.Input.TimeRange, false), "Application")); + + Regex regexQuery = new Regex(getStringSetting(healthCheckSettingsDictionary, "APMApplicationNameEnvironmentRegex", "(production|prod|qa|test|tst|nonprod|perf|performance|sit|clt|dev|uat|poc|pov|demo|stage|stg)"), RegexOptions.IgnoreCase); + Match regexMatch = regexQuery.Match(jobTarget.Application); + if (regexMatch.Success == true && regexMatch.Groups.Count == 2) + { + healthCheckRuleResult.Grade = 5; + healthCheckRuleResult.Description = String.Format("The Application Name '{0}' contains environment designation '{1}'", jobTarget.Application, regexMatch.Groups[1].Value); + } + else + { + healthCheckRuleResult.Grade = 3; + healthCheckRuleResult.Description = String.Format("The Application Name '{0}' does not contains environment designation", jobTarget.Application); + } + + return healthCheckRuleResult; + } + + #endregion + + #region Application Agent Properties + + /// + /// Built-in properties modified from their default values + /// Any change is graded 3 + /// + /// + /// + /// + /// + private List evaluate_APMApplication_Properties_BuiltIn_Modified( + JobTarget jobTarget, + Dictionary healthCheckSettingsDictionary, + JobConfiguration jobConfiguration, + List agentPropertiesList) + { + string thisHealthRuleCode = "APM-003-APP-DEFAULT-PROPERTY-MODIFIED"; + loggerConsole.Info("Evaluating default Agent Properties modified ({0})", thisHealthRuleCode); + + List healthCheckRuleResults = new List(); + + HealthCheckRuleResult healthCheckRuleResult = createHealthCheckRuleResult(jobTarget, "APMApp", jobTarget.Application, jobTarget.ApplicationID, "Agent Property Configuration", thisHealthRuleCode, "App Agent Property Modified"); + healthCheckRuleResult.RuleLink = String.Format(@"=HYPERLINK(""{0}"", """")", String.Format("{0}#{1}", FilePathMap.ApplicationSummaryWordReportFilePath(jobTarget, jobConfiguration.Input.TimeRange, false), "Application_Properties")); + healthCheckRuleResult.Grade = 5; + healthCheckRuleResult.Description = "None of the built-in Agent Properties are modified from their default values"; + + if (agentPropertiesList != null && agentPropertiesList.Count > 0) + { + List agentPropertiesBuiltInList = agentPropertiesList.Where(p => AGENT_PROPERTIES_BUILTIN.Contains(p.PropertyName) == true && p.IsDefault == false && p.TierName.Length == 0).ToList(); + if (agentPropertiesBuiltInList != null && agentPropertiesBuiltInList.Count > 0) + { + foreach (AgentConfigurationProperty agentProperty in agentPropertiesBuiltInList) + { + HealthCheckRuleResult healthCheckRuleResult1 = healthCheckRuleResult.Clone(); + healthCheckRuleResult1.Grade = 3; + + switch (agentProperty.PropertyType) + { + case "BOOLEAN": + healthCheckRuleResult1.Description = String.Format("Built-in Agent Property '{0}/{1} [{2}]' value is '{3}' and modified from its default value '{4}'", agentProperty.AgentType, agentProperty.PropertyName, agentProperty.PropertyType, agentProperty.BooleanValue, agentProperty.BooleanDefaultValue); + break; + + case "INTEGER": + healthCheckRuleResult1.Description = String.Format("Built-in Agent Property '{0}/{1} [{2}]' value is '{3}' and modified from its default value '{4}'", agentProperty.AgentType, agentProperty.PropertyName, agentProperty.PropertyType, agentProperty.IntegerValue, agentProperty.IntegerDefaultValue); + break; + + case "STRING": + healthCheckRuleResult1.Description = String.Format("Built-in Agent Property '{0}/{1} [{2}]' value is '{3}' and modified from its default value '{4}'", agentProperty.AgentType, agentProperty.PropertyName, agentProperty.PropertyType, agentProperty.StringValue, agentProperty.StringDefaultValue); + break; + + default: + break; + } + + healthCheckRuleResults.Add(healthCheckRuleResult1); + } + } + } + + if (healthCheckRuleResults.Count == 0) + { + healthCheckRuleResults.Add(healthCheckRuleResult); + } + + return healthCheckRuleResults; + } + + /// + /// Non-built in properties added + /// Any change is graded 3 + /// + /// + /// + /// + /// + /// + private List evaluate_APMApplication_Properties_New_Added( + JobTarget jobTarget, + Dictionary healthCheckSettingsDictionary, + JobConfiguration jobConfiguration, + List agentPropertiesList) + { + string thisHealthRuleCode = "APM-004-APP-PROPERTY-ADDED"; + loggerConsole.Info("Evaluating non-default Agent Properties added ({0})", thisHealthRuleCode); + + List healthCheckRuleResults = new List(); + + HealthCheckRuleResult healthCheckRuleResult = createHealthCheckRuleResult(jobTarget, "APMApp", jobTarget.Application, jobTarget.ApplicationID, "Agent Property Configuration", thisHealthRuleCode, "App Agent Property Added"); + healthCheckRuleResult.RuleLink = String.Format(@"=HYPERLINK(""{0}"", """")", String.Format("{0}#{1}", FilePathMap.ApplicationSummaryWordReportFilePath(jobTarget, jobConfiguration.Input.TimeRange, false), "Application_Properties")); + healthCheckRuleResult.Grade = 5; + healthCheckRuleResult.Description = "No additional non-default Agent Properties are added to application configuration"; + + if (agentPropertiesList != null && agentPropertiesList.Count > 0) + { + List agentPropertiesNonBuiltIntList = agentPropertiesList.Where(p => AGENT_PROPERTIES_BUILTIN.Contains(p.PropertyName) == false && p.TierName.Length == 0).ToList(); + if (agentPropertiesNonBuiltIntList != null && agentPropertiesNonBuiltIntList.Count > 0) + { + foreach (AgentConfigurationProperty agentProperty in agentPropertiesNonBuiltIntList) + { + HealthCheckRuleResult healthCheckRuleResult1 = healthCheckRuleResult.Clone(); + healthCheckRuleResult1.Grade = 3; + + switch (agentProperty.PropertyType) + { + case "BOOLEAN": + healthCheckRuleResult1.Description = String.Format("Non-default Agent Property '{0}/{1} [{2}]' value is '{3}' and its default value is '{4}'", agentProperty.AgentType, agentProperty.PropertyName, agentProperty.PropertyType, agentProperty.BooleanValue, agentProperty.BooleanDefaultValue); + break; + + case "INTEGER": + healthCheckRuleResult1.Description = String.Format("Non-default Agent Property '{0}/{1} [{2}]' value is '{3}' and its default value is '{4}'", agentProperty.AgentType, agentProperty.PropertyName, agentProperty.PropertyType, agentProperty.IntegerValue, agentProperty.IntegerDefaultValue); + break; + + case "STRING": + healthCheckRuleResult1.Description = String.Format("Non-default Agent Property '{0}/{1} [{2}]' value is '{3}' and its default value is '{4}'", agentProperty.AgentType, agentProperty.PropertyName, agentProperty.PropertyType, agentProperty.StringValue, agentProperty.StringDefaultValue); + break; + + default: + break; + } + + healthCheckRuleResults.Add(healthCheckRuleResult1); + } + } + } + + if (healthCheckRuleResults.Count == 0) + { + healthCheckRuleResults.Add(healthCheckRuleResult); + } + + return healthCheckRuleResults; + } + + /// + /// Well-known properties - analytics-dynamic-service-enabled + /// if it is not set at all , grade 5 + /// if it is set, grade 5 + /// if it is set for some but not others, grade 1 + /// + /// + /// + /// + /// + /// + private List evaluate_APMApplication_Properties_WellKnown_analytics_dynamic_service_enabled( + JobTarget jobTarget, + Dictionary healthCheckSettingsDictionary, + JobConfiguration jobConfiguration, + List agentPropertiesList) + { + string thisHealthRuleCode = "APM-005-APP-SIGNIFICANT-PROPERTY-SET"; + loggerConsole.Info("Evaluating significat Agent Property analytics-dynamic-service-enabled ({0})", thisHealthRuleCode); + + List healthCheckRuleResults = new List(); + + HealthCheckRuleResult healthCheckRuleResult = createHealthCheckRuleResult(jobTarget, "APMApp", jobTarget.Application, jobTarget.ApplicationID, "Agent Property Configuration", thisHealthRuleCode, "App Agent Property Set (analytics-dynamic-service-enabled)"); + healthCheckRuleResult.RuleLink = String.Format(@"=HYPERLINK(""{0}"", """")", String.Format("{0}#{1}", FilePathMap.ApplicationSummaryWordReportFilePath(jobTarget, jobConfiguration.Input.TimeRange, false), "Application_Properties")); + healthCheckRuleResult.Grade = 5; + healthCheckRuleResult.Description = "BIQ/Analytics is not enabled via 'analytics-dynamic-service-enabled' Agent Property for any agent types"; + + if (agentPropertiesList != null && agentPropertiesList.Count > 0) + { + List agentPropertiesAnalyticsEnabledList = agentPropertiesList.Where(p => p.PropertyName == "analytics-dynamic-service-enabled" && p.BooleanValue == true && p.TierName.Length == 0).ToList(); + if (agentPropertiesAnalyticsEnabledList != null && agentPropertiesAnalyticsEnabledList.Count > 0) + { + foreach (AgentConfigurationProperty agentProperty in agentPropertiesAnalyticsEnabledList) + { + HealthCheckRuleResult healthCheckRuleResult1 = healthCheckRuleResult.Clone(); + healthCheckRuleResult1.Grade = 5; + healthCheckRuleResult1.Description = String.Format("BIQ/Analytics is enabled via '{0}/{1} [{2}]' Agent Property set to '{3}' for agent type '{4}'", agentProperty.AgentType, agentProperty.PropertyName, agentProperty.PropertyType, agentProperty.BooleanValue, agentProperty.AgentType); + + healthCheckRuleResults.Add(healthCheckRuleResult1); + } + } + + List agentPropertiesAnalyticsDisabledList = agentPropertiesList.Where(p => p.PropertyName == "analytics-dynamic-service-enabled" && p.BooleanValue == false && p.TierName.Length == 0).ToList(); + if (agentPropertiesAnalyticsDisabledList != null && agentPropertiesAnalyticsDisabledList.Count > 0) + { + foreach (AgentConfigurationProperty agentProperty in agentPropertiesAnalyticsDisabledList) + { + HealthCheckRuleResult healthCheckRuleResult1 = healthCheckRuleResult.Clone(); + healthCheckRuleResult1.Grade = 1; + healthCheckRuleResult1.Description = String.Format("BIQ/Analytics is disabled via '{0}/{1} [{2}]' Agent Property set to '{3}' for agent type '{4}'", agentProperty.AgentType, agentProperty.PropertyName, agentProperty.PropertyType, agentProperty.BooleanValue, agentProperty.AgentType); + + healthCheckRuleResults.Add(healthCheckRuleResult1); + } + } + } + + if (healthCheckRuleResults.Count == 0) + { + healthCheckRuleResults.Add(healthCheckRuleResult); + } + + return healthCheckRuleResults; + } + + /// + /// Well-known properties - find-entry-points + /// If it is set at all, grade 2 + /// + /// + /// + /// + /// + /// + private List evaluate_APMApplication_Properties_WellKnown_find_entry_points( + JobTarget jobTarget, + Dictionary healthCheckSettingsDictionary, + JobConfiguration jobConfiguration, + List agentPropertiesList) + { + string thisHealthRuleCode = "APM-005-APP-SIGNIFICANT-PROPERTY-SET"; + loggerConsole.Info("Evaluating significat Agent Property find-entry-points ({0})", thisHealthRuleCode); + + List healthCheckRuleResults = new List(); + + HealthCheckRuleResult healthCheckRuleResult = createHealthCheckRuleResult(jobTarget, "APMApp", jobTarget.Application, jobTarget.ApplicationID, "Agent Property Configuration", thisHealthRuleCode, "App Agent Property Set (find-entry-points)"); + healthCheckRuleResult.RuleLink = String.Format(@"=HYPERLINK(""{0}"", """")", String.Format("{0}#{1}", FilePathMap.ApplicationSummaryWordReportFilePath(jobTarget, jobConfiguration.Input.TimeRange, false), "Application_Properties")); + healthCheckRuleResult.Grade = 5; + healthCheckRuleResult.Description = "Business Transaction discovery stack logging is disabled via 'find-entry-points' Agent Property for all agent types"; + + if (agentPropertiesList != null && agentPropertiesList.Count > 0) + { + List agentPropertiesFindEntryPointsDisabledList = agentPropertiesList.Where(p => p.PropertyName == "find-entry-points" && p.BooleanValue == false && p.TierName.Length == 0).ToList(); + if (agentPropertiesFindEntryPointsDisabledList != null && agentPropertiesFindEntryPointsDisabledList.Count > 0) + { + foreach (AgentConfigurationProperty agentProperty in agentPropertiesFindEntryPointsDisabledList) + { + HealthCheckRuleResult healthCheckRuleResult1 = healthCheckRuleResult.Clone(); + healthCheckRuleResult1.Grade = 5; + healthCheckRuleResult1.Description = String.Format("Business Transaction discovery stack logging is disabled via '{0}/{1} [{2}]' Agent Property set to '{3}' for agent type '{4}'", agentProperty.AgentType, agentProperty.PropertyName, agentProperty.PropertyType, agentProperty.BooleanValue, agentProperty.AgentType); + + healthCheckRuleResults.Add(healthCheckRuleResult1); + } + } + + List agentPropertiesFindEntryPointsEnabledList = agentPropertiesList.Where(p => p.PropertyName == "find-entry-points" && p.BooleanValue == true && p.TierName.Length == 0).ToList(); + if (agentPropertiesFindEntryPointsEnabledList != null && agentPropertiesFindEntryPointsEnabledList.Count > 0) + { + foreach (AgentConfigurationProperty agentProperty in agentPropertiesFindEntryPointsEnabledList) + { + HealthCheckRuleResult healthCheckRuleResult1 = healthCheckRuleResult.Clone(); + healthCheckRuleResult1.Grade = 2; + healthCheckRuleResult1.Description = String.Format("Business Transaction discovery stack logging is enabled via '{0}/{1} [{2}]' Agent Property set to '{3}' for agent type '{4}'", agentProperty.AgentType, agentProperty.PropertyName, agentProperty.PropertyType, agentProperty.BooleanValue, agentProperty.AgentType); + + healthCheckRuleResults.Add(healthCheckRuleResult1); + } + } + } + + if (healthCheckRuleResults.Count == 0) + { + healthCheckRuleResults.Add(healthCheckRuleResult); + + } + return healthCheckRuleResults; + } + + /// + /// Well-known properties - use-old-servlet-split-for-get-parm-value-rule + /// You set it, you get graded lowest + /// + /// + /// + /// + /// + /// + private List evaluate_APMApplication_Properties_WellKnown_use_old_servlet_split_for_get_parm_value_rule( + JobTarget jobTarget, + Dictionary healthCheckSettingsDictionary, + JobConfiguration jobConfiguration, + List agentPropertiesList) + { + string thisHealthRuleCode = "APM-005-APP-SIGNIFICANT-PROPERTY-SET"; + loggerConsole.Info("Evaluating significat Agent Property use-old-servlet-split-for-get-parm-value-rule ({0})", thisHealthRuleCode); + + List healthCheckRuleResults = new List(); + + HealthCheckRuleResult healthCheckRuleResult = createHealthCheckRuleResult(jobTarget, "APMApp", jobTarget.Application, jobTarget.ApplicationID, "Agent Property Configuration", thisHealthRuleCode, "App Agent Property Set (use-old-servlet-split-for-get-parm-value-rule)"); + healthCheckRuleResult.RuleLink = String.Format(@"=HYPERLINK(""{0}"", """")", String.Format("{0}#{1}", FilePathMap.ApplicationSummaryWordReportFilePath(jobTarget, jobConfiguration.Input.TimeRange, false), "Application_Properties")); + healthCheckRuleResult.Grade = 5; + healthCheckRuleResult.Description = "Dangerous Servlet parameter parsing option is disabled via 'use-old-servlet-split-for-get-parm-value-rule' Agent Property for all agent types"; + + if (agentPropertiesList != null && agentPropertiesList.Count > 0) + { + List agentPropertiesEvilOldServletSplitEnabledList = agentPropertiesList.Where(p => p.PropertyName == "use-old-servlet-split-for-get-parm-value-rule" && p.BooleanValue == true && p.TierName.Length == 0).ToList(); + if (agentPropertiesEvilOldServletSplitEnabledList != null && agentPropertiesEvilOldServletSplitEnabledList.Count > 0) + { + foreach (AgentConfigurationProperty agentProperty in agentPropertiesEvilOldServletSplitEnabledList) + { + HealthCheckRuleResult healthCheckRuleResult1 = healthCheckRuleResult.Clone(); + healthCheckRuleResult1.Grade = 1; + healthCheckRuleResult1.Description = String.Format("Dangerous Servlet parameter parsing option is enabled via '{0}/{1} [{2}]' Agent Property set to '{3}' for agent type '{4}'", agentProperty.AgentType, agentProperty.PropertyName, agentProperty.PropertyType, agentProperty.BooleanValue, agentProperty.AgentType); + + healthCheckRuleResults.Add(healthCheckRuleResult1); + } + } + } + + if (healthCheckRuleResults.Count == 0) + { + healthCheckRuleResults.Add(healthCheckRuleResult); + } + + return healthCheckRuleResults; + } + + /// + /// Well-known properties - max-business-transactions + /// Set higher than standard - grade 2 + /// Set lower than standard, grade 3 + /// + /// + /// + /// + /// + /// + private List evaluate_APMApplication_Properties_WellKnown_use_max_business_transactions( + JobTarget jobTarget, + Dictionary healthCheckSettingsDictionary, + JobConfiguration jobConfiguration, + List agentPropertiesList) + { + string thisHealthRuleCode = "APM-005-APP-SIGNIFICANT-PROPERTY-SET"; + loggerConsole.Info("Evaluating significat Agent Property max-business-transactions ({0})", thisHealthRuleCode); + + List healthCheckRuleResults = new List(); + + HealthCheckRuleResult healthCheckRuleResult = createHealthCheckRuleResult(jobTarget, "APMApp", jobTarget.Application, jobTarget.ApplicationID, "Agent Property Configuration", thisHealthRuleCode, "App Agent Property Set (max-business-transactions)"); + healthCheckRuleResult.RuleLink = String.Format(@"=HYPERLINK(""{0}"", """")", String.Format("{0}#{1}", FilePathMap.ApplicationSummaryWordReportFilePath(jobTarget, jobConfiguration.Input.TimeRange, false), "Application_Properties")); + healthCheckRuleResult.Grade = 5; + healthCheckRuleResult.Description = "Maximum Business Transaction slot registration are at default value via 'max-business-transactions' Agent Property for all agent types"; + + if (agentPropertiesList != null && agentPropertiesList.Count > 0) + { + List agentPropertiesMaxBTGreaterThanDefault = agentPropertiesList.Where(p => p.PropertyName == "max-business-transactions" && p.IntegerValue > 50 && p.TierName.Length == 0).ToList(); + if (agentPropertiesMaxBTGreaterThanDefault != null && agentPropertiesMaxBTGreaterThanDefault.Count > 0) + { + foreach (AgentConfigurationProperty agentProperty in agentPropertiesMaxBTGreaterThanDefault) + { + HealthCheckRuleResult healthCheckRuleResult1 = healthCheckRuleResult.Clone(); + healthCheckRuleResult1.Grade = 2; + healthCheckRuleResult1.Description = String.Format("Higher than standard Business Transaction slot registration value is set via '{0}/{1} [{2}]' Agent Property set to '{3}' for agent type '{4}'", agentProperty.AgentType, agentProperty.PropertyName, agentProperty.PropertyType, agentProperty.IntegerValue, agentProperty.AgentType); + + healthCheckRuleResults.Add(healthCheckRuleResult1); + } + } + + List agentPropertiesMaxBTLessThanDefault = agentPropertiesList.Where(p => p.PropertyName == "max-business-transactions" && p.IntegerValue < 50 && p.TierName.Length == 0).ToList(); + if (agentPropertiesMaxBTLessThanDefault != null && agentPropertiesMaxBTLessThanDefault.Count > 0) + { + foreach (AgentConfigurationProperty agentProperty in agentPropertiesMaxBTLessThanDefault) + { + HealthCheckRuleResult healthCheckRuleResult1 = healthCheckRuleResult.Clone(); + healthCheckRuleResult1.Grade = 3; + healthCheckRuleResult1.Description = String.Format("Lower than standard Business Transaction slot registration value is set via '{0}/{1} [{2}]' Agent Property set to '{3}' for agent type '{4}'", agentProperty.AgentType, agentProperty.PropertyName, agentProperty.PropertyType, agentProperty.IntegerValue, agentProperty.AgentType); + + healthCheckRuleResults.Add(healthCheckRuleResult1); + } + } + } + + if (healthCheckRuleResults.Count == 0) + { + healthCheckRuleResults.Add(healthCheckRuleResult); + } + + return healthCheckRuleResults; + } + + #endregion + + #region Tier Agent Property evaluations + + /// + /// Tier override has properties? + /// Any change is graded 3 + /// + /// + /// + /// + /// + private List evaluate_APMApplication_Tier_Properties_Overriden( + JobTarget jobTarget, + Dictionary healthCheckSettingsDictionary, + JobConfiguration jobConfiguration, + List agentPropertiesList, + List tiersList) + { + string thisHealthRuleCode = "APM-006-APP-TIER-PROPERTIES-OVERRIDEN"; + loggerConsole.Info("Evaluating Tier Agent Properties override ({0})", thisHealthRuleCode); + + List healthCheckRuleResults = new List(); + + HealthCheckRuleResult healthCheckRuleResult = createHealthCheckRuleResult(jobTarget, "APMApp", jobTarget.Application, jobTarget.ApplicationID, "Agent Property Configuration", thisHealthRuleCode, "App Tier Agent Property Override"); + healthCheckRuleResult.RuleLink = String.Format(@"=HYPERLINK(""{0}"", """")", String.Format("{0}#{1}", FilePathMap.ApplicationSummaryWordReportFilePath(jobTarget, jobConfiguration.Input.TimeRange, false), "TODO")); + healthCheckRuleResult.Grade = 5; + healthCheckRuleResult.Description = "None of the Application Tiers have Agent Properties override"; + + if (agentPropertiesList != null && agentPropertiesList.Count > 0) + { + List agentPropertiesTierOverridePropertiesList = agentPropertiesList.Where(p => p.TierName.Length > 0).ToList(); + if (agentPropertiesTierOverridePropertiesList != null && agentPropertiesTierOverridePropertiesList.Count > 0) + { + var agentPropertiesTierOverridePropertiesListUniqueTiers = agentPropertiesTierOverridePropertiesList.GroupBy(p => p.TierName); + foreach (var uniqueTier in agentPropertiesTierOverridePropertiesListUniqueTiers) + { + List agentPropertiesInTier = uniqueTier.ToList(); + AgentConfigurationProperty agentProperty = agentPropertiesInTier[0]; + + HealthCheckRuleResult healthCheckRuleResult1 = healthCheckRuleResult.Clone(); + + healthCheckRuleResult1.EntityType = "APMTier"; + healthCheckRuleResult1.EntityName = agentProperty.TierName; + if (tiersList != null) + { + APMTier tier = tiersList.Where(t => t.TierName == agentProperty.TierName).FirstOrDefault(); + if (tier != null) + { + healthCheckRuleResult1.EntityID = tier.TierID; + } + else + { + healthCheckRuleResult1.EntityID = 0; + } + } + + healthCheckRuleResult1.Grade = 3; + healthCheckRuleResult1.Description = String.Format("Tier '{0} [{1}]' has Agent Property override flag on, overriding '{2}' properties", agentProperty.TierName, agentProperty.AgentType, agentPropertiesInTier.Count); + + healthCheckRuleResults.Add(healthCheckRuleResult1); + } + } + } + + if (healthCheckRuleResults.Count == 0) + { + healthCheckRuleResults.Add(healthCheckRuleResult); + } + + return healthCheckRuleResults; + } + + /// + /// Tier override has things changed from defaults + /// Any change is graded 3 + /// + /// + /// + /// + /// + private List evaluate_APMApplication_Tier_Properties_Overriden_BuiltIn_Modified( + JobTarget jobTarget, + Dictionary healthCheckSettingsDictionary, + JobConfiguration jobConfiguration, + List agentPropertiesList, + List tiersList) + { + string thisHealthRuleCode = "APM-006-APP-TIER-DEFAULT-PROPERTY-MODIFIED"; + loggerConsole.Info("Evaluating default properties in Tier Agent Properties override ({0})", thisHealthRuleCode); + + List healthCheckRuleResults = new List(); + + HealthCheckRuleResult healthCheckRuleResult = createHealthCheckRuleResult(jobTarget, "APMApp", jobTarget.Application, jobTarget.ApplicationID, "Agent Property Configuration", thisHealthRuleCode, "App Tier Agent Property Modified"); + healthCheckRuleResult.RuleLink = String.Format(@"=HYPERLINK(""{0}"", """")", String.Format("{0}#{1}", FilePathMap.ApplicationSummaryWordReportFilePath(jobTarget, jobConfiguration.Input.TimeRange, false), "TODO")); + healthCheckRuleResult.Grade = 5; + healthCheckRuleResult.Description = "None of the Application Tiers with Agent Properties override on have modified built-in properties"; + + if (agentPropertiesList != null && agentPropertiesList.Count > 0) + { + List agentPropertiesBuiltInList = agentPropertiesList.Where(p => AGENT_PROPERTIES_BUILTIN.Contains(p.PropertyName) == true && p.IsDefault == false && p.TierName.Length > 0).ToList(); + if (agentPropertiesBuiltInList != null && agentPropertiesBuiltInList.Count > 0) + { + foreach (AgentConfigurationProperty agentProperty in agentPropertiesBuiltInList) + { + HealthCheckRuleResult healthCheckRuleResult1 = healthCheckRuleResult.Clone(); + healthCheckRuleResult1.Grade = 3; + + healthCheckRuleResult1.EntityType = "APMTier"; + healthCheckRuleResult1.EntityName = agentProperty.TierName; + if (tiersList != null) + { + APMTier tier = tiersList.Where(t => t.TierName == agentProperty.TierName).FirstOrDefault(); + if (tier != null) + { + healthCheckRuleResult1.EntityID = tier.TierID; + } + else + { + healthCheckRuleResult1.EntityID = 0; + } + } + + switch (agentProperty.PropertyType) + { + case "BOOLEAN": + healthCheckRuleResult1.Description = String.Format("Built-in Agent Property '{0}/{1} [{2}]' value is '{3}' and modified from its default value '{4}'", agentProperty.AgentType, agentProperty.PropertyName, agentProperty.PropertyType, agentProperty.BooleanValue, agentProperty.BooleanDefaultValue); + break; + + case "INTEGER": + healthCheckRuleResult1.Description = String.Format("Built-in Agent Property '{0}/{1} [{2}]' value is '{3}' and modified from its default value '{4}'", agentProperty.AgentType, agentProperty.PropertyName, agentProperty.PropertyType, agentProperty.IntegerValue, agentProperty.IntegerDefaultValue); + break; + + case "STRING": + healthCheckRuleResult1.Description = String.Format("Built-in Agent Property '{0}/{1} [{2}]' value is '{3}' and modified from its default value '{4}'", agentProperty.AgentType, agentProperty.PropertyName, agentProperty.PropertyType, agentProperty.StringValue, agentProperty.StringDefaultValue); + break; + + default: + break; + } + + healthCheckRuleResults.Add(healthCheckRuleResult1); + } + } + } + + if (healthCheckRuleResults.Count == 0) + { + healthCheckRuleResults.Add(healthCheckRuleResult); + } + + return healthCheckRuleResults; + } + + #endregion + + } +} diff --git a/ProcessingSteps/Index/IndexApplicationConfigurationDifferences.cs b/ProcessingSteps/Index/IndexApplicationConfigurationDifferences.cs index 6c57292..0d2cb86 100644 --- a/ProcessingSteps/Index/IndexApplicationConfigurationDifferences.cs +++ b/ProcessingSteps/Index/IndexApplicationConfigurationDifferences.cs @@ -259,7 +259,18 @@ public override bool Execute(ProgramOptions programOptions, JobConfiguration job #endregion - #region Service Endpoint Rules + #region Service Endpoint Discovery Rules + + loggerConsole.Info("Service Endpoint Discovery Rules"); + + List serviceEndpointDiscoveryRulesListReference = FileIOHelper.ReadListFromCSVFile(FilePathMap.APMServiceEndpointDiscoveryRulesIndexFilePath(referenceTarget), new ServiceEndpointDiscoveryRuleReportMap()); + List serviceEndpointDiscoveryRulesListDifference = FileIOHelper.ReadListFromCSVFile(FilePathMap.APMServiceEndpointDiscoveryRulesIndexFilePath(jobTarget), new ServiceEndpointDiscoveryRuleReportMap()); + + configurationDifferencesList.AddRange(compareListOfEntities(referenceTarget, jobTarget, serviceEndpointDiscoveryRulesListReference, serviceEndpointDiscoveryRulesListDifference)); + + #endregion + + #region Service Endpoint Entry Rules loggerConsole.Info("Service Endpoint Entry Rules"); diff --git a/ProcessingSteps/JobStepBase.cs b/ProcessingSteps/JobStepBase.cs index d49aaa3..244f0d3 100644 --- a/ProcessingSteps/JobStepBase.cs +++ b/ProcessingSteps/JobStepBase.cs @@ -24,6 +24,60 @@ public class JobStepBase #endregion + #region Agent Properties + + internal static List AGENT_PROPERTIES_BUILTIN = new List + { + { "adaptive-callgraph-granularity" }, + { "api-thread-activity-timeout-in-seconds" }, + { "api-transaction-timeout-in-seconds" }, + { "async-transaction-demarcator" }, + { "callgraph-granularity-in-ms" }, + { "capture-error-urls" }, + { "capture-raw-sql" }, + { "collection-capture-period-in-minutes" }, + { "collect-user-data-sync" }, + { "disable-custom-exit-points-for" }, + { "disable-exit-call-correlation-for" }, + { "disable-exit-call-metrics-for" }, + { "dont-show-packages" }, + { "downstream-tx-detection-enabled" }, + { "enable-collection-monitoring" }, + { "enable-default-http-error-code-reporter" }, + { "enable-instance-monitoring" }, + { "enable-json-bci-rules" }, + { "enable-object-size-monitoring" }, + { "enable-soap-header-correlation" }, + { "enable-startup-snapshot-policy" }, + { "enable-transaction-correlation" }, + { "enable-xml-bci-rules" }, + { "end-to-end-message-latency-threshold-millis" }, + { "find-entry-points" }, + { "jdbc-callable-statements" }, + { "jdbc-connections" }, + { "jdbc-prepared-statements" }, + { "jdbc-statements" }, + { "leak-diagnostic-interval-in-minutes" }, + { "log-request-payload" }, + { "max-business-transactions" }, + { "max-jdbc-calls-per-callgraph" }, + { "max-jdbc-calls-per-snapshot" }, + { "min-duration-for-jdbc-call-in-ms" }, + { "minimum-age-for-evaluation-in-minutes" }, + { "minimum-size-for-evaluation-in-mb" }, + { "min-load-per-minute-diagnostic-session-trigger" }, + { "on-demand-snapshots" }, + { "rest-num-segments" }, + { "rest-transaction-naming" }, + { "rest-uri-segment-scheme" }, + { "show-packages" }, + { "slow-request-deviation" }, + { "slow-request-monitor-interval" }, + { "slow-request-threshold" } + }; + + #endregion + #region Event types // There are a bazillion types of events @@ -116,9 +170,9 @@ public class JobStepBase { "HTTP_REQUEST_ACTION_STARTED" }, { "HTTP_REQUEST_ACTION_FAILED" }, { "HTTP_REQUEST_ACTION_END" }, - { "RUNBOOK_DIAGNOSTIC SESSION_STARTED" }, - { "RUNBOOK_DIAGNOSTIC SESSION_FAILED" }, - { "RUNBOOK_DIAGNOSTIC SESSION_END" }, + { "RUNBOOK_DIAGNOSTIC_SESSION_STARTED" }, + { "RUNBOOK_DIAGNOSTIC_SESSION_FAILED" }, + { "RUNBOOK_DIAGNOSTIC_SESSION_END" }, { "RUN_LOCAL_SCRIPT_ACTION_STARTED" }, { "RUN_LOCAL_SCRIPT_ACTION_FAILED" }, { "RUN_LOCAL_SCRIPT_ACTION_END" }, diff --git a/ProcessingSteps/JobStepRouter.cs b/ProcessingSteps/JobStepRouter.cs index 468453a..ac4c62f 100644 --- a/ProcessingSteps/JobStepRouter.cs +++ b/ProcessingSteps/JobStepRouter.cs @@ -75,6 +75,8 @@ public class JobStepRouter JobStatus.IndexAPMFlowmaps, JobStatus.IndexAPMSnapshots, + JobStatus.IndexAPMHealthCheck, + // Report data JobStatus.ReportControllerAndApplicationConfiguration, JobStatus.ReportControllerUsersGroupsRolesAndPermissions, @@ -99,6 +101,8 @@ public class JobStepRouter JobStatus.ReportAPMFlameGraphs, JobStatus.ReportAPMEntityDetails, + + JobStatus.ReportHealthCheck, JobStatus.ReportAPMApplicationSummary, JobStatus.ReportAPMEntityDashboardScreenshots, @@ -324,6 +328,8 @@ private static JobStepBase getJobStepFromFactory(JobStatus jobStatus) case JobStatus.IndexAPMSnapshots: return new IndexAPMSnapshots(); + case JobStatus.IndexAPMHealthCheck: + return new IndexAPMHealthCheck(); // Report data case JobStatus.ReportControllerAndApplicationConfiguration: @@ -367,6 +373,8 @@ private static JobStepBase getJobStepFromFactory(JobStatus jobStatus) case JobStatus.ReportAPMEntityDetails: return new ReportAPMEntityDetails(); + case JobStatus.ReportHealthCheck: + return new ReportHealthCheck(); case JobStatus.ReportAPMApplicationSummary: return new ReportAPMApplicationSummary(); diff --git a/ProcessingSteps/Report/JobStepReportBase.cs b/ProcessingSteps/Report/JobStepReportBase.cs index d144c64..fec17de 100644 --- a/ProcessingSteps/Report/JobStepReportBase.cs +++ b/ProcessingSteps/Report/JobStepReportBase.cs @@ -337,7 +337,7 @@ internal static string getExcelTableOrSheetSafeString(string stringToClear) char[] excelTableInvalidChars = { ' ', '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '-', '=', ',', '/', '\\', '[', ']', ':', '?', '|', '"', '<', '>' }; foreach (var c in excelTableInvalidChars) { - stringToClear = stringToClear.Replace(c, '-'); + stringToClear = stringToClear.Replace(c, '_'); } // Apparently it is possible to have a NUL character as a BT name courtesy of penetration testing somehow stringToClear = stringToClear.Replace("\u0000", "NULL"); diff --git a/ProcessingSteps/Report/ReportAPMApplicationSummary.cs b/ProcessingSteps/Report/ReportAPMApplicationSummary.cs index e58cdd7..94ed15d 100644 --- a/ProcessingSteps/Report/ReportAPMApplicationSummary.cs +++ b/ProcessingSteps/Report/ReportAPMApplicationSummary.cs @@ -1,6 +1,8 @@ using AppDynamics.Dexter.ReportObjectMaps; using AppDynamics.Dexter.ReportObjects; using Aspose.Words; +using Aspose.Words.Drawing; +using Aspose.Words.Drawing.Charts; using Aspose.Words.Lists; using Aspose.Words.Saving; using Aspose.Words.Tables; @@ -23,7 +25,6 @@ public class ReportAPMApplicationSummary : JobStepReportBase #endregion - public override bool Execute(ProgramOptions programOptions, JobConfiguration jobConfiguration) { Stopwatch stopWatch = new Stopwatch(); @@ -50,9 +51,20 @@ public override bool Execute(ProgramOptions programOptions, JobConfiguration job return true; } - logger.Info("Setting Aspose License"); - Aspose.Words.License license = new Aspose.Words.License(); - license.SetLicense("Aspose.Words.lic"); + try + { + logger.Info("Setting Aspose License"); + Aspose.Words.License license = new Aspose.Words.License(); + license.SetLicense("Aspose.Words.lic"); + } + catch (Exception ex) + { + logger.Error("No Aspose license"); + logger.Error(ex); + loggerConsole.Warn("No Aspose license, will not generate document"); + + return true; + } try { @@ -116,8 +128,11 @@ public override bool Execute(ProgramOptions programOptions, JobConfiguration job List resolvedBackendsList = FileIOHelper.ReadListFromCSVFile(FilePathMap.APMMappedBackendsIndexFilePath(jobTarget), new APMResolvedBackendReportMap()); - //List eventsAllList = FileIOHelper.ReadListFromCSVFile(FilePathMap.ApplicationEventsIndexFilePath(jobTarget), new EventReportMap()); - //List healthRuleViolationEventsAllList = FileIOHelper.ReadListFromCSVFile(FilePathMap.ApplicationHealthRuleViolationsIndexFilePath(jobTarget), new HealthRuleViolationEventReportMap()); + List businessTransactionsOverflowList = FileIOHelper.ReadListFromCSVFile(FilePathMap.APMOverflowBusinessTransactionsIndexFilePath(jobTarget), new APMOverflowBusinessTransactionReportMap()); + + //List eventsList = FileIOHelper.ReadListFromCSVFile(FilePathMap.ApplicationEventsIndexFilePath(jobTarget), new EventReportMap()); + //List healthRuleViolationEventsList = FileIOHelper.ReadListFromCSVFile(FilePathMap.ApplicationHealthRuleViolationsIndexFilePath(jobTarget), new HealthRuleViolationEventReportMap()); + //List snapshotsAllList = FileIOHelper.ReadListFromCSVFile(FilePathMap.SnapshotsIndexFilePath(jobTarget), new SnapshotReportMap()); //List segmentsAllList = FileIOHelper.ReadListFromCSVFile(FilePathMap.SnapshotsSegmentsIndexFilePath(jobTarget), new SegmentReportMap()); //List exitCallsAllList = FileIOHelper.ReadListFromCSVFile(FilePathMap.SnapshotsExitCallsIndexFilePath(jobTarget), new ExitCallReportMap()); @@ -125,6 +140,18 @@ public override bool Execute(ProgramOptions programOptions, JobConfiguration job //List detectedErrorsAllList = FileIOHelper.ReadListFromCSVFile(FilePathMap.SnapshotsDetectedErrorsIndexFilePath(jobTarget), new DetectedErrorReportMap()); //List businessDataAllList = FileIOHelper.ReadListFromCSVFile(FilePathMap.SnapshotsBusinessDataIndexFilePath(jobTarget), new BusinessDataReportMap()); + List applicationActivityFlowsList = FileIOHelper.ReadListFromCSVFile(FilePathMap.ApplicationFlowmapIndexFilePath(jobTarget), new ApplicationActivityFlowReportMap()); + List tiersActivityFlowsList = FileIOHelper.ReadListFromCSVFile(FilePathMap.TiersFlowmapIndexFilePath(jobTarget), new TierActivityFlowReportMap()); + List nodesActivityFlowsList = FileIOHelper.ReadListFromCSVFile(FilePathMap.NodesFlowmapIndexFilePath(jobTarget), new NodeActivityFlowReportMap()); + List businessTransactionsActivityFlowsList = FileIOHelper.ReadListFromCSVFile(FilePathMap.BusinessTransactionsFlowmapIndexFilePath(jobTarget), new BusinessTransactionActivityFlowReportMap()); + List backendsActivityFlowsList = FileIOHelper.ReadListFromCSVFile(FilePathMap.BackendsFlowmapIndexFilePath(jobTarget), new BackendActivityFlowReportMap()); + + List healthRulesList = FileIOHelper.ReadListFromCSVFile(FilePathMap.ApplicationHealthRulesIndexFilePath(jobTarget), new HealthRuleReportMap()); + List policiesList = FileIOHelper.ReadListFromCSVFile(FilePathMap.ApplicationPoliciesIndexFilePath(jobTarget), new PolicyReportMap()); + List actionsList = FileIOHelper.ReadListFromCSVFile(FilePathMap.ApplicationActionsIndexFilePath(jobTarget), new ActionReportMap()); + List policyActionMappingList = FileIOHelper.ReadListFromCSVFile(FilePathMap.ApplicationPolicyActionMappingsIndexFilePath(jobTarget), new PolicyActionMappingReportMap()); + + List agentPropertiesList = FileIOHelper.ReadListFromCSVFile(FilePathMap.APMAgentConfigurationPropertiesIndexFilePath(jobTarget), new AgentConfigurationPropertyReportMap()); #endregion @@ -158,185 +185,495 @@ public override bool Execute(ProgramOptions programOptions, JobConfiguration job APMApplication application = applicationsList[0]; ControllerSummary controllerSummary = controllerSummariesList[0]; - Table table = insertNameValueTable(builder); - - insertNameValueRow(builder, table, "Controller", String.Format("{0}, Version {1} ({2})", application.Controller, controllerSummary.Version, controllerSummary.VersionDetail)); - insertNameValueRow(builder, table, "Saas or OnPrem", application.Controller.ToLower().Contains("saas.appdynamics") ? "SaaS" : "OnPrem"); - insertNameValueRow(builder, table, "Application", String.Format("{0} ({1}) {2}", application.ApplicationName, application.ApplicationID, application.Description)); - - StringBuilder sb = new StringBuilder(200); - sb.AppendFormat("{0} total ", application.NumTiers); + + Table tableApplicationSummary = insertTableApplicationSummary(builder); + + insertCellStringValue(builder, "Controller"); + insertCellStringValue(builder, application.Controller); + insertCellStringValue(builder, application.Controller.ToLower().Contains("saas.appdynamics") ? "SaaS" : "On Premises"); + builder.EndRow(); + + insertCellStringValue(builder, "Version"); + insertCellStringValue(builder, controllerSummary.Version); + insertCellStringValue(builder, controllerSummary.VersionDetail); + builder.EndRow(); + + insertCellStringValue(builder, "Application"); + insertCellStringValue(builder, String.Format("{0} ({1}) {2} [{3}]", application.ApplicationName, application.ApplicationID, application.Description, jobTarget.Type)); + insertCellNoValue(builder); + builder.Write("Navigate to: "); + if (applicationsMetricsList != null && applicationsMetricsList.Count > 0) + { + APMApplication applicationWithMetrics = applicationsMetricsList[0]; + insertLinkToURL(builder, hyperLinkStyle, "Controller", applicationWithMetrics.ControllerLink); + builder.Write(", "); + insertLinkToURL(builder, hyperLinkStyle, "Application", applicationWithMetrics.ApplicationLink); + } + else + { + insertLinkToURL(builder, hyperLinkStyle, "Controller", application.ControllerLink); + builder.Write(", "); + insertLinkToURL(builder, hyperLinkStyle, "Application", application.ApplicationLink); + } + builder.EndRow(); + + finalizeTableApplicationSummary(builder, tableApplicationSummary); + + #endregion + + #region Entity Types Table + + insertHeading(builder, StyleIdentifier.Heading2, "Entity Types and Activity", String.Empty, listHeadingsOutline, 1); + + builder.ParagraphFormat.StyleIdentifier = StyleIdentifier.Normal; + + Table tableApplicationEntitySummary = insertTableApplicationEntityTypes(builder); + + #region Tiers + + insertCellNoValue(builder); insertLinkToBookmark(builder, hyperLinkStyle, "Tiers", "Tiers"); if (tiersList != null && tiersList.Count > 0) { + List tierTypesList = new List(100); + List tierTypesCountsList = new List(100); + List tierTypeAndCountsList = new List(100); + var groupTypes = tiersList.GroupBy(t => t.AgentType); - sb.Append("("); - foreach (var groupType in groupTypes) - { - sb.AppendFormat("{0} {1}", groupType.Count(), groupType.Key); - sb.Append(", "); - } - if (sb.Length > 2) sb.Remove(sb.Length - 2, 2); - sb.Append("), "); + measureTypesOfItemsInGroupBy(groupTypes, tierTypeAndCountsList, tierTypesList, tierTypesCountsList); + + insertCellStringValue(builder, String.Format("{0} total\n{1}", tiersList.Count, String.Join("\n", tierTypeAndCountsList.ToArray()))); + insertCellNoValue(builder); + insertPieChart(builder, "Tier Types", tierTypesList.ToArray(), tierTypesCountsList.ToArray()); } - if (tiersMetricsList != null) + else { - sb.AppendFormat("{0} active/{1} inactive", tiersMetricsList.Count(t => t.HasActivity == true), tiersMetricsList.Count(t => t.HasActivity == false)); + insertCellStringValue(builder, "No tier list available"); + insertCellStringValue(builder, String.Empty); } - insertNameValueRow(builder, table, "Tiers", sb.ToString()); - sb = new StringBuilder(200); - sb.AppendFormat("{0} total ", application.NumNodes); + if (tiersMetricsList != null && tiersMetricsList.Count > 0) + { + string[] tierActivityArray = new string[2]; + tierActivityArray[0] = "Has Activity"; + tierActivityArray[1] = "No Activity"; + double[] tierActivityCountsArray = new double[2]; + + tierActivityCountsArray[0] = tiersMetricsList.Count(t => t.HasActivity == true); + tierActivityCountsArray[1] = tiersMetricsList.Count(t => t.HasActivity == false); + + insertCellStringValue(builder, String.Format("{0} active\n{1} inactive", tierActivityCountsArray[0], tierActivityCountsArray[1])); + insertCellNoValue(builder); + insertPieChart(builder, "Tier Activity", tierActivityArray, tierActivityCountsArray); + } + else + { + insertCellStringValue(builder, "No metrics available"); + insertCellStringValue(builder, String.Empty); + } + builder.EndRow(); + + #endregion + + #region Nodes + + insertCellNoValue(builder); insertLinkToBookmark(builder, hyperLinkStyle, "Nodes", "Nodes"); if (nodesList != null && nodesList.Count > 0) { - var groupTypes = nodesList.GroupBy(n => n.AgentType); - sb.Append("("); - foreach (var groupType in groupTypes) - { - sb.AppendFormat("{0} {1}", groupType.Count(), groupType.Key); - sb.Append(", "); - } - if (sb.Length > 2) sb.Remove(sb.Length - 2, 2); - sb.Append("), "); + List nodeTypesList = new List(100); + List nodeTypesCountsList = new List(100); + List nodeTypeAndCountsList = new List(100); + + var groupTypes = nodesList.GroupBy(t => t.AgentType); + measureTypesOfItemsInGroupBy(groupTypes, nodeTypeAndCountsList, nodeTypesList, nodeTypesCountsList); + + insertCellStringValue(builder, String.Format("{0} total\n{1}", nodesList.Count, String.Join("\n", nodeTypeAndCountsList.ToArray()))); + insertCellNoValue(builder); + insertPieChart(builder, "Node Types", nodeTypesList.ToArray(), nodeTypesCountsList.ToArray()); } - if (nodesMetricsList != null) + else + { + insertCellStringValue(builder, "No node list available"); + insertCellStringValue(builder, String.Empty); + } + + if (nodesMetricsList != null && nodesMetricsList.Count > 0) + { + string[] nodeActivityArray = new string[2]; + nodeActivityArray[0] = "Has Activity"; + nodeActivityArray[1] = "No Activity"; + double[] nodeActivityCountsArray = new double[2]; + + nodeActivityCountsArray[0] = nodesMetricsList.Count(t => t.HasActivity == true); + nodeActivityCountsArray[1] = nodesMetricsList.Count(t => t.HasActivity == false); + + insertCellStringValue(builder, String.Format("{0} active\n{1} inactive", nodeActivityCountsArray[0], nodeActivityCountsArray[1])); + insertCellNoValue(builder); + insertPieChart(builder, "Node Activity", nodeActivityArray, nodeActivityCountsArray); + } + else { - sb.AppendFormat("{0} active/{1} inactive", nodesMetricsList.Count(t => t.HasActivity == true), nodesMetricsList.Count(t => t.HasActivity == false)); + insertCellStringValue(builder, "No metrics available"); + insertCellStringValue(builder, String.Empty); } - insertNameValueRow(builder, table, "Nodes", sb.ToString()); + builder.EndRow(); + + #endregion - sb = new StringBuilder(200); - sb.AppendFormat("{0} total ", application.NumBTs); + #region Business Transactions + + insertCellNoValue(builder); insertLinkToBookmark(builder, hyperLinkStyle, "Business Transactions", "Business_Transactions"); if (businessTransactionsList != null && businessTransactionsList.Count > 0) { - var groupTypes = businessTransactionsList.GroupBy(b => b.BTType); - sb.Append("("); - foreach (var groupType in groupTypes) - { - sb.AppendFormat("{0} {1}", groupType.Count(), groupType.Key); - sb.Append(", "); - } - if (sb.Length > 2) sb.Remove(sb.Length - 2, 2); - sb.Append("), "); + List businessTransactionTypesList = new List(100); + List businessTransactionTypesCountsList = new List(100); + List businessTransactionTypeAndCountsList = new List(100); + + var groupTypes = businessTransactionsList.GroupBy(t => t.BTType); + measureTypesOfItemsInGroupBy(groupTypes, businessTransactionTypeAndCountsList, businessTransactionTypesList, businessTransactionTypesCountsList); + + insertCellStringValue(builder, String.Format("{0} total\n{1}", businessTransactionsList.Count, String.Join("\n", businessTransactionTypeAndCountsList.ToArray()))); + insertCellNoValue(builder); + insertPieChart(builder, "Business Transaction Types", businessTransactionTypesList.ToArray(), businessTransactionTypesCountsList.ToArray()); + } + else + { + insertCellStringValue(builder, "No business transaction list available"); + insertCellStringValue(builder, String.Empty); + } + + if (businessTransactionsMetricsList != null && businessTransactionsMetricsList.Count > 0) + { + string[] businessTransactionActivityArray = new string[2]; + businessTransactionActivityArray[0] = "Has Activity"; + businessTransactionActivityArray[1] = "No Activity"; + double[] businessTransactionActivityCountsArray = new double[2]; + + businessTransactionActivityCountsArray[0] = businessTransactionsMetricsList.Count(t => t.HasActivity == true); + businessTransactionActivityCountsArray[1] = businessTransactionsMetricsList.Count(t => t.HasActivity == false); + + insertCellStringValue(builder, String.Format("{0} active\n{1} inactive", businessTransactionActivityCountsArray[0], businessTransactionActivityCountsArray[1])); + insertCellNoValue(builder); + insertPieChart(builder, "Business Transaction Activity", businessTransactionActivityArray, businessTransactionActivityCountsArray); + } + else + { + insertCellStringValue(builder, "No metrics available"); + insertCellStringValue(builder, String.Empty); + } + builder.EndRow(); + + #endregion + + #region Business Transactions - Overflow + + insertCellStringValue(builder, "Overflow Business Transactions"); + if (businessTransactionsList != null && businessTransactionsList.Count > 0 && + businessTransactionsOverflowList != null && businessTransactionsOverflowList.Count > 0) + { + List businessTransactionTypesList = new List(100); + List businessTransactionTypesCountsList = new List(100); + List businessTransactionTypeAndCountsList = new List(100); + + var groupTypes = businessTransactionsOverflowList.GroupBy(t => t.BTType); + measureTypesOfItemsInGroupBy(groupTypes, businessTransactionTypeAndCountsList, businessTransactionTypesList, businessTransactionTypesCountsList); + + insertCellStringValue(builder, String.Format("{0} total\n{1} unregistered\n{2}", businessTransactionsList.Where(b => b.BTType == "OVERFLOW").Count(), businessTransactionsOverflowList.Count, String.Join("\n", businessTransactionTypeAndCountsList.ToArray()))); + insertCellNoValue(builder); + insertPieChart(builder, "Overflow Business Transaction Types", businessTransactionTypesList.ToArray(), businessTransactionTypesCountsList.ToArray()); } - if (businessTransactionsMetricsList != null) + else { - sb.AppendFormat("{0} active/{1} inactive", businessTransactionsMetricsList.Count(t => t.HasActivity == true), businessTransactionsMetricsList.Count(t => t.HasActivity == false)); + insertCellStringValue(builder, "No business transaction list available"); + insertCellStringValue(builder, String.Empty); } - insertNameValueRow(builder, table, "Business Transactions", sb.ToString()); - sb = new StringBuilder(200); if (businessTransactionsMetricsList != null && businessTransactionsMetricsList.Count > 0) { - sb.AppendFormat("{0} active/{1} inactive", businessTransactionsMetricsList.Count(t => t.BTType == "OVERFLOW" && t.HasActivity == true), businessTransactionsMetricsList.Count(t => t.BTType == "OVERFLOW" && t.HasActivity == false)); + string[] businessTransactionActivityArray = new string[2]; + businessTransactionActivityArray[0] = "Has Activity"; + businessTransactionActivityArray[1] = "No Activity"; + double[] businessTransactionActivityCountsArray = new double[2]; + + businessTransactionActivityCountsArray[0] = businessTransactionsMetricsList.Where(b => b.BTType == "OVERFLOW").Count(t => t.HasActivity == true); + businessTransactionActivityCountsArray[1] = businessTransactionsMetricsList.Where(b => b.BTType == "OVERFLOW").Count(t => t.HasActivity == false); + + insertCellStringValue(builder, String.Format("{0} active\n{1} inactive", businessTransactionActivityCountsArray[0], businessTransactionActivityCountsArray[1])); + insertCellNoValue(builder); + insertPieChart(builder, "Business Transaction Activity", businessTransactionActivityArray, businessTransactionActivityCountsArray); + } + else + { + insertCellStringValue(builder, "No metrics available"); + insertCellStringValue(builder, String.Empty); } - insertNameValueRow(builder, table, "Overflow BTs", sb.ToString()); + builder.EndRow(); + #endregion + + #region Backends - sb = new StringBuilder(200); - sb.AppendFormat("{0} total ", application.NumBackends); + insertCellNoValue(builder); insertLinkToBookmark(builder, hyperLinkStyle, "Backends", "Backends"); if (backendsList != null && backendsList.Count > 0) { - var groupTypes = backendsList.GroupBy(b => b.BackendType); - sb.Append("("); - foreach (var groupType in groupTypes) - { - sb.AppendFormat("{0} {1}", groupType.Count(), groupType.Key); - sb.Append(", "); - } - if (sb.Length > 2) sb.Remove(sb.Length - 2, 2); - sb.Append("), "); + List backendTypesList = new List(100); + List backendTypesCountsList = new List(100); + List backendTypeAndCountsList = new List(100); + + var groupTypes = backendsList.GroupBy(t => t.BackendType); + measureTypesOfItemsInGroupBy(groupTypes, backendTypeAndCountsList, backendTypesList, backendTypesCountsList); + + insertCellStringValue(builder, String.Format("{0} total\n{1}", backendsList.Count, String.Join("\n", backendTypeAndCountsList.ToArray()))); + insertCellNoValue(builder); + insertPieChart(builder, "Backend Types", backendTypesList.ToArray(), backendTypesCountsList.ToArray()); } - if (backendsMetricsList != null) + else { - sb.AppendFormat("{0} active/{1} inactive", backendsMetricsList.Count(t => t.HasActivity == true), backendsMetricsList.Count(t => t.HasActivity == false)); + insertCellStringValue(builder, "No backend list available"); + insertCellStringValue(builder, String.Empty); } - insertNameValueRow(builder, table, "Backends", sb.ToString()); - sb = new StringBuilder(200); - sb.AppendFormat("{0} total ", application.NumSEPs); + if (backendsMetricsList != null && backendsMetricsList.Count > 0) + { + string[] backendActivityArray = new string[2]; + backendActivityArray[0] = "Has Activity"; + backendActivityArray[1] = "No Activity"; + double[] backendActivityCountsArray = new double[2]; + + backendActivityCountsArray[0] = backendsMetricsList.Count(t => t.HasActivity == true); + backendActivityCountsArray[1] = backendsMetricsList.Count(t => t.HasActivity == false); + + insertCellStringValue(builder, String.Format("{0} active\n{1} inactive", backendActivityCountsArray[0], backendActivityCountsArray[1])); + insertCellNoValue(builder); + insertPieChart(builder, "Backend Activity", backendActivityArray, backendActivityCountsArray); + } + else + { + insertCellStringValue(builder, "No metrics available"); + insertCellStringValue(builder, String.Empty); + } + builder.EndRow(); + + #endregion + + #region Service Endpoints + + insertCellNoValue(builder); insertLinkToBookmark(builder, hyperLinkStyle, "Service Endpoints", "Service_Endpoints"); if (serviceEndpointsList != null && serviceEndpointsList.Count > 0) { - var groupTypes = serviceEndpointsList.GroupBy(b => b.SEPType); - sb.Append("("); - foreach (var groupType in groupTypes) - { - sb.AppendFormat("{0} {1}", groupType.Count(), groupType.Key); - sb.Append(", "); - } - if (sb.Length > 2) sb.Remove(sb.Length - 2, 2); - sb.Append("), "); + List serviceEndpointTypesList = new List(100); + List serviceEndpointTypesCountsList = new List(100); + List serviceEndpointTypeAndCountsList = new List(100); + + var groupTypes = serviceEndpointsList.GroupBy(t => t.SEPType); + measureTypesOfItemsInGroupBy(groupTypes, serviceEndpointTypeAndCountsList, serviceEndpointTypesList, serviceEndpointTypesCountsList); + + insertCellStringValue(builder, String.Format("{0} total\n{1}", serviceEndpointsList.Count, String.Join("\n", serviceEndpointTypeAndCountsList.ToArray()))); + insertCellNoValue(builder); + insertPieChart(builder, "Service Endpoint Types", serviceEndpointTypesList.ToArray(), serviceEndpointTypesCountsList.ToArray()); } - if (serviceEndpointsMetricsList != null) + else { - sb.AppendFormat("{0} active/{1} inactive", serviceEndpointsMetricsList.Count(t => t.HasActivity == true), serviceEndpointsMetricsList.Count(t => t.HasActivity == false)); + insertCellStringValue(builder, "No service endpoint list available"); + insertCellStringValue(builder, String.Empty); } - insertNameValueRow(builder, table, "Service Endpoints", sb.ToString()); - sb = new StringBuilder(200); - sb.AppendFormat("{0} total ", application.NumErrors); + if (serviceEndpointsMetricsList != null && serviceEndpointsMetricsList.Count > 0) + { + string[] serviceEndpointActivityArray = new string[2]; + serviceEndpointActivityArray[0] = "Has Activity"; + serviceEndpointActivityArray[1] = "No Activity"; + double[] serviceEndpointActivityCountsArray = new double[2]; + + serviceEndpointActivityCountsArray[0] = serviceEndpointsMetricsList.Count(t => t.HasActivity == true); + serviceEndpointActivityCountsArray[1] = serviceEndpointsMetricsList.Count(t => t.HasActivity == false); + + insertCellStringValue(builder, String.Format("{0} active\n{1} inactive", serviceEndpointActivityCountsArray[0], serviceEndpointActivityCountsArray[1])); + insertCellNoValue(builder); + insertPieChart(builder, "Service Endpoint Activity", serviceEndpointActivityArray, serviceEndpointActivityCountsArray); + } + else + { + insertCellStringValue(builder, "No metrics available"); + insertCellStringValue(builder, String.Empty); + } + builder.EndRow(); + + #endregion + + #region Errors + + insertCellNoValue(builder); insertLinkToBookmark(builder, hyperLinkStyle, "Errors", "Errors"); if (errorsList != null && errorsList.Count > 0) { - var groupTypes = errorsList.GroupBy(e => e.ErrorType); - sb.Append("("); - foreach (var groupType in groupTypes) - { - sb.AppendFormat("{0} {1}", groupType.Count(), groupType.Key); - sb.Append(", "); - } - if (sb.Length > 2) sb.Remove(sb.Length - 2, 2); - sb.Append("), "); + List errorTypesList = new List(100); + List errorTypesCountsList = new List(100); + List errorTypeAndCountsList = new List(100); + + var groupTypes = errorsList.GroupBy(t => t.ErrorType); + measureTypesOfItemsInGroupBy(groupTypes, errorTypeAndCountsList, errorTypesList, errorTypesCountsList); + + insertCellStringValue(builder, String.Format("{0} total\n{1}", errorsList.Count, String.Join("\n", errorTypeAndCountsList.ToArray()))); + insertCellNoValue(builder); + insertPieChart(builder, "Error Types", errorTypesList.ToArray(), errorTypesCountsList.ToArray()); } - if (errorsMetricsList != null) + else { - sb.AppendFormat("{0} active/{1} inactive", errorsMetricsList.Count(t => t.HasActivity == true), errorsMetricsList.Count(t => t.HasActivity == false)); + insertCellStringValue(builder, "No error list available"); + insertCellStringValue(builder, String.Empty); } - insertNameValueRow(builder, table, "Errors", sb.ToString()); - sb = new StringBuilder(200); - sb.AppendFormat("{0} total ", application.NumIPs); + if (errorsMetricsList != null && errorsMetricsList.Count > 0) + { + string[] errorActivityArray = new string[2]; + errorActivityArray[0] = "Has Activity"; + errorActivityArray[1] = "No Activity"; + double[] errorActivityCountsArray = new double[2]; + + errorActivityCountsArray[0] = errorsMetricsList.Count(t => t.HasActivity == true); + errorActivityCountsArray[1] = errorsMetricsList.Count(t => t.HasActivity == false); + + insertCellStringValue(builder, String.Format("{0} active\n{1} inactive", errorActivityCountsArray[0], errorActivityCountsArray[1])); + insertCellNoValue(builder); + insertPieChart(builder, "Error Activity", errorActivityArray, errorActivityCountsArray); + } + else + { + insertCellStringValue(builder, "No metrics available"); + insertCellStringValue(builder, String.Empty); + } + builder.EndRow(); + + #endregion + + #region Information Points + + insertCellNoValue(builder); insertLinkToBookmark(builder, hyperLinkStyle, "Information Points", "Information_Points"); if (informationPointsList != null && informationPointsList.Count > 0) { - var groupTypes = informationPointsList.GroupBy(p => p.IPType); - sb.Append("("); - foreach (var groupType in groupTypes) - { - sb.AppendFormat("{0} {1}", groupType.Count(), groupType.Key); - sb.Append(", "); - } - if (sb.Length > 2) sb.Remove(sb.Length - 2, 2); - sb.Append("), "); + List informationPointTypesList = new List(100); + List informationPointTypesCountsList = new List(100); + List informationPointTypeAndCountsList = new List(100); + + var groupTypes = informationPointsList.GroupBy(t => t.IPType); + measureTypesOfItemsInGroupBy(groupTypes, informationPointTypeAndCountsList, informationPointTypesList, informationPointTypesCountsList); + + insertCellStringValue(builder, String.Format("{0} total\n{1}", informationPointsList.Count, String.Join("\n", informationPointTypeAndCountsList.ToArray()))); + insertCellNoValue(builder); + insertPieChart(builder, "Information Point Types", informationPointTypesList.ToArray(), informationPointTypesCountsList.ToArray()); } - if (informationPointsMetricsList != null) + else { - sb.AppendFormat("{0} active/{1} inactive", informationPointsMetricsList.Count(t => t.HasActivity == true), informationPointsMetricsList.Count(t => t.HasActivity == false)); + insertCellStringValue(builder, "No information point list available"); + insertCellStringValue(builder, String.Empty); } - insertNameValueRow(builder, table, "Information Points", sb.ToString()); - sb = new StringBuilder(200); + if (informationPointsMetricsList != null && informationPointsMetricsList.Count > 0) + { + string[] informationPointActivityArray = new string[2]; + informationPointActivityArray[0] = "Has Activity"; + informationPointActivityArray[1] = "No Activity"; + double[] informationPointActivityCountsArray = new double[2]; + + informationPointActivityCountsArray[0] = informationPointsMetricsList.Count(t => t.HasActivity == true); + informationPointActivityCountsArray[1] = informationPointsMetricsList.Count(t => t.HasActivity == false); + + insertCellStringValue(builder, String.Format("{0} active\n{1} inactive", informationPointActivityCountsArray[0], informationPointActivityCountsArray[1])); + insertCellNoValue(builder); + insertPieChart(builder, "Information Point Activity", informationPointActivityArray, informationPointActivityCountsArray); + } + else + { + insertCellStringValue(builder, "No metrics available"); + insertCellStringValue(builder, String.Empty); + } + builder.EndRow(); + + #endregion + + finalizeTableApplicationEntityTypes(builder, tableApplicationEntitySummary); + + #endregion + + #region Detected Entity Dependencies + + insertHeading(builder, StyleIdentifier.Heading2, "Detected Entity Dependencies", String.Empty, listHeadingsOutline, 1); + + builder.ParagraphFormat.StyleIdentifier = StyleIdentifier.Normal; + + Table tableApplicationEntityMapped = insertTableApplicationEntityMapped(builder); + + #region Explicitly Registered Business Transactions + + insertCellStringValue(builder, "Business Transaction Source"); + if (businessTransactionsList != null && businessTransactionsList.Count > 0) + { + List businessTransactionTypesList = new List(100); + List businessTransactionTypesCountsList = new List(100); + List businessTransactionTypeAndCountsList = new List(100); + + var groupTypes = businessTransactionsList.Where(t => t.IsExplicitRule == true).GroupBy(t => t.BTType); + measureTypesOfItemsInGroupBy(groupTypes, businessTransactionTypeAndCountsList, businessTransactionTypesList, businessTransactionTypesCountsList); + + insertCellStringValue(builder, String.Format("Explicitly registered\n{0} total\n{1}", businessTransactionsList.Where(t => t.IsExplicitRule == true).Count(), String.Join("\n", businessTransactionTypeAndCountsList.ToArray()))); + insertCellNoValue(builder); + insertPieChart(builder, "Explicit Business Transaction", businessTransactionTypesList.ToArray(), businessTransactionTypesCountsList.ToArray()); + } + else + { + insertCellStringValue(builder, "No business transaction list available"); + insertCellStringValue(builder, String.Empty); + } + if (businessTransactionsList != null && businessTransactionsList.Count > 0) + { + List businessTransactionTypesList = new List(100); + List businessTransactionTypesCountsList = new List(100); + List businessTransactionTypeAndCountsList = new List(100); + + var groupTypes = businessTransactionsList.Where(t => t.IsExplicitRule == false).GroupBy(t => t.BTType); + measureTypesOfItemsInGroupBy(groupTypes, businessTransactionTypeAndCountsList, businessTransactionTypesList, businessTransactionTypesCountsList); + + insertCellStringValue(builder, String.Format("Automatically registered\n{0} total\n{1}", businessTransactionsList.Where(t => t.IsExplicitRule == false).Count(), String.Join("\n", businessTransactionTypeAndCountsList.ToArray()))); + insertCellNoValue(builder); + insertPieChart(builder, "Automatic Business Transaction", businessTransactionTypesList.ToArray(), businessTransactionTypesCountsList.ToArray()); + } + else + { + insertCellStringValue(builder, "No business transaction list available"); + insertCellStringValue(builder, String.Empty); + } + + builder.EndRow(); + + #endregion + + #region Mapped Backends + + insertCellStringValue(builder, "Mapped Backends"); if (resolvedBackendsList != null && resolvedBackendsList.Count > 0) { - sb.AppendFormat("{0} total ", resolvedBackendsList.Count); + List backendTypesList = new List(100); + List backendTypesCountsList = new List(100); + List backendTypeAndCountsList = new List(100); - var groupTypes = resolvedBackendsList.GroupBy(b => b.BackendType); - sb.Append("("); - foreach (var groupType in groupTypes) - { - sb.AppendFormat("{0} {1}", groupType.Count(), groupType.Key); - sb.Append(", "); - } - if (sb.Length > 2) sb.Remove(sb.Length - 2, 2); - sb.Append(")"); + var groupTypes = resolvedBackendsList.GroupBy(t => t.BackendType); + measureTypesOfItemsInGroupBy(groupTypes, backendTypeAndCountsList, backendTypesList, backendTypesCountsList); + insertCellStringValue(builder, String.Format("{0} total\n{1}", resolvedBackendsList.Count, String.Join("\n", backendTypeAndCountsList.ToArray()))); + insertCellNoValue(builder); + insertPieChart(builder, "Mapped Backend Types", backendTypesList.ToArray(), backendTypesCountsList.ToArray()); + } + else + { + insertCellStringValue(builder, "No mapped backend list available"); + insertCellStringValue(builder, String.Empty); } - insertNameValueRow(builder, table, "Mapped Backends", sb.ToString()); + insertCellNoValue(builder); + insertCellNoValue(builder); - insertCellWithContent(builder, table, "Links"); - Cell cell = builder.InsertCell(); - insertLinkToURL(builder, hyperLinkStyle, "Controller", application.ControllerLink); - builder.Write(", "); - insertLinkToURL(builder, hyperLinkStyle, "Controller", application.ControllerLink); builder.EndRow(); - finalizeNameValueTable(builder, table); + #endregion + + finalizeTableApplicationEntityMapped(builder, tableApplicationEntityMapped); #endregion @@ -360,11 +697,66 @@ public override bool Execute(ProgramOptions programOptions, JobConfiguration job #region Flowmap - insertHeading(builder, StyleIdentifier.Heading2, "Flowmap", String.Empty, listHeadingsOutline, 1); - + insertHeading(builder, StyleIdentifier.Heading2, "Flowmap in Grid Form", String.Empty, listHeadingsOutline, 1); builder.ParagraphFormat.StyleIdentifier = StyleIdentifier.Normal; - builder.Writeln("TODO"); + + Table tableApplicationActivityGrid = insertTableActivityGrid(builder); + + if (applicationActivityFlowsList != null && applicationActivityFlowsList.Count > 0) + { + foreach (ActivityFlow activityFlow in applicationActivityFlowsList) + { + insertRowActivityGrid(builder, activityFlow); + } + } + + finalizeTableActivityGrid(builder, tableApplicationActivityGrid); + + #endregion + + #region Agent Properties + + if (agentPropertiesList != null && agentPropertiesList.Count > 0 && agentPropertiesList.Where(p => p.IsDefault == false).Count() > 0) + { + insertHeading(builder, StyleIdentifier.Heading2, "Agent Properties", "Application_Properties", listHeadingsOutline, 1); + + builder.ParagraphFormat.StyleIdentifier = StyleIdentifier.Normal; + + Table tableApplicationAgentProperties = insertTableApplicationAgentProperties(builder); + + foreach (AgentConfigurationProperty agentProperty in agentPropertiesList.Where(p => p.IsDefault == false)) + { + insertCellStringValue(builder, agentProperty.TierName.Length == 0 ? "Application" : agentProperty.TierName); + insertCellStringValue(builder, agentProperty.AgentType); + insertCellStringValue(builder, agentProperty.PropertyName); + insertCellStringValue(builder, agentProperty.PropertyType); + switch (agentProperty.PropertyType) + { + case "BOOLEAN": + insertCellStringValue(builder, agentProperty.BooleanValue); + insertCellNoValue(builder); insertStrikethroughText(builder, agentProperty.BooleanDefaultValue.ToString()); + break; + + case "INTEGER": + insertCellStringValue(builder, agentProperty.IntegerValue); + insertCellNoValue(builder); insertStrikethroughText(builder, agentProperty.IntegerDefaultValue.ToString()); + break; + + case "STRING": + insertCellStringValue(builder, agentProperty.StringValue); + insertCellNoValue(builder); insertStrikethroughText(builder, agentProperty.StringDefaultValue); + break; + + default: + break; + } + insertCellNoValue(builder); insertTextWithSize(builder, agentProperty.Description, 8); + builder.EndRow(); + } + + finalizeApplicationAgentProperties(builder, tableApplicationAgentProperties); + } #endregion } @@ -387,18 +779,40 @@ public override bool Execute(ProgramOptions programOptions, JobConfiguration job #region Summary Table - insertHeading( - builder, - StyleIdentifier.Heading2, - "Summary", - String.Empty, - listHeadingsOutline, - 1); + insertHeading(builder, StyleIdentifier.Heading2, "Summary", String.Empty, listHeadingsOutline, 1); builder.ParagraphFormat.StyleIdentifier = StyleIdentifier.Normal; - Table table = insertNameValueTable(builder); - finalizeNameValueTable(builder, table); + Table table = insertTableTiersSummary(builder); + + foreach (APMTier tier in tiersList) + { + APMTier tierWithMetric = tier; + if (tiersMetricsList != null) tierWithMetric = tiersMetricsList.Where(t => t.TierID == tier.TierID).FirstOrDefault(); + + insertCellNoValue(builder); insertLinkToBookmark(builder, hyperLinkStyle, tier.TierName, getShortenedEntityNameForWordBookmark("tier", tier.TierName, tier.TierID)); + insertCellStringValue(builder, tier.AgentType); + insertCellNoValue(builder); insertLinkToBookmark(builder, hyperLinkStyle, tier.NumNodes.ToString(), getShortenedEntityNameForWordBookmark("tiernode", tier.TierName, tier.TierID)); + if (nodesList != null) + { + insertCellStringValue(builder, nodesList.Where(n => n.TierID == tier.TierID && n.MachineAgentPresent == true).Count()); + } + else + { + insertCellStringValue(builder, 0); + } + insertCellNoValue(builder); insertLinkToBookmark(builder, hyperLinkStyle, tier.NumBTs.ToString(), getShortenedEntityNameForWordBookmark("tierbt", tier.TierName, tier.TierID)); + insertCellNoValue(builder); insertLinkToBookmark(builder, hyperLinkStyle, tier.NumSEPs.ToString(), getShortenedEntityNameForWordBookmark("tiersep", tier.TierName, tier.TierID)); + insertCellNoValue(builder); insertLinkToBookmark(builder, hyperLinkStyle, tier.NumErrors.ToString(), getShortenedEntityNameForWordBookmark("tiererr", tier.TierName, tier.TierID)); + insertCellStringValue(builder, tierWithMetric.AvailAgent); + insertCellStringValue(builder, tierWithMetric.AvailMachine); + insertCellStringValue(builder, tierWithMetric.HasActivity); + insertCellStringValue(builder, -123); + insertCellStringValue(builder, -321); + builder.EndRow(); + } + + finalizeTableTiersSummary(builder, table); #endregion @@ -406,6 +820,9 @@ public override bool Execute(ProgramOptions programOptions, JobConfiguration job foreach (APMTier tier in tiersList) { + APMTier tierWithMetric = tier; + if (tiersMetricsList != null) tierWithMetric = tiersMetricsList.Where(t => t.TierID == tier.TierID).FirstOrDefault(); + insertHeading(builder, StyleIdentifier.Heading2, String.Format("{0} [{1}] ({2})", tier.TierName, tier.AgentType, tier.TierID), getShortenedEntityNameForWordBookmark("tier", tier.TierName, tier.TierID), listHeadingsOutline, 1); insertLinksToEntityTypeSections(builder); @@ -416,13 +833,94 @@ public override bool Execute(ProgramOptions programOptions, JobConfiguration job builder.ParagraphFormat.StyleIdentifier = StyleIdentifier.Normal; - table = insertNameValueTable(builder); - finalizeNameValueTable(builder, table); + table = insertTableTierEntityTypes(builder); - #endregion + // APM Node versions + insertCellStringValue(builder, "Node APM"); + if (nodesList != null && nodesList.Count > 0) + { + List nodeTypesList = new List(100); + List nodeTypesCountsList = new List(100); + List nodeTypeAndCountsList = new List(100); - builder.ParagraphFormat.StyleIdentifier = StyleIdentifier.Normal; - builder.Writeln(tier.ToString()); + var groupTypes = nodesList.Where(n => n.TierID == tier.TierID && n.AgentPresent == true).GroupBy(t => t.AgentVersion); + measureTypesOfItemsInGroupBy(groupTypes, nodeTypeAndCountsList, nodeTypesList, nodeTypesCountsList); + + insertCellStringValue(builder, String.Format("{0} total\n{1}", nodesList.Where(n => n.TierID == tier.TierID && n.AgentPresent == true).Count(), String.Join("\n", nodeTypeAndCountsList.ToArray()))); + insertCellNoValue(builder); + insertPieChart(builder, "Node Versions", nodeTypesList.ToArray(), nodeTypesCountsList.ToArray()); + } + else + { + insertCellStringValue(builder, "No node list available"); + insertCellStringValue(builder, String.Empty); + } + + if (nodesMetricsList != null && nodesMetricsList.Count > 0) + { + string[] nodeActivityArray = new string[2]; + nodeActivityArray[0] = "Has Activity"; + nodeActivityArray[1] = "No Activity"; + double[] nodeActivityCountsArray = new double[2]; + + nodeActivityCountsArray[0] = nodesMetricsList.Where(n => n.TierID == tier.TierID && n.IsAPMAgentUsed == true).Count(t => t.HasActivity == true); + nodeActivityCountsArray[1] = nodesMetricsList.Where(n => n.TierID == tier.TierID && n.IsAPMAgentUsed == true).Count(t => t.HasActivity == false); + + insertCellStringValue(builder, String.Format("{0} active\n{1} inactive", nodeActivityCountsArray[0], nodeActivityCountsArray[1])); + insertCellNoValue(builder); + insertPieChart(builder, "Node Activity", nodeActivityArray, nodeActivityCountsArray); + } + else + { + insertCellStringValue(builder, "No metrics available"); + insertCellStringValue(builder, String.Empty); + } + builder.EndRow(); + + // Machine Agent + insertCellStringValue(builder, "Node MA"); + if (nodesList != null && nodesList.Count > 0) + { + List nodeTypesList = new List(100); + List nodeTypesCountsList = new List(100); + List nodeTypeAndCountsList = new List(100); + + var groupTypes = nodesList.Where(n => n.TierID == tier.TierID && n.MachineAgentPresent == true).GroupBy(t => t.MachineAgentVersion); + measureTypesOfItemsInGroupBy(groupTypes, nodeTypeAndCountsList, nodeTypesList, nodeTypesCountsList); + + insertCellStringValue(builder, String.Format("{0} total\n{1}", nodesList.Where(n => n.TierID == tier.TierID && n.MachineAgentPresent == true).Count(), String.Join("\n", nodeTypeAndCountsList.ToArray()))); + insertCellNoValue(builder); + insertPieChart(builder, "Node Versions", nodeTypesList.ToArray(), nodeTypesCountsList.ToArray()); + } + else + { + insertCellStringValue(builder, "No node list available"); + insertCellStringValue(builder, String.Empty); + } + + if (nodesMetricsList != null && nodesMetricsList.Count > 0) + { + string[] nodeActivityArray = new string[2]; + nodeActivityArray[0] = "Has Activity"; + nodeActivityArray[1] = "No Activity"; + double[] nodeActivityCountsArray = new double[2]; + + nodeActivityCountsArray[0] = nodesMetricsList.Where(n => n.TierID == tier.TierID && n.IsMachineAgentUsed == true).Count(t => t.HasActivity == true); + nodeActivityCountsArray[1] = nodesMetricsList.Where(n => n.TierID == tier.TierID && n.IsMachineAgentUsed == true).Count(t => t.HasActivity == false); + + insertCellStringValue(builder, String.Format("{0} active\n{1} inactive", nodeActivityCountsArray[0], nodeActivityCountsArray[1])); + insertCellNoValue(builder); + insertPieChart(builder, "Node Activity", nodeActivityArray, nodeActivityCountsArray); + } + else + { + insertCellStringValue(builder, "No metrics available"); + insertCellStringValue(builder, String.Empty); + } + builder.EndRow(); + finalizeTableTierEntityTypes(builder, table); + + #endregion #region Dashboard @@ -437,13 +935,75 @@ public override bool Execute(ProgramOptions programOptions, JobConfiguration job else { builder.ParagraphFormat.StyleIdentifier = StyleIdentifier.Normal; - builder.Writeln("No dashboard captured"); + builder.Writeln("No dashboard captured"); + } + + #endregion + + #region Flowmap + + insertHeading(builder, StyleIdentifier.Heading3, "Flowmap in Grid Form", String.Empty, listHeadingsOutline, 2); + + builder.ParagraphFormat.StyleIdentifier = StyleIdentifier.Normal; + + Table tableApplicationActivityGrid = insertTableActivityGrid(builder); + + if (tiersActivityFlowsList != null && tiersActivityFlowsList.Count > 0) + { + List thisTierAcvitityFlowsList = tiersActivityFlowsList.Where(a => a.TierID == tier.TierID).ToList(); + foreach (ActivityFlow activityFlow in thisTierAcvitityFlowsList) + { + insertRowActivityGrid(builder, activityFlow); + } + } + + finalizeTableActivityGrid(builder, tableApplicationActivityGrid); + + #endregion + + #region Agent Properties + + if (agentPropertiesList != null && agentPropertiesList.Count > 0 && agentPropertiesList.Where(p => p.TierName == tier.TierName && p.IsDefault == false).Count() > 0) + { + insertHeading(builder, StyleIdentifier.Heading3, "Agent Properties", getShortenedEntityNameForWordBookmark("tierprop", tier.TierName, tier.TierID), listHeadingsOutline, 2); + + builder.ParagraphFormat.StyleIdentifier = StyleIdentifier.Normal; + + Table tableTierAgentProperties = insertTableTierAgentProperties(builder); + + foreach (AgentConfigurationProperty agentProperty in agentPropertiesList.Where(p => p.TierName == tier.TierName && p.IsDefault == false)) + { + insertCellStringValue(builder, agentProperty.PropertyName); + insertCellStringValue(builder, agentProperty.PropertyType); + switch (agentProperty.PropertyType) + { + case "BOOLEAN": + insertCellStringValue(builder, agentProperty.BooleanValue); + insertCellNoValue(builder); insertStrikethroughText(builder, agentProperty.BooleanDefaultValue.ToString()); + break; + + case "INTEGER": + insertCellStringValue(builder, agentProperty.IntegerValue); + insertCellNoValue(builder); insertStrikethroughText(builder, agentProperty.IntegerDefaultValue.ToString()); + break; + + case "STRING": + insertCellStringValue(builder, agentProperty.StringValue); + insertCellNoValue(builder); insertStrikethroughText(builder, agentProperty.StringDefaultValue); + break; + + default: + break; + } + insertCellNoValue(builder); insertTextWithSize(builder, agentProperty.Description, 8); + builder.EndRow(); + } + + finalizeTierAgentProperties(builder, tableTierAgentProperties); } #endregion - builder.InsertBreak(BreakType.PageBreak); - if (j % 10 == 0) { Console.Write("[{0}].", j); @@ -472,11 +1032,11 @@ public override bool Execute(ProgramOptions programOptions, JobConfiguration job #region Summary Table insertHeading(builder, StyleIdentifier.Heading2, "Summary", String.Empty, listHeadingsOutline, 1); - + builder.ParagraphFormat.StyleIdentifier = StyleIdentifier.Normal; - Table table = insertNameValueTable(builder); - finalizeNameValueTable(builder, table); + Table table = insertTableApplicationSummary(builder); + finalizeTableApplicationSummary(builder, table); #endregion @@ -510,8 +1070,8 @@ public override bool Execute(ProgramOptions programOptions, JobConfiguration job builder.ParagraphFormat.StyleIdentifier = StyleIdentifier.Normal; - table = insertNameValueTable(builder); - finalizeNameValueTable(builder, table); + table = insertTableApplicationSummary(builder); + finalizeTableApplicationSummary(builder, table); #endregion @@ -536,7 +1096,26 @@ public override bool Execute(ProgramOptions programOptions, JobConfiguration job #endregion - builder.InsertBreak(BreakType.PageBreak); + #region Flowmap + + insertHeading(builder, StyleIdentifier.Heading4, "Flowmap in Grid Form", String.Empty, listHeadingsOutline, 3); + + builder.ParagraphFormat.StyleIdentifier = StyleIdentifier.Normal; + + Table tableNodeActivityGrid = insertTableActivityGrid(builder); + + if (nodesActivityFlowsList != null && nodesActivityFlowsList.Count > 0) + { + List thisNodeAcvitityFlowsList = nodesActivityFlowsList.Where(a => a.NodeID == node.NodeID).ToList(); + foreach (ActivityFlow activityFlow in thisNodeAcvitityFlowsList) + { + insertRowActivityGrid(builder, activityFlow); + } + } + + finalizeTableActivityGrid(builder, tableNodeActivityGrid); + + #endregion if (j % 10 == 0) { @@ -558,7 +1137,7 @@ public override bool Execute(ProgramOptions programOptions, JobConfiguration job #region Business Transactions - insertHeading(builder, StyleIdentifier.Heading1, "Business Transactions", "BTs", listHeadingsOutline, 0); + insertHeading(builder, StyleIdentifier.Heading1, "Business Transactions", "Business_Transactions", listHeadingsOutline, 0); insertLinksToEntityTypeSections(builder); @@ -572,8 +1151,8 @@ public override bool Execute(ProgramOptions programOptions, JobConfiguration job builder.ParagraphFormat.StyleIdentifier = StyleIdentifier.Normal; - Table table = insertNameValueTable(builder); - finalizeNameValueTable(builder, table); + Table table = insertTableApplicationSummary(builder); + finalizeTableApplicationSummary(builder, table); #endregion @@ -585,7 +1164,7 @@ public override bool Execute(ProgramOptions programOptions, JobConfiguration job foreach (APMTier tier in tiersList) { - insertHeading( builder, StyleIdentifier.Heading2, String.Format("{0} [{1}] ({2})", tier.TierName, tier.AgentType, tier.TierID), getShortenedEntityNameForWordBookmark("tierbt", tier.TierName, tier.TierID), listHeadingsOutline, 1); + insertHeading(builder, StyleIdentifier.Heading2, String.Format("{0} [{1}] ({2})", tier.TierName, tier.AgentType, tier.TierID), getShortenedEntityNameForWordBookmark("tierbt", tier.TierName, tier.TierID), listHeadingsOutline, 1); insertLinksToEntityTypeSections(builder); @@ -607,8 +1186,8 @@ public override bool Execute(ProgramOptions programOptions, JobConfiguration job builder.ParagraphFormat.StyleIdentifier = StyleIdentifier.Normal; - table = insertNameValueTable(builder); - finalizeNameValueTable(builder, table); + table = insertTableApplicationSummary(builder); + finalizeTableApplicationSummary(builder, table); #endregion @@ -633,7 +1212,26 @@ public override bool Execute(ProgramOptions programOptions, JobConfiguration job #endregion - builder.InsertBreak(BreakType.PageBreak); + #region Flowmap + + insertHeading(builder, StyleIdentifier.Heading4, "Flowmap in Grid Form", String.Empty, listHeadingsOutline, 3); + + builder.ParagraphFormat.StyleIdentifier = StyleIdentifier.Normal; + + Table tableBusinessTransactionActivityGrid = insertTableActivityGrid(builder); + + if (businessTransactionsActivityFlowsList != null && businessTransactionsActivityFlowsList.Count > 0) + { + List thisBusinessTransactionAcvitityFlowsList = businessTransactionsActivityFlowsList.Where(a => a.BTID == businessTransaction.BTID).ToList(); + foreach (ActivityFlow activityFlow in thisBusinessTransactionAcvitityFlowsList) + { + insertRowActivityGrid(builder, activityFlow); + } + } + + finalizeTableActivityGrid(builder, tableBusinessTransactionActivityGrid); + + #endregion if (j % 10 == 0) { @@ -667,12 +1265,12 @@ public override bool Execute(ProgramOptions programOptions, JobConfiguration job #region Summary Table - insertHeading( builder, StyleIdentifier.Heading2, "Summary", String.Empty, listHeadingsOutline, 1); + insertHeading(builder, StyleIdentifier.Heading2, "Summary", String.Empty, listHeadingsOutline, 1); builder.ParagraphFormat.StyleIdentifier = StyleIdentifier.Normal; - Table table = insertNameValueTable(builder); - finalizeNameValueTable(builder, table); + Table table = insertTableApplicationSummary(builder); + finalizeTableApplicationSummary(builder, table); #endregion @@ -690,8 +1288,8 @@ public override bool Execute(ProgramOptions programOptions, JobConfiguration job builder.ParagraphFormat.StyleIdentifier = StyleIdentifier.Normal; - table = insertNameValueTable(builder); - finalizeNameValueTable(builder, table); + table = insertTableApplicationSummary(builder); + finalizeTableApplicationSummary(builder, table); #endregion @@ -716,7 +1314,26 @@ public override bool Execute(ProgramOptions programOptions, JobConfiguration job #endregion - builder.InsertBreak(BreakType.PageBreak); + #region Flowmap + + insertHeading(builder, StyleIdentifier.Heading3, "Flowmap in Grid Form", String.Empty, listHeadingsOutline, 2); + + builder.ParagraphFormat.StyleIdentifier = StyleIdentifier.Normal; + + Table tableBackendActivityGrid = insertTableActivityGrid(builder); + + if (backendsActivityFlowsList != null && backendsActivityFlowsList.Count > 0) + { + List thisBackendAcvitityFlowsList = backendsActivityFlowsList.Where(a => a.BackendID == backend.BackendID).ToList(); + foreach (ActivityFlow activityFlow in thisBackendAcvitityFlowsList) + { + insertRowActivityGrid(builder, activityFlow); + } + } + + finalizeTableActivityGrid(builder, tableBackendActivityGrid); + + #endregion if (j % 10 == 0) { @@ -735,7 +1352,7 @@ public override bool Execute(ProgramOptions programOptions, JobConfiguration job #region Service Endpoints - insertHeading(builder, StyleIdentifier.Heading1, "Service Endpoints", "SEPs", listHeadingsOutline, 0); + insertHeading(builder, StyleIdentifier.Heading1, "Service Endpoints", "Service_Endpoints", listHeadingsOutline, 0); insertLinksToEntityTypeSections(builder); @@ -749,8 +1366,8 @@ public override bool Execute(ProgramOptions programOptions, JobConfiguration job builder.ParagraphFormat.StyleIdentifier = StyleIdentifier.Normal; - Table table = insertNameValueTable(builder); - finalizeNameValueTable(builder, table); + Table table = insertTableApplicationSummary(builder); + finalizeTableApplicationSummary(builder, table); #endregion @@ -784,16 +1401,14 @@ public override bool Execute(ProgramOptions programOptions, JobConfiguration job builder.ParagraphFormat.StyleIdentifier = StyleIdentifier.Normal; - table = insertNameValueTable(builder); - finalizeNameValueTable(builder, table); + table = insertTableApplicationSummary(builder); + finalizeTableApplicationSummary(builder, table); #endregion builder.ParagraphFormat.StyleIdentifier = StyleIdentifier.Normal; builder.Writeln(serviceEndpoint.ToString()); - builder.InsertBreak(BreakType.PageBreak); - if (j % 10 == 0) { Console.Write("[{0}].", j); @@ -828,8 +1443,8 @@ public override bool Execute(ProgramOptions programOptions, JobConfiguration job builder.ParagraphFormat.StyleIdentifier = StyleIdentifier.Normal; - Table table = insertNameValueTable(builder); - finalizeNameValueTable(builder, table); + Table table = insertTableApplicationSummary(builder); + finalizeTableApplicationSummary(builder, table); #endregion @@ -863,16 +1478,14 @@ public override bool Execute(ProgramOptions programOptions, JobConfiguration job builder.ParagraphFormat.StyleIdentifier = StyleIdentifier.Normal; - table = insertNameValueTable(builder); - finalizeNameValueTable(builder, table); + table = insertTableApplicationSummary(builder); + finalizeTableApplicationSummary(builder, table); #endregion builder.ParagraphFormat.StyleIdentifier = StyleIdentifier.Normal; builder.Writeln(error.ToString()); - builder.InsertBreak(BreakType.PageBreak); - if (j % 10 == 0) { Console.Write("[{0}].", j); @@ -893,7 +1506,7 @@ public override bool Execute(ProgramOptions programOptions, JobConfiguration job #region Information Points - insertHeading(builder, StyleIdentifier.Heading1, "Information Points", "IPs", listHeadingsOutline, 0); + insertHeading(builder, StyleIdentifier.Heading1, "Information Points", "Information_Points", listHeadingsOutline, 0); insertLinksToEntityTypeSections(builder); @@ -909,8 +1522,8 @@ public override bool Execute(ProgramOptions programOptions, JobConfiguration job builder.ParagraphFormat.StyleIdentifier = StyleIdentifier.Normal; - Table table = insertNameValueTable(builder); - finalizeNameValueTable(builder, table); + Table table = insertTableApplicationSummary(builder); + finalizeTableApplicationSummary(builder, table); #endregion @@ -928,16 +1541,14 @@ public override bool Execute(ProgramOptions programOptions, JobConfiguration job builder.ParagraphFormat.StyleIdentifier = StyleIdentifier.Normal; - table = insertNameValueTable(builder); - finalizeNameValueTable(builder, table); + table = insertTableApplicationSummary(builder); + finalizeTableApplicationSummary(builder, table); #endregion builder.ParagraphFormat.StyleIdentifier = StyleIdentifier.Normal; builder.Writeln(informationPoint.ToString()); - builder.InsertBreak(BreakType.PageBreak); - if (j % 10 == 0) { Console.Write("[{0}].", j); @@ -953,6 +1564,7 @@ public override bool Execute(ProgramOptions programOptions, JobConfiguration job #endregion + // Save the final document finalizeAndSaveApplicationSummaryReport(applicationSummaryDocument, FilePathMap.ApplicationSummaryWordReportFilePath(jobTarget, jobConfiguration.Input.TimeRange, true)); #endregion @@ -1016,8 +1628,10 @@ public override bool ShouldExecute(JobConfiguration jobConfiguration) return (jobConfiguration.Output.ApplicationSummary == true); } + #region Document prep and saving + private Document createApplicationSummaryDocument(ProgramOptions programOptions, JobConfiguration jobConfiguration, JobTarget jobTarget) - { + { Document doc = new Document(); DocumentBuilder builder = new DocumentBuilder(doc); @@ -1153,7 +1767,7 @@ private Document createApplicationSummaryDocument(ProgramOptions programOptions, builder.ParagraphFormat.StyleIdentifier = StyleIdentifier.Title; builder.Writeln("AppDynamics DEXTER Application Summary Report"); - + builder.ParagraphFormat.StyleIdentifier = StyleIdentifier.Normal; builder.Writeln(""); builder.Writeln(""); @@ -1191,19 +1805,6 @@ private Document createApplicationSummaryDocument(ProgramOptions programOptions, #endregion - //#region Top - - //builder.ParagraphFormat.StyleIdentifier = StyleIdentifier.Heading1; - //builder.StartBookmark("Top"); - //builder.Writeln("Top"); - //builder.EndBookmark("Top"); - - //builder.Writeln(String.Format("TODO fill out some summary about {0}/{1} ({2})", jobTarget.Controller, jobTarget.Application, jobTarget.ApplicationID)); - - // builder.InsertBreak(BreakType.PageBreak); - - //#endregion - return doc; } @@ -1278,68 +1879,7 @@ private static bool finalizeAndSaveApplicationSummaryReport(Document doc, string return true; } - private static void insertLinksToEntityTypeSections(DocumentBuilder builder) - { - Style hyperLinkStyle = builder.Document.Styles["HyperLinkStyle"]; - - builder.ParagraphFormat.StyleIdentifier = StyleIdentifier.Normal; - - builder.Write("Jump to: "); - - //builder.Font.Style = hyperLinkStyle; - //builder.InsertHyperlink("Top", "Top", true); - //builder.Font.ClearFormatting(); - - //builder.Write(", "); - - builder.Font.Style = hyperLinkStyle; - builder.InsertHyperlink("Application", "Application", true); - builder.Font.ClearFormatting(); - - builder.Write(", "); - - builder.Font.Style = hyperLinkStyle; - builder.InsertHyperlink("Tiers", "Tiers", true); - builder.Font.ClearFormatting(); - - builder.Write(", "); - - builder.Font.Style = hyperLinkStyle; - builder.InsertHyperlink("Nodes", "Nodes", true); - builder.Font.ClearFormatting(); - - builder.Write(", "); - - builder.Font.Style = hyperLinkStyle; - builder.InsertHyperlink("BTs", "BTs", true); - builder.Font.ClearFormatting(); - - builder.Write(", "); - - builder.Font.Style = hyperLinkStyle; - builder.InsertHyperlink("Backends", "Backends", true); - builder.Font.ClearFormatting(); - - builder.Write(", "); - - builder.Font.Style = hyperLinkStyle; - builder.InsertHyperlink("Service Endpoints", "SEPs", true); - builder.Font.ClearFormatting(); - - builder.Write(", "); - - builder.Font.Style = hyperLinkStyle; - builder.InsertHyperlink("Errors", "Errors", true); - builder.Font.ClearFormatting(); - - builder.Write(", "); - - builder.Font.Style = hyperLinkStyle; - builder.InsertHyperlink("Information Points", "IPs", true); - builder.Font.ClearFormatting(); - - builder.Writeln(""); - } + #endregion private static void insertHeading(DocumentBuilder builder, StyleIdentifier headingStyle, string headingName, string headingBookmarkName, List listHeadingsOutline, int listNumberingOutlineLevel) { @@ -1378,6 +1918,28 @@ private static void insertLinkToBookmark(DocumentBuilder builder, Style hyperLin builder.Font.ClearFormatting(); } + #region Insertion of links to various entities + + private static void insertLinksToEntityTypeSections(DocumentBuilder builder) + { + Style hyperLinkStyle = builder.Document.Styles["HyperLinkStyle"]; + + builder.ParagraphFormat.StyleIdentifier = StyleIdentifier.Normal; + + builder.Write("Jump to: "); + + insertLinkToBookmark(builder, hyperLinkStyle, "Application", "Application"); builder.Write(", "); + insertLinkToBookmark(builder, hyperLinkStyle, "Tiers", "Tiers"); builder.Write(", "); + insertLinkToBookmark(builder, hyperLinkStyle, "Nodes", "Nodes"); builder.Write(", "); + insertLinkToBookmark(builder, hyperLinkStyle, "Business Transactions", "Business_Transactions"); builder.Write(", "); + insertLinkToBookmark(builder, hyperLinkStyle, "Backends", "Backends"); builder.Write(", "); + insertLinkToBookmark(builder, hyperLinkStyle, "Service Endpoints", "Service_Endpoints"); builder.Write(", "); + insertLinkToBookmark(builder, hyperLinkStyle, "Errors", "Errors"); builder.Write(", "); + insertLinkToBookmark(builder, hyperLinkStyle, "Information Points", "Information_Points"); + + builder.Writeln(""); + } + private static void insertLinksToTiers(List tiersList, DocumentBuilder builder, Style hyperLinkStyle, string bookmarkPrefix) { builder.ParagraphFormat.StyleIdentifier = StyleIdentifier.Normal; @@ -1394,13 +1956,13 @@ private static void insertLinksToTiers(List tiersList, DocumentBuilder } } builder.Writeln(""); - builder.InsertBreak(BreakType.PageBreak); } private static void insertLinksToTiers(List tiersList, DocumentBuilder builder, Style hyperLinkStyle) { insertLinksToTiers(tiersList, builder, hyperLinkStyle, "tier"); } + private static void insertLinksToTiersInNodes(List tiersList, DocumentBuilder builder, Style hyperLinkStyle) { insertLinksToTiers(tiersList, builder, hyperLinkStyle, "tiernode"); @@ -1429,9 +1991,7 @@ private static void insertLinksToNodes(List nodesList, DocumentBuilder { APMNode node = nodesList[i]; - builder.Font.Style = hyperLinkStyle; - builder.InsertHyperlink(node.NodeName, getShortenedEntityNameForWordBookmark("node", node.NodeName, node.NodeID), true); - builder.Font.ClearFormatting(); + insertLinkToBookmark(builder, hyperLinkStyle, node.NodeName, getShortenedEntityNameForWordBookmark("node", node.NodeName, node.NodeID)); if (i < nodesList.Count - 1) { @@ -1439,7 +1999,6 @@ private static void insertLinksToNodes(List nodesList, DocumentBuilder } } builder.Writeln(""); - builder.InsertBreak(BreakType.PageBreak); } private static void insertLinksToBusinessTransactions(List businessTransactionsList, DocumentBuilder builder, Style hyperLinkStyle) @@ -1450,9 +2009,7 @@ private static void insertLinksToBusinessTransactions(List backendsList, DocumentBuilder builder, Style hyperLinkStyle) @@ -1471,9 +2027,7 @@ private static void insertLinksToBackends(List backendsList, Documen { APMBackend backend = backendsList[i]; - builder.Font.Style = hyperLinkStyle; - builder.InsertHyperlink(backend.BackendName, getShortenedEntityNameForWordBookmark("back", backend.BackendName, backend.BackendID), true); - builder.Font.ClearFormatting(); + insertLinkToBookmark(builder, hyperLinkStyle, backend.BackendName, getShortenedEntityNameForWordBookmark("back", backend.BackendName, backend.BackendID)); if (i < backendsList.Count - 1) { @@ -1481,7 +2035,6 @@ private static void insertLinksToBackends(List backendsList, Documen } } builder.Writeln(""); - builder.InsertBreak(BreakType.PageBreak); } private static void insertLinksToServiceEndpoints(List serviceEndpointsList, DocumentBuilder builder, Style hyperLinkStyle) @@ -1492,9 +2045,7 @@ private static void insertLinksToServiceEndpoints(List servi { APMServiceEndpoint serviceEndpoint = serviceEndpointsList[i]; - builder.Font.Style = hyperLinkStyle; - builder.InsertHyperlink(serviceEndpoint.SEPName, getShortenedEntityNameForWordBookmark("sep", serviceEndpoint.SEPName, serviceEndpoint.SEPID), true); - builder.Font.ClearFormatting(); + insertLinkToBookmark(builder, hyperLinkStyle, serviceEndpoint.SEPName, getShortenedEntityNameForWordBookmark("sep", serviceEndpoint.SEPName, serviceEndpoint.SEPID)); if (i < serviceEndpointsList.Count - 1) { @@ -1502,7 +2053,6 @@ private static void insertLinksToServiceEndpoints(List servi } } builder.Writeln(""); - builder.InsertBreak(BreakType.PageBreak); } private static void insertLinksToErrors(List errorsList, DocumentBuilder builder, Style hyperLinkStyle) @@ -1513,9 +2063,7 @@ private static void insertLinksToErrors(List errorsList, DocumentBuild { APMError error = errorsList[i]; - builder.Font.Style = hyperLinkStyle; - builder.InsertHyperlink(error.ErrorName, getShortenedEntityNameForWordBookmark("error", error.ErrorName, error.ErrorID), true); - builder.Font.ClearFormatting(); + insertLinkToBookmark(builder, hyperLinkStyle, error.ErrorName, getShortenedEntityNameForWordBookmark("error", error.ErrorName, error.ErrorID)); if (i < errorsList.Count - 1) { @@ -1523,7 +2071,6 @@ private static void insertLinksToErrors(List errorsList, DocumentBuild } } builder.Writeln(""); - builder.InsertBreak(BreakType.PageBreak); } private static void insertLinksToInformationPoints(List informationPointsList, DocumentBuilder builder, Style hyperLinkStyle) @@ -1534,33 +2081,231 @@ private static void insertLinksToInformationPoints(List inf { APMInformationPoint informationPoint = informationPointsList[i]; - builder.Font.Style = hyperLinkStyle; - builder.InsertHyperlink(informationPoint.IPName, getShortenedEntityNameForWordBookmark("ip", informationPoint.IPName, informationPoint.IPID), true); - builder.Font.ClearFormatting(); - + insertLinkToBookmark(builder, hyperLinkStyle, informationPoint.IPName, getShortenedEntityNameForWordBookmark("ip", informationPoint.IPName, informationPoint.IPID)); if (i < informationPointsList.Count - 1) { builder.Write(", "); } } builder.Writeln(""); - builder.InsertBreak(BreakType.PageBreak); } - internal static Table insertNameValueTable(DocumentBuilder builder) - { + #endregion + + #region Helper functions for creation of various tables + + internal static Table insertTableApplicationSummary(DocumentBuilder builder) + { + Table table = builder.StartTable(); + + Cell cell = insertCellStringValue(builder, "Property"); + cell.CellFormat.PreferredWidth = PreferredWidth.FromPoints(100); + cell = insertCellStringValue(builder, "Value"); + cell.CellFormat.PreferredWidth = PreferredWidth.FromPoints(400); + cell = insertCellStringValue(builder, "Detail"); + cell.CellFormat.PreferredWidth = PreferredWidth.FromPoints(300); + + builder.EndRow(); + + return table; + } + + internal static void finalizeTableApplicationSummary(DocumentBuilder builder, Table table) + { + finalizeTableStyleAndResize(builder, table); + } + + internal static Table insertTableApplicationEntityTypes(DocumentBuilder builder) + { + Table table = builder.StartTable(); + + Cell cell = insertCellStringValue(builder, "Property"); + cell.CellFormat.PreferredWidth = PreferredWidth.FromPoints(100); + cell = insertCellStringValue(builder, "Types"); + cell.CellFormat.PreferredWidth = PreferredWidth.FromPoints(400); + cell = insertCellStringValue(builder, "Types Chart"); + cell.CellFormat.PreferredWidth = PreferredWidth.FromPoints(300); + cell = insertCellStringValue(builder, "Activity"); + cell.CellFormat.PreferredWidth = PreferredWidth.FromPoints(400); + cell = insertCellStringValue(builder, "Activity Chart"); + cell.CellFormat.PreferredWidth = PreferredWidth.FromPoints(300); + + builder.EndRow(); + + return table; + } + + internal static void finalizeTableApplicationEntityTypes(DocumentBuilder builder, Table table) + { + finalizeTableStyleAndResize(builder, table); + } + + internal static Table insertTableApplicationEntityMapped(DocumentBuilder builder) + { + Table table = builder.StartTable(); + + Cell cell = insertCellStringValue(builder, "Property"); + cell.CellFormat.PreferredWidth = PreferredWidth.FromPoints(100); + cell = insertCellStringValue(builder, "Value"); + cell.CellFormat.PreferredWidth = PreferredWidth.FromPoints(400); + cell = insertCellStringValue(builder, "Chart"); + cell.CellFormat.PreferredWidth = PreferredWidth.FromPoints(300); + cell = insertCellStringValue(builder, "Value"); + cell.CellFormat.PreferredWidth = PreferredWidth.FromPoints(400); + cell = insertCellStringValue(builder, "Chart"); + cell.CellFormat.PreferredWidth = PreferredWidth.FromPoints(300); + + builder.EndRow(); + + return table; + } + + internal static void finalizeTableApplicationEntityMapped(DocumentBuilder builder, Table table) + { + finalizeTableStyleAndResize(builder, table); + } + + internal static Table insertTableActivityGrid(DocumentBuilder builder) + { + Table table = builder.StartTable(); + + Cell cell = insertCellStringValue(builder, "Type"); + cell = insertCellStringValue(builder, "Direction"); + cell = insertCellStringValue(builder, "From"); + cell = insertCellStringValue(builder, "From Type"); + cell = insertCellStringValue(builder, "To"); + cell = insertCellStringValue(builder, "To Type"); + + cell = insertCellStringValue(builder, "ART"); + cell = insertCellStringValue(builder, "Calls"); + cell = insertCellStringValue(builder, "CPM"); + cell = insertCellStringValue(builder, "Errors"); + cell = insertCellStringValue(builder, "EPM"); + cell = insertCellStringValue(builder, "Errors %"); + + builder.EndRow(); + + return table; + } + + internal static Row insertRowActivityGrid(DocumentBuilder builder, ActivityFlow activityFlow) + { + insertCellStringValue(builder, activityFlow.CallType); + insertCellStringValue(builder, activityFlow.CallDirection); + insertCellStringValue(builder, activityFlow.FromName); + insertCellStringValue(builder, activityFlow.FromType); + insertCellStringValue(builder, activityFlow.ToName); + insertCellStringValue(builder, activityFlow.ToType); + insertCellStringValue(builder, activityFlow.ART); + insertCellStringValue(builder, activityFlow.Calls); + insertCellStringValue(builder, activityFlow.CPM); + insertCellStringValue(builder, activityFlow.Errors); + insertCellStringValue(builder, activityFlow.EPM); + insertCellStringValue(builder, activityFlow.ErrorsPercentage); + Row row = builder.EndRow(); + return row; + } + + internal static void finalizeTableActivityGrid(DocumentBuilder builder, Table table) + { + finalizeTableStyleAndResize(builder, table); + } + + internal static Table insertTableTiersSummary(DocumentBuilder builder) + { + Table table = builder.StartTable(); + + Cell cell = insertCellStringValue(builder, "Tier"); + cell = insertCellStringValue(builder, "Type"); + cell = insertCellStringValue(builder, "# APM Nodes"); + cell = insertCellStringValue(builder, "# Machine Nodes"); + cell = insertCellStringValue(builder, "# BTs"); + cell = insertCellStringValue(builder, "# SEPs"); + cell = insertCellStringValue(builder, "# Errors"); + cell = insertCellStringValue(builder, "Agent Avail"); + cell = insertCellStringValue(builder, "Machine Avail"); + cell = insertCellStringValue(builder, "TX Activity"); + cell = insertCellStringValue(builder, "# Custom Props"); + cell = insertCellStringValue(builder, "# Events"); + + builder.EndRow(); + + return table; + } + + internal static void finalizeTableTiersSummary(DocumentBuilder builder, Table table) + { + finalizeTableStyleAndResize(builder, table); + } + + internal static Table insertTableTierEntityTypes(DocumentBuilder builder) + { Table table = builder.StartTable(); - Cell cell = insertCellWithContent(builder, table, "Property"); + + Cell cell = insertCellStringValue(builder, "Property"); cell.CellFormat.PreferredWidth = PreferredWidth.FromPoints(100); - cell = insertCellWithContent(builder, table, "Value"); - cell.CellFormat.PreferredWidth = PreferredWidth.FromPoints(600); + cell = insertCellStringValue(builder, "Types"); + cell.CellFormat.PreferredWidth = PreferredWidth.FromPoints(400); + cell = insertCellStringValue(builder, "Types Chart"); + cell.CellFormat.PreferredWidth = PreferredWidth.FromPoints(300); + cell = insertCellStringValue(builder, "Activity"); + cell.CellFormat.PreferredWidth = PreferredWidth.FromPoints(400); + cell = insertCellStringValue(builder, "Activity Chart"); + cell.CellFormat.PreferredWidth = PreferredWidth.FromPoints(300); + + builder.EndRow(); + + return table; + } + + internal static void finalizeTableTierEntityTypes(DocumentBuilder builder, Table table) + { + finalizeTableStyleAndResize(builder, table); + } + + internal static Table insertTableApplicationAgentProperties(DocumentBuilder builder) + { + Table table = builder.StartTable(); + + Cell cell = insertCellStringValue(builder, "Scope"); + cell = insertCellStringValue(builder, "Agent Type"); + cell = insertCellStringValue(builder, "Name"); + cell = insertCellStringValue(builder, "Type"); + cell = insertCellStringValue(builder, "Value"); + cell = insertCellStringValue(builder, "Old Value"); + cell = insertCellStringValue(builder, "Description"); + + builder.EndRow(); + + return table; + } + + internal static void finalizeApplicationAgentProperties(DocumentBuilder builder, Table table) + { + finalizeTableStyleAndResize(builder, table); + } + + internal static Table insertTableTierAgentProperties(DocumentBuilder builder) + { + Table table = builder.StartTable(); + + Cell cell = insertCellStringValue(builder, "Name"); + cell = insertCellStringValue(builder, "Type"); + cell = insertCellStringValue(builder, "Value"); + cell = insertCellStringValue(builder, "Old Value"); + cell = insertCellStringValue(builder, "Description"); builder.EndRow(); return table; } - internal static void finalizeNameValueTable(DocumentBuilder builder, Table table) + internal static void finalizeTierAgentProperties(DocumentBuilder builder, Table table) + { + finalizeTableStyleAndResize(builder, table); + } + + internal static void finalizeTableStyleAndResize(DocumentBuilder builder, Table table) { table.StyleIdentifier = StyleIdentifier.ListTable1Light; table.AutoFit(AutoFitBehavior.AutoFitToContents); @@ -1568,24 +2313,94 @@ internal static void finalizeNameValueTable(DocumentBuilder builder, Table table builder.EndTable(); } - internal static void insertNameValueRow(DocumentBuilder builder, Table table, string propertyName, object propertyValue) + #endregion + + internal static Cell insertCellNoValue(DocumentBuilder builder) { - insertNameValueRow(builder, table, propertyName, propertyValue.ToString()); + Cell cell = builder.InsertCell(); + return cell; } - internal static void insertNameValueRow(DocumentBuilder builder, Table table, string propertyName, string propertyValue) + internal static Cell insertCellStringValue(DocumentBuilder builder, string cellContent) { - insertCellWithContent(builder, table, propertyName); - insertCellWithContent(builder, table, propertyValue); - builder.EndRow(); + Cell cell = insertCellNoValue(builder); + builder.Write(cellContent); + return cell; } - internal static Cell insertCellWithContent(DocumentBuilder builder, Table table, string cellContent) + internal static Cell insertCellStringValue(DocumentBuilder builder, object cellContent) { - Cell cell = builder.InsertCell(); - builder.Write(cellContent); + Cell cell = insertCellNoValue(builder); + builder.Write(cellContent.ToString()); return cell; } + private static void insertStrikethroughText(DocumentBuilder builder, String textContent) + { + builder.Font.StrikeThrough = true; + builder.Write(textContent); + builder.Font.ClearFormatting(); + } + + private static void insertTextWithSize(DocumentBuilder builder, String textContent, int fontSize) + { + builder.Font.Size = fontSize; + builder.Write(textContent); + builder.Font.ClearFormatting(); + } + + internal static Shape insertPieChart(DocumentBuilder builder, string chartTitle, string[] categories, double[] values) + { + // If no data is passed, Aspose acts very cute and adds a mock Sales pie chart out of thin air. I'd rather have a blank one + if (categories.Length == 0) + { + categories = new string[1]; + categories[0] = ""; + values = new double[1]; + values[0] = 0; + } + if (categories.Length > 0 && values.Length > 0) + { + Shape shape = builder.InsertChart(ChartType.Pie, 300, 130); + Chart chart = shape.Chart; + chart.Series.Clear(); + ChartSeries series = chart.Series.Add(chartTitle, categories, values); + chart.Legend.Position = LegendPosition.Right; + chart.Title.Overlay = true; + chart.Title.Show = false; + + ChartDataLabelCollection labels = series.DataLabels; + labels.ShowPercentage = true; + labels.ShowValue = true; + labels.ShowLeaderLines = false; + labels.Separator = "-"; + + return shape; + } + else + { + return null; + } + } + + internal void measureTypesOfItemsInGroupBy(IEnumerable> groupTypesToMeasure, List prettyFormatList, List typesList, List countsList) + { + foreach (var groupType in groupTypesToMeasure) + { + prettyFormatList.Add(String.Format("{0} {1}", groupType.Count(), groupType.Key)); + typesList.Add(groupType.Key); + countsList.Add(groupType.Count()); + } + } + + internal void measureTypesOfItemsInGroupBy(IEnumerable> groupTypesToMeasure, List prettyFormatList, List typesList, List countsList) + { + foreach (var groupType in groupTypesToMeasure) + { + prettyFormatList.Add(String.Format("{0} {1}", groupType.Count(), groupType.Key)); + typesList.Add(groupType.Key); + countsList.Add(groupType.Count()); + } + } } } diff --git a/ProcessingSteps/Report/ReportAPMMetricGraphs.cs b/ProcessingSteps/Report/ReportAPMMetricGraphs.cs index 8ac2a6e..9c9da5f 100644 --- a/ProcessingSteps/Report/ReportAPMMetricGraphs.cs +++ b/ProcessingSteps/Report/ReportAPMMetricGraphs.cs @@ -1290,7 +1290,7 @@ private void fillTransactionalScatterPlotsForEntityType( if (rangeARTValues != null && rangeCPMValues != null) { - ExcelChartSerie series = chart.Series.Add(rangeCPMValues, rangeARTValues); + ExcelChartSerie series = chart.Series.Add(rangeARTValues, rangeCPMValues); ExcelScatterChartSerie series1 = (ExcelScatterChartSerie)series; series.Header = String.Format("{0} vs {1}", memART.MetricName, memCPM.MetricName); series1.DataLabel.ShowValue = true; @@ -1307,7 +1307,7 @@ private void fillTransactionalScatterPlotsForEntityType( if (rangeARTValues != null && rangeEPMValues != null) { - ExcelChartSerie series = chart.Series.Add(rangeEPMValues, rangeARTValues); + ExcelChartSerie series = chart.Series.Add(rangeARTValues, rangeEPMValues); ExcelScatterChartSerie series1 = (ExcelScatterChartSerie)series; series.Header = String.Format("{0} vs {1}", memART.MetricName, memEPM.MetricName); series1.DataLabel.ShowValue = true; diff --git a/ProcessingSteps/Report/ReportControllerAndApplicationConfiguration.cs b/ProcessingSteps/Report/ReportControllerAndApplicationConfiguration.cs index 9bd695c..9513222 100644 --- a/ProcessingSteps/Report/ReportControllerAndApplicationConfiguration.cs +++ b/ProcessingSteps/Report/ReportControllerAndApplicationConfiguration.cs @@ -62,14 +62,16 @@ public class ReportControllerAndApplicationConfiguration : JobStepReportBase private const string SHEET_APM_METHOD_INVOCATION_DATA_COLLECTORS = "32.APM MIDCs"; private const string SHEET_APM_HTTP_DATA_COLLECTORS = "33.APM HTTP DCs"; private const string SHEET_APM_AGENT_CALL_GRAPH_SETTINGS = "34.APM Call Graph Settings"; - private const string SHEET_APM_SERVICE_ENDPOINT_RULES_SETTINGS = "35.APM Service Endpoint Rules"; - private const string SHEET_APM_DEVELOPER_MODE_NODES = "36.APM Developer Mode Nodes"; - private const string SHEET_APM_ERROR_DETECTION_RULES = "37.APM Error Detection Rules"; - private const string SHEET_APM_ERROR_DETECTION_IGNORE_MESSAGES = "38.APM Error Ignore Messages"; - private const string SHEET_APM_ERROR_DETECTION_IGNORE_LOGGERS = "39.APM Error Ignore Loggers"; - private const string SHEET_APM_ERROR_DETECTION_LOGGERS = "40.APM Error Loggers"; - private const string SHEET_APM_ERROR_DETECTION_HTTP_CODES = "41.APM Error HTTP Codes"; - private const string SHEET_APM_ERROR_DETECTION_REDIRECT_PAGES = "42.APM Error Redired Pages"; + private const string SHEET_APM_SERVICE_ENDPOINT_DISCOVERY_RULES = "35.APM SEP Discovery Rules"; + private const string SHEET_APM_SERVICE_ENDPOINT_ENTRY_RULES = "36.APM SEP Entry Rules"; + private const string SHEET_APM_SERVICE_ENDPOINT_ENTRY_RULES_PIVOT_TYPE = "36.APM SEP Entry Rules.Type"; + private const string SHEET_APM_DEVELOPER_MODE_NODES = "37.APM Developer Mode Nodes"; + private const string SHEET_APM_ERROR_DETECTION_RULES = "38.APM Error Detection Rules"; + private const string SHEET_APM_ERROR_DETECTION_IGNORE_MESSAGES = "39.APM Error Ignore Messages"; + private const string SHEET_APM_ERROR_DETECTION_IGNORE_LOGGERS = "40.APM Error Ignore Loggers"; + private const string SHEET_APM_ERROR_DETECTION_LOGGERS = "41.APM Error Loggers"; + private const string SHEET_APM_ERROR_DETECTION_HTTP_CODES = "42.APM Error HTTP Codes"; + private const string SHEET_APM_ERROR_DETECTION_REDIRECT_PAGES = "43.APM Error Redired Pages"; // DB Configuration private const string SHEET_DB_APPLICATION_CONFIGURATION = "50.DB Application Config"; @@ -102,7 +104,6 @@ public class ReportControllerAndApplicationConfiguration : JobStepReportBase private const string TABLE_CONTROLLER_EMAIL_ALERT_TEMPLATES = "t_ALERT_EmailAlertTemplates"; private const string TABLE_CONTROLLER_HTTP_ALERT_TEMPLATES = "t_ALERT_HttpAlertTemplates"; private const string TABLE_APP_HEALTH_RULES_SUMMARY = "t_ALERT_HealthRulesSummary"; - private const string TABLE_APP_HEALTH_RULES = "t_ALERT_HealthRules"; private const string TABLE_APP_POLICIES = "t_ALERT_Policies"; private const string TABLE_APP_ACTIONS = "t_ALERT_Actions"; private const string TABLE_APP_POLICIES_TO_ACTIONS_MAPPING = "t_ALERT_PolicyToActionsMapping"; @@ -124,6 +125,7 @@ public class ReportControllerAndApplicationConfiguration : JobStepReportBase private const string TABLE_APM_TIER_SETTINGS = "t_APM_Tiers"; private const string TABLE_APM_BUSINESS_TRANSACTION_SETTINGS = "t_APM_BusinessTransactions"; private const string TABLE_APM_AGENT_CALL_GRAPH_SETTINGS = "t_APM_AgentCallGraphSettings"; + private const string TABLE_APM_SERVICE_ENDPOINT_DISCOVERY_RULES = "t_APM_SEPDiscoveryRules"; private const string TABLE_APM_SERVICE_ENDPOINT_ENTRY_RULES = "t_APM_SEPEntryRules"; private const string TABLE_APM_DEVELOPER_MODE_NODES = "t_APM_DevModeNodes"; private const string TABLE_APM_ERROR_DETECTION_RULES = "t_APM_ErrorDetectionRules"; @@ -132,6 +134,7 @@ public class ReportControllerAndApplicationConfiguration : JobStepReportBase private const string TABLE_APM_ERROR_DETECTION_LOGGERS = "t_APM_ErrorLoggers"; private const string TABLE_APM_ERROR_DETECTION_HTTP_CODES = "t_APM_ErrorHTTPCodes"; private const string TABLE_APM_ERROR_DETECTION_REDIRECT_PAGES = "t_APM_ErrorRediredPages"; + // DB Configuration private const string TABLE_DB_APPLICATION_CONFIGURATION = "t_DB_ApplicationConfiguration"; private const string TABLE_DB_COLLECTOR_DEFINITIONS = "t_DB_CollectorDefinitions"; @@ -162,6 +165,7 @@ public class ReportControllerAndApplicationConfiguration : JobStepReportBase private const string PIVOT_APM_BUSINESS_TRANSACTION_ENTRY_RULES_LOCATION = "p_APM_BTEntryRulesLocation"; private const string PIVOT_APM_BUSINESS_TRANSACTION_ENTRY_RULES_20_TYPE = "p_APM_BTEntryRules20Type"; private const string PIVOT_APM_BUSINESS_TRANSACTION_ENTRY_RULES_20_LOCATION = "p_APM_BTEntryRules20Location"; + private const string PIVOT_APM_SERVICE_ENDPOINT_ENTRY_RULES_TYPE = "p_APM_SEPEntryRulesType"; private const string PIVOT_APM_BACKEND_DISCOVERY_RULES_TYPE = "p_APM_BackendDiscoveryRulesType"; private const string PIVOT_APM_CUSTOM_EXIT_RULES_TYPE = "p_APM_CustomExitRulesType"; private const string PIVOT_APM_AGENT_CONFIGURATION_PROPERTIES_TYPE = "p_APM_AgentPropertiesType"; @@ -182,6 +186,7 @@ public class ReportControllerAndApplicationConfiguration : JobStepReportBase private const string GRAPH_APM_BUSINESS_TRANSACTION_ENTRY_RULES_LOCATION = "g_APM_BTEntryRulesLocation"; private const string GRAPH_APM_BUSINESS_TRANSACTION_ENTRY_RULES_20_TYPE = "g_APM_BTEntryRules20Type"; private const string GRAPH_APM_BUSINESS_TRANSACTION_ENTRY_RULES_20_LOCATION = "g_APM_BTEntryRules20Location"; + private const string GRAPH_APM_SERVICE_ENDPOINT_ENTRY_RULES_TYPE = "g_APM_SEPEntryRulesType"; private const string GRAPH_APM_BACKEND_DISCOVERY_RULES_TYPE = "g_APM_BackendDiscoveryRulesType"; private const string GRAPH_APM_CUSTOM_EXIT_RULES_TYPE = "g_APM_CustomExitRulesType"; private const string GRAPH_APM_AGENT_CONFIGURATION_PROPERTIES_TYPE = "g_APM_AgentPropertiesType"; @@ -526,12 +531,30 @@ public override bool Execute(ProgramOptions programOptions, JobConfiguration job sheet.Cells[1, 2].StyleName = "HyperLinkStyle"; sheet.View.FreezePanes(LIST_SHEET_START_TABLE_AT + 1, 1); - sheet = excelReport.Workbook.Worksheets.Add(SHEET_APM_SERVICE_ENDPOINT_RULES_SETTINGS); + sheet = excelReport.Workbook.Worksheets.Add(SHEET_APM_SERVICE_ENDPOINT_DISCOVERY_RULES); sheet.Cells[1, 1].Value = "Table of Contents"; sheet.Cells[1, 2].Formula = String.Format(@"=HYPERLINK(""#'{0}'!A1"", """")", SHEET_TOC); sheet.Cells[1, 2].StyleName = "HyperLinkStyle"; sheet.View.FreezePanes(LIST_SHEET_START_TABLE_AT + 1, 1); + sheet = excelReport.Workbook.Worksheets.Add(SHEET_APM_SERVICE_ENDPOINT_ENTRY_RULES); + sheet.Cells[1, 1].Value = "Table of Contents"; + sheet.Cells[1, 2].Formula = String.Format(@"=HYPERLINK(""#'{0}'!A1"", """")", SHEET_TOC); + sheet.Cells[1, 2].StyleName = "HyperLinkStyle"; + sheet.Cells[2, 1].Value = "Types of Rules"; + sheet.Cells[2, 2].Formula = String.Format(@"=HYPERLINK(""#'{0}'!A1"", """")", SHEET_APM_SERVICE_ENDPOINT_ENTRY_RULES_PIVOT_TYPE); + sheet.Cells[2, 2].StyleName = "HyperLinkStyle"; + sheet.View.FreezePanes(LIST_SHEET_START_TABLE_AT + 1, 1); + + sheet = excelReport.Workbook.Worksheets.Add(SHEET_APM_SERVICE_ENDPOINT_ENTRY_RULES_PIVOT_TYPE); + sheet.Cells[1, 1].Value = "Table of Contents"; + sheet.Cells[1, 2].Formula = String.Format(@"=HYPERLINK(""#'{0}'!A1"", """")", 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"", """")", SHEET_APM_SERVICE_ENDPOINT_ENTRY_RULES); + sheet.Cells[2, 2].StyleName = "HyperLinkStyle"; + sheet.View.FreezePanes(PIVOT_SHEET_START_PIVOT_AT + PIVOT_SHEET_CHART_HEIGHT + 3, 1); + sheet = excelReport.Workbook.Worksheets.Add(SHEET_APM_DEVELOPER_MODE_NODES); sheet.Cells[1, 1].Value = "Table of Contents"; sheet.Cells[1, 2].Formula = String.Format(@"=HYPERLINK(""#'{0}'!A1"", """")", SHEET_TOC); @@ -768,11 +791,20 @@ public override bool Execute(ProgramOptions programOptions, JobConfiguration job #endregion + #region APM Service Endpoint Discovery Rules + + loggerConsole.Info("List of APM Service Endpoint Discovery Rules"); + + sheet = excelReport.Workbook.Worksheets[SHEET_APM_SERVICE_ENDPOINT_DISCOVERY_RULES]; + EPPlusCSVHelper.ReadCSVFileIntoExcelRange(FilePathMap.APMServiceEndpointDiscoveryRulesReportFilePath(), 0, sheet, LIST_SHEET_START_TABLE_AT, 1); + + #endregion + #region APM Service Endpoint Entry Rules loggerConsole.Info("List of APM Service Endpoint Entry Rules"); - sheet = excelReport.Workbook.Worksheets[SHEET_APM_SERVICE_ENDPOINT_RULES_SETTINGS]; + sheet = excelReport.Workbook.Worksheets[SHEET_APM_SERVICE_ENDPOINT_ENTRY_RULES]; EPPlusCSVHelper.ReadCSVFileIntoExcelRange(FilePathMap.APMServiceEndpointEntryRulesReportFilePath(), 0, sheet, LIST_SHEET_START_TABLE_AT, 1); #endregion @@ -1505,10 +1537,35 @@ public override bool Execute(ProgramOptions programOptions, JobConfiguration job #endregion + #region APM Service Endpoint Discovery Rules + + // Make table + sheet = excelReport.Workbook.Worksheets[SHEET_APM_SERVICE_ENDPOINT_DISCOVERY_RULES]; + logger.Info("{0} Sheet ({1} rows)", sheet.Name, sheet.Dimension.Rows); + loggerConsole.Info("{0} Sheet ({1} rows)", sheet.Name, sheet.Dimension.Rows); + if (sheet.Dimension.Rows > LIST_SHEET_START_TABLE_AT) + { + range = sheet.Cells[LIST_SHEET_START_TABLE_AT, 1, sheet.Dimension.Rows, sheet.Dimension.Columns]; + table = sheet.Tables.Add(range, TABLE_APM_SERVICE_ENDPOINT_DISCOVERY_RULES); + 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["AgentType"].Position + 1).Width = 25; + sheet.Column(table.Columns["RuleName"].Position + 1).Width = 20; + sheet.Column(table.Columns["EntryPointType"].Position + 1).Width = 15; + } + + #endregion + #region APM Service Endpoint Entry Rules // Make table - sheet = excelReport.Workbook.Worksheets[SHEET_APM_SERVICE_ENDPOINT_RULES_SETTINGS]; + sheet = excelReport.Workbook.Worksheets[SHEET_APM_SERVICE_ENDPOINT_ENTRY_RULES]; logger.Info("{0} Sheet ({1} rows)", sheet.Name, sheet.Dimension.Rows); loggerConsole.Info("{0} Sheet ({1} rows)", sheet.Name, sheet.Dimension.Rows); if (sheet.Dimension.Rows > LIST_SHEET_START_TABLE_AT) @@ -1525,8 +1582,31 @@ public override bool Execute(ProgramOptions programOptions, JobConfiguration job sheet.Column(table.Columns["TierName"].Position + 1).Width = 20; sheet.Column(table.Columns["AgentType"].Position + 1).Width = 25; sheet.Column(table.Columns["RuleName"].Position + 1).Width = 20; - sheet.Column(table.Columns["EntryPointType"].Position + 1).Width = 20; - sheet.Column(table.Columns["RuleRawValue"].Position + 1).Width = 20; + sheet.Column(table.Columns["EntryPointType"].Position + 1).Width = 15; + + // Make pivot + sheet = excelReport.Workbook.Worksheets[SHEET_APM_SERVICE_ENDPOINT_ENTRY_RULES_PIVOT_TYPE]; + ExcelPivotTable pivot = sheet.PivotTables.Add(sheet.Cells[PIVOT_SHEET_START_PIVOT_AT + PIVOT_SHEET_CHART_HEIGHT + 1, 1], range, PIVOT_APM_SERVICE_ENDPOINT_ENTRY_RULES_TYPE); + setDefaultPivotTableSettings(pivot); + addFilterFieldToPivot(pivot, "IsExclusion"); + addFilterFieldToPivot(pivot, "IsEnabled"); + addRowFieldToPivot(pivot, "Controller"); + addRowFieldToPivot(pivot, "ApplicationName"); + addRowFieldToPivot(pivot, "AgentType"); + addRowFieldToPivot(pivot, "TierName"); + addRowFieldToPivot(pivot, "RuleName"); + addColumnFieldToPivot(pivot, "EntryPointType", eSortType.Ascending); + addDataFieldToPivot(pivot, "RuleName", DataFieldFunctions.Count); + + ExcelChart chart = sheet.Drawings.AddChart(GRAPH_APM_SERVICE_ENDPOINT_ENTRY_RULES_TYPE, eChartType.ColumnClustered, pivot); + chart.SetPosition(2, 0, 0, 0); + chart.SetSize(800, 300); + + sheet.Column(1).Width = 20; + sheet.Column(2).Width = 20; + sheet.Column(3).Width = 20; + sheet.Column(4).Width = 20; + sheet.Column(5).Width = 20; } #endregion @@ -1808,6 +1888,7 @@ public override bool Execute(ProgramOptions programOptions, JobConfiguration job ExcelPivotTable pivot = sheet.PivotTables.Add(sheet.Cells[PIVOT_SHEET_START_PIVOT_AT + PIVOT_SHEET_CHART_HEIGHT, 1], range, PIVOT_APM_AGENT_CONFIGURATION_PROPERTIES_TYPE); setDefaultPivotTableSettings(pivot); addFilterFieldToPivot(pivot, "IsDefault"); + addFilterFieldToPivot(pivot, "IsBuiltIn"); addRowFieldToPivot(pivot, "Controller"); addRowFieldToPivot(pivot, "ApplicationName"); addRowFieldToPivot(pivot, "AgentType"); diff --git a/ProcessingSteps/Report/ReportHealthCheck.cs b/ProcessingSteps/Report/ReportHealthCheck.cs new file mode 100644 index 0000000..c376393 --- /dev/null +++ b/ProcessingSteps/Report/ReportHealthCheck.cs @@ -0,0 +1,706 @@ +using AppDynamics.Dexter.ReportObjectMaps; +using AppDynamics.Dexter.ReportObjects; +using OfficeOpenXml; +using OfficeOpenXml.ConditionalFormatting; +using OfficeOpenXml.Style; +using OfficeOpenXml.Table; +using OfficeOpenXml.Table.PivotTable; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Text; + +namespace AppDynamics.Dexter.ProcessingSteps +{ + public class ReportHealthCheck : JobStepReportBase + { + #region Constants for report contents + + private const string SHEET_CONTROLLERS = "3.Controllers"; + private const string SHEET_APPLICATIONS = "4.Applications"; + + private const string SHEET_HEALTH_CHECK_RULE_RESULTS = "5.Health Check Results"; + private const string SHEET_HEALTH_CHECK_RULE_RESULTS_PIVOT = "5.Health Check Results.Rating"; + private const string SHEET_HEALTH_CHECK_RULE_RESULTS_DISPLAY = "5.Health Check Results.Display"; + private const string SHEET_HEALTH_CHECK_RULE_CATEGORY_RESULTS_DISPLAY = "6.{0}"; + + private const string TABLE_CONTROLLERS = "t_Controllers"; + private const string TABLE_APPLICATIONS = "t_Applications"; + + private const string TABLE_HEALTH_CHECK_RULE_RESULTS = "t_HealthCheckRuleResults"; + private const string TABLE_HEALTH_CHECK_RULE_APPLICATIONS = "t_HealthCheckRuleApplications"; + + private const string TABLE_HEALTH_CHECK_RULE_CATEGORY_RESULTS = "t_H_{0}"; + + private const string PIVOT_HEALTH_CHECK_RULE_RESULTS_TYPE = "p_HealthCheckRuleResults"; + + private const int LIST_SHEET_START_TABLE_AT = 4; + private const int PIVOT_SHEET_START_PIVOT_AT = 8; + private const int PIVOT_SHEET_CHART_HEIGHT = 14; + + #endregion + + public override bool Execute(ProgramOptions programOptions, JobConfiguration jobConfiguration) + { + Stopwatch stopWatch = new Stopwatch(); + stopWatch.Start(); + + StepTiming stepTimingFunction = new StepTiming(); + stepTimingFunction.JobFileName = programOptions.OutputJobFilePath; + stepTimingFunction.StepName = jobConfiguration.Status.ToString(); + stepTimingFunction.StepID = (int)jobConfiguration.Status; + stepTimingFunction.StartTime = DateTime.Now; + stepTimingFunction.NumEntities = jobConfiguration.Target.Count; + + this.DisplayJobStepStartingStatus(jobConfiguration); + + FilePathMap = new FilePathMap(programOptions, jobConfiguration); + + if (this.ShouldExecute(jobConfiguration) == false) + { + return true; + } + + if (jobConfiguration.Target.Count(t => t.Type == APPLICATION_TYPE_APM) == 0) + { + return true; + } + + try + { + loggerConsole.Info("Prepare APM Health Check Report File"); + + #region Prepare the report package + + // Prepare package + ExcelPackage excelReport = new ExcelPackage(); + excelReport.Workbook.Properties.Author = String.Format("AppDynamics DEXTER {0}", Assembly.GetEntryAssembly().GetName().Version); + excelReport.Workbook.Properties.Title = "AppDynamics DEXTER APM Health Check Report"; + excelReport.Workbook.Properties.Subject = programOptions.JobName; + + excelReport.Workbook.Properties.Comments = String.Format("Targets={0}\nFrom={1:o}\nTo={2:o}", jobConfiguration.Target.Count, jobConfiguration.Input.TimeRange.From, jobConfiguration.Input.TimeRange.To); + + #endregion + + #region Parameters sheet + + // Parameters sheet + ExcelWorksheet sheet = excelReport.Workbook.Worksheets.Add(SHEET_PARAMETERS); + + var hyperLinkStyle = sheet.Workbook.Styles.CreateNamedStyle("HyperLinkStyle"); + hyperLinkStyle.Style.Font.UnderLineType = ExcelUnderLineType.Single; + hyperLinkStyle.Style.Font.Color.SetColor(colorBlueForHyperlinks); + + var timelineStyle = sheet.Workbook.Styles.CreateNamedStyle("TimelineStyle"); + timelineStyle.Style.Font.Name = "Consolas"; + timelineStyle.Style.Font.Size = 8; + + fillReportParametersSheet(sheet, jobConfiguration, "AppDynamics DEXTER APM Health Check Report"); + + #endregion + + #region TOC sheet + + // Navigation sheet with link to other sheets + sheet = excelReport.Workbook.Worksheets.Add(SHEET_TOC); + + #endregion + + #region Entity sheets and their associated pivot + + // Entity sheets + sheet = excelReport.Workbook.Worksheets.Add(SHEET_CONTROLLERS); + sheet.Cells[1, 1].Value = "Table of Contents"; + sheet.Cells[1, 2].Formula = String.Format(@"=HYPERLINK(""#'{0}'!A1"", """")", SHEET_TOC); + sheet.Cells[1, 2].StyleName = "HyperLinkStyle"; + sheet.View.FreezePanes(LIST_SHEET_START_TABLE_AT + 1, 1); + + sheet = excelReport.Workbook.Worksheets.Add(SHEET_APPLICATIONS); + sheet.Cells[1, 1].Value = "Table of Contents"; + sheet.Cells[1, 2].Formula = String.Format(@"=HYPERLINK(""#'{0}'!A1"", """")", SHEET_TOC); + sheet.Cells[1, 2].StyleName = "HyperLinkStyle"; + sheet.View.FreezePanes(LIST_SHEET_START_TABLE_AT + 1, 1); + + sheet = excelReport.Workbook.Worksheets.Add(SHEET_HEALTH_CHECK_RULE_RESULTS); + sheet.Cells[1, 1].Value = "Table of Contents"; + sheet.Cells[1, 2].Formula = String.Format(@"=HYPERLINK(""#'{0}'!A1"", """")", SHEET_TOC); + sheet.Cells[1, 2].StyleName = "HyperLinkStyle"; + sheet.Cells[2, 1].Value = "See Pivot"; + sheet.Cells[2, 2].Formula = String.Format(@"=HYPERLINK(""#'{0}'!A1"", """")", SHEET_HEALTH_CHECK_RULE_RESULTS_PIVOT); + sheet.Cells[2, 2].StyleName = "HyperLinkStyle"; + sheet.Cells[3, 1].Value = "See Report"; + sheet.Cells[3, 2].Formula = String.Format(@"=HYPERLINK(""#'{0}'!A1"", """")", SHEET_HEALTH_CHECK_RULE_RESULTS_DISPLAY); + sheet.Cells[3, 2].StyleName = "HyperLinkStyle"; + sheet.View.FreezePanes(LIST_SHEET_START_TABLE_AT + 1, 1); + + sheet = excelReport.Workbook.Worksheets.Add(SHEET_HEALTH_CHECK_RULE_RESULTS_PIVOT); + sheet.Cells[1, 1].Value = "Table of Contents"; + sheet.Cells[1, 2].Formula = String.Format(@"=HYPERLINK(""#'{0}'!A1"", """")", 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"", """")", SHEET_HEALTH_CHECK_RULE_RESULTS); + sheet.Cells[2, 2].StyleName = "HyperLinkStyle"; + sheet.View.FreezePanes(PIVOT_SHEET_START_PIVOT_AT + 2, 1); + + sheet = excelReport.Workbook.Worksheets.Add(SHEET_HEALTH_CHECK_RULE_RESULTS_DISPLAY); + sheet.Cells[1, 1].Value = "Table of Contents"; + sheet.Cells[1, 2].Formula = String.Format(@"=HYPERLINK(""#'{0}'!A1"", """")", 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"", """")", SHEET_HEALTH_CHECK_RULE_RESULTS); + sheet.Cells[2, 2].StyleName = "HyperLinkStyle"; + sheet.View.FreezePanes(LIST_SHEET_START_TABLE_AT + 1, 1); + + #endregion + + #region Report file variables + + ExcelRangeBase range = null; + ExcelTable table = null; + + #endregion + + loggerConsole.Info("Fill APM Health Check Report File"); + + #region Controllers + + loggerConsole.Info("List of Controllers"); + + sheet = excelReport.Workbook.Worksheets[SHEET_CONTROLLERS]; + EPPlusCSVHelper.ReadCSVFileIntoExcelRange(FilePathMap.ControllerSummaryReportFilePath(), 0, sheet, LIST_SHEET_START_TABLE_AT, 1); + + #endregion + + #region Applications + + loggerConsole.Info("List of Applications"); + + sheet = excelReport.Workbook.Worksheets[SHEET_APPLICATIONS]; + EPPlusCSVHelper.ReadCSVFileIntoExcelRange(FilePathMap.ApplicationSnapshotsReportFilePath(), 0, sheet, LIST_SHEET_START_TABLE_AT, 1); + + #endregion + + #region Health Check Results + + loggerConsole.Info("List of Health Check Results"); + + sheet = excelReport.Workbook.Worksheets[SHEET_HEALTH_CHECK_RULE_RESULTS]; + EPPlusCSVHelper.ReadCSVFileIntoExcelRange(FilePathMap.APMHealthCheckRuleResultsReportFilePath(), 0, sheet, LIST_SHEET_START_TABLE_AT, 1); + + #endregion + + loggerConsole.Info("Finalize APM Health Check Report File"); + + #region Controllers sheet + + // Make table + sheet = excelReport.Workbook.Worksheets[SHEET_CONTROLLERS]; + logger.Info("{0} Sheet ({1} rows)", sheet.Name, sheet.Dimension.Rows); + loggerConsole.Info("{0} Sheet ({1} rows)", sheet.Name, sheet.Dimension.Rows); + if (sheet.Dimension.Rows > LIST_SHEET_START_TABLE_AT) + { + range = sheet.Cells[LIST_SHEET_START_TABLE_AT, 1, sheet.Dimension.Rows, sheet.Dimension.Columns]; + table = sheet.Tables.Add(range, TABLE_CONTROLLERS); + table.ShowHeader = true; + table.TableStyle = TableStyles.Medium2; + table.ShowFilter = true; + table.ShowTotal = false; + + sheet.Column(table.Columns["Controller"].Position + 1).Width = 25; + sheet.Column(table.Columns["Version"].Position + 1).Width = 15; + } + + #endregion + + #region Applications + + // Make table + sheet = excelReport.Workbook.Worksheets[SHEET_APPLICATIONS]; + logger.Info("{0} Sheet ({1} rows)", sheet.Name, sheet.Dimension.Rows); + loggerConsole.Info("{0} Sheet ({1} rows)", sheet.Name, sheet.Dimension.Rows); + if (sheet.Dimension.Rows > LIST_SHEET_START_TABLE_AT) + { + range = sheet.Cells[LIST_SHEET_START_TABLE_AT, 1, sheet.Dimension.Rows, sheet.Dimension.Columns]; + table = sheet.Tables.Add(range, TABLE_APPLICATIONS); + table.ShowHeader = true; + table.TableStyle = TableStyles.Medium2; + table.ShowFilter = true; + table.ShowTotal = false; + + //adjustColumnsOfEntityRowTableInMetricReport(HealthCheckRuleResult.ENTITY_TYPE, sheet, table); + + ExcelAddress cfAddressNum = new ExcelAddress(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(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(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(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(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(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); + } + + #endregion + + #region Health Check Results + + // Make table + sheet = excelReport.Workbook.Worksheets[SHEET_HEALTH_CHECK_RULE_RESULTS]; + logger.Info("{0} Sheet ({1} rows)", sheet.Name, sheet.Dimension.Rows); + loggerConsole.Info("{0} Sheet ({1} rows)", sheet.Name, sheet.Dimension.Rows); + if (sheet.Dimension.Rows > LIST_SHEET_START_TABLE_AT) + { + range = sheet.Cells[LIST_SHEET_START_TABLE_AT, 1, sheet.Dimension.Rows, sheet.Dimension.Columns]; + table = sheet.Tables.Add(range, TABLE_HEALTH_CHECK_RULE_RESULTS); + table.ShowHeader = true; + table.TableStyle = TableStyles.Medium2; + table.ShowFilter = true; + table.ShowTotal = false; + + sheet.Column(table.Columns["Controller"].Position + 1).Width = 15; + sheet.Column(table.Columns["Application"].Position + 1).Width = 20; + sheet.Column(table.Columns["EntityName"].Position + 1).Width = 20; + sheet.Column(table.Columns["Category"].Position + 1).Width = 30; + sheet.Column(table.Columns["Code"].Position + 1).Width = 15; + sheet.Column(table.Columns["Name"].Position + 1).Width = 50; + sheet.Column(table.Columns["Description"].Position + 1).Width = 30; + + ExcelAddress cfAddressGrade = new ExcelAddress(LIST_SHEET_START_TABLE_AT + 1, table.Columns["Grade"].Position + 1, sheet.Dimension.Rows, table.Columns["Grade"].Position + 1); + var cfGrade = sheet.ConditionalFormatting.AddThreeColorScale(cfAddressGrade); + cfGrade.LowValue.Type = eExcelConditionalFormattingValueObjectType.Num; + cfGrade.LowValue.Color = colorRedFor3ColorScales; + cfGrade.LowValue.Value = 1; + cfGrade.MiddleValue.Type = eExcelConditionalFormattingValueObjectType.Num; + cfGrade.MiddleValue.Value = 3; + cfGrade.MiddleValue.Color = colorYellowFor3ColorScales; + cfGrade.HighValue.Type = eExcelConditionalFormattingValueObjectType.Num; + cfGrade.HighValue.Color = colorGreenFor3ColorScales; + cfGrade.HighValue.Value = 5; + + sheet = excelReport.Workbook.Worksheets[SHEET_HEALTH_CHECK_RULE_RESULTS_PIVOT]; + ExcelPivotTable pivot = sheet.PivotTables.Add(sheet.Cells[PIVOT_SHEET_START_PIVOT_AT, 1], range, PIVOT_HEALTH_CHECK_RULE_RESULTS_TYPE); + setDefaultPivotTableSettings(pivot); + addFilterFieldToPivot(pivot, "EntityType"); + addRowFieldToPivot(pivot, "Controller"); + addRowFieldToPivot(pivot, "Application"); + addRowFieldToPivot(pivot, "EntityName"); + addColumnFieldToPivot(pivot, "Category", eSortType.Ascending); + addColumnFieldToPivot(pivot, "Name", eSortType.Ascending); + addDataFieldToPivot(pivot, "Grade", DataFieldFunctions.Average); + + sheet.Column(1).Width = 20; + sheet.Column(2).Width = 20; + sheet.Column(3).Width = 20; + } + + #endregion + + #region Health Check Results Display + + sheet = excelReport.Workbook.Worksheets[SHEET_HEALTH_CHECK_RULE_RESULTS_DISPLAY]; + + List healthCheckRuleResults = FileIOHelper.ReadListFromCSVFile(FilePathMap.APMHealthCheckRuleResultsReportFilePath(), new HealthCheckRuleResultReportMap()); + if (healthCheckRuleResults != null) + { + #region Output summary of Applications by Category table + + // Make this following table out of the list of health rule evaluations + // Controller | Application | Category1 | Category2 | Category 3 + // ------------------------------------------------------------- + // CntrVal | AppName | Avg(Grade)| Avg(Grade)| Avg(Grade) + + // To do this, we measure number of rows (Controller/Application pairs) and Columns (Category values), and build a table + int numRows = healthCheckRuleResults.Select(h => String.Format("{0}/{1}", h.Controller, h.Application)).Distinct().Count(); + int numColumns = healthCheckRuleResults.Select(h => h.Category).Distinct().Count(); + + Dictionary categoryTableRowsLookup = new Dictionary(numRows); + Dictionary categoryTableColumnsLookup = new Dictionary(numColumns); + + List[,] categoryTableValues = new List[numRows, numColumns]; + + foreach (HealthCheckRuleResult healthCheckRuleResult in healthCheckRuleResults) + { + int rowIndex = 0; + int columnIndex = 0; + + string rowIndexValue = String.Format("{0}/{1}", healthCheckRuleResult.Controller, healthCheckRuleResult.Application); + string columnIndexValue = healthCheckRuleResult.Category; + + if (categoryTableRowsLookup.ContainsKey(rowIndexValue) == true) + { + rowIndex = categoryTableRowsLookup[rowIndexValue]; + } + else + { + rowIndex = categoryTableRowsLookup.Count; + categoryTableRowsLookup.Add(rowIndexValue, rowIndex); + } + + if (categoryTableColumnsLookup.ContainsKey(columnIndexValue) == true) + { + columnIndex = categoryTableColumnsLookup[columnIndexValue]; + } + else + { + columnIndex = categoryTableColumnsLookup.Count; + categoryTableColumnsLookup.Add(columnIndexValue, columnIndex); + } + + // Fill in the cell + List healthCheckRuleResultsInCell = categoryTableValues[rowIndex, columnIndex]; + if (healthCheckRuleResultsInCell == null) + { + healthCheckRuleResultsInCell = new List(); + categoryTableValues[rowIndex, columnIndex] = healthCheckRuleResultsInCell; + } + healthCheckRuleResultsInCell.Add(healthCheckRuleResult); + } + + // Output headers + int rowTableStart = 4; + int gradeColumnStart = 4; + int fromRow = rowTableStart; + int fromColumn = gradeColumnStart; + sheet.Cells[fromRow, 1].Value = "Controller"; + sheet.Cells[fromRow, 2].Value = "Application"; + sheet.Cells[fromRow, 3].Value = "ApplicationID"; + foreach (KeyValuePair categoriesKVP in categoryTableColumnsLookup) + { + sheet.Cells[fromRow, fromColumn].Value = categoriesKVP.Key; + sheet.Cells[fromRow - 1, fromColumn].Formula = String.Format(@"=HYPERLINK(""#'{0}'!A1"", """")", String.Format(SHEET_HEALTH_CHECK_RULE_CATEGORY_RESULTS_DISPLAY, categoriesKVP.Key)); + sheet.Cells[fromRow - 1, fromColumn].StyleName = "HyperLinkStyle"; + fromColumn++; + } + fromRow++; + + // Output table + for (int rowIndex = 0; rowIndex < numRows; rowIndex++) + { + for (int columnIndex = 0; columnIndex < numColumns; columnIndex++) + { + List healthCheckRuleResultsInCell = categoryTableValues[rowIndex, columnIndex]; + if (healthCheckRuleResultsInCell != null && healthCheckRuleResultsInCell.Count > 0) + { + double gradeAverage = Math.Round((double)healthCheckRuleResultsInCell.Sum(h => h.Grade) / healthCheckRuleResultsInCell.Count, 1); + + sheet.Cells[fromRow + rowIndex, gradeColumnStart + columnIndex].Value = gradeAverage; + + sheet.Cells[fromRow + rowIndex, 1].Value = healthCheckRuleResultsInCell[0].Controller; + sheet.Cells[fromRow + rowIndex, 2].Value = healthCheckRuleResultsInCell[0].Application; + sheet.Cells[fromRow + rowIndex, 3].Value = healthCheckRuleResultsInCell[0].ApplicationID; + } + else + { + sheet.Cells[fromRow + rowIndex, gradeColumnStart + columnIndex].Value = "-"; + } + } + } + fromRow = fromRow + numRows; + + // Insert the table + range = sheet.Cells[4, 1, 4 + numRows, 3 + numColumns]; + table = sheet.Tables.Add(range, TABLE_HEALTH_CHECK_RULE_APPLICATIONS); + table.ShowHeader = true; + table.TableStyle = TableStyles.None; + table.TableStyle = TableStyles.Medium2; + table.ShowFilter = true; + table.ShowTotal = false; + + // Resize the columns + sheet.Column(table.Columns["Controller"].Position + 1).Width = 20; + sheet.Column(table.Columns["Application"].Position + 1).Width = 25; + for (int columnIndex = 0; columnIndex < numColumns; columnIndex++) + { + sheet.Column(gradeColumnStart + columnIndex).Width = 15; + // Make the header column cells wrap text for Categories headings + sheet.Cells[rowTableStart, gradeColumnStart + columnIndex].Style.WrapText = true; + } + + // Make header row taller + sheet.Row(rowTableStart).Height = 30; + + // Color code it + ExcelAddress cfGradeNum = new ExcelAddress(LIST_SHEET_START_TABLE_AT + 1, 4, sheet.Dimension.Rows, 4 + numColumns); + var cfGrade = sheet.ConditionalFormatting.AddThreeColorScale(cfGradeNum); + cfGrade.LowValue.Type = eExcelConditionalFormattingValueObjectType.Num; + cfGrade.LowValue.Color = colorRedFor3ColorScales; + cfGrade.LowValue.Value = 1; + cfGrade.MiddleValue.Type = eExcelConditionalFormattingValueObjectType.Num; + cfGrade.MiddleValue.Value = 3; + cfGrade.MiddleValue.Color = colorYellowFor3ColorScales; + cfGrade.HighValue.Type = eExcelConditionalFormattingValueObjectType.Num; + cfGrade.HighValue.Color = colorGreenFor3ColorScales; + cfGrade.HighValue.Value = 5; + + #endregion + + #region Output individual categories on separate sheets + + // Get list of categories for which we'll be making things + List listOfCategories = healthCheckRuleResults.Select(h => h.Category).Distinct().ToList(); + + foreach (string category in listOfCategories) + { + sheet = excelReport.Workbook.Worksheets.Add(String.Format(SHEET_HEALTH_CHECK_RULE_CATEGORY_RESULTS_DISPLAY, category)); + sheet.Cells[1, 1].Value = "Table of Contents"; + sheet.Cells[1, 2].Formula = String.Format(@"=HYPERLINK(""#'{0}'!A1"", """")", 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"", """")", SHEET_HEALTH_CHECK_RULE_RESULTS); + sheet.Cells[2, 2].StyleName = "HyperLinkStyle"; + sheet.Cells[3, 1].Value = "See Display"; + sheet.Cells[3, 2].Formula = String.Format(@"=HYPERLINK(""#'{0}'!A1"", """")", SHEET_HEALTH_CHECK_RULE_RESULTS_DISPLAY); + sheet.Cells[3, 2].StyleName = "HyperLinkStyle"; + sheet.View.FreezePanes(LIST_SHEET_START_TABLE_AT + 1, 1); + + + // Make this following table out of the list of health rule evaluations + // Controller | Application | EntityType | EntityName | Rule 1 | Rule 2 | Rule 3 + // ----------------------------------------------------------------------------- + // CntrVal | AppName | APMApp | AppName | Grade | Grade | Grade (with comment of value) + + // To do this, we measure number of rows (Controller/Application/EntityType/EntityName quads) and Columns (Rules within Category), and build a table + numRows = healthCheckRuleResults.Where(h => h.Category == category).Select(h => String.Format("{0}/{1}/{2}/{3}", h.Controller, h.Application, h.EntityType, h.EntityName)).Distinct().Count(); + numColumns = healthCheckRuleResults.Where(h => h.Category == category).Select(h => h.Name).Distinct().Count(); + + Dictionary nameTableRowsLookup = new Dictionary(numRows); + Dictionary nameTableColumnsLookup = new Dictionary(numColumns); + + List[,] nameTableValues = new List[numRows, numColumns]; + + foreach (HealthCheckRuleResult healthCheckRuleResult in healthCheckRuleResults) + { + // Only process the rules with the desired category + if (healthCheckRuleResult.Category != category) continue; + + int rowIndex = 0; + int columnIndex = 0; + + string rowIndexValue = String.Format("{0}/{1}/{2}/{3}", healthCheckRuleResult.Controller, healthCheckRuleResult.Application, healthCheckRuleResult.EntityType, healthCheckRuleResult.EntityName); + string columnIndexValue = healthCheckRuleResult.Name; + + if (nameTableRowsLookup.ContainsKey(rowIndexValue) == true) + { + rowIndex = nameTableRowsLookup[rowIndexValue]; + } + else + { + rowIndex = nameTableRowsLookup.Count; + nameTableRowsLookup.Add(rowIndexValue, rowIndex); + } + + if (nameTableColumnsLookup.ContainsKey(columnIndexValue) == true) + { + columnIndex = nameTableColumnsLookup[columnIndexValue]; + } + else + { + columnIndex = nameTableColumnsLookup.Count; + nameTableColumnsLookup.Add(columnIndexValue, columnIndex); + } + + // Fill in the cell + List healthCheckRuleResultsInCell = nameTableValues[rowIndex, columnIndex]; + if (healthCheckRuleResultsInCell == null) + { + healthCheckRuleResultsInCell = new List(); + nameTableValues[rowIndex, columnIndex] = healthCheckRuleResultsInCell; + } + healthCheckRuleResultsInCell.Add(healthCheckRuleResult); + } + + // Output headers + rowTableStart = 4; + gradeColumnStart = 6; + fromRow = rowTableStart; + fromColumn = gradeColumnStart; + sheet.Cells[fromRow, 1].Value = "Controller"; + sheet.Cells[fromRow, 2].Value = "Application"; + sheet.Cells[fromRow, 3].Value = "ApplicationID"; + sheet.Cells[fromRow, 4].Value = "EntityType"; + sheet.Cells[fromRow, 5].Value = "EntityName"; + foreach (KeyValuePair namesKVP in nameTableColumnsLookup) + { + sheet.Cells[fromRow, fromColumn].Value = namesKVP.Key; + fromColumn++; + } + fromRow++; + + // Output table + for (int rowIndex = 0; rowIndex < numRows; rowIndex++) + { + for (int columnIndex = 0; columnIndex < numColumns; columnIndex++) + { + List healthCheckRuleResultsInCell = nameTableValues[rowIndex, columnIndex]; + if (healthCheckRuleResultsInCell != null && healthCheckRuleResultsInCell.Count > 0) + { + double gradeAverage = Math.Round((double)healthCheckRuleResultsInCell.Sum(h => h.Grade) / healthCheckRuleResultsInCell.Count, 1); + + sheet.Cells[fromRow + rowIndex, gradeColumnStart + columnIndex].Value = gradeAverage; + + sheet.Cells[fromRow + rowIndex, 1].Value = healthCheckRuleResultsInCell[0].Controller; + sheet.Cells[fromRow + rowIndex, 2].Value = healthCheckRuleResultsInCell[0].Application; + sheet.Cells[fromRow + rowIndex, 3].Value = healthCheckRuleResultsInCell[0].ApplicationID; + sheet.Cells[fromRow + rowIndex, 4].Value = healthCheckRuleResultsInCell[0].EntityType; + sheet.Cells[fromRow + rowIndex, 5].Value = healthCheckRuleResultsInCell[0].EntityName; + + StringBuilder sb = new StringBuilder(healthCheckRuleResultsInCell.Count * 128); + for (int k = 0; k < healthCheckRuleResultsInCell.Count; k++) + { + HealthCheckRuleResult healthCheckRuleResult = healthCheckRuleResultsInCell[k]; + sb.AppendFormat("{0}: {1}\n", k + 1, wordWrapString(healthCheckRuleResult.Description, 100)); + } + + ExcelComment comment = sheet.Cells[fromRow + rowIndex, gradeColumnStart + columnIndex].AddComment(sb.ToString(), healthCheckRuleResultsInCell[0].Code); + comment.AutoFit = true; + } + else + { + sheet.Cells[fromRow + rowIndex, gradeColumnStart + columnIndex].Value = "-"; + } + } + } + fromRow = fromRow + numRows; + + // Insert the table + range = sheet.Cells[4, 1, 4 + numRows, 5 + numColumns]; + table = sheet.Tables.Add(range, getExcelTableOrSheetSafeString(String.Format(TABLE_HEALTH_CHECK_RULE_CATEGORY_RESULTS, category))); + table.ShowHeader = true; + table.TableStyle = TableStyles.None; + table.TableStyle = TableStyles.Medium2; + table.ShowFilter = true; + table.ShowTotal = false; + + // Resize the columns + sheet.Column(table.Columns["Controller"].Position + 1).Width = 20; + sheet.Column(table.Columns["Application"].Position + 1).Width = 25; + sheet.Column(table.Columns["EntityName"].Position + 1).Width = 25; + for (int columnIndex = 0; columnIndex < numColumns; columnIndex++) + { + sheet.Column(gradeColumnStart + columnIndex).Width = 15; + // Make the header column cells wrap text for Categories headings + sheet.Cells[rowTableStart, gradeColumnStart + columnIndex].Style.WrapText = true; + } + + // Make header row taller + sheet.Row(rowTableStart).Height = 90; + + // Color code it + cfGradeNum = new ExcelAddress(LIST_SHEET_START_TABLE_AT + 1, 5, sheet.Dimension.Rows, 5 + numColumns); + cfGrade = sheet.ConditionalFormatting.AddThreeColorScale(cfGradeNum); + cfGrade.LowValue.Type = eExcelConditionalFormattingValueObjectType.Num; + cfGrade.LowValue.Color = colorRedFor3ColorScales; + cfGrade.LowValue.Value = 1; + cfGrade.MiddleValue.Type = eExcelConditionalFormattingValueObjectType.Num; + cfGrade.MiddleValue.Value = 3; + cfGrade.MiddleValue.Color = colorYellowFor3ColorScales; + cfGrade.HighValue.Type = eExcelConditionalFormattingValueObjectType.Num; + cfGrade.HighValue.Color = colorGreenFor3ColorScales; + cfGrade.HighValue.Value = 5; + } + + #endregion + } + + #endregion + + #region TOC sheet + + // TOC sheet again + sheet = excelReport.Workbook.Worksheets[SHEET_TOC]; + fillTableOfContentsSheet(sheet, excelReport); + + #endregion + + #region Save file + + FileIOHelper.CreateFolder(FilePathMap.ReportFolderPath()); + + string reportFilePath = FilePathMap.APMHealthCheckResultsExcelReportFilePath(jobConfiguration.Input.TimeRange); + logger.Info("Saving Excel report {0}", reportFilePath); + loggerConsole.Info("Saving Excel report {0}", reportFilePath); + + try + { + // Save full report Excel files + excelReport.SaveAs(new FileInfo(reportFilePath)); + } + catch (InvalidOperationException ex) + { + logger.Warn("Unable to save Excel file {0}", reportFilePath); + logger.Warn(ex); + loggerConsole.Warn("Unable to save Excel file {0}", reportFilePath); + } + + #endregion + + return true; + } + catch (Exception ex) + { + logger.Error(ex); + loggerConsole.Error(ex); + + return false; + } + finally + { + stopWatch.Stop(); + + this.DisplayJobStepEndedStatus(jobConfiguration, stopWatch); + + stepTimingFunction.EndTime = DateTime.Now; + stepTimingFunction.Duration = stopWatch.Elapsed; + stepTimingFunction.DurationMS = stopWatch.ElapsedMilliseconds; + + List stepTimings = new List(1); + stepTimings.Add(stepTimingFunction); + FileIOHelper.WriteListToCSVFile(stepTimings, new StepTimingReportMap(), FilePathMap.StepTimingReportFilePath(), true); + } + } + + public override bool ShouldExecute(JobConfiguration jobConfiguration) + { + logger.Trace("Output.HealthCheck={0}", jobConfiguration.Output.HealthCheck); + loggerConsole.Trace("Output.HealthCheck={0}", jobConfiguration.Output.HealthCheck); + if (jobConfiguration.Output.HealthCheck == false) + { + loggerConsole.Trace("Skipping report of health check"); + } + return (jobConfiguration.Output.HealthCheck == true); + } + + public string wordWrapString(string stringToBreak, int lengthOfEachLine) + { + StringBuilder sb = new StringBuilder(stringToBreak.Length + stringToBreak.Length / lengthOfEachLine); + string[] stringToBreakWordsArray = stringToBreak.Split(' '); + + int lineLength = 0; + foreach (string word in stringToBreakWordsArray) + { + lineLength = lineLength + word.Length + 1; + if (lineLength > lengthOfEachLine) + { + sb.AppendLine(); + lineLength = word.Length + 1; + + } + sb.Append(word); + sb.Append(" "); + } + + return sb.ToString(); + } + } +} diff --git a/Program.cs b/Program.cs index a21cdd0..5876f14 100644 --- a/Program.cs +++ b/Program.cs @@ -292,14 +292,14 @@ public static void RunProgramETL(ProgramOptions programOptions) // Validate Metrics selection if (jobConfiguration.Input.MetricsSelectionCriteria == null) { - jobConfiguration.Input.MetricsSelectionCriteria = new string[0]; + jobConfiguration.Input.MetricsSelectionCriteria = new string[1]; jobConfiguration.Input.MetricsSelectionCriteria[0] = "TransactionApplication"; } // Validate Events selection if (jobConfiguration.Input.EventsSelectionCriteria == null || jobConfiguration.Input.EventsSelectionCriteria.Length == 0) { - jobConfiguration.Input.EventsSelectionCriteria = new string[0]; + jobConfiguration.Input.EventsSelectionCriteria = new string[1]; jobConfiguration.Input.EventsSelectionCriteria[0] = "None"; } diff --git a/Properties/AssemblyInfo.cs b/Properties/AssemblyInfo.cs index 3d10b7d..47668f0 100644 --- a/Properties/AssemblyInfo.cs +++ b/Properties/AssemblyInfo.cs @@ -5,11 +5,11 @@ // set of attributes. Change these attribute values to modify the information // associated with an assembly. [assembly: AssemblyTitle("AppDynamics DEXTER")] -[assembly: AssemblyDescription("Turn your AppDynamics data into a queryable Data Warehouse with advanced reporting, including entities, configuration, metrics, flowmaps, events, snapshots and call graph flame graphs")] +[assembly: AssemblyDescription("Turn your AppDynamics data into a queryable Data Warehouse with advanced reporting, including entities, configuration, configuration comparison, metrics, flowmaps, events, snapshots, call graph flame graphs and health checks")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("Cisco/AppDynamics")] [assembly: AssemblyProduct("DEXTER - Data EXTraction and Enhanced Reporting")] -[assembly: AssemblyCopyright("Copyright © 2017-2019")] +[assembly: AssemblyCopyright("Copyright © 2017-2020")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] @@ -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.2.45.0")] -[assembly: AssemblyFileVersion("1.2.45.0")] +[assembly: AssemblyVersion("1.2.46.0")] +[assembly: AssemblyFileVersion("1.2.46.0")] diff --git a/Properties/launchSettings.json b/Properties/launchSettings.json index 0cb31e6..fe913d1 100644 --- a/Properties/launchSettings.json +++ b/Properties/launchSettings.json @@ -2,7 +2,7 @@ "profiles": { "AppDynamics.Dexter.Core": { "commandName": "Project", - "commandLineArgs": "-j D:\\AppD.Dexter.Out\\Farmers\\fig.ccperf.loadtest.json -o D:\\AppD.Dexter.Out\\Farmers -v" + "commandLineArgs": "-j \"C:\\appdynamics\\AppDynamics.DEXTER\\JobFiles\\demo.sep.refactor.json\" -o D:\\AppD.Dexter.Out\\demo -v" } } } \ No newline at end of file diff --git a/ReportObjects/ConfigurationAPM/APMApplicationConfiguration.cs b/ReportObjects/ConfigurationAPM/APMApplicationConfiguration.cs index 3fbba1d..307e71a 100644 --- a/ReportObjects/ConfigurationAPM/APMApplicationConfiguration.cs +++ b/ReportObjects/ConfigurationAPM/APMApplicationConfiguration.cs @@ -22,7 +22,9 @@ public class APMApplicationConfiguration : ConfigurationEntityBase [FieldComparison(FieldComparisonType.ValueComparison)] public int NumBT20DiscoveryRules { get; set; } [FieldComparison(FieldComparisonType.ValueComparison)] - public int NumSEPRules { get; set; } + public int NumSEPDiscoveryRules { get; set; } + [FieldComparison(FieldComparisonType.ValueComparison)] + public int NumSEPEntryRules { get; set; } [FieldComparison(FieldComparisonType.ValueComparison)] public int NumBackendRules { get; set; } [FieldComparison(FieldComparisonType.ValueComparison)] diff --git a/ReportObjects/ConfigurationAPM/AgentConfigurationProperty.cs b/ReportObjects/ConfigurationAPM/AgentConfigurationProperty.cs index 131cd68..b94bbe9 100644 --- a/ReportObjects/ConfigurationAPM/AgentConfigurationProperty.cs +++ b/ReportObjects/ConfigurationAPM/AgentConfigurationProperty.cs @@ -39,6 +39,8 @@ public class AgentConfigurationProperty : ConfigurationEntityBase [FieldComparison(FieldComparisonType.ValueComparison)] public bool IsDefault { get; set; } + [FieldComparison(FieldComparisonType.ValueComparison)] + public bool IsBuiltIn { get; set; } public override string EntityIdentifier { diff --git a/ReportObjects/ConfigurationAPM/Maps/APMApplicationConfigurationReportMap.cs b/ReportObjects/ConfigurationAPM/Maps/APMApplicationConfigurationReportMap.cs index 377fea6..a4568d0 100644 --- a/ReportObjects/ConfigurationAPM/Maps/APMApplicationConfigurationReportMap.cs +++ b/ReportObjects/ConfigurationAPM/Maps/APMApplicationConfigurationReportMap.cs @@ -19,7 +19,8 @@ public APMApplicationConfigurationReportMap() Map(m => m.NumBT20DiscoveryRules).Index(i); i++; Map(m => m.NumBT20EntryRules).Index(i); i++; Map(m => m.NumBT20ExcludeRules).Index(i); i++; - Map(m => m.NumSEPRules).Index(i); i++; + Map(m => m.NumSEPDiscoveryRules).Index(i); i++; + Map(m => m.NumSEPEntryRules).Index(i); i++; Map(m => m.NumBackendRules).Index(i); i++; Map(m => m.NumInfoPointRules).Index(i); i++; Map(m => m.NumAgentProps).Index(i); i++; diff --git a/ReportObjects/ConfigurationAPM/Maps/AgentConfigurationPropertyReportMap.cs b/ReportObjects/ConfigurationAPM/Maps/AgentConfigurationPropertyReportMap.cs index 1e88fb3..0a4fc87 100644 --- a/ReportObjects/ConfigurationAPM/Maps/AgentConfigurationPropertyReportMap.cs +++ b/ReportObjects/ConfigurationAPM/Maps/AgentConfigurationPropertyReportMap.cs @@ -17,6 +17,7 @@ public AgentConfigurationPropertyReportMap() Map(m => m.PropertyType).Index(i); i++; Map(m => m.Description).Index(i); i++; Map(m => m.IsDefault).Index(i); i++; + Map(m => m.IsBuiltIn).Index(i); i++; Map(m => m.StringValue).Index(i); i++; Map(m => m.IntegerValue).Index(i); i++; diff --git a/ReportObjects/ConfigurationAPM/Maps/ServiceEndpointDiscoveryRuleReportMap.cs b/ReportObjects/ConfigurationAPM/Maps/ServiceEndpointDiscoveryRuleReportMap.cs new file mode 100644 index 0000000..5be37a0 --- /dev/null +++ b/ReportObjects/ConfigurationAPM/Maps/ServiceEndpointDiscoveryRuleReportMap.cs @@ -0,0 +1,28 @@ +using AppDynamics.Dexter.ReportObjects; +using CsvHelper.Configuration; + +namespace AppDynamics.Dexter.ReportObjectMaps +{ + public class ServiceEndpointDiscoveryRuleReportMap : ClassMap + { + public ServiceEndpointDiscoveryRuleReportMap() + { + 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.AgentType).Index(i); i++; + Map(m => m.RuleName).Index(i); i++; + Map(m => m.EntryPointType).Index(i); i++; + Map(m => m.NamingConfigType).Index(i); i++; + Map(m => m.Version).Index(i); i++; + Map(m => m.IsEnabled).Index(i); i++; + Map(m => m.DiscoveryType).Index(i); i++; + + Map(m => m.ApplicationID).Index(i); i++; + Map(m => m.ControllerLink).Index(i); i++; + Map(m => m.ApplicationLink).Index(i); i++; + } + } +} \ No newline at end of file diff --git a/ReportObjects/ConfigurationAPM/Maps/ServiceEndpointEntryRuleReportMap.cs b/ReportObjects/ConfigurationAPM/Maps/ServiceEndpointEntryRuleReportMap.cs index e509418..37955ec 100644 --- a/ReportObjects/ConfigurationAPM/Maps/ServiceEndpointEntryRuleReportMap.cs +++ b/ReportObjects/ConfigurationAPM/Maps/ServiceEndpointEntryRuleReportMap.cs @@ -15,16 +15,18 @@ public ServiceEndpointEntryRuleReportMap() Map(m => m.AgentType).Index(i); i++; Map(m => m.RuleName).Index(i); i++; Map(m => m.EntryPointType).Index(i); i++; - Map(m => m.NamingConfigType).Index(i); i++; - Map(m => m.IsMonitoringEnabled).Index(i); i++; - Map(m => m.DiscoveryType).Index(i); i++; - Map(m => m.IsOverride).Index(i); i++; + Map(m => m.Version).Index(i); i++; + + Map(m => m.IsEnabled).Index(i); i++; + Map(m => m.IsExclusion).Index(i); i++; + Map(m => m.Priority).Index(i); i++; + + Map(m => m.MatchConditions).Index(i); i++; + Map(m => m.Actions).Index(i); i++; Map(m => m.NumDetectedSEPs).Index(i); i++; Map(m => m.DetectedSEPs).Index(i); i++; - Map(m => m.RuleRawValue).Index(i); i++; - Map(m => m.ApplicationID).Index(i); i++; Map(m => m.ControllerLink).Index(i); i++; Map(m => m.ApplicationLink).Index(i); i++; diff --git a/ReportObjects/ConfigurationAPM/ServiceEndpointDiscoveryRule.cs b/ReportObjects/ConfigurationAPM/ServiceEndpointDiscoveryRule.cs new file mode 100644 index 0000000..e68115c --- /dev/null +++ b/ReportObjects/ConfigurationAPM/ServiceEndpointDiscoveryRule.cs @@ -0,0 +1,63 @@ +using System; + +namespace AppDynamics.Dexter.ReportObjects +{ + public class ServiceEndpointDiscoveryRule : ConfigurationEntityBase + { + public string AgentType { get; set; } + public string RuleName { get; set; } + [FieldComparison(FieldComparisonType.ValueComparison)] + public string EntryPointType { get; set; } + [FieldComparison(FieldComparisonType.ValueComparison)] + public int Version { get; set; } + [FieldComparison(FieldComparisonType.ValueComparison)] + public bool IsEnabled { get; set; } + [FieldComparison(FieldComparisonType.ValueComparison)] + public string DiscoveryType { get; set; } + [FieldComparison(FieldComparisonType.ValueComparison)] + public string NamingConfigType { get; set; } + + public override string EntityIdentifier + { + get + { + return String.Format("{0}/{1}/{2}", this.EntryPointType, this.AgentType, this.TierName); + } + } + + public override string EntityName + { + get + { + return this.EntryPointType; + } + } + + public override string RuleType + { + get + { + return "APMServiceEndpointDiscoveryRule"; + } + } + + public override string RuleSubType + { + get + { + return this.AgentType; + } + } + + public override String ToString() + { + return String.Format( + "ServiceEndpointDiscoveryRule: {0}/{1}/{2} {3} {4}", + this.Controller, + this.ApplicationName, + this.TierName, + this.AgentType, + this.EntryPointType); + } + } +} diff --git a/ReportObjects/ConfigurationAPM/ServiceEndpointEntryRule.cs b/ReportObjects/ConfigurationAPM/ServiceEndpointEntryRule.cs index a6cb47e..d36b728 100644 --- a/ReportObjects/ConfigurationAPM/ServiceEndpointEntryRule.cs +++ b/ReportObjects/ConfigurationAPM/ServiceEndpointEntryRule.cs @@ -9,27 +9,29 @@ public class ServiceEndpointEntryRule : ConfigurationEntityBase [FieldComparison(FieldComparisonType.ValueComparison)] public string EntryPointType { get; set; } [FieldComparison(FieldComparisonType.ValueComparison)] - public bool IsOverride { get; set; } + public int Version { get; set; } [FieldComparison(FieldComparisonType.ValueComparison)] - public bool IsMonitoringEnabled { get; set; } + public bool IsEnabled { get; set; } [FieldComparison(FieldComparisonType.ValueComparison)] - public string DiscoveryType { get; set; } + public bool IsExclusion { get; set; } [FieldComparison(FieldComparisonType.ValueComparison)] - public string NamingConfigType { get; set; } + public int Priority { get; set; } + + [FieldComparison(FieldComparisonType.JSONValueComparison)] + public string MatchConditions { get; set; } + [FieldComparison(FieldComparisonType.JSONValueComparison)] + public string Actions { get; set; } [FieldComparison(FieldComparisonType.ValueComparison)] public int NumDetectedSEPs { get; set; } [FieldComparison(FieldComparisonType.SemicolonMultiLineValueComparison)] public string DetectedSEPs { get; set; } - [FieldComparison(FieldComparisonType.XmlValueComparison)] - public string RuleRawValue { get; set; } - public override string EntityIdentifier { get { - return String.Format("{0}/{1}/{2}", this.EntryPointType, this.AgentType, this.TierName); + return String.Format("{0}/{1}/{2}/{3}", this.RuleName, this.EntryPointType, this.AgentType, this.TierName); } } diff --git a/ReportObjects/HealthCheck/HealthCheckRuleResult.cs b/ReportObjects/HealthCheck/HealthCheckRuleResult.cs new file mode 100644 index 0000000..1fccd80 --- /dev/null +++ b/ReportObjects/HealthCheck/HealthCheckRuleResult.cs @@ -0,0 +1,43 @@ +using System; + +namespace AppDynamics.Dexter.ReportObjects +{ + public class HealthCheckRuleResult + { + public string Controller { get; set; } + + public long ApplicationID { get; set; } + public string Application { get; set; } + + public string EntityType { get; set; } + public string EntityName { get; set; } + public long EntityID { get; set; } + + public string Category { get; set; } + public string Code { get; set; } + public string Name { get; set; } + public double Grade { get; set; } + public string Description { get; set; } + + public DateTime EvaluationTime { get; set; } + public string Version { get; set; } + + public string RuleLink { get; set; } + + public HealthCheckRuleResult Clone() + { + return (HealthCheckRuleResult)this.MemberwiseClone(); + } + + public override String ToString() + { + return String.Format( + "HealthCheckRuleResult: {0}/{1}({2}) {3}={4}", + this.Controller, + this.Application, + this.ApplicationID, + this.Name, + this.Grade); + } + } +} diff --git a/ReportObjects/HealthCheck/HealthCheckSettingMapping.cs b/ReportObjects/HealthCheck/HealthCheckSettingMapping.cs new file mode 100644 index 0000000..72b31e8 --- /dev/null +++ b/ReportObjects/HealthCheck/HealthCheckSettingMapping.cs @@ -0,0 +1,20 @@ +using System; + +namespace AppDynamics.Dexter.ReportObjects +{ + public class HealthCheckSettingMapping + { + public string Name { get; set; } + public string Value { get; set; } + public string DataType { get; set; } + + public override String ToString() + { + return String.Format( + "Name: {0}={1} ({2})", + this.Name, + this.Value, + this.DataType); + } + } +} diff --git a/ReportObjects/HealthCheck/Maps/HealthCheckRuleResultReportMap.cs b/ReportObjects/HealthCheck/Maps/HealthCheckRuleResultReportMap.cs new file mode 100644 index 0000000..bec916d --- /dev/null +++ b/ReportObjects/HealthCheck/Maps/HealthCheckRuleResultReportMap.cs @@ -0,0 +1,32 @@ +using AppDynamics.Dexter.ReportObjects; +using CsvHelper.Configuration; + +namespace AppDynamics.Dexter.ReportObjectMaps +{ + public class HealthCheckRuleResultReportMap : ClassMap + { + public HealthCheckRuleResultReportMap() + { + int i = 0; + Map(m => m.Controller).Index(i); i++; + Map(m => m.Application).Index(i); i++; + + Map(m => m.EntityType).Index(i); i++; + Map(m => m.EntityName).Index(i); i++; + + Map(m => m.Category).Index(i); i++; + Map(m => m.Code).Index(i); i++; + Map(m => m.Name).Index(i); i++; + Map(m => m.Grade).Index(i); i++; + Map(m => m.Description).Index(i); i++; + + Map(m => m.EvaluationTime).Index(i); i++; + Map(m => m.Version).Index(i); i++; + + Map(m => m.ApplicationID).Index(i); i++; + Map(m => m.EntityID).Index(i); i++; + + Map(m => m.RuleLink).Index(i); i++; + } + } +} \ No newline at end of file diff --git a/ReportObjects/HealthCheck/Maps/HealthCheckSettingMappingMap.cs b/ReportObjects/HealthCheck/Maps/HealthCheckSettingMappingMap.cs new file mode 100644 index 0000000..32bd156 --- /dev/null +++ b/ReportObjects/HealthCheck/Maps/HealthCheckSettingMappingMap.cs @@ -0,0 +1,16 @@ +using AppDynamics.Dexter.ReportObjects; +using CsvHelper.Configuration; + +namespace AppDynamics.Dexter.ReportObjectMaps +{ + public class HealthCheckSettingMappingMap : ClassMap + { + public HealthCheckSettingMappingMap() + { + int i = 0; + Map(m => m.Name).Index(i); i++; + Map(m => m.Value).Index(i); i++; + Map(m => m.DataType).Index(i); i++; + } + } +} diff --git a/global.json b/global.json index bab6623..67fa600 100644 --- a/global.json +++ b/global.json @@ -1,5 +1,5 @@ { "sdk": { - "version": "3.0.100" + "version": "3.1.100" } } \ No newline at end of file