/// <summary> /// Constructor /// </summary> /// <param name="azureMonitorClient">Client to communicate with Azure Monitor</param> /// <param name="metricSinkWriter">Writer to send metrics to all configured sinks</param> /// <param name="azureScrapingPrometheusMetricsCollector">Collector to send metrics related to the runtime</param> /// <param name="logger">General logger</param> public ScraperConfiguration(AzureMonitorClient azureMonitorClient, MetricSinkWriter metricSinkWriter, IAzureScrapingPrometheusMetricsCollector azureScrapingPrometheusMetricsCollector, ILogger logger) { Guard.NotNull(azureMonitorClient, nameof(azureMonitorClient)); Guard.NotNull(logger, nameof(logger)); Guard.NotNull(metricSinkWriter, nameof(metricSinkWriter)); Guard.NotNull(azureScrapingPrometheusMetricsCollector, nameof(azureScrapingPrometheusMetricsCollector)); AzureMonitorClient = azureMonitorClient; Logger = logger; MetricSinkWriter = metricSinkWriter; AzureScrapingPrometheusMetricsCollector = azureScrapingPrometheusMetricsCollector; }
private static void ScheduleResourcesScraping(MetricsDeclaration metricsDeclaration, MetricSinkWriter metricSinkWriter, AzureMonitorClientFactory azureMonitorClientFactory, IAzureScrapingPrometheusMetricsCollector azureScrapingPrometheusMetricsCollector, IMemoryCache resourceMetricDefinitionMemoryCache, IScrapingMutex scrapingTaskMutex, IConfiguration configuration, IOptions <AzureMonitorIntegrationConfiguration> azureMonitorIntegrationConfiguration, IOptions <AzureMonitorLoggingConfiguration> azureMonitorLoggingConfiguration, ILoggerFactory loggerFactory, ILogger <Startup> logger, IServiceCollection services) { var jobName = GenerateResourceScrapingJobName(metricsDeclaration, logger); services.AddScheduler(builder => { builder.AddJob(jobServices => new ResourcesScrapingJob(jobName, metricsDeclaration, jobServices.GetService <ResourceDiscoveryRepository>(), metricSinkWriter, jobServices.GetService <MetricScraperFactory>(), azureMonitorClientFactory, azureScrapingPrometheusMetricsCollector, resourceMetricDefinitionMemoryCache, scrapingTaskMutex, configuration, azureMonitorIntegrationConfiguration, azureMonitorLoggingConfiguration, loggerFactory, jobServices.GetService <ILogger <ResourcesScrapingJob> >()), schedulerOptions => { schedulerOptions.CronSchedule = metricsDeclaration.Metrics[0].Scraping.Schedule; schedulerOptions.RunImmediately = true; }, jobName: jobName); builder.AddUnobservedTaskExceptionHandler(s => { return ((_, exceptionEventArgs) => { var exceptionLogger = s.GetService <ILogger <BackgroundJobMonitor> >(); BackgroundJobMonitor.HandleException(jobName, exceptionEventArgs, exceptionLogger); }); }); }); logger.LogInformation("Scheduled scraping job {JobName}.", jobName); }
/// <summary> /// Create a metrics scraping job for one or more resources, either enumerated specifically or /// identified via resource definition groups. All metrics included are expected to have /// the same scraping schedule. /// </summary> /// <param name="jobName">name of scheduled job</param> /// <param name="metricsDeclaration">declaration of which metrics to collect from which resources</param> /// <param name="resourceDiscoveryRepository">repository source for discovering resources via criteria</param> /// <param name="metricSinkWriter">destination for metric reporting output</param> /// <param name="metricScraperFactory">means of obtaining a metrics scraper for a particular type of resource</param> /// <param name="azureMonitorClientFactory">means of obtaining a Azure Monitor client</param> /// <param name="azureScrapingPrometheusMetricsCollector">metrics collector to write metrics to Prometheus</param> /// <param name="resourceMetricDefinitionMemoryCache">cache of metric definitions by resource ID</param> /// <param name="scrapingTaskMutex">semaphore used to limit concurrency of tasks if configured, or null for no limiting</param> /// <param name="configuration">Promitor configuration</param> /// <param name="azureMonitorIntegrationConfiguration">options for Azure Monitor integration</param> /// <param name="azureMonitorLoggingConfiguration">options for Azure Monitor logging</param> /// <param name="loggerFactory">means to obtain a logger</param> /// <param name="logger">logger to use for scraping detail</param> public ResourcesScrapingJob(string jobName, MetricsDeclaration metricsDeclaration, ResourceDiscoveryRepository resourceDiscoveryRepository, MetricSinkWriter metricSinkWriter, MetricScraperFactory metricScraperFactory, AzureMonitorClientFactory azureMonitorClientFactory, IAzureScrapingPrometheusMetricsCollector azureScrapingPrometheusMetricsCollector, IMemoryCache resourceMetricDefinitionMemoryCache, IScrapingMutex scrapingTaskMutex, IConfiguration configuration, IOptions <AzureMonitorIntegrationConfiguration> azureMonitorIntegrationConfiguration, IOptions <AzureMonitorLoggingConfiguration> azureMonitorLoggingConfiguration, ILoggerFactory loggerFactory, ILogger <ResourcesScrapingJob> logger) : base(jobName, logger) { Guard.NotNullOrWhitespace(jobName, nameof(jobName)); Guard.NotNull(metricsDeclaration, nameof(metricsDeclaration)); Guard.NotNull(metricsDeclaration.AzureMetadata, $"{nameof(metricsDeclaration)}.{nameof(metricsDeclaration.AzureMetadata)}"); Guard.NotNull(metricsDeclaration.Metrics, $"{nameof(metricsDeclaration)}.{nameof(metricsDeclaration.Metrics)}"); Guard.NotNull(resourceDiscoveryRepository, nameof(resourceDiscoveryRepository)); Guard.NotNull(metricSinkWriter, nameof(metricSinkWriter)); Guard.NotNull(metricScraperFactory, nameof(metricScraperFactory)); Guard.NotNull(azureMonitorClientFactory, nameof(azureMonitorClientFactory)); Guard.NotNull(azureScrapingPrometheusMetricsCollector, nameof(azureScrapingPrometheusMetricsCollector)); Guard.NotNull(resourceMetricDefinitionMemoryCache, nameof(resourceMetricDefinitionMemoryCache)); Guard.NotNull(configuration, nameof(configuration)); Guard.NotNull(azureMonitorIntegrationConfiguration, nameof(azureMonitorIntegrationConfiguration)); Guard.NotNull(azureMonitorLoggingConfiguration, nameof(azureMonitorLoggingConfiguration)); Guard.NotNull(loggerFactory, nameof(loggerFactory)); // all metrics must have the same scraping schedule or it is not possible for them to share the same job VerifyAllMetricsHaveSameScrapingSchedule(metricsDeclaration); _metricsDeclaration = metricsDeclaration; _resourceDiscoveryRepository = resourceDiscoveryRepository; _metricSinkWriter = metricSinkWriter; _metricScraperFactory = metricScraperFactory; _azureMonitorClientFactory = azureMonitorClientFactory; _azureScrapingPrometheusMetricsCollector = azureScrapingPrometheusMetricsCollector; _resourceMetricDefinitionMemoryCache = resourceMetricDefinitionMemoryCache; _scrapingTaskMutex = scrapingTaskMutex; _configuration = configuration; _azureMonitorIntegrationConfiguration = azureMonitorIntegrationConfiguration; _azureMonitorLoggingConfiguration = azureMonitorLoggingConfiguration; _loggerFactory = loggerFactory; }
/// <summary> /// Constructor /// </summary> /// <param name="tenantId">Id of the tenant that is being interacted with via Azure Resource Manager</param> /// <param name="subscriptionId">Id of the subscription that is being interacted with via Azure Resource Manager</param> /// <param name="azureAuthenticationInfo">Information regarding authentication with Microsoft Azure</param> /// <param name="metricSinkWriter">Metrics writer to all sinks</param> /// <param name="azureScrapingPrometheusMetricsCollector">Metrics collector to write metrics to Prometheus</param> /// <param name="logger">Logger to write telemetry to</param> public AzureResourceManagerThrottlingRequestHandler(string tenantId, string subscriptionId, AzureAuthenticationInfo azureAuthenticationInfo, MetricSinkWriter metricSinkWriter, IAzureScrapingPrometheusMetricsCollector azureScrapingPrometheusMetricsCollector, ILogger logger) : base(azureScrapingPrometheusMetricsCollector, logger) { Guard.NotNullOrWhitespace(tenantId, nameof(tenantId)); Guard.NotNullOrWhitespace(subscriptionId, nameof(subscriptionId)); Guard.NotNull(metricSinkWriter, nameof(metricSinkWriter)); Guard.NotNull(azureScrapingPrometheusMetricsCollector, nameof(azureScrapingPrometheusMetricsCollector)); Guard.NotNull(azureAuthenticationInfo, nameof(azureAuthenticationInfo)); _metricSinkWriter = metricSinkWriter; _azureScrapingPrometheusMetricsCollector = azureScrapingPrometheusMetricsCollector; var id = DetermineApplicationId(azureAuthenticationInfo); _metricLabels = new Dictionary <string, string> { { "tenant_id", tenantId }, { "subscription_id", subscriptionId }, { "app_id", id }, }; }
private static AzureMonitorClient CreateNewAzureMonitorClient(AzureEnvironment cloud, string tenantId, string subscriptionId, MetricSinkWriter metricSinkWriter, IAzureScrapingPrometheusMetricsCollector azureScrapingPrometheusMetricsCollector, IMemoryCache resourceMetricDefinitionMemoryCache, IConfiguration configuration, IOptions <AzureMonitorIntegrationConfiguration> azureMonitorIntegrationConfiguration, IOptions <AzureMonitorLoggingConfiguration> azureMonitorLoggingConfiguration, ILoggerFactory loggerFactory) { var azureCredentials = AzureAuthenticationFactory.GetConfiguredAzureAuthentication(configuration); var azureMonitorClient = new AzureMonitorClient(cloud, tenantId, subscriptionId, azureCredentials, metricSinkWriter, azureScrapingPrometheusMetricsCollector, resourceMetricDefinitionMemoryCache, loggerFactory, azureMonitorIntegrationConfiguration, azureMonitorLoggingConfiguration); return(azureMonitorClient); }
/// <summary> /// Provides an Azure Monitor client /// </summary> /// <param name="cloud">Name of the Azure cloud to interact with</param> /// <param name="tenantId">Id of the tenant that owns the Azure subscription</param> /// <param name="subscriptionId">Id of the Azure subscription</param> /// <param name="metricSinkWriter">Writer to send metrics to all configured sinks</param> /// <param name="azureScrapingPrometheusMetricsCollector">Metrics collector to write metrics to Prometheus</param> /// <param name="resourceMetricDefinitionMemoryCache">Memory cache to store items in</param> /// <param name="configuration">Configuration of Promitor</param> /// <param name="azureMonitorIntegrationConfiguration">Options for Azure Monitor integration</param> /// <param name="azureMonitorLoggingConfiguration">Options for Azure Monitor logging</param> /// <param name="loggerFactory">Factory to create loggers with</param> public AzureMonitorClient CreateIfNotExists(AzureEnvironment cloud, string tenantId, string subscriptionId, MetricSinkWriter metricSinkWriter, IAzureScrapingPrometheusMetricsCollector azureScrapingPrometheusMetricsCollector, IMemoryCache resourceMetricDefinitionMemoryCache, IConfiguration configuration, IOptions <AzureMonitorIntegrationConfiguration> azureMonitorIntegrationConfiguration, IOptions <AzureMonitorLoggingConfiguration> azureMonitorLoggingConfiguration, ILoggerFactory loggerFactory) { if (_azureMonitorClients.ContainsKey(subscriptionId)) { return(_azureMonitorClients[subscriptionId]); } var azureMonitorClient = CreateNewAzureMonitorClient(cloud, tenantId, subscriptionId, metricSinkWriter, azureScrapingPrometheusMetricsCollector, resourceMetricDefinitionMemoryCache, configuration, azureMonitorIntegrationConfiguration, azureMonitorLoggingConfiguration, loggerFactory); _azureMonitorClients.TryAdd(subscriptionId, azureMonitorClient); return(azureMonitorClient); }
/// <summary> /// Creates a scraper that is capable of scraping a specific resource type /// </summary> /// <param name="metricDefinitionResourceType">Resource type to scrape</param> /// <param name="metricSinkWriter">Writer to send metrics to all sinks</param> /// <param name="azureScrapingPrometheusMetricsCollector">Collector to send metrics related to the runtime</param> /// <param name="azureMonitorClient">Client to interact with Azure Monitor</param> public IScraper <IAzureResourceDefinition> CreateScraper(ResourceType metricDefinitionResourceType, MetricSinkWriter metricSinkWriter, IAzureScrapingPrometheusMetricsCollector azureScrapingPrometheusMetricsCollector, AzureMonitorClient azureMonitorClient) { var scraperConfiguration = new ScraperConfiguration(azureMonitorClient, metricSinkWriter, azureScrapingPrometheusMetricsCollector, _logger); switch (metricDefinitionResourceType) { case ResourceType.ApiManagement: return(new ApiManagementScraper(scraperConfiguration)); case ResourceType.ApplicationGateway: return(new ApplicationGatewayScraper(scraperConfiguration)); case ResourceType.ApplicationInsights: return(new ApplicationInsightsScraper(scraperConfiguration)); case ResourceType.AppPlan: return(new AppPlanScraper(scraperConfiguration)); case ResourceType.AutomationAccount: return(new AutomationAccountScraper(scraperConfiguration)); case ResourceType.BlobStorage: return(new BlobStorageScraper(scraperConfiguration)); case ResourceType.Cdn: return(new CdnScraper(scraperConfiguration)); case ResourceType.ContainerInstance: return(new ContainerInstanceScraper(scraperConfiguration)); case ResourceType.ContainerRegistry: return(new ContainerRegistryScraper(scraperConfiguration)); case ResourceType.CosmosDb: return(new CosmosDbScraper(scraperConfiguration)); case ResourceType.DataFactory: return(new DataFactoryScraper(scraperConfiguration)); case ResourceType.DataShare: return(new DataShareScraper(scraperConfiguration)); case ResourceType.DeviceProvisioningService: return(new DeviceProvisioningServiceScraper(scraperConfiguration)); case ResourceType.EventHubs: return(new EventHubsScraper(scraperConfiguration)); case ResourceType.ExpressRouteCircuit: return(new ExpressRouteCircuitScraper(scraperConfiguration)); case ResourceType.FileStorage: return(new FileStorageScraper(scraperConfiguration)); case ResourceType.FrontDoor: return(new FrontDoorScraper(scraperConfiguration)); case ResourceType.FunctionApp: return(new FunctionAppScraper(scraperConfiguration)); case ResourceType.Generic: return(new GenericScraper(scraperConfiguration)); case ResourceType.IoTHub: return(new IoTHubScraper(scraperConfiguration)); case ResourceType.KeyVault: return(new KeyVaultScraper(scraperConfiguration)); case ResourceType.KubernetesService: return(new KubernetesServiceScraper(scraperConfiguration)); case ResourceType.LoadBalancer: return(new LoadBalancerScraper(scraperConfiguration)); case ResourceType.LogicApp: return(new LogicAppScraper(scraperConfiguration)); case ResourceType.MariaDb: return(new MariaDbScraper(scraperConfiguration)); case ResourceType.MonitorAutoscale: return(new MonitorAutoscaleScraper(scraperConfiguration)); case ResourceType.MySql: return(new MySqlScraper(scraperConfiguration)); case ResourceType.NetworkGateway: return(new NetworkGatewayScraper(scraperConfiguration)); case ResourceType.NetworkInterface: return(new NetworkInterfaceScraper(scraperConfiguration)); case ResourceType.PostgreSql: return(new PostgreSqlScraper(scraperConfiguration)); case ResourceType.RedisCache: return(new RedisCacheScraper(scraperConfiguration)); case ResourceType.RedisEnterpriseCache: return(new RedisEnterpriseCacheScraper(scraperConfiguration)); case ResourceType.ServiceBusNamespace: return(new ServiceBusNamespaceScraper(scraperConfiguration)); case ResourceType.SqlDatabase: return(new SqlDatabaseScraper(scraperConfiguration)); case ResourceType.SqlElasticPool: return(new SqlElasticPoolScraper(scraperConfiguration)); case ResourceType.SqlManagedInstance: return(new SqlManagedInstanceScraper(scraperConfiguration)); case ResourceType.SqlServer: return(new SqlServerScraper(scraperConfiguration)); case ResourceType.StorageAccount: return(new StorageAccountScraper(scraperConfiguration)); case ResourceType.StorageQueue: return(new StorageQueueScraper(scraperConfiguration)); case ResourceType.SynapseApacheSparkPool: return(new SynapseApacheSparkPoolScraper(scraperConfiguration)); case ResourceType.SynapseSqlPool: return(new SynapseSqlPoolScraper(scraperConfiguration)); case ResourceType.SynapseWorkspace: return(new SynapseWorkspaceScraper(scraperConfiguration)); case ResourceType.VirtualMachine: return(new VirtualMachineScraper(scraperConfiguration)); case ResourceType.VirtualMachineScaleSet: return(new VirtualMachineScaleSetScraper(scraperConfiguration)); case ResourceType.VirtualNetwork: return(new VirtualNetworkScraper(scraperConfiguration)); case ResourceType.WebApp: return(new WebAppScraper(scraperConfiguration)); default: throw new ArgumentOutOfRangeException(nameof(metricDefinitionResourceType), metricDefinitionResourceType, "Matching scraper not found"); } }
/// <summary> /// Constructor /// </summary> /// <param name="azureCloud">Name of the Azure cloud to interact with</param> /// <param name="tenantId">Id of the tenant that owns the Azure subscription</param> /// <param name="subscriptionId">Id of the Azure subscription</param> /// <param name="azureAuthenticationInfo">Information regarding authentication with Microsoft Azure</param> /// <param name="metricSinkWriter">Writer to send metrics to all configured sinks</param> /// <param name="azureScrapingPrometheusMetricsCollector">Metrics collector to write metrics to Prometheus</param> /// <param name="resourceMetricDefinitionMemoryCache">Memory cache to store items in for performance optimizations</param> /// <param name="loggerFactory">Factory to create loggers with</param> /// <param name="azureMonitorIntegrationConfiguration">Options for Azure Monitor logging</param> /// <param name="azureMonitorLoggingConfiguration">Options for Azure Monitor integration</param> public AzureMonitorClient(AzureEnvironment azureCloud, string tenantId, string subscriptionId, AzureAuthenticationInfo azureAuthenticationInfo, MetricSinkWriter metricSinkWriter, IAzureScrapingPrometheusMetricsCollector azureScrapingPrometheusMetricsCollector, IMemoryCache resourceMetricDefinitionMemoryCache, ILoggerFactory loggerFactory, IOptions <AzureMonitorIntegrationConfiguration> azureMonitorIntegrationConfiguration, IOptions <AzureMonitorLoggingConfiguration> azureMonitorLoggingConfiguration) { Guard.NotNullOrWhitespace(tenantId, nameof(tenantId)); Guard.NotNullOrWhitespace(subscriptionId, nameof(subscriptionId)); Guard.NotNull(azureAuthenticationInfo, nameof(azureAuthenticationInfo)); Guard.NotNull(azureMonitorIntegrationConfiguration, nameof(azureMonitorIntegrationConfiguration)); Guard.NotNull(azureMonitorLoggingConfiguration, nameof(azureMonitorLoggingConfiguration)); Guard.NotNull(resourceMetricDefinitionMemoryCache, nameof(resourceMetricDefinitionMemoryCache)); _resourceMetricDefinitionMemoryCache = resourceMetricDefinitionMemoryCache; _azureMonitorIntegrationConfiguration = azureMonitorIntegrationConfiguration; _logger = loggerFactory.CreateLogger <AzureMonitorClient>(); _authenticatedAzureSubscription = CreateAzureClient(azureCloud, tenantId, subscriptionId, azureAuthenticationInfo, loggerFactory, metricSinkWriter, azureScrapingPrometheusMetricsCollector, azureMonitorLoggingConfiguration); }
private IAzure CreateAzureClient(AzureEnvironment azureCloud, string tenantId, string subscriptionId, AzureAuthenticationInfo azureAuthenticationInfo, ILoggerFactory loggerFactory, MetricSinkWriter metricSinkWriter, IAzureScrapingPrometheusMetricsCollector azureScrapingPrometheusMetricsCollector, IOptions <AzureMonitorLoggingConfiguration> azureMonitorLoggingConfiguration) { var credentials = AzureAuthenticationFactory.CreateAzureAuthentication(azureCloud, tenantId, azureAuthenticationInfo, _azureCredentialsFactory); var throttlingLogger = loggerFactory.CreateLogger <AzureResourceManagerThrottlingRequestHandler>(); var monitorHandler = new AzureResourceManagerThrottlingRequestHandler(tenantId, subscriptionId, azureAuthenticationInfo, metricSinkWriter, azureScrapingPrometheusMetricsCollector, throttlingLogger); var azureClientConfiguration = Microsoft.Azure.Management.Fluent.Azure.Configure() .WithDelegatingHandler(monitorHandler); var azureMonitorLogging = azureMonitorLoggingConfiguration.Value; if (azureMonitorLogging.IsEnabled) { var integrationLogger = loggerFactory.CreateLogger <AzureMonitorIntegrationLogger>(); ServiceClientTracing.AddTracingInterceptor(new AzureMonitorIntegrationLogger(integrationLogger)); ServiceClientTracing.IsEnabled = true; azureClientConfiguration = azureClientConfiguration.WithDelegatingHandler(new HttpLoggingDelegatingHandler()) .WithLogLevel(azureMonitorLogging.InformationLevel); } return(azureClientConfiguration .Authenticate(credentials) .WithSubscription(subscriptionId)); }