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; }