From 13ea14aaa1f9f6dd792c39da64bee2ec52d7d9ec Mon Sep 17 00:00:00 2001 From: aaronweissler <46028218+aaronweissler@users.noreply.github.com> Date: Fri, 5 Aug 2022 15:59:18 +0200 Subject: [PATCH 01/53] WIP Use multiple MetricDimensions --- .../AzureMonitorScraper.cs | 9 +++--- .../Model/AzureMetricConfiguration.cs | 11 +++++++- .../ResourceTypes/AzureMessagingScraper.cs | 6 ++-- .../ResourceTypes/DataFactoryScraper.cs | 6 ++-- .../ResourceTypes/DataShareScraper.cs | 6 ++-- .../AzureMonitorClient.cs | 28 +++++++++++-------- 6 files changed, 41 insertions(+), 25 deletions(-) diff --git a/src/Promitor.Core.Scraping/AzureMonitorScraper.cs b/src/Promitor.Core.Scraping/AzureMonitorScraper.cs index a7ff55496..2578cda9c 100644 --- a/src/Promitor.Core.Scraping/AzureMonitorScraper.cs +++ b/src/Promitor.Core.Scraping/AzureMonitorScraper.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Threading.Tasks; using GuardNet; using Microsoft.Azure.Management.Monitor.Fluent.Models; @@ -45,7 +46,7 @@ protected override async Task ScrapeResourceAsync(string subscript var metricLimit = DetermineMetricLimit(scrapeDefinition); // Determine the metric dimension to use, if any - var dimensionName = DetermineMetricDimension(metricName, resourceDefinition, scrapeDefinition.AzureMetricConfiguration?.Dimension); + List dimensionName = DetermineMetricDimensions(metricName, resourceDefinition, scrapeDefinition.AzureMetricConfiguration?.Dimensions); List measuredMetrics = new List(); try @@ -107,10 +108,10 @@ protected virtual string DetermineMetricFilter(string metricName, TResourceDefin /// /// Name of the metric being queried /// Contains the resource cast to the specific resource type. - /// Provides information concerning the configured metric dimension. - protected virtual string DetermineMetricDimension(string metricName, TResourceDefinition resourceDefinition, MetricDimension dimension) + /// Provides information concerning the configured metric dimensions. + protected virtual List DetermineMetricDimensions(string metricName, TResourceDefinition resourceDefinition, List dimensions) { - return dimension?.Name; + return dimensions?.Select(dimension => dimension.Name).ToList(); } /// diff --git a/src/Promitor.Core.Scraping/Configuration/Model/AzureMetricConfiguration.cs b/src/Promitor.Core.Scraping/Configuration/Model/AzureMetricConfiguration.cs index 577db9a8d..0e61d2cbf 100644 --- a/src/Promitor.Core.Scraping/Configuration/Model/AzureMetricConfiguration.cs +++ b/src/Promitor.Core.Scraping/Configuration/Model/AzureMetricConfiguration.cs @@ -1,4 +1,7 @@ -namespace Promitor.Core.Scraping.Configuration.Model +using System; +using System.Collections.Generic; + +namespace Promitor.Core.Scraping.Configuration.Model { public class AzureMetricConfiguration { @@ -15,8 +18,14 @@ public class AzureMetricConfiguration /// /// Information about the dimension of an Azure Monitor metric /// + [Obsolete("Dimension is deprecated, use Dimensions instead.")] public MetricDimension Dimension { get; set; } + /// + /// Information about the dimension of an Azure Monitor metric + /// + public List Dimensions { get; set; } + /// /// Configuration on how to aggregate the metric /// diff --git a/src/Promitor.Core.Scraping/ResourceTypes/AzureMessagingScraper.cs b/src/Promitor.Core.Scraping/ResourceTypes/AzureMessagingScraper.cs index 80db3ad01..ad150c7a5 100644 --- a/src/Promitor.Core.Scraping/ResourceTypes/AzureMessagingScraper.cs +++ b/src/Promitor.Core.Scraping/ResourceTypes/AzureMessagingScraper.cs @@ -40,16 +40,16 @@ protected override Dictionary DetermineMetricLabels(TResourceDef return metricLabels; } - protected override string DetermineMetricDimension(string metricName, TResourceDefinition resourceDefinition, MetricDimension dimension) + protected override List DetermineMetricDimensions(string metricName, TResourceDefinition resourceDefinition, List dimensions) { if (IsEntityDeclared(resourceDefinition)) { - return base.DetermineMetricDimension(metricName, resourceDefinition, dimension); + return base.DetermineMetricDimensions(metricName, resourceDefinition, dimensions); } Logger.LogTrace("Using 'EntityName' dimension since no topic was configured."); - return "EntityName"; + return new List { "EntityName" }; } protected override string DetermineMetricFilter(string metricName, TResourceDefinition resourceDefinition) diff --git a/src/Promitor.Core.Scraping/ResourceTypes/DataFactoryScraper.cs b/src/Promitor.Core.Scraping/ResourceTypes/DataFactoryScraper.cs index a684b5058..ee2ec8d90 100644 --- a/src/Promitor.Core.Scraping/ResourceTypes/DataFactoryScraper.cs +++ b/src/Promitor.Core.Scraping/ResourceTypes/DataFactoryScraper.cs @@ -48,17 +48,17 @@ protected override Dictionary DetermineMetricLabels(DataFactoryR return metricLabels; } - protected override string DetermineMetricDimension(string metricName, DataFactoryResourceDefinition resourceDefinition, MetricDimension dimension) + protected override List DetermineMetricDimensions(string metricName, DataFactoryResourceDefinition resourceDefinition, List dimensions) { if (IsPipelineNameConfigured(resourceDefinition)) { - return base.DetermineMetricDimension(metricName, resourceDefinition, dimension); + return base.DetermineMetricDimensions(metricName, resourceDefinition, dimensions); } var dimensionName = GetMetricFilterFieldName(metricName); Logger.LogTrace($"Using '{dimensionName}' dimension since no pipeline name was configured."); - return dimensionName; + return new List { dimensionName }; } private static bool IsPipelineNameConfigured(DataFactoryResourceDefinition resourceDefinition) diff --git a/src/Promitor.Core.Scraping/ResourceTypes/DataShareScraper.cs b/src/Promitor.Core.Scraping/ResourceTypes/DataShareScraper.cs index 5ac73c34b..287122527 100644 --- a/src/Promitor.Core.Scraping/ResourceTypes/DataShareScraper.cs +++ b/src/Promitor.Core.Scraping/ResourceTypes/DataShareScraper.cs @@ -38,17 +38,17 @@ protected override string DetermineMetricFilter(string metricName, DataShareReso return $"{fieldName} eq '{entityName}'"; } - protected override string DetermineMetricDimension(string metricName, DataShareResourceDefinition resourceDefinition, MetricDimension dimension) + protected override List DetermineMetricDimensions(string metricName, DataShareResourceDefinition resourceDefinition, List dimensions) { if (IsShareNameConfigured(resourceDefinition)) { - return base.DetermineMetricDimension(metricName, resourceDefinition, dimension); + return base.DetermineMetricDimensions(metricName, resourceDefinition, dimensions); } var dimensionName = GetMetricFilterFieldName(metricName); Logger.LogTrace($"Using '{dimensionName}' dimension since no share name was configured."); - return dimensionName; + return new List { dimensionName }; } protected override List EnrichMeasuredMetrics(DataShareResourceDefinition resourceDefinition, string dimensionName, List metricValues) diff --git a/src/Promitor.Integrations.AzureMonitor/AzureMonitorClient.cs b/src/Promitor.Integrations.AzureMonitor/AzureMonitorClient.cs index 0e3a143a5..1e7c66116 100644 --- a/src/Promitor.Integrations.AzureMonitor/AzureMonitorClient.cs +++ b/src/Promitor.Integrations.AzureMonitor/AzureMonitorClient.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Text; using System.Threading.Tasks; using Microsoft.Azure.Management.Fluent; using Microsoft.Azure.Management.Monitor.Fluent; @@ -66,14 +67,14 @@ public AzureMonitorClient(AzureEnvironment azureCloud, string tenantId, string s /// Queries Azure Monitor to get the latest value for a specific metric /// /// Name of the metric - /// Name of dimension to split metric on + /// List of names of dimensions to split metric on /// Aggregation for the metric to use /// Interval that is used to aggregate metrics /// Id of the resource to query /// Optional filter to filter out metrics /// Limit of resources to query metrics for when using filtering /// Latest representation of the metric - public async Task> QueryMetricAsync(string metricName, string metricDimension, AggregationType aggregationType, TimeSpan aggregationInterval, + public async Task> QueryMetricAsync(string metricName, List metricDimensions, AggregationType aggregationType, TimeSpan aggregationInterval, string resourceId, string metricFilter = null, int? metricLimit = null) { Guard.NotNullOrWhitespace(metricName, nameof(metricName)); @@ -91,10 +92,10 @@ public async Task> QueryMetricAsync(string metricName, stri var closestAggregationInterval = DetermineAggregationInterval(metricName, aggregationInterval, metricDefinition.MetricAvailabilities); // Get the most recent metric - var relevantMetric = await GetRelevantMetric(metricName, aggregationType, closestAggregationInterval, metricFilter, metricDimension, metricDefinition, metricLimit, startQueryingTime); + var relevantMetric = await GetRelevantMetric(metricName, aggregationType, closestAggregationInterval, metricFilter, metricDimensions, metricDefinition, metricLimit, startQueryingTime); if (relevantMetric.Timeseries.Count < 1) { - throw new MetricInformationNotFoundException(metricName, "No time series was found", metricDimension); + throw new MetricInformationNotFoundException(metricName, "No time series was found", metricDimensions); } var measuredMetrics = new List(); @@ -109,7 +110,7 @@ public async Task> QueryMetricAsync(string metricName, stri // Get the metric value according to the requested aggregation type var requestedMetricAggregate = InterpretMetricValue(aggregationType, mostRecentMetricValue); - var measuredMetric = string.IsNullOrWhiteSpace(metricDimension) ? MeasuredMetric.CreateWithoutDimension(requestedMetricAggregate) : MeasuredMetric.CreateForDimension(requestedMetricAggregate, metricDimension, timeseries); + var measuredMetric = string.IsNullOrWhiteSpace(metricDimensions) ? MeasuredMetric.CreateWithoutDimension(requestedMetricAggregate) : MeasuredMetric.CreateForDimension(requestedMetricAggregate, metricDimensions, timeseries); measuredMetrics.Add(measuredMetric); } @@ -171,9 +172,9 @@ private static TimeSpan GetClosestAggregationInterval(TimeSpan requestedAggregat } private async Task GetRelevantMetric(string metricName, AggregationType metricAggregation, TimeSpan metricInterval, - string metricFilter, string metricDimension, IMetricDefinition metricDefinition, int? metricLimit, DateTime recordDateTime) + string metricFilter, List metricDimensions, IMetricDefinition metricDefinition, int? metricLimit, DateTime recordDateTime) { - var metricQuery = CreateMetricsQuery(metricAggregation, metricInterval, metricFilter, metricDimension, metricLimit, metricDefinition, recordDateTime); + var metricQuery = CreateMetricsQuery(metricAggregation, metricInterval, metricFilter, metricDimensions, metricLimit, metricDefinition, recordDateTime); var metrics = await metricQuery.ExecuteAsync(); // We already filtered this out so only expect to have one @@ -220,8 +221,8 @@ private MetricValue GetMostRecentMetricValue(string metricName, TimeSeriesElemen throw new Exception($"Unable to determine the metrics value for aggregator '{metricAggregation}'"); } } - - private IWithMetricsQueryExecute CreateMetricsQuery(AggregationType metricAggregation, TimeSpan metricsInterval, string metricFilter, string metricDimension, + + private IWithMetricsQueryExecute CreateMetricsQuery(AggregationType metricAggregation, TimeSpan metricsInterval, string metricFilter, List metricDimensions, int? metricLimit, IMetricDefinition metricDefinition, DateTime recordDateTime) { var historyStartingFromInHours = _azureMonitorIntegrationConfiguration.Value.History.StartingFromInHours; @@ -239,9 +240,14 @@ private IWithMetricsQueryExecute CreateMetricsQuery(AggregationType metricAggreg metricQuery.SelectTop(queryLimit); } - if (string.IsNullOrWhiteSpace(metricDimension) == false) + metricDimensions.RemoveAll(string.IsNullOrWhiteSpace); + metricDimensions. + + string metricDimensionsFilter = + + if (string.IsNullOrWhiteSpace(metricDimensions) == false) { - metricQuery.WithOdataFilter($"{metricDimension} eq '*'"); + metricQuery.WithOdataFilter($"{metricDimensions} eq '*'"); metricQuery.SelectTop(queryLimit); } From fdb5590b24219f7bdc14124c00e2f23f00daff29 Mon Sep 17 00:00:00 2001 From: Patrick Eichhorn Date: Fri, 12 Aug 2022 10:43:58 +0200 Subject: [PATCH 02/53] WIP use multiple metric dimensions --- .../AzureMonitorScraper.cs | 16 +++---- .../ResourceTypes/AzureMessagingScraper.cs | 6 +-- .../ResourceTypes/DataShareScraper.cs | 13 ++++-- src/Promitor.Core.Scraping/Scraper.cs | 2 +- src/Promitor.Core/Metrics/MeasuredMetric.cs | 42 +++++++++++-------- .../AzureMonitorClient.cs | 14 +++---- .../MetricInformationNotFoundException.cs | 9 ++-- .../PrometheusScrapingEndpointMetricSink.cs | 5 ++- ...ometheusScrapingEndpointMetricSinkTests.cs | 4 +- 9 files changed, 61 insertions(+), 50 deletions(-) diff --git a/src/Promitor.Core.Scraping/AzureMonitorScraper.cs b/src/Promitor.Core.Scraping/AzureMonitorScraper.cs index 2578cda9c..97c0cca07 100644 --- a/src/Promitor.Core.Scraping/AzureMonitorScraper.cs +++ b/src/Promitor.Core.Scraping/AzureMonitorScraper.cs @@ -46,19 +46,19 @@ protected override async Task ScrapeResourceAsync(string subscript var metricLimit = DetermineMetricLimit(scrapeDefinition); // Determine the metric dimension to use, if any - List dimensionName = DetermineMetricDimensions(metricName, resourceDefinition, scrapeDefinition.AzureMetricConfiguration?.Dimensions); + List dimensionNames = DetermineMetricDimensions(metricName, resourceDefinition, scrapeDefinition.AzureMetricConfiguration?.Dimensions); List measuredMetrics = new List(); try { // Query Azure Monitor for metrics - measuredMetrics = await AzureMonitorClient.QueryMetricAsync(metricName, dimensionName, aggregationType, aggregationInterval, resourceUri, metricFilter, metricLimit); + measuredMetrics = await AzureMonitorClient.QueryMetricAsync(metricName, dimensionNames, aggregationType, aggregationInterval, resourceUri, metricFilter, metricLimit); } catch (MetricInformationNotFoundException metricsNotFoundException) { - Logger.LogWarning("No metric information found for metric {MetricName} with dimension {MetricDimension}. Details: {Details}", metricsNotFoundException.Name, metricsNotFoundException.Dimension, metricsNotFoundException.Details); + Logger.LogWarning("No metric information found for metric {MetricName} with dimensions {MetricDimensions}. Details: {Details}", metricsNotFoundException.Name, metricsNotFoundException.Dimensions, metricsNotFoundException.Details); - var measuredMetric = string.IsNullOrWhiteSpace(dimensionName) ? MeasuredMetric.CreateWithoutDimension(null) : MeasuredMetric.CreateForDimension(null, dimensionName, "unknown"); + var measuredMetric = dimensionNames.Any() ? MeasuredMetric.CreateForDimension((double?)null, dimensionNames, Enumerable.Repeat("unknown",dimensionNames.Count).ToList()) : MeasuredMetric.CreateWithoutDimension(null); measuredMetrics.Add(measuredMetric); } @@ -66,7 +66,7 @@ protected override async Task ScrapeResourceAsync(string subscript var metricLabels = DetermineMetricLabels(resourceDefinition); // Enrich measured metrics, in case we need to - var finalMetricValues = EnrichMeasuredMetrics(resourceDefinition, dimensionName, measuredMetrics); + var finalMetricValues = EnrichMeasuredMetrics(resourceDefinition, dimensionNames, measuredMetrics); // We're done! return new ScrapeResult(subscriptionId, scrapeDefinition.ResourceGroupName, resourceDefinition.ResourceName, resourceUri, finalMetricValues, metricLabels); @@ -85,10 +85,10 @@ protected override async Task ScrapeResourceAsync(string subscript /// metrics to align with others /// /// Contains the resource cast to the specific resource type. - /// Name of the specified dimension provided by the scraper + /// /// Measured metric values that were found /// - protected virtual List EnrichMeasuredMetrics(TResourceDefinition resourceDefinition, string dimensionName, List metricValues) + protected virtual List EnrichMeasuredMetrics(TResourceDefinition resourceDefinition, List dimensionNames, List metricValues) { return metricValues; } @@ -111,7 +111,7 @@ protected virtual string DetermineMetricFilter(string metricName, TResourceDefin /// Provides information concerning the configured metric dimensions. protected virtual List DetermineMetricDimensions(string metricName, TResourceDefinition resourceDefinition, List dimensions) { - return dimensions?.Select(dimension => dimension.Name).ToList(); + return dimensions?.Select(dimension => dimension.Name).Where(dimensionName => !string.IsNullOrWhiteSpace(dimensionName)).ToList(); } /// diff --git a/src/Promitor.Core.Scraping/ResourceTypes/AzureMessagingScraper.cs b/src/Promitor.Core.Scraping/ResourceTypes/AzureMessagingScraper.cs index ad150c7a5..4f6bcb76f 100644 --- a/src/Promitor.Core.Scraping/ResourceTypes/AzureMessagingScraper.cs +++ b/src/Promitor.Core.Scraping/ResourceTypes/AzureMessagingScraper.cs @@ -16,12 +16,12 @@ protected AzureMessagingScraper(ScraperConfiguration scraperConfiguration) { } - protected override List EnrichMeasuredMetrics(TResourceDefinition resourceDefinition, string dimensionName, List metricValues) + protected override List EnrichMeasuredMetrics(TResourceDefinition resourceDefinition, List dimensionNames, List metricValues) { // Change Azure Monitor Dimension name to more representable value - foreach (var measuredMetric in metricValues.Where(metricValue => string.IsNullOrWhiteSpace(metricValue.DimensionName) == false)) + foreach (var measuredMetric in metricValues.Where(metricValue => metricValue.DimensionNames.Any())) { - measuredMetric.DimensionName = EntityNameLabel; + measuredMetric.DimensionNames[0] = EntityNameLabel; // TODO } return metricValues; diff --git a/src/Promitor.Core.Scraping/ResourceTypes/DataShareScraper.cs b/src/Promitor.Core.Scraping/ResourceTypes/DataShareScraper.cs index 287122527..710557424 100644 --- a/src/Promitor.Core.Scraping/ResourceTypes/DataShareScraper.cs +++ b/src/Promitor.Core.Scraping/ResourceTypes/DataShareScraper.cs @@ -51,13 +51,18 @@ protected override List DetermineMetricDimensions(string metricName, Dat return new List { dimensionName }; } - protected override List EnrichMeasuredMetrics(DataShareResourceDefinition resourceDefinition, string dimensionName, List metricValues) + protected override List EnrichMeasuredMetrics(DataShareResourceDefinition resourceDefinition, List dimensionNames, List metricValues) { // Change Azure Monitor dimension name to more representable value - foreach (var measuredMetric in metricValues.Where(metricValue => metricValue.DimensionName == "ShareName" - || metricValue.DimensionName == "ShareSubscriptionName")) + foreach (var measuredMetric in metricValues) { - measuredMetric.DimensionName = "share_name"; + for (int i = 0; i < measuredMetric.DimensionNames.Count; i++) + { + if (measuredMetric.DimensionNames[i] == "ShareName" || measuredMetric.DimensionNames[i] == "ShareSubscriptionName") + { + measuredMetric.DimensionNames[i] = "share_name"; + } + } } return metricValues; diff --git a/src/Promitor.Core.Scraping/Scraper.cs b/src/Promitor.Core.Scraping/Scraper.cs index 6a8ffb9d6..1698e8f4f 100644 --- a/src/Promitor.Core.Scraping/Scraper.cs +++ b/src/Promitor.Core.Scraping/Scraper.cs @@ -142,7 +142,7 @@ private void LogMeasuredMetrics(ScrapeDefinition scrap { if (measuredMetric.IsDimensional) { - Logger.LogInformation("Found value {MetricValue} for metric {MetricName} with dimension {DimensionValue} as part of {DimensionName} dimension with aggregation interval {AggregationInterval}", measuredMetric.Value, scrapeDefinition.PrometheusMetricDefinition.Name, measuredMetric.DimensionValue, measuredMetric.DimensionName, aggregationInterval); + Logger.LogInformation("Found value {MetricValue} for metric {MetricName} with dimension {DimensionValue} as part of {DimensionName} dimension with aggregation interval {AggregationInterval}", measuredMetric.Value, scrapeDefinition.PrometheusMetricDefinition.Name, measuredMetric.DimensionValues, measuredMetric.DimensionNames, aggregationInterval); } else { diff --git a/src/Promitor.Core/Metrics/MeasuredMetric.cs b/src/Promitor.Core/Metrics/MeasuredMetric.cs index 52ccc4a2b..b1e993419 100644 --- a/src/Promitor.Core/Metrics/MeasuredMetric.cs +++ b/src/Promitor.Core/Metrics/MeasuredMetric.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Linq; using GuardNet; using Microsoft.Azure.Management.Monitor.Fluent.Models; @@ -15,12 +16,12 @@ public class MeasuredMetric /// /// Name of dimension for a metric /// - public string DimensionName { get; set; } + public List DimensionNames { get; set; } /// /// Name of dimension for a metric /// - public string DimensionValue { get; } + public List DimensionValues { get; } /// /// Indication whether or not the metric represents a dimension @@ -32,16 +33,16 @@ private MeasuredMetric(double? value) Value = value; } - private MeasuredMetric(double? value, string dimensionName, string dimensionValue) + private MeasuredMetric(double? value, List dimensionNames, List dimensionValues) { - Guard.NotNullOrWhitespace(dimensionName, nameof(dimensionName)); - Guard.NotNullOrWhitespace(dimensionValue, nameof(dimensionValue)); + Guard.NotAny(dimensionNames, nameof(dimensionNames)); + Guard.NotAny(dimensionValues, nameof(dimensionValues)); Value = value; IsDimensional = true; - DimensionName = dimensionName; - DimensionValue = dimensionValue; + DimensionNames = dimensionNames; + DimensionValues = dimensionValues; } /// @@ -57,30 +58,35 @@ public static MeasuredMetric CreateWithoutDimension(double? value) /// Create a measured metric for a given dimension /// /// Measured metric value - /// Name of dimension that is being scraped + /// /// Timeseries representing one of the dimensions - public static MeasuredMetric CreateForDimension(double? value, string dimensionName, TimeSeriesElement timeseries) + public static MeasuredMetric CreateForDimension(double? value, List dimensionNames, TimeSeriesElement timeseries) { - Guard.NotNullOrWhitespace(dimensionName, nameof(dimensionName)); + Guard.NotAny(dimensionNames, nameof(dimensionNames)); Guard.NotNull(timeseries, nameof(timeseries)); Guard.For(() => timeseries.Metadatavalues.Any() == false); - var dimensionValue = timeseries.Metadatavalues.Single(metadataValue => metadataValue.Name?.Value.Equals(dimensionName, StringComparison.InvariantCultureIgnoreCase) == true); - return CreateForDimension(value, dimensionName, dimensionValue.Value); + var dimensionValues = new List(); + foreach (var dimensionName in dimensionNames) + { + dimensionValues.Add(timeseries.Metadatavalues.Single(metadataValue => metadataValue.Name?.Value.Equals(dimensionName, StringComparison.InvariantCultureIgnoreCase) == true).Value); + } + + return CreateForDimension(value, dimensionNames, dimensionValues); } /// /// Create a measured metric for a given dimension /// /// Measured metric value - /// Name of dimension that is being scraped - /// Value of the dimension that is being scraped - public static MeasuredMetric CreateForDimension(double? value, string dimensionName, string dimensionValue) + /// + /// + public static MeasuredMetric CreateForDimension(double? value, List dimensionNames, List dimensionValues) { - Guard.NotNullOrWhitespace(dimensionName, nameof(dimensionName)); - Guard.NotNullOrWhitespace(dimensionValue, nameof(dimensionValue)); + Guard.NotAny(dimensionNames, nameof(dimensionNames)); + Guard.NotAny(dimensionValues, nameof(dimensionValues)); - return new MeasuredMetric(value, dimensionName, dimensionValue); + return new MeasuredMetric(value, dimensionNames, dimensionValues); } } } diff --git a/src/Promitor.Integrations.AzureMonitor/AzureMonitorClient.cs b/src/Promitor.Integrations.AzureMonitor/AzureMonitorClient.cs index 1e7c66116..3abe740de 100644 --- a/src/Promitor.Integrations.AzureMonitor/AzureMonitorClient.cs +++ b/src/Promitor.Integrations.AzureMonitor/AzureMonitorClient.cs @@ -110,7 +110,7 @@ public async Task> QueryMetricAsync(string metricName, List // Get the metric value according to the requested aggregation type var requestedMetricAggregate = InterpretMetricValue(aggregationType, mostRecentMetricValue); - var measuredMetric = string.IsNullOrWhiteSpace(metricDimensions) ? MeasuredMetric.CreateWithoutDimension(requestedMetricAggregate) : MeasuredMetric.CreateForDimension(requestedMetricAggregate, metricDimensions, timeseries); + var measuredMetric = metricDimensions.Any() ? MeasuredMetric.CreateForDimension(requestedMetricAggregate, metricDimensions, timeseries) : MeasuredMetric.CreateWithoutDimension(requestedMetricAggregate); measuredMetrics.Add(measuredMetric); } @@ -239,18 +239,14 @@ private IWithMetricsQueryExecute CreateMetricsQuery(AggregationType metricAggreg metricQuery.WithOdataFilter(filter); metricQuery.SelectTop(queryLimit); } - - metricDimensions.RemoveAll(string.IsNullOrWhiteSpace); - metricDimensions. - - string metricDimensionsFilter = - if (string.IsNullOrWhiteSpace(metricDimensions) == false) + if (metricDimensions.Any()) { - metricQuery.WithOdataFilter($"{metricDimensions} eq '*'"); + string metricDimensionsFilter = string.Join(" and ", metricDimensions.Select(metricDimension => $"{metricDimension} eq '*'")); + metricQuery.WithOdataFilter(metricDimensionsFilter); metricQuery.SelectTop(queryLimit); } - + return metricQuery; } diff --git a/src/Promitor.Integrations.AzureMonitor/Exceptions/MetricInformationNotFoundException.cs b/src/Promitor.Integrations.AzureMonitor/Exceptions/MetricInformationNotFoundException.cs index 246b3273f..308e4f8af 100644 --- a/src/Promitor.Integrations.AzureMonitor/Exceptions/MetricInformationNotFoundException.cs +++ b/src/Promitor.Integrations.AzureMonitor/Exceptions/MetricInformationNotFoundException.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using GuardNet; namespace Promitor.Integrations.AzureMonitor.Exceptions @@ -23,15 +24,15 @@ public class MetricInformationNotFoundException : Exception /// Constructor /// /// Name of the metric - /// Dimension of the metric /// Details that provide more context about the scenario - public MetricInformationNotFoundException(string name, string details, string dimension) : base($"No metric information was found for '{name}' with dimension '{dimension}'. Reason: '{details}'") + /// + public MetricInformationNotFoundException(string name, string details, List dimensions) : base($"No metric information was found for '{name}' with dimensions '{dimensions}'. Reason: '{details}'") { Guard.NotNullOrWhitespace(name, nameof(name)); Guard.NotNullOrWhitespace(details, nameof(details)); Name = name; - Dimension = dimension; + Dimensions = dimensions; Details = details; } @@ -43,7 +44,7 @@ public class MetricInformationNotFoundException : Exception /// /// Dimension of the metric /// - public string Dimension { get; } + public List Dimensions { get; } /// /// Details that provide more context about the scenario diff --git a/src/Promitor.Integrations.Sinks.Prometheus/PrometheusScrapingEndpointMetricSink.cs b/src/Promitor.Integrations.Sinks.Prometheus/PrometheusScrapingEndpointMetricSink.cs index 640db2b9d..65b8fbc40 100644 --- a/src/Promitor.Integrations.Sinks.Prometheus/PrometheusScrapingEndpointMetricSink.cs +++ b/src/Promitor.Integrations.Sinks.Prometheus/PrometheusScrapingEndpointMetricSink.cs @@ -94,7 +94,10 @@ private Dictionary DetermineLabels(PrometheusMetricDefinition me if (measuredMetric.IsDimensional) { - labels.Add(measuredMetric.DimensionName.SanitizeForPrometheusLabelKey(), measuredMetric.DimensionValue); + for (int i = 0; i < measuredMetric.DimensionNames.Count; i++) + { + labels.Add(measuredMetric.DimensionNames[i].SanitizeForPrometheusLabelKey(), measuredMetric.DimensionValues[i]); + } } if (metricDefinition?.Labels?.Any() == true) diff --git a/src/Promitor.Tests.Unit/Metrics/Sinks/PrometheusScrapingEndpointMetricSinkTests.cs b/src/Promitor.Tests.Unit/Metrics/Sinks/PrometheusScrapingEndpointMetricSinkTests.cs index a61230e35..16f041277 100644 --- a/src/Promitor.Tests.Unit/Metrics/Sinks/PrometheusScrapingEndpointMetricSinkTests.cs +++ b/src/Promitor.Tests.Unit/Metrics/Sinks/PrometheusScrapingEndpointMetricSinkTests.cs @@ -146,7 +146,7 @@ public async Task ReportMetricAsync_GetsValidInputWithTwoMetricValuesOfWhichOneI { Metadatavalues = new List { new MetadataValue(name: new LocalizableString(dimensionName), value: dimensionValue) } }; - var firstMetric = MeasuredMetric.CreateForDimension(firstMetricValue, dimensionName.ToUpper(), timeSeries); + var firstMetric = MeasuredMetric.CreateForDimension((double?)firstMetricValue, (List)dimensionName.ToUpper(), timeSeries); var secondMetric = MeasuredMetric.CreateWithoutDimension(secondMetricValue); var scrapeResult = ScrapeResultGenerator.GenerateFromMetric(firstMetric); scrapeResult.MetricValues.Add(secondMetric); @@ -258,7 +258,7 @@ public async Task ReportMetricAsync_GetsValidInputWithOneDimensions_Successfully { Metadatavalues = new List { new MetadataValue(name: new LocalizableString(dimensionName), value: dimensionValue) } }; - var measuredMetric = MeasuredMetric.CreateForDimension(metricValue, dimensionName.ToUpper(), timeSeries); + var measuredMetric = MeasuredMetric.CreateForDimension((double?)metricValue, (List)dimensionName.ToUpper(), timeSeries); var scrapeResult = ScrapeResultGenerator.GenerateFromMetric(measuredMetric); var metricsDeclarationProvider = CreateMetricsDeclarationProvider(metricName); var prometheusConfiguration = CreatePrometheusConfiguration(); From 3f52b6a733188ad84468c61924a12066b032190e Mon Sep 17 00:00:00 2001 From: aaronweissler <46028218+aaronweissler@users.noreply.github.com> Date: Fri, 12 Aug 2022 13:19:53 +0200 Subject: [PATCH 03/53] Add Deserialization for List of Dimensions --- .../AzureMetricConfigurationDeserializer.cs | 21 +++++++++++++++++++ .../v1/Model/AzureMetricConfigurationV1.cs | 9 +++++++- 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/src/Promitor.Core.Scraping/Configuration/Serialization/v1/Core/AzureMetricConfigurationDeserializer.cs b/src/Promitor.Core.Scraping/Configuration/Serialization/v1/Core/AzureMetricConfigurationDeserializer.cs index bb9467c1d..127d0f04c 100644 --- a/src/Promitor.Core.Scraping/Configuration/Serialization/v1/Core/AzureMetricConfigurationDeserializer.cs +++ b/src/Promitor.Core.Scraping/Configuration/Serialization/v1/Core/AzureMetricConfigurationDeserializer.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using Microsoft.Azure.Management.AppService.Fluent.Models; using Microsoft.Extensions.Logging; using Promitor.Core.Scraping.Configuration.Serialization.v1.Model; using YamlDotNet.RepresentationModel; @@ -7,6 +8,10 @@ namespace Promitor.Core.Scraping.Configuration.Serialization.v1.Core { public class AzureMetricConfigurationDeserializer : Deserializer { + private const string DimensionsTag = "dimensions"; + private const string DimensionTag = "dimension"; + private readonly IDeserializer _dimensionDeserializer; + public AzureMetricConfigurationDeserializer(IDeserializer dimensionDeserializer, IDeserializer aggregationDeserializer, ILogger logger) : base(logger) { @@ -19,6 +24,22 @@ public AzureMetricConfigurationDeserializer(IDeserializer dim Map(config => config.Aggregation) .IsRequired() .MapUsingDeserializer(aggregationDeserializer); + + _dimensionDeserializer = dimensionDeserializer; + } + + public override AzureMetricConfigurationV1 Deserialize(YamlMappingNode node, IErrorReporter errorReporter) + { + var azureMetricConfiguration = base.Deserialize(node, errorReporter); + + // TODO: add backwards compatibility, only accept one of dimension or dimensions and map dimension to list with one entry + + if (node.Children.TryGetValue(DimensionsTag, out var dimensionsNode)) + { + azureMetricConfiguration.Dimensions = _dimensionDeserializer.Deserialize((YamlSequenceNode)dimensionsNode, errorReporter); + } + + return azureMetricConfiguration; } private object DetermineLimit(string rawLimit, KeyValuePair nodePair, IErrorReporter errorReporter) diff --git a/src/Promitor.Core.Scraping/Configuration/Serialization/v1/Model/AzureMetricConfigurationV1.cs b/src/Promitor.Core.Scraping/Configuration/Serialization/v1/Model/AzureMetricConfigurationV1.cs index 2f33068ef..4e8240afd 100644 --- a/src/Promitor.Core.Scraping/Configuration/Serialization/v1/Model/AzureMetricConfigurationV1.cs +++ b/src/Promitor.Core.Scraping/Configuration/Serialization/v1/Model/AzureMetricConfigurationV1.cs @@ -1,4 +1,6 @@ -namespace Promitor.Core.Scraping.Configuration.Serialization.v1.Model +using System.Collections.Generic; + +namespace Promitor.Core.Scraping.Configuration.Serialization.v1.Model { public class AzureMetricConfigurationV1 { @@ -17,6 +19,11 @@ public class AzureMetricConfigurationV1 /// public MetricDimensionV1 Dimension { get; set; } + /// + /// Information about the dimension of an Azure Monitor metric + /// + public IReadOnlyCollection Dimensions { get; set; } + /// /// The settings for how the metric should be aggregated before being returned from Azure. /// From e08f48f83d83faed381b09d1af4a57e79b973a6c Mon Sep 17 00:00:00 2001 From: aaronweissler <46028218+aaronweissler@users.noreply.github.com> Date: Fri, 12 Aug 2022 15:10:26 +0200 Subject: [PATCH 04/53] Add backwards compatibility to deserialization --- .../AzureMetricConfigurationDeserializer.cs | 20 +++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/src/Promitor.Core.Scraping/Configuration/Serialization/v1/Core/AzureMetricConfigurationDeserializer.cs b/src/Promitor.Core.Scraping/Configuration/Serialization/v1/Core/AzureMetricConfigurationDeserializer.cs index 127d0f04c..aa0702a67 100644 --- a/src/Promitor.Core.Scraping/Configuration/Serialization/v1/Core/AzureMetricConfigurationDeserializer.cs +++ b/src/Promitor.Core.Scraping/Configuration/Serialization/v1/Core/AzureMetricConfigurationDeserializer.cs @@ -8,8 +8,8 @@ namespace Promitor.Core.Scraping.Configuration.Serialization.v1.Core { public class AzureMetricConfigurationDeserializer : Deserializer { - private const string DimensionsTag = "dimensions"; - private const string DimensionTag = "dimension"; + private const string MultipleDimensionsTag = "dimensions"; + private const string SingleDimensionTag = "dimension"; private readonly IDeserializer _dimensionDeserializer; public AzureMetricConfigurationDeserializer(IDeserializer dimensionDeserializer, IDeserializer aggregationDeserializer, ILogger logger) @@ -19,11 +19,11 @@ public AzureMetricConfigurationDeserializer(IDeserializer dim .IsRequired(); Map(config => config.Limit) .MapUsing(DetermineLimit); - Map(config => config.Dimension) - .MapUsingDeserializer(dimensionDeserializer); Map(config => config.Aggregation) .IsRequired() .MapUsingDeserializer(aggregationDeserializer); + IgnoreField(MultipleDimensionsTag); + IgnoreField(SingleDimensionTag); _dimensionDeserializer = dimensionDeserializer; } @@ -32,11 +32,15 @@ public override AzureMetricConfigurationV1 Deserialize(YamlMappingNode node, IEr { var azureMetricConfiguration = base.Deserialize(node, errorReporter); - // TODO: add backwards compatibility, only accept one of dimension or dimensions and map dimension to list with one entry - - if (node.Children.TryGetValue(DimensionsTag, out var dimensionsNode)) + if (node.Children.TryGetValue(MultipleDimensionsTag, out var multipleDimensionsNode)) + { + azureMetricConfiguration.Dimensions = _dimensionDeserializer.Deserialize((YamlSequenceNode)multipleDimensionsNode, errorReporter); + } + + else if (node.Children.TryGetValue(SingleDimensionTag, out var singleDimensionNode)) { - azureMetricConfiguration.Dimensions = _dimensionDeserializer.Deserialize((YamlSequenceNode)dimensionsNode, errorReporter); + errorReporter.ReportWarning(node, "Usage of 'dimension' is deprecated in favor of using 'dimensions'."); + azureMetricConfiguration.Dimensions = new List{ _dimensionDeserializer.Deserialize((YamlMappingNode)singleDimensionNode, errorReporter) }; } return azureMetricConfiguration; From 1e2e998a49a4b9c25533c3218cfc3ba41c9f8a32 Mon Sep 17 00:00:00 2001 From: aaronweissler <46028218+aaronweissler@users.noreply.github.com> Date: Fri, 12 Aug 2022 15:34:38 +0200 Subject: [PATCH 05/53] Remove old Dimension attribute --- .../Configuration/Model/AzureMetricConfiguration.cs | 6 ------ .../Serialization/v1/Model/AzureMetricConfigurationV1.cs | 5 ----- 2 files changed, 11 deletions(-) diff --git a/src/Promitor.Core.Scraping/Configuration/Model/AzureMetricConfiguration.cs b/src/Promitor.Core.Scraping/Configuration/Model/AzureMetricConfiguration.cs index 0e61d2cbf..85a6a8382 100644 --- a/src/Promitor.Core.Scraping/Configuration/Model/AzureMetricConfiguration.cs +++ b/src/Promitor.Core.Scraping/Configuration/Model/AzureMetricConfiguration.cs @@ -15,12 +15,6 @@ public class AzureMetricConfiguration /// public int? Limit { get; set; } - /// - /// Information about the dimension of an Azure Monitor metric - /// - [Obsolete("Dimension is deprecated, use Dimensions instead.")] - public MetricDimension Dimension { get; set; } - /// /// Information about the dimension of an Azure Monitor metric /// diff --git a/src/Promitor.Core.Scraping/Configuration/Serialization/v1/Model/AzureMetricConfigurationV1.cs b/src/Promitor.Core.Scraping/Configuration/Serialization/v1/Model/AzureMetricConfigurationV1.cs index 4e8240afd..c090ea05d 100644 --- a/src/Promitor.Core.Scraping/Configuration/Serialization/v1/Model/AzureMetricConfigurationV1.cs +++ b/src/Promitor.Core.Scraping/Configuration/Serialization/v1/Model/AzureMetricConfigurationV1.cs @@ -14,11 +14,6 @@ public class AzureMetricConfigurationV1 /// public int? Limit { get; set; } - /// - /// Information about the dimension of an Azure Monitor metric - /// - public MetricDimensionV1 Dimension { get; set; } - /// /// Information about the dimension of an Azure Monitor metric /// From 573554a8c9d0c78cb035187fb246b68c604c018f Mon Sep 17 00:00:00 2001 From: Patrick Eichhorn Date: Fri, 12 Aug 2022 16:09:55 +0200 Subject: [PATCH 06/53] Change Log message --- src/Promitor.Core.Scraping/Scraper.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Promitor.Core.Scraping/Scraper.cs b/src/Promitor.Core.Scraping/Scraper.cs index 1698e8f4f..60a0a79ef 100644 --- a/src/Promitor.Core.Scraping/Scraper.cs +++ b/src/Promitor.Core.Scraping/Scraper.cs @@ -142,7 +142,7 @@ private void LogMeasuredMetrics(ScrapeDefinition scrap { if (measuredMetric.IsDimensional) { - Logger.LogInformation("Found value {MetricValue} for metric {MetricName} with dimension {DimensionValue} as part of {DimensionName} dimension with aggregation interval {AggregationInterval}", measuredMetric.Value, scrapeDefinition.PrometheusMetricDefinition.Name, measuredMetric.DimensionValues, measuredMetric.DimensionNames, aggregationInterval); + Logger.LogInformation("Found value {MetricValue} for metric {MetricName} with dimension values {DimensionValue} as part of the dimensions {DimensionName} with aggregation interval {AggregationInterval}", measuredMetric.Value, scrapeDefinition.PrometheusMetricDefinition.Name, measuredMetric.DimensionValues, measuredMetric.DimensionNames, aggregationInterval); } else { From 6df4f896d593a08d886f0aa55b4fb8145f85bce7 Mon Sep 17 00:00:00 2001 From: Patrick Eichhorn Date: Fri, 12 Aug 2022 16:11:09 +0200 Subject: [PATCH 07/53] WIP add support for multiple dimensions --- .../ResourceTypes/EventHubsMetricValidator.cs | 5 ++--- .../ResourceTypes/ServiceBusNamespaceMetricValidator.cs | 5 ++--- .../Builders/Metrics/v1/MetricsDeclarationBuilder.cs | 7 +++++-- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/Promitor.Agents.Scraper/Validation/MetricDefinitions/ResourceTypes/EventHubsMetricValidator.cs b/src/Promitor.Agents.Scraper/Validation/MetricDefinitions/ResourceTypes/EventHubsMetricValidator.cs index bb03f5f01..04771d6d1 100644 --- a/src/Promitor.Agents.Scraper/Validation/MetricDefinitions/ResourceTypes/EventHubsMetricValidator.cs +++ b/src/Promitor.Agents.Scraper/Validation/MetricDefinitions/ResourceTypes/EventHubsMetricValidator.cs @@ -17,9 +17,8 @@ public IEnumerable Validate(MetricDefinition metricDefinition) Guard.NotNull(metricDefinition, nameof(metricDefinition)); var errorMessages = new List(); - - var configuredDimension = metricDefinition.AzureMetricConfiguration?.Dimension?.Name; - var isEntityNameDimensionConfigured = string.IsNullOrWhiteSpace(configuredDimension) == false && configuredDimension.Equals(EntityNameDimension, StringComparison.InvariantCultureIgnoreCase); + + var isEntityNameDimensionConfigured = metricDefinition.AzureMetricConfiguration?.Dimensions?.Where(dimension => dimension.Name.Equals(EntityNameDimension, StringComparison.InvariantCultureIgnoreCase)).Any() ?? false; foreach (var resourceDefinition in metricDefinition.Resources.Cast()) { diff --git a/src/Promitor.Agents.Scraper/Validation/MetricDefinitions/ResourceTypes/ServiceBusNamespaceMetricValidator.cs b/src/Promitor.Agents.Scraper/Validation/MetricDefinitions/ResourceTypes/ServiceBusNamespaceMetricValidator.cs index 570cd70c8..a9df8ab95 100644 --- a/src/Promitor.Agents.Scraper/Validation/MetricDefinitions/ResourceTypes/ServiceBusNamespaceMetricValidator.cs +++ b/src/Promitor.Agents.Scraper/Validation/MetricDefinitions/ResourceTypes/ServiceBusNamespaceMetricValidator.cs @@ -18,9 +18,8 @@ public IEnumerable Validate(MetricDefinition metricDefinition) var errorMessages = new List(); - var configuredDimension = metricDefinition.AzureMetricConfiguration?.Dimension?.Name; - var isEntityNameDimensionConfigured = string.IsNullOrWhiteSpace(configuredDimension) == false && configuredDimension.Equals(EntityNameDimension, StringComparison.InvariantCultureIgnoreCase); - + var isEntityNameDimensionConfigured = metricDefinition.AzureMetricConfiguration?.Dimensions?.Where(dimension => dimension.Name.Equals(EntityNameDimension, StringComparison.InvariantCultureIgnoreCase)).Any() ?? false; + foreach (var resourceDefinition in metricDefinition.Resources.Cast()) { if (string.IsNullOrWhiteSpace(resourceDefinition.Namespace)) diff --git a/src/Promitor.Tests.Unit/Builders/Metrics/v1/MetricsDeclarationBuilder.cs b/src/Promitor.Tests.Unit/Builders/Metrics/v1/MetricsDeclarationBuilder.cs index 7e9d32e8d..b4bca532e 100644 --- a/src/Promitor.Tests.Unit/Builders/Metrics/v1/MetricsDeclarationBuilder.cs +++ b/src/Promitor.Tests.Unit/Builders/Metrics/v1/MetricsDeclarationBuilder.cs @@ -1044,9 +1044,12 @@ private AzureMetricConfigurationV1 CreateAzureMetricConfiguration(string azureMe if (string.IsNullOrWhiteSpace(metricDimension) == false) { - metricConfig.Dimension = new MetricDimensionV1 + metricConfig.Dimensions = new List { - Name = metricDimension + new() + { + Name = metricDimension + } }; } From b997736e8cc28db1c7b6e6efaab68eae77bbff7d Mon Sep 17 00:00:00 2001 From: aaronweissler <46028218+aaronweissler@users.noreply.github.com> Date: Mon, 12 Sep 2022 12:18:14 +0200 Subject: [PATCH 08/53] Fix and Add Serialization Test --- ...ureMetricConfigurationDeserializerTests.cs | 31 ++++++++++++++++--- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/src/Promitor.Tests.Unit/Serialization/v1/Core/AzureMetricConfigurationDeserializerTests.cs b/src/Promitor.Tests.Unit/Serialization/v1/Core/AzureMetricConfigurationDeserializerTests.cs index 66f218e2d..e8f3fc6b1 100644 --- a/src/Promitor.Tests.Unit/Serialization/v1/Core/AzureMetricConfigurationDeserializerTests.cs +++ b/src/Promitor.Tests.Unit/Serialization/v1/Core/AzureMetricConfigurationDeserializerTests.cs @@ -1,4 +1,6 @@ -using System.ComponentModel; +using System; +using System.Collections.Generic; +using System.ComponentModel; using Microsoft.Extensions.Logging.Abstractions; using Moq; using Promitor.Core.Scraping.Configuration.Serialization; @@ -108,13 +110,34 @@ public void Deserialize_DimensionSupplied_UsesDeserializer() var dimensionNode = (YamlMappingNode)node.Children["dimension"]; var dimension = new MetricDimensionV1(); - _dimensionDeserializer.Setup(d => d.DeserializeObject(dimensionNode, _errorReporter.Object)).Returns(dimension); + _dimensionDeserializer.Setup(d => d.Deserialize(dimensionNode, _errorReporter.Object)).Returns(dimension); + + // Act + var config = _deserializer.Deserialize(node, _errorReporter.Object); + + // Assert + Assert.Equal(new List { dimension }, config.Dimensions); + } + + [Fact] + public void Deserialize_DimensionsSupplied_UsesDeserializer() + { + // Arrange + const string yamlText = + @"dimensions: + - name: EntityPath + - name: Test"; + var node = YamlUtils.CreateYamlNode(yamlText); + var dimensionsNode = (YamlSequenceNode)node.Children["dimensions"]; + + var dimensions = new List { new MetricDimensionV1(), new MetricDimensionV1() }; + _dimensionDeserializer.Setup(d => d.Deserialize(dimensionsNode, _errorReporter.Object)).Returns(dimensions); // Act var config = _deserializer.Deserialize(node, _errorReporter.Object); // Assert - Assert.Same(dimension, config.Dimension); + Assert.Same(dimensions, config.Dimensions); } [Fact] @@ -123,7 +146,7 @@ public void Deserialize_DimensionNotSupplied_Null() YamlAssert.PropertyNull( _deserializer, "metricName: ActiveMessages", - c => c.Dimension); + c => c.Dimensions); } [Fact] From 399978e85644c6c059057e87e7b06c7668d2ce4a Mon Sep 17 00:00:00 2001 From: aaronweissler <46028218+aaronweissler@users.noreply.github.com> Date: Mon, 12 Sep 2022 13:38:14 +0200 Subject: [PATCH 09/53] Add parameter docs --- src/Promitor.Core.Scraping/AzureMonitorScraper.cs | 2 +- src/Promitor.Core/Metrics/MeasuredMetric.cs | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Promitor.Core.Scraping/AzureMonitorScraper.cs b/src/Promitor.Core.Scraping/AzureMonitorScraper.cs index 97c0cca07..fac0ee733 100644 --- a/src/Promitor.Core.Scraping/AzureMonitorScraper.cs +++ b/src/Promitor.Core.Scraping/AzureMonitorScraper.cs @@ -85,7 +85,7 @@ protected override async Task ScrapeResourceAsync(string subscript /// metrics to align with others /// /// Contains the resource cast to the specific resource type. - /// + /// List of names of the specified dimensions provided by the scraper. /// Measured metric values that were found /// protected virtual List EnrichMeasuredMetrics(TResourceDefinition resourceDefinition, List dimensionNames, List metricValues) diff --git a/src/Promitor.Core/Metrics/MeasuredMetric.cs b/src/Promitor.Core/Metrics/MeasuredMetric.cs index b1e993419..058daaecc 100644 --- a/src/Promitor.Core/Metrics/MeasuredMetric.cs +++ b/src/Promitor.Core/Metrics/MeasuredMetric.cs @@ -58,7 +58,7 @@ public static MeasuredMetric CreateWithoutDimension(double? value) /// Create a measured metric for a given dimension /// /// Measured metric value - /// + /// List of names of dimensions that are being scraped /// Timeseries representing one of the dimensions public static MeasuredMetric CreateForDimension(double? value, List dimensionNames, TimeSeriesElement timeseries) { @@ -79,8 +79,8 @@ public static MeasuredMetric CreateForDimension(double? value, List dime /// Create a measured metric for a given dimension /// /// Measured metric value - /// - /// + /// List of names of dimensions that are being scraped + /// List of values of the dimension that are being scraped public static MeasuredMetric CreateForDimension(double? value, List dimensionNames, List dimensionValues) { Guard.NotAny(dimensionNames, nameof(dimensionNames)); From ef0a44b9fe7d4afc388f3204d905da926b6dd5ef Mon Sep 17 00:00:00 2001 From: aaronweissler <46028218+aaronweissler@users.noreply.github.com> Date: Mon, 12 Sep 2022 13:38:27 +0200 Subject: [PATCH 10/53] Fix PrometheusScrapingEndpointMetricSinkTests --- .../Sinks/PrometheusScrapingEndpointMetricSinkTests.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Promitor.Tests.Unit/Metrics/Sinks/PrometheusScrapingEndpointMetricSinkTests.cs b/src/Promitor.Tests.Unit/Metrics/Sinks/PrometheusScrapingEndpointMetricSinkTests.cs index 16f041277..fba4a5391 100644 --- a/src/Promitor.Tests.Unit/Metrics/Sinks/PrometheusScrapingEndpointMetricSinkTests.cs +++ b/src/Promitor.Tests.Unit/Metrics/Sinks/PrometheusScrapingEndpointMetricSinkTests.cs @@ -146,7 +146,7 @@ public async Task ReportMetricAsync_GetsValidInputWithTwoMetricValuesOfWhichOneI { Metadatavalues = new List { new MetadataValue(name: new LocalizableString(dimensionName), value: dimensionValue) } }; - var firstMetric = MeasuredMetric.CreateForDimension((double?)firstMetricValue, (List)dimensionName.ToUpper(), timeSeries); + var firstMetric = MeasuredMetric.CreateForDimension(firstMetricValue, new List{ dimensionName.ToUpper() }, timeSeries); var secondMetric = MeasuredMetric.CreateWithoutDimension(secondMetricValue); var scrapeResult = ScrapeResultGenerator.GenerateFromMetric(firstMetric); scrapeResult.MetricValues.Add(secondMetric); @@ -258,7 +258,7 @@ public async Task ReportMetricAsync_GetsValidInputWithOneDimensions_Successfully { Metadatavalues = new List { new MetadataValue(name: new LocalizableString(dimensionName), value: dimensionValue) } }; - var measuredMetric = MeasuredMetric.CreateForDimension((double?)metricValue, (List)dimensionName.ToUpper(), timeSeries); + var measuredMetric = MeasuredMetric.CreateForDimension(metricValue, new List{ dimensionName.ToUpper() }, timeSeries); var scrapeResult = ScrapeResultGenerator.GenerateFromMetric(measuredMetric); var metricsDeclarationProvider = CreateMetricsDeclarationProvider(metricName); var prometheusConfiguration = CreatePrometheusConfiguration(); From 0b08cd43d84cbfd3245046463c6b0dbc68bfc1d5 Mon Sep 17 00:00:00 2001 From: aaronweissler <46028218+aaronweissler@users.noreply.github.com> Date: Mon, 12 Sep 2022 14:51:51 +0200 Subject: [PATCH 11/53] Use var instead of int on IDE recommendation --- src/Promitor.Core.Scraping/ResourceTypes/DataShareScraper.cs | 2 +- .../PrometheusScrapingEndpointMetricSink.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Promitor.Core.Scraping/ResourceTypes/DataShareScraper.cs b/src/Promitor.Core.Scraping/ResourceTypes/DataShareScraper.cs index 710557424..09ebfef95 100644 --- a/src/Promitor.Core.Scraping/ResourceTypes/DataShareScraper.cs +++ b/src/Promitor.Core.Scraping/ResourceTypes/DataShareScraper.cs @@ -56,7 +56,7 @@ protected override List EnrichMeasuredMetrics(DataShareResourceD // Change Azure Monitor dimension name to more representable value foreach (var measuredMetric in metricValues) { - for (int i = 0; i < measuredMetric.DimensionNames.Count; i++) + for (var i = 0; i < measuredMetric.DimensionNames.Count; i++) { if (measuredMetric.DimensionNames[i] == "ShareName" || measuredMetric.DimensionNames[i] == "ShareSubscriptionName") { diff --git a/src/Promitor.Integrations.Sinks.Prometheus/PrometheusScrapingEndpointMetricSink.cs b/src/Promitor.Integrations.Sinks.Prometheus/PrometheusScrapingEndpointMetricSink.cs index 65b8fbc40..491c47983 100644 --- a/src/Promitor.Integrations.Sinks.Prometheus/PrometheusScrapingEndpointMetricSink.cs +++ b/src/Promitor.Integrations.Sinks.Prometheus/PrometheusScrapingEndpointMetricSink.cs @@ -94,7 +94,7 @@ private Dictionary DetermineLabels(PrometheusMetricDefinition me if (measuredMetric.IsDimensional) { - for (int i = 0; i < measuredMetric.DimensionNames.Count; i++) + for (var i = 0; i < measuredMetric.DimensionNames.Count; i++) { labels.Add(measuredMetric.DimensionNames[i].SanitizeForPrometheusLabelKey(), measuredMetric.DimensionValues[i]); } From 05cbac399810996e4b2f4fd1b8b73bf77c9881b7 Mon Sep 17 00:00:00 2001 From: aaronweissler <46028218+aaronweissler@users.noreply.github.com> Date: Mon, 12 Sep 2022 15:02:20 +0200 Subject: [PATCH 12/53] Fix IDE recommendations --- src/Promitor.Core.Scraping/AzureMonitorScraper.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Promitor.Core.Scraping/AzureMonitorScraper.cs b/src/Promitor.Core.Scraping/AzureMonitorScraper.cs index fac0ee733..9ed5f157f 100644 --- a/src/Promitor.Core.Scraping/AzureMonitorScraper.cs +++ b/src/Promitor.Core.Scraping/AzureMonitorScraper.cs @@ -46,9 +46,9 @@ protected override async Task ScrapeResourceAsync(string subscript var metricLimit = DetermineMetricLimit(scrapeDefinition); // Determine the metric dimension to use, if any - List dimensionNames = DetermineMetricDimensions(metricName, resourceDefinition, scrapeDefinition.AzureMetricConfiguration?.Dimensions); + var dimensionNames = DetermineMetricDimensions(metricName, resourceDefinition, scrapeDefinition.AzureMetricConfiguration?.Dimensions); - List measuredMetrics = new List(); + var measuredMetrics = new List(); try { // Query Azure Monitor for metrics @@ -58,7 +58,7 @@ protected override async Task ScrapeResourceAsync(string subscript { Logger.LogWarning("No metric information found for metric {MetricName} with dimensions {MetricDimensions}. Details: {Details}", metricsNotFoundException.Name, metricsNotFoundException.Dimensions, metricsNotFoundException.Details); - var measuredMetric = dimensionNames.Any() ? MeasuredMetric.CreateForDimension((double?)null, dimensionNames, Enumerable.Repeat("unknown",dimensionNames.Count).ToList()) : MeasuredMetric.CreateWithoutDimension(null); + var measuredMetric = dimensionNames.Any() ? MeasuredMetric.CreateForDimension(null, dimensionNames, Enumerable.Repeat("unknown",dimensionNames.Count).ToList()) : MeasuredMetric.CreateWithoutDimension(null); measuredMetrics.Add(measuredMetric); } From 5fb9cf5651ed9cdba42af3fdef6118edac4e1bbd Mon Sep 17 00:00:00 2001 From: aaronweissler <46028218+aaronweissler@users.noreply.github.com> Date: Mon, 12 Sep 2022 15:19:14 +0200 Subject: [PATCH 13/53] Add comment --- .../v1/Core/AzureMetricConfigurationDeserializer.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Promitor.Core.Scraping/Configuration/Serialization/v1/Core/AzureMetricConfigurationDeserializer.cs b/src/Promitor.Core.Scraping/Configuration/Serialization/v1/Core/AzureMetricConfigurationDeserializer.cs index aa0702a67..9965ca176 100644 --- a/src/Promitor.Core.Scraping/Configuration/Serialization/v1/Core/AzureMetricConfigurationDeserializer.cs +++ b/src/Promitor.Core.Scraping/Configuration/Serialization/v1/Core/AzureMetricConfigurationDeserializer.cs @@ -37,6 +37,7 @@ public override AzureMetricConfigurationV1 Deserialize(YamlMappingNode node, IEr azureMetricConfiguration.Dimensions = _dimensionDeserializer.Deserialize((YamlSequenceNode)multipleDimensionsNode, errorReporter); } + // backwards compatibility: if old tag "dimension" is used, a list containing only the one MetricDimension is created else if (node.Children.TryGetValue(SingleDimensionTag, out var singleDimensionNode)) { errorReporter.ReportWarning(node, "Usage of 'dimension' is deprecated in favor of using 'dimensions'."); From 6a9a6f0137168f2cfae92a13f55dd7212226eb57 Mon Sep 17 00:00:00 2001 From: aaronweissler <46028218+aaronweissler@users.noreply.github.com> Date: Mon, 12 Sep 2022 16:35:24 +0200 Subject: [PATCH 14/53] Remove unneeded imports --- .../Configuration/Model/AzureMetricConfiguration.cs | 3 +-- .../v1/Core/AzureMetricConfigurationDeserializer.cs | 1 - src/Promitor.Core.Scraping/ResourceTypes/DataShareScraper.cs | 1 - src/Promitor.Integrations.AzureMonitor/AzureMonitorClient.cs | 1 - .../v1/Core/AzureMetricConfigurationDeserializerTests.cs | 3 +-- 5 files changed, 2 insertions(+), 7 deletions(-) diff --git a/src/Promitor.Core.Scraping/Configuration/Model/AzureMetricConfiguration.cs b/src/Promitor.Core.Scraping/Configuration/Model/AzureMetricConfiguration.cs index 85a6a8382..1121ed060 100644 --- a/src/Promitor.Core.Scraping/Configuration/Model/AzureMetricConfiguration.cs +++ b/src/Promitor.Core.Scraping/Configuration/Model/AzureMetricConfiguration.cs @@ -1,5 +1,4 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; namespace Promitor.Core.Scraping.Configuration.Model { diff --git a/src/Promitor.Core.Scraping/Configuration/Serialization/v1/Core/AzureMetricConfigurationDeserializer.cs b/src/Promitor.Core.Scraping/Configuration/Serialization/v1/Core/AzureMetricConfigurationDeserializer.cs index 9965ca176..522a90c0d 100644 --- a/src/Promitor.Core.Scraping/Configuration/Serialization/v1/Core/AzureMetricConfigurationDeserializer.cs +++ b/src/Promitor.Core.Scraping/Configuration/Serialization/v1/Core/AzureMetricConfigurationDeserializer.cs @@ -1,5 +1,4 @@ using System.Collections.Generic; -using Microsoft.Azure.Management.AppService.Fluent.Models; using Microsoft.Extensions.Logging; using Promitor.Core.Scraping.Configuration.Serialization.v1.Model; using YamlDotNet.RepresentationModel; diff --git a/src/Promitor.Core.Scraping/ResourceTypes/DataShareScraper.cs b/src/Promitor.Core.Scraping/ResourceTypes/DataShareScraper.cs index 09ebfef95..3816e9be2 100644 --- a/src/Promitor.Core.Scraping/ResourceTypes/DataShareScraper.cs +++ b/src/Promitor.Core.Scraping/ResourceTypes/DataShareScraper.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Linq; using Microsoft.Extensions.Logging; using Promitor.Core.Contracts; using Promitor.Core.Contracts.ResourceTypes; diff --git a/src/Promitor.Integrations.AzureMonitor/AzureMonitorClient.cs b/src/Promitor.Integrations.AzureMonitor/AzureMonitorClient.cs index 3abe740de..9c8e0cac2 100644 --- a/src/Promitor.Integrations.AzureMonitor/AzureMonitorClient.cs +++ b/src/Promitor.Integrations.AzureMonitor/AzureMonitorClient.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Text; using System.Threading.Tasks; using Microsoft.Azure.Management.Fluent; using Microsoft.Azure.Management.Monitor.Fluent; diff --git a/src/Promitor.Tests.Unit/Serialization/v1/Core/AzureMetricConfigurationDeserializerTests.cs b/src/Promitor.Tests.Unit/Serialization/v1/Core/AzureMetricConfigurationDeserializerTests.cs index e8f3fc6b1..3311ab64e 100644 --- a/src/Promitor.Tests.Unit/Serialization/v1/Core/AzureMetricConfigurationDeserializerTests.cs +++ b/src/Promitor.Tests.Unit/Serialization/v1/Core/AzureMetricConfigurationDeserializerTests.cs @@ -1,5 +1,4 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.ComponentModel; using Microsoft.Extensions.Logging.Abstractions; using Moq; From b2dc85798ecfbb84383626e292bbbeea491c8351 Mon Sep 17 00:00:00 2001 From: aaronweissler <46028218+aaronweissler@users.noreply.github.com> Date: Fri, 16 Sep 2022 09:14:46 +0200 Subject: [PATCH 15/53] Add changelog --- changelog/content/experimental/unreleased.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/changelog/content/experimental/unreleased.md b/changelog/content/experimental/unreleased.md index e3b34ee41..aa54ba73c 100644 --- a/changelog/content/experimental/unreleased.md +++ b/changelog/content/experimental/unreleased.md @@ -5,9 +5,11 @@ version: --- #### Scraper - + - {{% tag added %}} Provide Azure Log Analytics scraper ([docs](https://docs.promitor.io/v2.9/scraping/providers/log-analytics/) | [#2132](https://github.com/tomkerkhove/promitor/pull/2132)) +- {{% tag added %}} Provide capability to use multiple metric dimensions by using new configuration property `dimensions` ([#1820](https://github.com/tomkerkhove/promitor/issues/1820)) +- {{% tag deprecated %}} Old configuration property for metric dimension `dimension` ([#1820](https://github.com/tomkerkhove/promitor/issues/1820)) #### Resource Discovery From 2bf11289ce03b67501558938e89d649c1a8fc8d2 Mon Sep 17 00:00:00 2001 From: aaronweissler <46028218+aaronweissler@users.noreply.github.com> Date: Fri, 16 Sep 2022 09:27:42 +0200 Subject: [PATCH 16/53] Add second dimension to example metric --- config/promitor/scraper/metrics.yaml | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/config/promitor/scraper/metrics.yaml b/config/promitor/scraper/metrics.yaml index dd21d2a9c..8a028a11e 100644 --- a/config/promitor/scraper/metrics.yaml +++ b/config/promitor/scraper/metrics.yaml @@ -173,7 +173,7 @@ metrics: resources: - accountName: promitor-testing-resource-eu-automation-1 - name: promitor_demo_frontdoor_backend_health_per_backend_pool - description: "Health percentage for a backed in Azure Front Door" + description: "Health percentage for a backend in Azure Front Door" resourceType: FrontDoor labels: app: promitor @@ -185,6 +185,20 @@ metrics: type: Average resourceDiscoveryGroups: - name: front-door-landscape + - name: promitor_demo_frontdoor_backend_health_per_backend_pool_and_backend + description: "Health percentage for a backend in Azure Front Door" + resourceType: FrontDoor + labels: + app: promitor + azureMetricConfiguration: + metricName: BackendHealthPercentage + dimensions: + - name: BackendPool + - name: Backend + aggregation: + type: Average + resourceDiscoveryGroups: + - name: front-door-landscape - name: promitor_demo_sql_elastic_pool_cpu description: "CPU percentage used for a Azure SQL Elastic Pool" resourceType: SqlElasticPool From 64c201d8b9a8d918dfe69ad2351f7a9b69c62011 Mon Sep 17 00:00:00 2001 From: aaronweissler <46028218+aaronweissler@users.noreply.github.com> Date: Fri, 16 Sep 2022 09:57:29 +0200 Subject: [PATCH 17/53] Add missing docstring --- .../Exceptions/MetricInformationNotFoundException.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Promitor.Integrations.AzureMonitor/Exceptions/MetricInformationNotFoundException.cs b/src/Promitor.Integrations.AzureMonitor/Exceptions/MetricInformationNotFoundException.cs index 308e4f8af..3f4683f4b 100644 --- a/src/Promitor.Integrations.AzureMonitor/Exceptions/MetricInformationNotFoundException.cs +++ b/src/Promitor.Integrations.AzureMonitor/Exceptions/MetricInformationNotFoundException.cs @@ -25,7 +25,7 @@ public class MetricInformationNotFoundException : Exception /// /// Name of the metric /// Details that provide more context about the scenario - /// + /// Dimensions of the metric public MetricInformationNotFoundException(string name, string details, List dimensions) : base($"No metric information was found for '{name}' with dimensions '{dimensions}'. Reason: '{details}'") { Guard.NotNullOrWhitespace(name, nameof(name)); From fb759052cac529e2ac89f56ba3c582ddaf739862 Mon Sep 17 00:00:00 2001 From: aaronweissler <46028218+aaronweissler@users.noreply.github.com> Date: Fri, 16 Sep 2022 10:13:06 +0200 Subject: [PATCH 18/53] Add HasDimensions method to remove code duplicate --- .../ResourceTypes/EventHubsMetricValidator.cs | 2 +- .../ServiceBusNamespaceMetricValidator.cs | 2 +- .../Model/AzureMetricConfiguration.cs | 14 +++++++++++++- 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/src/Promitor.Agents.Scraper/Validation/MetricDefinitions/ResourceTypes/EventHubsMetricValidator.cs b/src/Promitor.Agents.Scraper/Validation/MetricDefinitions/ResourceTypes/EventHubsMetricValidator.cs index 04771d6d1..b37cf9c5c 100644 --- a/src/Promitor.Agents.Scraper/Validation/MetricDefinitions/ResourceTypes/EventHubsMetricValidator.cs +++ b/src/Promitor.Agents.Scraper/Validation/MetricDefinitions/ResourceTypes/EventHubsMetricValidator.cs @@ -18,7 +18,7 @@ public IEnumerable Validate(MetricDefinition metricDefinition) var errorMessages = new List(); - var isEntityNameDimensionConfigured = metricDefinition.AzureMetricConfiguration?.Dimensions?.Where(dimension => dimension.Name.Equals(EntityNameDimension, StringComparison.InvariantCultureIgnoreCase)).Any() ?? false; + var isEntityNameDimensionConfigured = metricDefinition.AzureMetricConfiguration?.HasDimension(EntityNameDimension) ?? false; foreach (var resourceDefinition in metricDefinition.Resources.Cast()) { diff --git a/src/Promitor.Agents.Scraper/Validation/MetricDefinitions/ResourceTypes/ServiceBusNamespaceMetricValidator.cs b/src/Promitor.Agents.Scraper/Validation/MetricDefinitions/ResourceTypes/ServiceBusNamespaceMetricValidator.cs index a9df8ab95..c4e74d754 100644 --- a/src/Promitor.Agents.Scraper/Validation/MetricDefinitions/ResourceTypes/ServiceBusNamespaceMetricValidator.cs +++ b/src/Promitor.Agents.Scraper/Validation/MetricDefinitions/ResourceTypes/ServiceBusNamespaceMetricValidator.cs @@ -18,7 +18,7 @@ public IEnumerable Validate(MetricDefinition metricDefinition) var errorMessages = new List(); - var isEntityNameDimensionConfigured = metricDefinition.AzureMetricConfiguration?.Dimensions?.Where(dimension => dimension.Name.Equals(EntityNameDimension, StringComparison.InvariantCultureIgnoreCase)).Any() ?? false; + var isEntityNameDimensionConfigured = metricDefinition.AzureMetricConfiguration?.HasDimension(EntityNameDimension) ?? false; foreach (var resourceDefinition in metricDefinition.Resources.Cast()) { diff --git a/src/Promitor.Core.Scraping/Configuration/Model/AzureMetricConfiguration.cs b/src/Promitor.Core.Scraping/Configuration/Model/AzureMetricConfiguration.cs index 1121ed060..8ae5d365a 100644 --- a/src/Promitor.Core.Scraping/Configuration/Model/AzureMetricConfiguration.cs +++ b/src/Promitor.Core.Scraping/Configuration/Model/AzureMetricConfiguration.cs @@ -1,4 +1,6 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; +using System.Linq; namespace Promitor.Core.Scraping.Configuration.Model { @@ -23,5 +25,15 @@ public class AzureMetricConfiguration /// Configuration on how to aggregate the metric /// public MetricAggregation Aggregation { get; set; } + + /// + /// Checks whether the configuration contains a dimension with the given name. + /// + /// Dimension name to be checked for. + /// true if the dimension name was found, false otherwise + public bool HasDimension(string dimensionName) + { + return Dimensions?.Where(dimension => dimension.Name.Equals(dimensionName, StringComparison.InvariantCultureIgnoreCase)).Any() ?? false; + } } } \ No newline at end of file From a96fbb34c31d697599c0260d2da9c15ae5a1f2e4 Mon Sep 17 00:00:00 2001 From: aaronweissler <46028218+aaronweissler@users.noreply.github.com> Date: Fri, 16 Sep 2022 12:41:33 +0200 Subject: [PATCH 19/53] Combine dimensionNames and dimensionValues in List --- .../AzureMonitorScraper.cs | 2 +- .../ResourceTypes/AzureMessagingScraper.cs | 4 +- .../ResourceTypes/DataShareScraper.cs | 11 ++---- src/Promitor.Core.Scraping/Scraper.cs | 3 +- src/Promitor.Core/Metrics/MeasuredMetric.cs | 39 ++++++++----------- .../Metrics/MeasuredMetricDimension.cs | 26 +++++++++++++ .../PrometheusScrapingEndpointMetricSink.cs | 4 +- 7 files changed, 52 insertions(+), 37 deletions(-) create mode 100644 src/Promitor.Core/Metrics/MeasuredMetricDimension.cs diff --git a/src/Promitor.Core.Scraping/AzureMonitorScraper.cs b/src/Promitor.Core.Scraping/AzureMonitorScraper.cs index 9ed5f157f..42ec90a36 100644 --- a/src/Promitor.Core.Scraping/AzureMonitorScraper.cs +++ b/src/Promitor.Core.Scraping/AzureMonitorScraper.cs @@ -58,7 +58,7 @@ protected override async Task ScrapeResourceAsync(string subscript { Logger.LogWarning("No metric information found for metric {MetricName} with dimensions {MetricDimensions}. Details: {Details}", metricsNotFoundException.Name, metricsNotFoundException.Dimensions, metricsNotFoundException.Details); - var measuredMetric = dimensionNames.Any() ? MeasuredMetric.CreateForDimension(null, dimensionNames, Enumerable.Repeat("unknown",dimensionNames.Count).ToList()) : MeasuredMetric.CreateWithoutDimension(null); + var measuredMetric = dimensionNames.Any() ? MeasuredMetric.CreateForDimension(dimensionNames) : MeasuredMetric.CreateWithoutDimension(null); measuredMetrics.Add(measuredMetric); } diff --git a/src/Promitor.Core.Scraping/ResourceTypes/AzureMessagingScraper.cs b/src/Promitor.Core.Scraping/ResourceTypes/AzureMessagingScraper.cs index 4f6bcb76f..b95acc3e3 100644 --- a/src/Promitor.Core.Scraping/ResourceTypes/AzureMessagingScraper.cs +++ b/src/Promitor.Core.Scraping/ResourceTypes/AzureMessagingScraper.cs @@ -19,9 +19,9 @@ protected AzureMessagingScraper(ScraperConfiguration scraperConfiguration) protected override List EnrichMeasuredMetrics(TResourceDefinition resourceDefinition, List dimensionNames, List metricValues) { // Change Azure Monitor Dimension name to more representable value - foreach (var measuredMetric in metricValues.Where(metricValue => metricValue.DimensionNames.Any())) + foreach (var measuredMetric in metricValues.Where(metricValue => metricValue.Dimensions.Any())) { - measuredMetric.DimensionNames[0] = EntityNameLabel; // TODO + measuredMetric.Dimensions[0].Name = EntityNameLabel; // TODO } return metricValues; diff --git a/src/Promitor.Core.Scraping/ResourceTypes/DataShareScraper.cs b/src/Promitor.Core.Scraping/ResourceTypes/DataShareScraper.cs index 3816e9be2..94c8bb37d 100644 --- a/src/Promitor.Core.Scraping/ResourceTypes/DataShareScraper.cs +++ b/src/Promitor.Core.Scraping/ResourceTypes/DataShareScraper.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; using Microsoft.Extensions.Logging; using Promitor.Core.Contracts; using Promitor.Core.Contracts.ResourceTypes; @@ -53,15 +54,9 @@ protected override List DetermineMetricDimensions(string metricName, Dat protected override List EnrichMeasuredMetrics(DataShareResourceDefinition resourceDefinition, List dimensionNames, List metricValues) { // Change Azure Monitor dimension name to more representable value - foreach (var measuredMetric in metricValues) + foreach (var dimension in metricValues.SelectMany(measuredMetric => measuredMetric.Dimensions.Where(dimension => (dimension.Name == "ShareName" || dimension.Name == "ShareSubscriptionName")))) { - for (var i = 0; i < measuredMetric.DimensionNames.Count; i++) - { - if (measuredMetric.DimensionNames[i] == "ShareName" || measuredMetric.DimensionNames[i] == "ShareSubscriptionName") - { - measuredMetric.DimensionNames[i] = "share_name"; - } - } + dimension.Name = "share_name"; } return metricValues; diff --git a/src/Promitor.Core.Scraping/Scraper.cs b/src/Promitor.Core.Scraping/Scraper.cs index 60a0a79ef..09be2c757 100644 --- a/src/Promitor.Core.Scraping/Scraper.cs +++ b/src/Promitor.Core.Scraping/Scraper.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Threading.Tasks; using GuardNet; using Microsoft.Azure.Management.Monitor.Fluent.Models; @@ -142,7 +143,7 @@ private void LogMeasuredMetrics(ScrapeDefinition scrap { if (measuredMetric.IsDimensional) { - Logger.LogInformation("Found value {MetricValue} for metric {MetricName} with dimension values {DimensionValue} as part of the dimensions {DimensionName} with aggregation interval {AggregationInterval}", measuredMetric.Value, scrapeDefinition.PrometheusMetricDefinition.Name, measuredMetric.DimensionValues, measuredMetric.DimensionNames, aggregationInterval); + Logger.LogInformation("Found value {MetricValue} for metric {MetricName} with dimension values {DimensionValues} as part of the dimensions {DimensionNames} with aggregation interval {AggregationInterval}", measuredMetric.Value, scrapeDefinition.PrometheusMetricDefinition.Name, measuredMetric.Dimensions.Select(dimension => dimension.Value).ToList(), measuredMetric.Dimensions.Select(dimension => dimension.Name).ToList(), aggregationInterval); } else { diff --git a/src/Promitor.Core/Metrics/MeasuredMetric.cs b/src/Promitor.Core/Metrics/MeasuredMetric.cs index 058daaecc..497f8435b 100644 --- a/src/Promitor.Core/Metrics/MeasuredMetric.cs +++ b/src/Promitor.Core/Metrics/MeasuredMetric.cs @@ -14,14 +14,9 @@ public class MeasuredMetric public double? Value { get; } /// - /// Name of dimension for a metric + /// Measured dimensions. /// - public List DimensionNames { get; set; } - - /// - /// Name of dimension for a metric - /// - public List DimensionValues { get; } + public List Dimensions { get; } /// /// Indication whether or not the metric represents a dimension @@ -33,20 +28,18 @@ private MeasuredMetric(double? value) Value = value; } - private MeasuredMetric(double? value, List dimensionNames, List dimensionValues) + private MeasuredMetric(double? value, List dimensions) { - Guard.NotAny(dimensionNames, nameof(dimensionNames)); - Guard.NotAny(dimensionValues, nameof(dimensionValues)); + Guard.NotAny(dimensions, nameof(dimensions)); Value = value; IsDimensional = true; - DimensionNames = dimensionNames; - DimensionValues = dimensionValues; + Dimensions = dimensions; } /// - /// Create a measured metric without dimension + /// Create a measured metric without dimensions /// /// Measured metric value public static MeasuredMetric CreateWithoutDimension(double? value) @@ -55,7 +48,7 @@ public static MeasuredMetric CreateWithoutDimension(double? value) } /// - /// Create a measured metric for a given dimension + /// Create a measured metric for given dimensions /// /// Measured metric value /// List of names of dimensions that are being scraped @@ -66,27 +59,27 @@ public static MeasuredMetric CreateForDimension(double? value, List dime Guard.NotNull(timeseries, nameof(timeseries)); Guard.For(() => timeseries.Metadatavalues.Any() == false); - var dimensionValues = new List(); + var dimensions = new List(); foreach (var dimensionName in dimensionNames) { - dimensionValues.Add(timeseries.Metadatavalues.Single(metadataValue => metadataValue.Name?.Value.Equals(dimensionName, StringComparison.InvariantCultureIgnoreCase) == true).Value); + var dimensionValue = timeseries.Metadatavalues.Single(metadataValue => metadataValue.Name?.Value.Equals(dimensionName, StringComparison.InvariantCultureIgnoreCase) == true).Value; + dimensions.Add(new MeasuredMetricDimension(dimensionName, dimensionValue)); } - return CreateForDimension(value, dimensionNames, dimensionValues); + return new MeasuredMetric(value, dimensions); } /// - /// Create a measured metric for a given dimension + /// Create a measured metric for given dimensions when no metric information was found /// - /// Measured metric value /// List of names of dimensions that are being scraped - /// List of values of the dimension that are being scraped - public static MeasuredMetric CreateForDimension(double? value, List dimensionNames, List dimensionValues) + public static MeasuredMetric CreateForDimension(List dimensionNames) { Guard.NotAny(dimensionNames, nameof(dimensionNames)); - Guard.NotAny(dimensionValues, nameof(dimensionValues)); - return new MeasuredMetric(value, dimensionNames, dimensionValues); + var dimensions = dimensionNames.Select(name => new MeasuredMetricDimension(name, "unknown")).ToList(); + + return new MeasuredMetric(null, dimensions); } } } diff --git a/src/Promitor.Core/Metrics/MeasuredMetricDimension.cs b/src/Promitor.Core/Metrics/MeasuredMetricDimension.cs new file mode 100644 index 000000000..4be1da21a --- /dev/null +++ b/src/Promitor.Core/Metrics/MeasuredMetricDimension.cs @@ -0,0 +1,26 @@ +using System.Collections.Generic; +using GuardNet; + +namespace Promitor.Core.Metrics; + +public class MeasuredMetricDimension +{ + /// + /// Name of dimension + /// + public string Name { get; set; } + + /// + /// Value of dimension + /// + public string Value { get; } + + public MeasuredMetricDimension(string dimensionName, string dimensionValue) + { + Guard.NotNullOrWhitespace(dimensionName, nameof(dimensionName)); + Guard.NotNullOrWhitespace(dimensionValue, nameof(dimensionValue)); + + Value = dimensionValue; + Name = dimensionName; + } +} \ No newline at end of file diff --git a/src/Promitor.Integrations.Sinks.Prometheus/PrometheusScrapingEndpointMetricSink.cs b/src/Promitor.Integrations.Sinks.Prometheus/PrometheusScrapingEndpointMetricSink.cs index 491c47983..758f8502c 100644 --- a/src/Promitor.Integrations.Sinks.Prometheus/PrometheusScrapingEndpointMetricSink.cs +++ b/src/Promitor.Integrations.Sinks.Prometheus/PrometheusScrapingEndpointMetricSink.cs @@ -94,9 +94,9 @@ private Dictionary DetermineLabels(PrometheusMetricDefinition me if (measuredMetric.IsDimensional) { - for (var i = 0; i < measuredMetric.DimensionNames.Count; i++) + foreach (var dimension in measuredMetric.Dimensions) { - labels.Add(measuredMetric.DimensionNames[i].SanitizeForPrometheusLabelKey(), measuredMetric.DimensionValues[i]); + labels.Add(dimension.Name.SanitizeForPrometheusLabelKey(), dimension.Value); } } From 4cdd2c40fa5c7bccb62a6474c3f99841199b3b8b Mon Sep 17 00:00:00 2001 From: aaronweissler <46028218+aaronweissler@users.noreply.github.com> Date: Fri, 16 Sep 2022 12:42:10 +0200 Subject: [PATCH 20/53] Refactor method names to plural for dimensions --- src/Promitor.Core.Scraping/AzureMonitorScraper.cs | 2 +- .../ResourceTypes/StorageQueueScraper.cs | 2 +- src/Promitor.Core/Metrics/MeasuredMetric.cs | 6 +++--- .../AzureMonitorClient.cs | 2 +- .../Generators/ScrapeResultGenerator.cs | 2 +- .../Sinks/AtlassianStatuspageMetricSinkTests.cs | 8 ++++---- .../PrometheusScrapingEndpointMetricSinkTests.cs | 12 ++++++------ .../Metrics/Sinks/StatsDMetricSinkTests.cs | 6 +++--- 8 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/Promitor.Core.Scraping/AzureMonitorScraper.cs b/src/Promitor.Core.Scraping/AzureMonitorScraper.cs index 42ec90a36..94dbe7075 100644 --- a/src/Promitor.Core.Scraping/AzureMonitorScraper.cs +++ b/src/Promitor.Core.Scraping/AzureMonitorScraper.cs @@ -58,7 +58,7 @@ protected override async Task ScrapeResourceAsync(string subscript { Logger.LogWarning("No metric information found for metric {MetricName} with dimensions {MetricDimensions}. Details: {Details}", metricsNotFoundException.Name, metricsNotFoundException.Dimensions, metricsNotFoundException.Details); - var measuredMetric = dimensionNames.Any() ? MeasuredMetric.CreateForDimension(dimensionNames) : MeasuredMetric.CreateWithoutDimension(null); + var measuredMetric = dimensionNames.Any() ? MeasuredMetric.CreateForDimensions(dimensionNames) : MeasuredMetric.CreateWithoutDimensions(null); measuredMetrics.Add(measuredMetric); } diff --git a/src/Promitor.Core.Scraping/ResourceTypes/StorageQueueScraper.cs b/src/Promitor.Core.Scraping/ResourceTypes/StorageQueueScraper.cs index 81b3d2b53..eb3929b8a 100644 --- a/src/Promitor.Core.Scraping/ResourceTypes/StorageQueueScraper.cs +++ b/src/Promitor.Core.Scraping/ResourceTypes/StorageQueueScraper.cs @@ -51,7 +51,7 @@ protected override async Task ScrapeResourceAsync(string subscript var measuredMetrics = new List { - MeasuredMetric.CreateWithoutDimension(foundMetricValue) + MeasuredMetric.CreateWithoutDimensions(foundMetricValue) }; return new ScrapeResult(subscriptionId, scrapeDefinition.ResourceGroupName, resource.AccountName, resourceUri, measuredMetrics, labels); diff --git a/src/Promitor.Core/Metrics/MeasuredMetric.cs b/src/Promitor.Core/Metrics/MeasuredMetric.cs index 497f8435b..4807c2705 100644 --- a/src/Promitor.Core/Metrics/MeasuredMetric.cs +++ b/src/Promitor.Core/Metrics/MeasuredMetric.cs @@ -42,7 +42,7 @@ private MeasuredMetric(double? value, List dimensions) /// Create a measured metric without dimensions /// /// Measured metric value - public static MeasuredMetric CreateWithoutDimension(double? value) + public static MeasuredMetric CreateWithoutDimensions(double? value) { return new MeasuredMetric(value); } @@ -53,7 +53,7 @@ public static MeasuredMetric CreateWithoutDimension(double? value) /// Measured metric value /// List of names of dimensions that are being scraped /// Timeseries representing one of the dimensions - public static MeasuredMetric CreateForDimension(double? value, List dimensionNames, TimeSeriesElement timeseries) + public static MeasuredMetric CreateForDimensions(double? value, List dimensionNames, TimeSeriesElement timeseries) { Guard.NotAny(dimensionNames, nameof(dimensionNames)); Guard.NotNull(timeseries, nameof(timeseries)); @@ -73,7 +73,7 @@ public static MeasuredMetric CreateForDimension(double? value, List dime /// Create a measured metric for given dimensions when no metric information was found /// /// List of names of dimensions that are being scraped - public static MeasuredMetric CreateForDimension(List dimensionNames) + public static MeasuredMetric CreateForDimensions(List dimensionNames) { Guard.NotAny(dimensionNames, nameof(dimensionNames)); diff --git a/src/Promitor.Integrations.AzureMonitor/AzureMonitorClient.cs b/src/Promitor.Integrations.AzureMonitor/AzureMonitorClient.cs index 9c8e0cac2..2d26ecb6b 100644 --- a/src/Promitor.Integrations.AzureMonitor/AzureMonitorClient.cs +++ b/src/Promitor.Integrations.AzureMonitor/AzureMonitorClient.cs @@ -109,7 +109,7 @@ public async Task> QueryMetricAsync(string metricName, List // Get the metric value according to the requested aggregation type var requestedMetricAggregate = InterpretMetricValue(aggregationType, mostRecentMetricValue); - var measuredMetric = metricDimensions.Any() ? MeasuredMetric.CreateForDimension(requestedMetricAggregate, metricDimensions, timeseries) : MeasuredMetric.CreateWithoutDimension(requestedMetricAggregate); + var measuredMetric = metricDimensions.Any() ? MeasuredMetric.CreateForDimensions(requestedMetricAggregate, metricDimensions, timeseries) : MeasuredMetric.CreateWithoutDimensions(requestedMetricAggregate); measuredMetrics.Add(measuredMetric); } diff --git a/src/Promitor.Tests.Unit/Generators/ScrapeResultGenerator.cs b/src/Promitor.Tests.Unit/Generators/ScrapeResultGenerator.cs index d1213f278..e46f3b72c 100644 --- a/src/Promitor.Tests.Unit/Generators/ScrapeResultGenerator.cs +++ b/src/Promitor.Tests.Unit/Generators/ScrapeResultGenerator.cs @@ -21,7 +21,7 @@ public static ScrapeResult GenerateFromMetric(MeasuredMetric measuredMetric) public static ScrapeResult Generate(double metricValue) { - return GenerateFromMetric(MeasuredMetric.CreateWithoutDimension(metricValue)); + return GenerateFromMetric(MeasuredMetric.CreateWithoutDimensions(metricValue)); } } } \ No newline at end of file diff --git a/src/Promitor.Tests.Unit/Metrics/Sinks/AtlassianStatuspageMetricSinkTests.cs b/src/Promitor.Tests.Unit/Metrics/Sinks/AtlassianStatuspageMetricSinkTests.cs index be3136680..4e180de85 100644 --- a/src/Promitor.Tests.Unit/Metrics/Sinks/AtlassianStatuspageMetricSinkTests.cs +++ b/src/Promitor.Tests.Unit/Metrics/Sinks/AtlassianStatuspageMetricSinkTests.cs @@ -40,7 +40,7 @@ public async Task ReportMetricAsync_InputDoesNotContainMetricDescription_Succeed // Arrange var metricName = BogusGenerator.Name.FirstName(); var metricValue = BogusGenerator.Random.Double(); - var measuredMetric = MeasuredMetric.CreateWithoutDimension(metricValue); + var measuredMetric = MeasuredMetric.CreateWithoutDimensions(metricValue); var scrapeResult = ScrapeResultGenerator.GenerateFromMetric(measuredMetric); var systemMetricConfigOptions = BogusAtlassianStatuspageMetricSinkConfigurationGenerator.GetSinkConfiguration(); var atlassianStatuspageClientMock = new Mock(); @@ -74,7 +74,7 @@ public async Task ReportMetricAsync_GetsValidInputWithMetricValueAndPromitorToSy var systemMetricId = BogusGenerator.Name.FirstName(); var metricDescription = BogusGenerator.Lorem.Sentence(); var metricValue = BogusGenerator.Random.Double(); - var measuredMetric = MeasuredMetric.CreateWithoutDimension(metricValue); + var measuredMetric = MeasuredMetric.CreateWithoutDimensions(metricValue); var scrapeResult = ScrapeResultGenerator.GenerateFromMetric(measuredMetric); var systemMetricConfigOptions = BogusAtlassianStatuspageMetricSinkConfigurationGenerator.GetSinkConfiguration(systemMetricId: systemMetricId, promitorMetricName: promitorMetricName); var atlassianStatuspageClientMock = new Mock(); @@ -97,7 +97,7 @@ public async Task ReportMetricAsync_GetsValidInputWithoutMetricValueButWithPromi var metricDescription = BogusGenerator.Lorem.Sentence(); double? metricValue = null; // ReSharper disable once ExpressionIsAlwaysNull - var measuredMetric = MeasuredMetric.CreateWithoutDimension(metricValue); + var measuredMetric = MeasuredMetric.CreateWithoutDimensions(metricValue); var scrapeResult = ScrapeResultGenerator.GenerateFromMetric(measuredMetric); var systemMetricConfigOptions = BogusAtlassianStatuspageMetricSinkConfigurationGenerator.GetSinkConfiguration(systemMetricId: systemMetricId, promitorMetricName: promitorMetricName); var atlassianStatuspageClientMock = new Mock(); @@ -120,7 +120,7 @@ public async Task ReportMetricAsync_GetsValidInputWithPromitorMetricThatIsNotMap var metricDescription = BogusGenerator.Lorem.Sentence(); double? metricValue = null; // ReSharper disable once ExpressionIsAlwaysNull - var measuredMetric = MeasuredMetric.CreateWithoutDimension(metricValue); + var measuredMetric = MeasuredMetric.CreateWithoutDimensions(metricValue); var scrapeResult = ScrapeResultGenerator.GenerateFromMetric(measuredMetric); var systemMetricConfigOptions = BogusAtlassianStatuspageMetricSinkConfigurationGenerator.GetSinkConfiguration(promitorMetricName: promitorMetricName); var atlassianStatuspageClientMock = new Mock(); diff --git a/src/Promitor.Tests.Unit/Metrics/Sinks/PrometheusScrapingEndpointMetricSinkTests.cs b/src/Promitor.Tests.Unit/Metrics/Sinks/PrometheusScrapingEndpointMetricSinkTests.cs index fba4a5391..948267455 100644 --- a/src/Promitor.Tests.Unit/Metrics/Sinks/PrometheusScrapingEndpointMetricSinkTests.cs +++ b/src/Promitor.Tests.Unit/Metrics/Sinks/PrometheusScrapingEndpointMetricSinkTests.cs @@ -112,8 +112,8 @@ public async Task ReportMetricAsync_GetsValidInputWithTwoMetricValues_Successful var metricDescription = BogusGenerator.Lorem.Sentence(); var firstMetricValue = BogusGenerator.Random.Double(); var secondMetricValue = BogusGenerator.Random.Double(); - var firstMetric = MeasuredMetric.CreateWithoutDimension(firstMetricValue); - var secondMetric = MeasuredMetric.CreateWithoutDimension(secondMetricValue); + var firstMetric = MeasuredMetric.CreateWithoutDimensions(firstMetricValue); + var secondMetric = MeasuredMetric.CreateWithoutDimensions(secondMetricValue); var scrapeResult = ScrapeResultGenerator.GenerateFromMetric(firstMetric); scrapeResult.MetricValues.Add(secondMetric); var metricsDeclarationProvider = CreateMetricsDeclarationProvider(metricName); @@ -146,8 +146,8 @@ public async Task ReportMetricAsync_GetsValidInputWithTwoMetricValuesOfWhichOneI { Metadatavalues = new List { new MetadataValue(name: new LocalizableString(dimensionName), value: dimensionValue) } }; - var firstMetric = MeasuredMetric.CreateForDimension(firstMetricValue, new List{ dimensionName.ToUpper() }, timeSeries); - var secondMetric = MeasuredMetric.CreateWithoutDimension(secondMetricValue); + var firstMetric = MeasuredMetric.CreateForDimensions(firstMetricValue, new List{ dimensionName.ToUpper() }, timeSeries); + var secondMetric = MeasuredMetric.CreateWithoutDimensions(secondMetricValue); var scrapeResult = ScrapeResultGenerator.GenerateFromMetric(firstMetric); scrapeResult.MetricValues.Add(secondMetric); var metricsDeclarationProvider = CreateMetricsDeclarationProvider(metricName); @@ -228,7 +228,7 @@ public async Task ReportMetricAsync_GetsValidInputWithoutMetricValue_Successfull var metricDescription = BogusGenerator.Lorem.Sentence(); double? metricValue = null; // ReSharper disable once ExpressionIsAlwaysNull - var measuredMetric = MeasuredMetric.CreateWithoutDimension(metricValue); + var measuredMetric = MeasuredMetric.CreateWithoutDimensions(metricValue); var scrapeResult = ScrapeResultGenerator.GenerateFromMetric(measuredMetric); var metricsDeclarationProvider = CreateMetricsDeclarationProvider(metricName); var prometheusConfiguration = CreatePrometheusConfiguration(metricUnavailableValue: expectedDefaultValue); @@ -258,7 +258,7 @@ public async Task ReportMetricAsync_GetsValidInputWithOneDimensions_Successfully { Metadatavalues = new List { new MetadataValue(name: new LocalizableString(dimensionName), value: dimensionValue) } }; - var measuredMetric = MeasuredMetric.CreateForDimension(metricValue, new List{ dimensionName.ToUpper() }, timeSeries); + var measuredMetric = MeasuredMetric.CreateForDimensions(metricValue, new List{ dimensionName.ToUpper() }, timeSeries); var scrapeResult = ScrapeResultGenerator.GenerateFromMetric(measuredMetric); var metricsDeclarationProvider = CreateMetricsDeclarationProvider(metricName); var prometheusConfiguration = CreatePrometheusConfiguration(); diff --git a/src/Promitor.Tests.Unit/Metrics/Sinks/StatsDMetricSinkTests.cs b/src/Promitor.Tests.Unit/Metrics/Sinks/StatsDMetricSinkTests.cs index c63c1db0b..6f196fc69 100644 --- a/src/Promitor.Tests.Unit/Metrics/Sinks/StatsDMetricSinkTests.cs +++ b/src/Promitor.Tests.Unit/Metrics/Sinks/StatsDMetricSinkTests.cs @@ -39,7 +39,7 @@ public async Task ReportMetricAsync_InputDoesNotContainMetricDescription_Succeed // Arrange var metricName = BogusGenerator.Name.FirstName(); var metricValue = BogusGenerator.Random.Double(); - var measuredMetric = MeasuredMetric.CreateWithoutDimension(metricValue); + var measuredMetric = MeasuredMetric.CreateWithoutDimensions(metricValue); var scrapeResult = ScrapeResultGenerator.GenerateFromMetric(measuredMetric); var statsDPublisherMock = new Mock(); var metricSink = new StatsdMetricSink(statsDPublisherMock.Object, NullLogger.Instance); @@ -70,7 +70,7 @@ public async Task ReportMetricAsync_GetsValidInputWithMetricValue_SuccessfullyWr var metricName = BogusGenerator.Name.FirstName(); var metricDescription = BogusGenerator.Lorem.Sentence(); var metricValue = BogusGenerator.Random.Double(); - var measuredMetric = MeasuredMetric.CreateWithoutDimension(metricValue); + var measuredMetric = MeasuredMetric.CreateWithoutDimensions(metricValue); var scrapeResult = ScrapeResultGenerator.GenerateFromMetric(measuredMetric); var statsDPublisherMock = new Mock(); var metricSink = new StatsdMetricSink(statsDPublisherMock.Object, NullLogger.Instance); @@ -91,7 +91,7 @@ public async Task ReportMetricAsync_GetsValidInputWithoutMetricValue_Successfull var metricDescription = BogusGenerator.Lorem.Sentence(); double? metricValue = null; // ReSharper disable once ExpressionIsAlwaysNull - var measuredMetric = MeasuredMetric.CreateWithoutDimension(metricValue); + var measuredMetric = MeasuredMetric.CreateWithoutDimensions(metricValue); var scrapeResult = ScrapeResultGenerator.GenerateFromMetric(measuredMetric); var statsDPublisherMock = new Mock(); var metricSink = new StatsdMetricSink(statsDPublisherMock.Object, NullLogger.Instance); From 171392d3a71e8b90804d2a20ca10c4b262db063d Mon Sep 17 00:00:00 2001 From: aaronweissler <46028218+aaronweissler@users.noreply.github.com> Date: Fri, 16 Sep 2022 13:28:42 +0200 Subject: [PATCH 21/53] Removed unused using directives --- .../ResourceTypes/EventHubsMetricValidator.cs | 3 +-- .../ResourceTypes/ServiceBusNamespaceMetricValidator.cs | 3 +-- src/Promitor.Core/Metrics/MeasuredMetricDimension.cs | 3 +-- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/src/Promitor.Agents.Scraper/Validation/MetricDefinitions/ResourceTypes/EventHubsMetricValidator.cs b/src/Promitor.Agents.Scraper/Validation/MetricDefinitions/ResourceTypes/EventHubsMetricValidator.cs index b37cf9c5c..ecb3bf4fe 100644 --- a/src/Promitor.Agents.Scraper/Validation/MetricDefinitions/ResourceTypes/EventHubsMetricValidator.cs +++ b/src/Promitor.Agents.Scraper/Validation/MetricDefinitions/ResourceTypes/EventHubsMetricValidator.cs @@ -1,5 +1,4 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; using GuardNet; using Promitor.Core.Scraping.Configuration.Model.Metrics; diff --git a/src/Promitor.Agents.Scraper/Validation/MetricDefinitions/ResourceTypes/ServiceBusNamespaceMetricValidator.cs b/src/Promitor.Agents.Scraper/Validation/MetricDefinitions/ResourceTypes/ServiceBusNamespaceMetricValidator.cs index c4e74d754..a0eb20b95 100644 --- a/src/Promitor.Agents.Scraper/Validation/MetricDefinitions/ResourceTypes/ServiceBusNamespaceMetricValidator.cs +++ b/src/Promitor.Agents.Scraper/Validation/MetricDefinitions/ResourceTypes/ServiceBusNamespaceMetricValidator.cs @@ -1,5 +1,4 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; using GuardNet; using Promitor.Core.Scraping.Configuration.Model.Metrics; diff --git a/src/Promitor.Core/Metrics/MeasuredMetricDimension.cs b/src/Promitor.Core/Metrics/MeasuredMetricDimension.cs index 4be1da21a..1a106d06e 100644 --- a/src/Promitor.Core/Metrics/MeasuredMetricDimension.cs +++ b/src/Promitor.Core/Metrics/MeasuredMetricDimension.cs @@ -1,5 +1,4 @@ -using System.Collections.Generic; -using GuardNet; +using GuardNet; namespace Promitor.Core.Metrics; From 839de64ca1b9d6a3a94b2d4c90d1da783d24fca6 Mon Sep 17 00:00:00 2001 From: aaronweissler <46028218+aaronweissler@users.noreply.github.com> Date: Mon, 19 Sep 2022 09:04:47 +0200 Subject: [PATCH 22/53] Fix changelog linting errors --- changelog/content/experimental/unreleased.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/changelog/content/experimental/unreleased.md b/changelog/content/experimental/unreleased.md index aa54ba73c..6f9ebb1a1 100644 --- a/changelog/content/experimental/unreleased.md +++ b/changelog/content/experimental/unreleased.md @@ -5,10 +5,12 @@ version: --- #### Scraper - + - {{% tag added %}} Provide Azure Log Analytics scraper ([docs](https://docs.promitor.io/v2.9/scraping/providers/log-analytics/) | [#2132](https://github.com/tomkerkhove/promitor/pull/2132)) - {{% tag added %}} Provide capability to use multiple metric dimensions by using new configuration property `dimensions` ([#1820](https://github.com/tomkerkhove/promitor/issues/1820)) +- {{% tag added %}} Provide capability to use multiple metric dimensions by using new configuration property `dimensions` + ([#1820](https://github.com/tomkerkhove/promitor/issues/1820)) - {{% tag deprecated %}} Old configuration property for metric dimension `dimension` ([#1820](https://github.com/tomkerkhove/promitor/issues/1820)) #### Resource Discovery From 4e48149b25b54a1f2319d9d152e827f160c1a3e7 Mon Sep 17 00:00:00 2001 From: aaronweissler <46028218+aaronweissler@users.noreply.github.com> Date: Thu, 22 Sep 2022 14:39:40 +0200 Subject: [PATCH 23/53] Add support for YamlSequenceNodes in Deserializers --- .../Configuration/Serialization/Deserializer.cs | 7 ++++++- .../Serialization/FieldDeserializationInfo.cs | 4 ++-- .../FieldDeserializationInfoBuilder.cs | 4 ++-- .../Configuration/Serialization/IDeserializer.cs | 15 +-------------- .../Core/AzureMetricConfigurationDeserializer.cs | 16 +++++++++------- .../DeserializerTests/DeserializationTests.cs | 8 ++++---- .../MapUsingDeserializerTests.cs | 4 ++-- .../AzureMetricConfigurationDeserializerTests.cs | 2 +- .../v1/Core/MetricDefaultsDeserializerTests.cs | 4 ++-- .../v1/Core/MetricDefinitionDeserializerTests.cs | 4 ++-- .../Serialization/v1/Core/V1DeserializerTests.cs | 8 ++++---- .../Providers/StorageQueueDeserializerTests.cs | 2 +- 12 files changed, 36 insertions(+), 42 deletions(-) diff --git a/src/Promitor.Core.Scraping/Configuration/Serialization/Deserializer.cs b/src/Promitor.Core.Scraping/Configuration/Serialization/Deserializer.cs index 65f1e74e6..07463f3d3 100644 --- a/src/Promitor.Core.Scraping/Configuration/Serialization/Deserializer.cs +++ b/src/Promitor.Core.Scraping/Configuration/Serialization/Deserializer.cs @@ -116,7 +116,12 @@ private static object GetFieldValue( if (fieldDeserializationInfo.Deserializer != null) { - return fieldDeserializationInfo.Deserializer.DeserializeObject((YamlMappingNode)fieldNodePair.Value, errorReporter); + return fieldNodePair.Value switch + { + YamlMappingNode node => fieldDeserializationInfo.Deserializer.Deserialize(node, errorReporter), + YamlSequenceNode node => fieldDeserializationInfo.Deserializer.Deserialize(node, errorReporter), + _ => null + }; } var propertyType = Nullable.GetUnderlyingType(fieldDeserializationInfo.PropertyInfo.PropertyType) ?? fieldDeserializationInfo.PropertyInfo.PropertyType; diff --git a/src/Promitor.Core.Scraping/Configuration/Serialization/FieldDeserializationInfo.cs b/src/Promitor.Core.Scraping/Configuration/Serialization/FieldDeserializationInfo.cs index 653aa39c2..8ffe4ba8e 100644 --- a/src/Promitor.Core.Scraping/Configuration/Serialization/FieldDeserializationInfo.cs +++ b/src/Promitor.Core.Scraping/Configuration/Serialization/FieldDeserializationInfo.cs @@ -27,7 +27,7 @@ public FieldDeserializationInfo( bool isRequired, object defaultValue, Func, IErrorReporter, object> customMapperFunc, - IDeserializer deserializer, + IDeserializer deserializer, IReadOnlyCollection validators) { YamlFieldName = GetName(propertyInfo); @@ -67,7 +67,7 @@ public FieldDeserializationInfo( /// /// Gets a deserializer to use when deserializing the field. /// - public IDeserializer Deserializer { get; } + public IDeserializer Deserializer { get; } /// /// Gets the custom validators for the field. diff --git a/src/Promitor.Core.Scraping/Configuration/Serialization/FieldDeserializationInfoBuilder.cs b/src/Promitor.Core.Scraping/Configuration/Serialization/FieldDeserializationInfoBuilder.cs index d3cd42e66..b1e87c26b 100644 --- a/src/Promitor.Core.Scraping/Configuration/Serialization/FieldDeserializationInfoBuilder.cs +++ b/src/Promitor.Core.Scraping/Configuration/Serialization/FieldDeserializationInfoBuilder.cs @@ -17,7 +17,7 @@ public class FieldDeserializationInfoBuilder : IFieldDeseriali private bool _isRequired; private object _defaultValue; private Func, IErrorReporter, object> _customMapperFunc; - private IDeserializer _deserializer; + private IDeserializer _deserializer; /// /// Sets the expression that defines the property to map. @@ -76,7 +76,7 @@ public FieldDeserializationInfoBuilder MapUsing(Func /// The deserializer. /// The builder. - public FieldDeserializationInfoBuilder MapUsingDeserializer(IDeserializer deserializer) + public FieldDeserializationInfoBuilder MapUsingDeserializer(IDeserializer deserializer) { _deserializer = deserializer; diff --git a/src/Promitor.Core.Scraping/Configuration/Serialization/IDeserializer.cs b/src/Promitor.Core.Scraping/Configuration/Serialization/IDeserializer.cs index 6096f159c..09f583bdb 100644 --- a/src/Promitor.Core.Scraping/Configuration/Serialization/IDeserializer.cs +++ b/src/Promitor.Core.Scraping/Configuration/Serialization/IDeserializer.cs @@ -3,25 +3,12 @@ namespace Promitor.Core.Scraping.Configuration.Serialization { - /// - /// An object that can deserialize a yaml node into an object. - /// - public interface IDeserializer - { - /// - /// Deserializes the specified node. - /// - /// The node to deserialize. - /// Used to report deserialization errors. - /// The deserialized object. - object DeserializeObject(YamlMappingNode node, IErrorReporter errorReporter); - } /// /// An object that can deserialize a yaml node into an object. /// /// The type of object that can be deserialized. - public interface IDeserializer : IDeserializer where TObject: new() + public interface IDeserializer { /// /// Deserializes the specified node. diff --git a/src/Promitor.Core.Scraping/Configuration/Serialization/v1/Core/AzureMetricConfigurationDeserializer.cs b/src/Promitor.Core.Scraping/Configuration/Serialization/v1/Core/AzureMetricConfigurationDeserializer.cs index 522a90c0d..bf9a8612e 100644 --- a/src/Promitor.Core.Scraping/Configuration/Serialization/v1/Core/AzureMetricConfigurationDeserializer.cs +++ b/src/Promitor.Core.Scraping/Configuration/Serialization/v1/Core/AzureMetricConfigurationDeserializer.cs @@ -21,7 +21,8 @@ public AzureMetricConfigurationDeserializer(IDeserializer dim Map(config => config.Aggregation) .IsRequired() .MapUsingDeserializer(aggregationDeserializer); - IgnoreField(MultipleDimensionsTag); + Map(config => config.Dimensions) + .MapUsingDeserializer(dimensionDeserializer); IgnoreField(SingleDimensionTag); _dimensionDeserializer = dimensionDeserializer; @@ -30,16 +31,17 @@ public AzureMetricConfigurationDeserializer(IDeserializer dim public override AzureMetricConfigurationV1 Deserialize(YamlMappingNode node, IErrorReporter errorReporter) { var azureMetricConfiguration = base.Deserialize(node, errorReporter); - - if (node.Children.TryGetValue(MultipleDimensionsTag, out var multipleDimensionsNode)) - { - azureMetricConfiguration.Dimensions = _dimensionDeserializer.Deserialize((YamlSequenceNode)multipleDimensionsNode, errorReporter); - } // backwards compatibility: if old tag "dimension" is used, a list containing only the one MetricDimension is created - else if (node.Children.TryGetValue(SingleDimensionTag, out var singleDimensionNode)) + if (node.Children.TryGetValue(SingleDimensionTag, out var singleDimensionNode)) { errorReporter.ReportWarning(node, "Usage of 'dimension' is deprecated in favor of using 'dimensions'."); + if (node.Children.TryGetValue(MultipleDimensionsTag, out var multipleDimensionsNode)) + { + errorReporter.ReportWarning(node, "Both 'dimensions' and 'dimension' are defined. " + + "Only value from 'dimensions' will be used."); + return azureMetricConfiguration; + } azureMetricConfiguration.Dimensions = new List{ _dimensionDeserializer.Deserialize((YamlMappingNode)singleDimensionNode, errorReporter) }; } diff --git a/src/Promitor.Tests.Unit/Serialization/DeserializerTests/DeserializationTests.cs b/src/Promitor.Tests.Unit/Serialization/DeserializerTests/DeserializationTests.cs index 0861c9b97..5ff8e3903 100644 --- a/src/Promitor.Tests.Unit/Serialization/DeserializerTests/DeserializationTests.cs +++ b/src/Promitor.Tests.Unit/Serialization/DeserializerTests/DeserializationTests.cs @@ -13,7 +13,7 @@ public class DeserializationTests : UnitTest private static readonly TimeSpan defaultInterval = TimeSpan.FromMinutes(5); private readonly Mock _errorReporter = new Mock(); - private readonly Mock _childDeserializer = new Mock(); + private readonly Mock> _childDeserializer = new Mock>(); private readonly RegistrationConfigDeserializer _deserializer; public DeserializationTests() @@ -209,7 +209,7 @@ public void Deserialize_RequiredChildObject_CanUseChildDeserializer() childProperty: 123"); var child = new ChildConfig(); _childDeserializer.Setup( - d => d.DeserializeObject((YamlMappingNode)node.Children["child"], _errorReporter.Object)).Returns(child); + d => d.Deserialize((YamlMappingNode)node.Children["child"], _errorReporter.Object)).Returns(child); // Act var result = _deserializer.Deserialize(node, _errorReporter.Object); @@ -227,7 +227,7 @@ public void Deserialize_OptionalChildObject_CanUseChildDeserializer() childProperty: 123"); var child = new ChildConfig(); _childDeserializer.Setup( - d => d.DeserializeObject((YamlMappingNode)node.Children["optionalChild"], _errorReporter.Object)).Returns(child); + d => d.Deserialize((YamlMappingNode)node.Children["optionalChild"], _errorReporter.Object)).Returns(child); // Act var result = _deserializer.Deserialize(node, _errorReporter.Object); @@ -259,7 +259,7 @@ public class ChildConfig private class RegistrationConfigDeserializer: Deserializer { - public RegistrationConfigDeserializer(IDeserializer childDeserializer) : base(NullLogger.Instance) + public RegistrationConfigDeserializer(IDeserializer childDeserializer) : base(NullLogger.Instance) { Map(t => t.Name).IsRequired(); Map(t => t.Age).IsRequired(); diff --git a/src/Promitor.Tests.Unit/Serialization/FieldDeserializationInfoBuilderTests/MapUsingDeserializerTests.cs b/src/Promitor.Tests.Unit/Serialization/FieldDeserializationInfoBuilderTests/MapUsingDeserializerTests.cs index 20277d817..7d0110b4d 100644 --- a/src/Promitor.Tests.Unit/Serialization/FieldDeserializationInfoBuilderTests/MapUsingDeserializerTests.cs +++ b/src/Promitor.Tests.Unit/Serialization/FieldDeserializationInfoBuilderTests/MapUsingDeserializerTests.cs @@ -18,7 +18,7 @@ public MapUsingDeserializerTests() public void MapUsingDeserializer_SetsDeserializer() { // Arrange - var deserializer = Mock.Of(); + var deserializer = Mock.Of>(); // Act _builder.MapUsingDeserializer(deserializer); @@ -32,7 +32,7 @@ public void MapUsingDeserializer_SetsDeserializer() public void MapUsingDeserializer_ReturnsBuilder() { // Arrange - var deserializer = Mock.Of(); + var deserializer = Mock.Of>(); // Act var result = _builder.MapUsingDeserializer(deserializer); diff --git a/src/Promitor.Tests.Unit/Serialization/v1/Core/AzureMetricConfigurationDeserializerTests.cs b/src/Promitor.Tests.Unit/Serialization/v1/Core/AzureMetricConfigurationDeserializerTests.cs index 3311ab64e..87a8324aa 100644 --- a/src/Promitor.Tests.Unit/Serialization/v1/Core/AzureMetricConfigurationDeserializerTests.cs +++ b/src/Promitor.Tests.Unit/Serialization/v1/Core/AzureMetricConfigurationDeserializerTests.cs @@ -89,7 +89,7 @@ public void Deserialize_AggregationSupplied_UsesDeserializer() var aggregation = new MetricAggregationV1(); _aggregationDeserializer.Setup( - d => d.DeserializeObject(aggregationNode, _errorReporter.Object)).Returns(aggregation); + d => d.Deserialize(aggregationNode, _errorReporter.Object)).Returns(aggregation); // Act var config = _deserializer.Deserialize(node, _errorReporter.Object); diff --git a/src/Promitor.Tests.Unit/Serialization/v1/Core/MetricDefaultsDeserializerTests.cs b/src/Promitor.Tests.Unit/Serialization/v1/Core/MetricDefaultsDeserializerTests.cs index db9058c23..d388ee386 100644 --- a/src/Promitor.Tests.Unit/Serialization/v1/Core/MetricDefaultsDeserializerTests.cs +++ b/src/Promitor.Tests.Unit/Serialization/v1/Core/MetricDefaultsDeserializerTests.cs @@ -38,7 +38,7 @@ public void Deserialize_AggregationPresent_UsesAggregationDeserializer() var aggregationNode = (YamlMappingNode)node.Children["aggregation"]; var aggregation = new AggregationV1(); - _aggregationDeserializer.Setup(d => d.DeserializeObject(aggregationNode, _errorReporter.Object)).Returns(aggregation); + _aggregationDeserializer.Setup(d => d.Deserialize(aggregationNode, _errorReporter.Object)).Returns(aggregation); // Act var defaults = _deserializer.Deserialize(node, _errorReporter.Object); @@ -76,7 +76,7 @@ public void Deserialize_ScrapingPresent_UsesScrapingDeserializer() var scrapingNode = (YamlMappingNode)node.Children["scraping"]; var scraping = new ScrapingV1(); - _scrapingDeserializer.Setup(d => d.DeserializeObject(scrapingNode, _errorReporter.Object)).Returns(scraping); + _scrapingDeserializer.Setup(d => d.Deserialize(scrapingNode, _errorReporter.Object)).Returns(scraping); // Act var defaults = _deserializer.Deserialize(node, _errorReporter.Object); diff --git a/src/Promitor.Tests.Unit/Serialization/v1/Core/MetricDefinitionDeserializerTests.cs b/src/Promitor.Tests.Unit/Serialization/v1/Core/MetricDefinitionDeserializerTests.cs index fc03ab0f8..3c24d247a 100644 --- a/src/Promitor.Tests.Unit/Serialization/v1/Core/MetricDefinitionDeserializerTests.cs +++ b/src/Promitor.Tests.Unit/Serialization/v1/Core/MetricDefinitionDeserializerTests.cs @@ -176,7 +176,7 @@ public void Deserialize_AzureMetricConfigurationSupplied_UsesDeserializer() var configurationNode = (YamlMappingNode)node.Children["azureMetricConfiguration"]; var configuration = new AzureMetricConfigurationV1(); - _azureMetricConfigurationDeserializer.Setup(d => d.DeserializeObject(configurationNode, _errorReporter.Object)).Returns(configuration); + _azureMetricConfigurationDeserializer.Setup(d => d.Deserialize(configurationNode, _errorReporter.Object)).Returns(configuration); // Act var definition = _deserializer.Deserialize(node, _errorReporter.Object); @@ -270,7 +270,7 @@ public void Deserialize_ScrapingSupplied_UsesDeserializer() var scrapingNode = (YamlMappingNode)node.Children["scraping"]; var scraping = new ScrapingV1(); - _scrapingDeserializer.Setup(d => d.DeserializeObject(scrapingNode, _errorReporter.Object)).Returns(scraping); + _scrapingDeserializer.Setup(d => d.Deserialize(scrapingNode, _errorReporter.Object)).Returns(scraping); // Act var definition = _deserializer.Deserialize(node, _errorReporter.Object); diff --git a/src/Promitor.Tests.Unit/Serialization/v1/Core/V1DeserializerTests.cs b/src/Promitor.Tests.Unit/Serialization/v1/Core/V1DeserializerTests.cs index 9c0b0436a..220d2806d 100644 --- a/src/Promitor.Tests.Unit/Serialization/v1/Core/V1DeserializerTests.cs +++ b/src/Promitor.Tests.Unit/Serialization/v1/Core/V1DeserializerTests.cs @@ -89,7 +89,7 @@ public void Deserialize_AzureMetadata_UsesMetadataDeserializer() var yamlNode = YamlUtils.CreateYamlNode(config); var azureMetadata = new AzureMetadataV1(); _metadataDeserializer.Setup( - d => d.DeserializeObject(It.IsAny(), It.IsAny())).Returns(azureMetadata); + d => d.Deserialize(It.IsAny(), It.IsAny())).Returns(azureMetadata); // Act var declaration = _deserializer.Deserialize(yamlNode, _errorReporter.Object); @@ -104,7 +104,7 @@ public void Deserialize_AzureMetadataNotSupplied_SetsMetadataNull() // Arrange var yamlNode = YamlUtils.CreateYamlNode("version: v1"); _metadataDeserializer.Setup( - d => d.DeserializeObject(It.IsAny(), It.IsAny())).Returns(new AzureMetadataV1()); + d => d.Deserialize(It.IsAny(), It.IsAny())).Returns(new AzureMetadataV1()); // Act var declaration = _deserializer.Deserialize(yamlNode, _errorReporter.Object); @@ -125,7 +125,7 @@ public void Deserialize_MetricDefaults_UsesDefaultsDeserializer() var yamlNode = YamlUtils.CreateYamlNode(config); var metricDefaults = new MetricDefaultsV1(); _defaultsDeserializer.Setup( - d => d.DeserializeObject(It.IsAny(), It.IsAny())).Returns(metricDefaults); + d => d.Deserialize(It.IsAny(), It.IsAny())).Returns(metricDefaults); // Act var declaration = _deserializer.Deserialize(yamlNode, _errorReporter.Object); @@ -142,7 +142,7 @@ public void Deserialize_MetricDefaultsNotSupplied_SetsDefaultsNull() @"version: v1"; var yamlNode = YamlUtils.CreateYamlNode(config); _defaultsDeserializer.Setup( - d => d.DeserializeObject(It.IsAny(), It.IsAny())).Returns(new MetricDefaultsV1()); + d => d.Deserialize(It.IsAny(), It.IsAny())).Returns(new MetricDefaultsV1()); // Act var declaration = _deserializer.Deserialize(yamlNode, _errorReporter.Object); diff --git a/src/Promitor.Tests.Unit/Serialization/v1/Providers/StorageQueueDeserializerTests.cs b/src/Promitor.Tests.Unit/Serialization/v1/Providers/StorageQueueDeserializerTests.cs index d7db69aca..f0f986e8c 100644 --- a/src/Promitor.Tests.Unit/Serialization/v1/Providers/StorageQueueDeserializerTests.cs +++ b/src/Promitor.Tests.Unit/Serialization/v1/Providers/StorageQueueDeserializerTests.cs @@ -98,7 +98,7 @@ public void Deserialize_SasTokenSupplied_UsesDeserializer() var sasTokenNode = (YamlMappingNode)node.Children["sasToken"]; var secret = new SecretV1(); - _secretDeserializer.Setup(d => d.DeserializeObject(sasTokenNode, _errorReporter.Object)).Returns(secret); + _secretDeserializer.Setup(d => d.Deserialize(sasTokenNode, _errorReporter.Object)).Returns(secret); // Act var resource = _deserializer.Deserialize(node, _errorReporter.Object); From edc0e471a3e16a24e38196806e870addcb215afd Mon Sep 17 00:00:00 2001 From: aaronweissler <46028218+aaronweissler@users.noreply.github.com> Date: Fri, 23 Sep 2022 12:39:57 +0200 Subject: [PATCH 24/53] Re-add Dimension field and move consolidation --- .../AzureMetricConfigurationValidator.cs | 6 ++++ .../AzureMonitorScraper.cs | 17 +++++++--- .../Model/AzureMetricConfiguration.cs | 8 ++++- .../AzureMetricConfigurationDeserializer.cs | 23 ++----------- .../v1/Model/AzureMetricConfigurationV1.cs | 11 +++++-- .../ResourceTypes/AzureMessagingScraper.cs | 4 +-- .../ResourceTypes/DataFactoryScraper.cs | 4 +-- .../ResourceTypes/DataShareScraper.cs | 4 +-- ...ureMetricConfigurationDeserializerTests.cs | 33 +++++++++++++++++-- 9 files changed, 73 insertions(+), 37 deletions(-) diff --git a/src/Promitor.Agents.Scraper/Validation/MetricDefinitions/AzureMetricConfigurationValidator.cs b/src/Promitor.Agents.Scraper/Validation/MetricDefinitions/AzureMetricConfigurationValidator.cs index c2aeb65b8..3b0fac393 100644 --- a/src/Promitor.Agents.Scraper/Validation/MetricDefinitions/AzureMetricConfigurationValidator.cs +++ b/src/Promitor.Agents.Scraper/Validation/MetricDefinitions/AzureMetricConfigurationValidator.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using Kusto.Language; +using System.Linq; using Promitor.Core.Scraping.Configuration.Model; using Promitor.Core.Scraping.Configuration.Model.Metrics; using ResourceType = Promitor.Core.Contracts.ResourceType; @@ -54,6 +55,11 @@ private IEnumerable ValidateAzureMetricConfiguration(AzureMetricConfigur } } + if (azureMetricConfiguration.Dimension != null && azureMetricConfiguration.Dimensions.Any()) + { + errorMessages.Add("Only one of 'dimensions' and 'dimension' is allowed. Please use 'dimensions'."); + } + var metricAggregationValidator = new MetricAggregationValidator(_metricDefaults); var metricsAggregationErrorMessages = metricAggregationValidator.Validate(azureMetricConfiguration.Aggregation); errorMessages.AddRange(metricsAggregationErrorMessages); diff --git a/src/Promitor.Core.Scraping/AzureMonitorScraper.cs b/src/Promitor.Core.Scraping/AzureMonitorScraper.cs index 94dbe7075..54b187b82 100644 --- a/src/Promitor.Core.Scraping/AzureMonitorScraper.cs +++ b/src/Promitor.Core.Scraping/AzureMonitorScraper.cs @@ -7,9 +7,9 @@ using Microsoft.Extensions.Logging; using Promitor.Core.Contracts; using Promitor.Core.Metrics; +using Promitor.Core.Scraping.Configuration.Model; using Promitor.Core.Scraping.Configuration.Model.Metrics; using Promitor.Integrations.AzureMonitor.Exceptions; -using MetricDimension = Promitor.Core.Scraping.Configuration.Model.MetricDimension; namespace Promitor.Core.Scraping { @@ -46,7 +46,7 @@ protected override async Task ScrapeResourceAsync(string subscript var metricLimit = DetermineMetricLimit(scrapeDefinition); // Determine the metric dimension to use, if any - var dimensionNames = DetermineMetricDimensions(metricName, resourceDefinition, scrapeDefinition.AzureMetricConfiguration?.Dimensions); + var dimensionNames = DetermineMetricDimensions(metricName, resourceDefinition, scrapeDefinition.AzureMetricConfiguration); var measuredMetrics = new List(); try @@ -108,10 +108,17 @@ protected virtual string DetermineMetricFilter(string metricName, TResourceDefin /// /// Name of the metric being queried /// Contains the resource cast to the specific resource type. - /// Provides information concerning the configured metric dimensions. - protected virtual List DetermineMetricDimensions(string metricName, TResourceDefinition resourceDefinition, List dimensions) + /// + protected virtual List DetermineMetricDimensions(string metricName, TResourceDefinition resourceDefinition, AzureMetricConfiguration configuration) { - return dimensions?.Select(dimension => dimension.Name).Where(dimensionName => !string.IsNullOrWhiteSpace(dimensionName)).ToList(); + if (configuration.Dimension != null) + { + Logger.LogWarning("AzureMetricConfiguration property 'dimension' has been deprecated and will be removed in a future update. Please use 'dimensions' instead."); + return string.IsNullOrWhiteSpace(configuration.Dimension.Name) ? new List() : new List{ configuration.Dimension.Name }; + } + + return configuration.Dimensions?.Select(dimension => dimension.Name).Where(dimensionName => !string.IsNullOrWhiteSpace(dimensionName)).ToList(); + } /// diff --git a/src/Promitor.Core.Scraping/Configuration/Model/AzureMetricConfiguration.cs b/src/Promitor.Core.Scraping/Configuration/Model/AzureMetricConfiguration.cs index 8ae5d365a..d83cf8e87 100644 --- a/src/Promitor.Core.Scraping/Configuration/Model/AzureMetricConfiguration.cs +++ b/src/Promitor.Core.Scraping/Configuration/Model/AzureMetricConfiguration.cs @@ -16,10 +16,16 @@ public class AzureMetricConfiguration /// public int? Limit { get; set; } + /// + /// Information about the dimensions of an Azure Monitor metric + /// + public IReadOnlyCollection Dimensions { get; set; } + /// /// Information about the dimension of an Azure Monitor metric /// - public List Dimensions { get; set; } + [Obsolete("Dimension is deprecated, please use Dimensions instead.")] + public MetricDimension Dimension { get; set; } /// /// Configuration on how to aggregate the metric diff --git a/src/Promitor.Core.Scraping/Configuration/Serialization/v1/Core/AzureMetricConfigurationDeserializer.cs b/src/Promitor.Core.Scraping/Configuration/Serialization/v1/Core/AzureMetricConfigurationDeserializer.cs index bf9a8612e..b66d4e438 100644 --- a/src/Promitor.Core.Scraping/Configuration/Serialization/v1/Core/AzureMetricConfigurationDeserializer.cs +++ b/src/Promitor.Core.Scraping/Configuration/Serialization/v1/Core/AzureMetricConfigurationDeserializer.cs @@ -23,31 +23,12 @@ public AzureMetricConfigurationDeserializer(IDeserializer dim .MapUsingDeserializer(aggregationDeserializer); Map(config => config.Dimensions) .MapUsingDeserializer(dimensionDeserializer); - IgnoreField(SingleDimensionTag); + Map(config => config.Dimension) + .MapUsingDeserializer(dimensionDeserializer); _dimensionDeserializer = dimensionDeserializer; } - public override AzureMetricConfigurationV1 Deserialize(YamlMappingNode node, IErrorReporter errorReporter) - { - var azureMetricConfiguration = base.Deserialize(node, errorReporter); - - // backwards compatibility: if old tag "dimension" is used, a list containing only the one MetricDimension is created - if (node.Children.TryGetValue(SingleDimensionTag, out var singleDimensionNode)) - { - errorReporter.ReportWarning(node, "Usage of 'dimension' is deprecated in favor of using 'dimensions'."); - if (node.Children.TryGetValue(MultipleDimensionsTag, out var multipleDimensionsNode)) - { - errorReporter.ReportWarning(node, "Both 'dimensions' and 'dimension' are defined. " + - "Only value from 'dimensions' will be used."); - return azureMetricConfiguration; - } - azureMetricConfiguration.Dimensions = new List{ _dimensionDeserializer.Deserialize((YamlMappingNode)singleDimensionNode, errorReporter) }; - } - - return azureMetricConfiguration; - } - private object DetermineLimit(string rawLimit, KeyValuePair nodePair, IErrorReporter errorReporter) { if (int.TryParse(rawLimit, out int limit)) diff --git a/src/Promitor.Core.Scraping/Configuration/Serialization/v1/Model/AzureMetricConfigurationV1.cs b/src/Promitor.Core.Scraping/Configuration/Serialization/v1/Model/AzureMetricConfigurationV1.cs index c090ea05d..c6c0cf2f7 100644 --- a/src/Promitor.Core.Scraping/Configuration/Serialization/v1/Model/AzureMetricConfigurationV1.cs +++ b/src/Promitor.Core.Scraping/Configuration/Serialization/v1/Model/AzureMetricConfigurationV1.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; namespace Promitor.Core.Scraping.Configuration.Serialization.v1.Model { @@ -15,10 +16,16 @@ public class AzureMetricConfigurationV1 public int? Limit { get; set; } /// - /// Information about the dimension of an Azure Monitor metric + /// Information about the dimensions of an Azure Monitor metric /// public IReadOnlyCollection Dimensions { get; set; } + /// + /// Information about the dimension of an Azure Monitor metric + /// + [Obsolete("Dimension is deprecated, please use Dimensions instead.")] + public MetricDimensionV1 Dimension { get; set; } + /// /// The settings for how the metric should be aggregated before being returned from Azure. /// diff --git a/src/Promitor.Core.Scraping/ResourceTypes/AzureMessagingScraper.cs b/src/Promitor.Core.Scraping/ResourceTypes/AzureMessagingScraper.cs index b95acc3e3..93f6a3c3a 100644 --- a/src/Promitor.Core.Scraping/ResourceTypes/AzureMessagingScraper.cs +++ b/src/Promitor.Core.Scraping/ResourceTypes/AzureMessagingScraper.cs @@ -40,11 +40,11 @@ protected override Dictionary DetermineMetricLabels(TResourceDef return metricLabels; } - protected override List DetermineMetricDimensions(string metricName, TResourceDefinition resourceDefinition, List dimensions) + protected override List DetermineMetricDimensions(string metricName, TResourceDefinition resourceDefinition, AzureMetricConfiguration configuration) { if (IsEntityDeclared(resourceDefinition)) { - return base.DetermineMetricDimensions(metricName, resourceDefinition, dimensions); + return base.DetermineMetricDimensions(metricName, resourceDefinition, configuration); } Logger.LogTrace("Using 'EntityName' dimension since no topic was configured."); diff --git a/src/Promitor.Core.Scraping/ResourceTypes/DataFactoryScraper.cs b/src/Promitor.Core.Scraping/ResourceTypes/DataFactoryScraper.cs index ee2ec8d90..9b2d6fb96 100644 --- a/src/Promitor.Core.Scraping/ResourceTypes/DataFactoryScraper.cs +++ b/src/Promitor.Core.Scraping/ResourceTypes/DataFactoryScraper.cs @@ -48,11 +48,11 @@ protected override Dictionary DetermineMetricLabels(DataFactoryR return metricLabels; } - protected override List DetermineMetricDimensions(string metricName, DataFactoryResourceDefinition resourceDefinition, List dimensions) + protected override List DetermineMetricDimensions(string metricName, DataFactoryResourceDefinition resourceDefinition, AzureMetricConfiguration configuration) { if (IsPipelineNameConfigured(resourceDefinition)) { - return base.DetermineMetricDimensions(metricName, resourceDefinition, dimensions); + return base.DetermineMetricDimensions(metricName, resourceDefinition, configuration); } var dimensionName = GetMetricFilterFieldName(metricName); diff --git a/src/Promitor.Core.Scraping/ResourceTypes/DataShareScraper.cs b/src/Promitor.Core.Scraping/ResourceTypes/DataShareScraper.cs index 94c8bb37d..c5b26abbf 100644 --- a/src/Promitor.Core.Scraping/ResourceTypes/DataShareScraper.cs +++ b/src/Promitor.Core.Scraping/ResourceTypes/DataShareScraper.cs @@ -38,11 +38,11 @@ protected override string DetermineMetricFilter(string metricName, DataShareReso return $"{fieldName} eq '{entityName}'"; } - protected override List DetermineMetricDimensions(string metricName, DataShareResourceDefinition resourceDefinition, List dimensions) + protected override List DetermineMetricDimensions(string metricName, DataShareResourceDefinition resourceDefinition, AzureMetricConfiguration configuration) { if (IsShareNameConfigured(resourceDefinition)) { - return base.DetermineMetricDimensions(metricName, resourceDefinition, dimensions); + return base.DetermineMetricDimensions(metricName, resourceDefinition, configuration); } var dimensionName = GetMetricFilterFieldName(metricName); diff --git a/src/Promitor.Tests.Unit/Serialization/v1/Core/AzureMetricConfigurationDeserializerTests.cs b/src/Promitor.Tests.Unit/Serialization/v1/Core/AzureMetricConfigurationDeserializerTests.cs index 87a8324aa..d4379cbbc 100644 --- a/src/Promitor.Tests.Unit/Serialization/v1/Core/AzureMetricConfigurationDeserializerTests.cs +++ b/src/Promitor.Tests.Unit/Serialization/v1/Core/AzureMetricConfigurationDeserializerTests.cs @@ -115,7 +115,7 @@ public void Deserialize_DimensionSupplied_UsesDeserializer() var config = _deserializer.Deserialize(node, _errorReporter.Object); // Assert - Assert.Equal(new List { dimension }, config.Dimensions); + Assert.Equal(dimension, config.Dimension); } [Fact] @@ -129,7 +129,7 @@ public void Deserialize_DimensionsSupplied_UsesDeserializer() var node = YamlUtils.CreateYamlNode(yamlText); var dimensionsNode = (YamlSequenceNode)node.Children["dimensions"]; - var dimensions = new List { new MetricDimensionV1(), new MetricDimensionV1() }; + var dimensions = new List { new(), new() }; _dimensionDeserializer.Setup(d => d.Deserialize(dimensionsNode, _errorReporter.Object)).Returns(dimensions); // Act @@ -139,6 +139,35 @@ public void Deserialize_DimensionsSupplied_UsesDeserializer() Assert.Same(dimensions, config.Dimensions); } + [Fact] + public void Deserialize_DimensionAndDimensionsSupplied_UsesDeserializer() + { + // Arrange + const string yamlText = + @"dimension: + name: EntityPath +dimensions: + - name: EntityPath + - name: EntityName"; + var node = YamlUtils.CreateYamlNode(yamlText); + var dimensionNode = (YamlMappingNode)node.Children["dimension"]; + var dimensionsNode = (YamlSequenceNode)node.Children["dimensions"]; + + var dimension = new MetricDimensionV1(); + _dimensionDeserializer.Setup(d => d.Deserialize(dimensionNode, _errorReporter.Object)).Returns(dimension); + + + var dimensions = new List { new(), new() }; + _dimensionDeserializer.Setup(d => d.Deserialize(dimensionsNode, _errorReporter.Object)).Returns(dimensions); + + // Act + var config = _deserializer.Deserialize(node, _errorReporter.Object); + + // Assert + Assert.Equal(dimension, config.Dimension); + Assert.Same(dimensions, config.Dimensions); + } + [Fact] public void Deserialize_DimensionNotSupplied_Null() { From b0d807456b4ab7264215ff59914959d8033821d8 Mon Sep 17 00:00:00 2001 From: aaronweissler <46028218+aaronweissler@users.noreply.github.com> Date: Fri, 23 Sep 2022 12:40:28 +0200 Subject: [PATCH 25/53] Update MetricsDeclarationBuilder --- .../LogAnalyticsScraper.cs | 2 +- .../Metrics/v1/MetricsDeclarationBuilder.cs | 35 ++++++++----------- ...bsMetricsDeclarationValidationStepTests.cs | 9 ++--- ...ceMetricsDeclarationValidationStepTests.cs | 11 +++--- 4 files changed, 26 insertions(+), 31 deletions(-) diff --git a/src/Promitor.Core.Scraping/LogAnalyticsScraper.cs b/src/Promitor.Core.Scraping/LogAnalyticsScraper.cs index eaae858ce..15ba7e508 100644 --- a/src/Promitor.Core.Scraping/LogAnalyticsScraper.cs +++ b/src/Promitor.Core.Scraping/LogAnalyticsScraper.cs @@ -34,7 +34,7 @@ protected override async Task ScrapeResourceAsync(string subscript // Query Azure Log Analytics for result var result = await _logAnalyticsClient.RunKustoQueryAsync(workspaceId, query, aggregationInterval); - var measuredMetric = MeasuredMetric.CreateWithoutDimension(result); + var measuredMetric = MeasuredMetric.CreateWithoutDimensions(result); measuredMetrics.Add(measuredMetric); var metricLabels = DetermineMetricLabels(resourceDefinition); diff --git a/src/Promitor.Tests.Unit/Builders/Metrics/v1/MetricsDeclarationBuilder.cs b/src/Promitor.Tests.Unit/Builders/Metrics/v1/MetricsDeclarationBuilder.cs index b4bca532e..f935e3df2 100644 --- a/src/Promitor.Tests.Unit/Builders/Metrics/v1/MetricsDeclarationBuilder.cs +++ b/src/Promitor.Tests.Unit/Builders/Metrics/v1/MetricsDeclarationBuilder.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; using AutoMapper; using Microsoft.Azure.Management.Monitor.Fluent.Models; using Microsoft.Extensions.Logging.Abstractions; @@ -316,7 +317,7 @@ public MetricsDeclarationBuilder WithDeviceProvisioningServiceMetric(string metr public MetricsDeclarationBuilder WithEventHubsMetric(string metricName = "promitor-event-hubs", string metricDescription = "Description for a metric", - string metricDimension = "", + IReadOnlyCollection metricDimensions = null, string topicName = "promitor-queue", string eventHubsNamespace = "promitor-namespace", string azureMetricName = "Total", @@ -330,7 +331,7 @@ public MetricsDeclarationBuilder WithEventHubsMetric(string metricName = "promit Namespace = eventHubsNamespace }; - CreateAndAddMetricDefinition(ResourceType.EventHubs, metricName, metricDescription, resourceDiscoveryGroupName, omitResource, azureMetricName, azureMetricLimit, resource, metricDimension); + CreateAndAddMetricDefinition(ResourceType.EventHubs, metricName, metricDescription, resourceDiscoveryGroupName, omitResource, azureMetricName, azureMetricLimit, resource, metricDimensions); return this; } @@ -507,7 +508,7 @@ public MetricsDeclarationBuilder WithLogAnalytics(string metricName = "promitor" string resourceDiscoveryGroupName = "", int? azureMetricLimit = null, bool omitResource = false, - string metricDimension = null, + IReadOnlyCollection metricDimensions = null, Dictionary labels = null, string query = "Usage | take 1 | extend result = Quantity | project result", string interval = "10:00:00:00") @@ -519,7 +520,7 @@ public MetricsDeclarationBuilder WithLogAnalytics(string metricName = "promitor" }; CreateAndAddMetricDefinition(ResourceType.LogAnalytics, metricName, metricDescription, resourceDiscoveryGroupName, omitResource, - azureMetricName, azureMetricLimit, new List { resource }, metricDimension, labels, query, interval); + azureMetricName, azureMetricLimit, new List { resource }, metricDimensions, labels, query, interval); return this; } @@ -692,7 +693,7 @@ public MetricsDeclarationBuilder WithRedisEnterpriseCacheMetric(string metricNam public MetricsDeclarationBuilder WithServiceBusMetric(string metricName = "promitor-service-bus", string metricDescription = "Description for a metric", - string metricDimension = "", + IReadOnlyCollection metricDimensions = null, string queueName = "promitor-queue", string topicName = "", string serviceBusNamespace = "promitor-namespace", @@ -728,7 +729,7 @@ public MetricsDeclarationBuilder WithServiceBusMetric(string metricName = "promi serviceBusQueueResources.Add(resource); } - CreateAndAddMetricDefinition(ResourceType.ServiceBusNamespace, metricName, metricDescription, resourceDiscoveryGroupName, omitResource, azureMetricName, azureMetricLimit, serviceBusQueueResources, metricDimension, labels); + CreateAndAddMetricDefinition(ResourceType.ServiceBusNamespace, metricName, metricDescription, resourceDiscoveryGroupName, omitResource, azureMetricName, azureMetricLimit, serviceBusQueueResources, metricDimensions, labels); return this; } @@ -993,16 +994,17 @@ public MetricsDeclarationBuilder WithWebAppMetric(string metricName = "promitor- return this; } - private void CreateAndAddMetricDefinition(ResourceType resourceType, string metricName, string metricDescription, string resourceDiscoveryGroupName, bool omitResource, string azureMetricName, int? azureMetricLimit, AzureResourceDefinitionV1 resource, string metricDimension = null) + private void CreateAndAddMetricDefinition(ResourceType resourceType, string metricName, string metricDescription, string resourceDiscoveryGroupName, bool omitResource, string azureMetricName, int? azureMetricLimit, AzureResourceDefinitionV1 resource, IReadOnlyCollection metricDimensions = null) { - CreateAndAddMetricDefinition(resourceType, metricName, metricDescription, resourceDiscoveryGroupName, omitResource, azureMetricName, azureMetricLimit, new List { resource }, metricDimension); + CreateAndAddMetricDefinition(resourceType, metricName, metricDescription, resourceDiscoveryGroupName, omitResource, azureMetricName, azureMetricLimit, new List { resource }, metricDimensions); } private void CreateAndAddMetricDefinition(ResourceType resourceType, string metricName, string metricDescription, string resourceDiscoveryGroupName, bool omitResource, - string azureMetricName, int? azureMetricLimit, List resources, string metricDimension = null, Dictionary labels = null, string query = "", string interval = "10:00:00:00") + string azureMetricName, int? azureMetricLimit, List resources, IReadOnlyCollection metricDimensions = null, Dictionary labels = null, string query = "", string interval = "10:00:00:00") { - var azureMetricConfiguration = CreateAzureMetricConfiguration(azureMetricName, azureMetricLimit, metricDimension); + var azureMetricConfiguration = CreateAzureMetricConfiguration(azureMetricName, azureMetricLimit, metricDimensions); var logAnalyticsConfiguration = CreateLogAnalyticsConfiguration(query, interval); + var metric = new MetricDefinitionV1 { Name = metricName, @@ -1030,7 +1032,7 @@ private void CreateAndAddMetricDefinition(ResourceType resourceType, string metr _metrics.Add(metric); } - private AzureMetricConfigurationV1 CreateAzureMetricConfiguration(string azureMetricName, int? azureMetricLimit, string metricDimension = "") + private AzureMetricConfigurationV1 CreateAzureMetricConfiguration(string azureMetricName, int? azureMetricLimit, IReadOnlyCollection metricDimensions = null) { var metricConfig = new AzureMetricConfigurationV1 { @@ -1042,16 +1044,7 @@ private AzureMetricConfigurationV1 CreateAzureMetricConfiguration(string azureMe } }; - if (string.IsNullOrWhiteSpace(metricDimension) == false) - { - metricConfig.Dimensions = new List - { - new() - { - Name = metricDimension - } - }; - } + metricConfig.Dimensions = metricDimensions != null ? metricDimensions.Select(name => new MetricDimensionV1{ Name = name }).ToList() : new List(); return metricConfig; } diff --git a/src/Promitor.Tests.Unit/Validation/Scraper/Metrics/ResourceTypes/EventHubsMetricsDeclarationValidationStepTests.cs b/src/Promitor.Tests.Unit/Validation/Scraper/Metrics/ResourceTypes/EventHubsMetricsDeclarationValidationStepTests.cs index 40710ec81..0d0480aab 100644 --- a/src/Promitor.Tests.Unit/Validation/Scraper/Metrics/ResourceTypes/EventHubsMetricsDeclarationValidationStepTests.cs +++ b/src/Promitor.Tests.Unit/Validation/Scraper/Metrics/ResourceTypes/EventHubsMetricsDeclarationValidationStepTests.cs @@ -1,4 +1,5 @@ -using System.ComponentModel; +using System.Collections.Generic; +using System.ComponentModel; using Microsoft.Extensions.Logging.Abstractions; using Promitor.Agents.Scraper.Validation.Steps; using Promitor.Tests.Unit.Builders.Metrics.v1; @@ -52,7 +53,7 @@ public void EventHubsMetricsDeclaration_UseEntityNameDimensionWithoutTopicName_S { // Arrange var rawDeclaration = MetricsDeclarationBuilder.WithMetadata() - .WithEventHubsMetric(metricDimension: "EntityName", topicName: string.Empty) + .WithEventHubsMetric(metricDimensions: new List{"EntityName"}, topicName: string.Empty) .Build(Mapper); var metricsDeclarationProvider = new MetricsDeclarationProviderStub(rawDeclaration, Mapper); @@ -69,7 +70,7 @@ public void EventHubsMetricsDeclaration_UseEntityNameDimensionWithTopicName_Fail { // Arrange var rawDeclaration = MetricsDeclarationBuilder.WithMetadata() - .WithEventHubsMetric(metricDimension: "EntityName") + .WithEventHubsMetric(metricDimensions: new List{"EntityName"}) .Build(Mapper); var metricsDeclarationProvider = new MetricsDeclarationProviderStub(rawDeclaration, Mapper); @@ -86,7 +87,7 @@ public void EventHubsMetricsDeclaration_UseAllowedDimension_Succeeded() { // Arrange var rawDeclaration = MetricsDeclarationBuilder.WithMetadata() - .WithEventHubsMetric(metricDimension: "OperationResult") + .WithEventHubsMetric(metricDimensions: new List{"OperationResult"}) .Build(Mapper); var metricsDeclarationProvider = new MetricsDeclarationProviderStub(rawDeclaration, Mapper); diff --git a/src/Promitor.Tests.Unit/Validation/Scraper/Metrics/ResourceTypes/ServiceBusNamespaceMetricsDeclarationValidationStepTests.cs b/src/Promitor.Tests.Unit/Validation/Scraper/Metrics/ResourceTypes/ServiceBusNamespaceMetricsDeclarationValidationStepTests.cs index aa7caacc4..674745c55 100644 --- a/src/Promitor.Tests.Unit/Validation/Scraper/Metrics/ResourceTypes/ServiceBusNamespaceMetricsDeclarationValidationStepTests.cs +++ b/src/Promitor.Tests.Unit/Validation/Scraper/Metrics/ResourceTypes/ServiceBusNamespaceMetricsDeclarationValidationStepTests.cs @@ -1,4 +1,5 @@ -using System.ComponentModel; +using System.Collections.Generic; +using System.ComponentModel; using Microsoft.Extensions.Logging.Abstractions; using Promitor.Agents.Scraper.Validation.Steps; using Promitor.Tests.Unit.Builders.Metrics.v1; @@ -52,7 +53,7 @@ public void ServiceBusNamespaceMetricsDeclaration_UseEntityNameDimensionAndQueue { // Arrange var rawDeclaration = MetricsDeclarationBuilder.WithMetadata() - .WithServiceBusMetric(metricDimension: "EntityName") + .WithServiceBusMetric(metricDimensions: new List{"EntityName"}) .Build(Mapper); var metricsDeclarationProvider = new MetricsDeclarationProviderStub(rawDeclaration, Mapper); @@ -69,7 +70,7 @@ public void ServiceBusNamespaceMetricsDeclaration_UseEntityNameDimensionAndTopic { // Arrange var rawDeclaration = MetricsDeclarationBuilder.WithMetadata() - .WithServiceBusMetric(queueName: string.Empty, topicName: "test-topic", metricDimension: "EntityName") + .WithServiceBusMetric(queueName: string.Empty, topicName: "test-topic", metricDimensions: new List{"EntityName"}) .Build(Mapper); var metricsDeclarationProvider = new MetricsDeclarationProviderStub(rawDeclaration, Mapper); @@ -86,7 +87,7 @@ public void ServiceBusNamespaceMetricsDeclaration_UseAllowedDimension_Succeeded( { // Arrange var rawDeclaration = MetricsDeclarationBuilder.WithMetadata() - .WithServiceBusMetric(metricDimension: "OperationResult") + .WithServiceBusMetric(metricDimensions: new List{"OperationResult"}) .Build(Mapper); var metricsDeclarationProvider = new MetricsDeclarationProviderStub(rawDeclaration, Mapper); @@ -103,7 +104,7 @@ public void ServiceBusNamespaceMetricsDeclaration_UseEntityNameDimension_Succeed { // Arrange var rawDeclaration = MetricsDeclarationBuilder.WithMetadata() - .WithServiceBusMetric(metricDimension: "EntityName", queueName: string.Empty) + .WithServiceBusMetric(metricDimensions: new List{"EntityName"}, queueName: string.Empty) .Build(Mapper); var metricsDeclarationProvider = new MetricsDeclarationProviderStub(rawDeclaration, Mapper); From 693143b63a4eba3cc5470ce36b219e02e5b6cbe9 Mon Sep 17 00:00:00 2001 From: aaronweissler <46028218+aaronweissler@users.noreply.github.com> Date: Fri, 23 Sep 2022 12:41:19 +0200 Subject: [PATCH 26/53] Add AzureMetricConfigurationValidator Tests --- .../AzureMetricConfigurationValidatorTest.cs | 72 +++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 src/Promitor.Tests.Unit/Validation/Scraper/Metrics/AzureMetricConfigurationValidatorTest.cs diff --git a/src/Promitor.Tests.Unit/Validation/Scraper/Metrics/AzureMetricConfigurationValidatorTest.cs b/src/Promitor.Tests.Unit/Validation/Scraper/Metrics/AzureMetricConfigurationValidatorTest.cs new file mode 100644 index 000000000..afcf32afd --- /dev/null +++ b/src/Promitor.Tests.Unit/Validation/Scraper/Metrics/AzureMetricConfigurationValidatorTest.cs @@ -0,0 +1,72 @@ +using System.Collections.Generic; +using Promitor.Agents.Scraper.Validation.MetricDefinitions; +using Promitor.Core.Scraping.Configuration.Model; +using Xunit; +using MetricDimension = Promitor.Core.Scraping.Configuration.Model.MetricDimension; + +namespace Promitor.Tests.Unit.Validation.Scraper.Metrics; + +public class AzureMetricConfigurationValidatorTest +{ + [Fact] + public void DimensionsAndDimension_Fails() + { + // Arrange + var metricConfig = new AzureMetricConfiguration + { + MetricName = "testMetric", + + }; + + metricConfig.Dimensions = new List { new(), new() }; + metricConfig.Dimension = new MetricDimension(); + + // Act + var azureMetricConfigurationValidator = new AzureMetricConfigurationValidator( new MetricDefaults()); + var validationErrors = azureMetricConfigurationValidator.Validate(metricConfig); + + // Assert + Assert.NotEmpty(validationErrors); + } + + [Fact] + public void OnlyDimension_Succeeds() + { + // Arrange + var metricConfig = new AzureMetricConfiguration + { + MetricName = "testMetric", + + }; + + metricConfig.Dimension = new MetricDimension(); + metricConfig.Dimensions = new List(); + + // Act + var azureMetricConfigurationValidator = new AzureMetricConfigurationValidator( new MetricDefaults()); + var validationErrors = azureMetricConfigurationValidator.Validate(metricConfig); + + // Assert + Assert.Empty(validationErrors); + } + + [Fact] + public void OnlyDimensions_Succeeds() + { + // Arrange + var metricConfig = new AzureMetricConfiguration + { + MetricName = "testMetric", + + }; + + metricConfig.Dimensions = new List { new(), new() }; + + // Act + var azureMetricConfigurationValidator = new AzureMetricConfigurationValidator( new MetricDefaults()); + var validationErrors = azureMetricConfigurationValidator.Validate(metricConfig); + + // Assert + Assert.Empty(validationErrors); + } +} \ No newline at end of file From 9ca09969bcaaf848219cc27de4c86142cbdef000 Mon Sep 17 00:00:00 2001 From: aaronweissler <46028218+aaronweissler@users.noreply.github.com> Date: Fri, 23 Sep 2022 12:53:55 +0200 Subject: [PATCH 27/53] Fix HasDimension for re-added Dimension field --- .../Configuration/Model/AzureMetricConfiguration.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Promitor.Core.Scraping/Configuration/Model/AzureMetricConfiguration.cs b/src/Promitor.Core.Scraping/Configuration/Model/AzureMetricConfiguration.cs index d83cf8e87..73e94c42d 100644 --- a/src/Promitor.Core.Scraping/Configuration/Model/AzureMetricConfiguration.cs +++ b/src/Promitor.Core.Scraping/Configuration/Model/AzureMetricConfiguration.cs @@ -39,6 +39,10 @@ public class AzureMetricConfiguration /// true if the dimension name was found, false otherwise public bool HasDimension(string dimensionName) { + if (Dimension != null) + { + return Dimension.Name.Equals(dimensionName, StringComparison.InvariantCultureIgnoreCase); + } return Dimensions?.Where(dimension => dimension.Name.Equals(dimensionName, StringComparison.InvariantCultureIgnoreCase)).Any() ?? false; } } From 91f15a7de8187357a1efdebbfaf85023290deae8 Mon Sep 17 00:00:00 2001 From: aaronweissler <46028218+aaronweissler@users.noreply.github.com> Date: Fri, 23 Sep 2022 12:58:03 +0200 Subject: [PATCH 28/53] Fail validation for MessagingScrapers if more than one dimension is defined --- .../ResourceTypes/EventHubsMetricValidator.cs | 5 +++++ .../ResourceTypes/ServiceBusNamespaceMetricValidator.cs | 5 +++++ .../ResourceTypes/AzureMessagingScraper.cs | 2 +- 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/Promitor.Agents.Scraper/Validation/MetricDefinitions/ResourceTypes/EventHubsMetricValidator.cs b/src/Promitor.Agents.Scraper/Validation/MetricDefinitions/ResourceTypes/EventHubsMetricValidator.cs index ecb3bf4fe..ffe82dfa7 100644 --- a/src/Promitor.Agents.Scraper/Validation/MetricDefinitions/ResourceTypes/EventHubsMetricValidator.cs +++ b/src/Promitor.Agents.Scraper/Validation/MetricDefinitions/ResourceTypes/EventHubsMetricValidator.cs @@ -16,6 +16,11 @@ public IEnumerable Validate(MetricDefinition metricDefinition) Guard.NotNull(metricDefinition, nameof(metricDefinition)); var errorMessages = new List(); + + if (metricDefinition.AzureMetricConfiguration?.Dimensions?.Count > 1) + { + errorMessages.Add("At least one Dimension other than EntityName is defined."); + } var isEntityNameDimensionConfigured = metricDefinition.AzureMetricConfiguration?.HasDimension(EntityNameDimension) ?? false; diff --git a/src/Promitor.Agents.Scraper/Validation/MetricDefinitions/ResourceTypes/ServiceBusNamespaceMetricValidator.cs b/src/Promitor.Agents.Scraper/Validation/MetricDefinitions/ResourceTypes/ServiceBusNamespaceMetricValidator.cs index a0eb20b95..e2961043b 100644 --- a/src/Promitor.Agents.Scraper/Validation/MetricDefinitions/ResourceTypes/ServiceBusNamespaceMetricValidator.cs +++ b/src/Promitor.Agents.Scraper/Validation/MetricDefinitions/ResourceTypes/ServiceBusNamespaceMetricValidator.cs @@ -17,6 +17,11 @@ public IEnumerable Validate(MetricDefinition metricDefinition) var errorMessages = new List(); + if (metricDefinition.AzureMetricConfiguration?.Dimensions?.Count > 1) + { + errorMessages.Add("At least one Dimension other than EntityName is defined."); + } + var isEntityNameDimensionConfigured = metricDefinition.AzureMetricConfiguration?.HasDimension(EntityNameDimension) ?? false; foreach (var resourceDefinition in metricDefinition.Resources.Cast()) diff --git a/src/Promitor.Core.Scraping/ResourceTypes/AzureMessagingScraper.cs b/src/Promitor.Core.Scraping/ResourceTypes/AzureMessagingScraper.cs index 93f6a3c3a..88bb8acac 100644 --- a/src/Promitor.Core.Scraping/ResourceTypes/AzureMessagingScraper.cs +++ b/src/Promitor.Core.Scraping/ResourceTypes/AzureMessagingScraper.cs @@ -21,7 +21,7 @@ protected override List EnrichMeasuredMetrics(TResourceDefinitio // Change Azure Monitor Dimension name to more representable value foreach (var measuredMetric in metricValues.Where(metricValue => metricValue.Dimensions.Any())) { - measuredMetric.Dimensions[0].Name = EntityNameLabel; // TODO + measuredMetric.Dimensions[0].Name = EntityNameLabel; } return metricValues; From ea6507de47f6b2aeb4e197a042ceea08cff36881 Mon Sep 17 00:00:00 2001 From: aaronweissler <46028218+aaronweissler@users.noreply.github.com> Date: Fri, 23 Sep 2022 13:13:43 +0200 Subject: [PATCH 29/53] Fix linting errors --- src/Promitor.Core.Scraping/AzureMonitorScraper.cs | 1 - .../Configuration/Serialization/IDeserializer.cs | 1 - .../v1/Core/AzureMetricConfigurationDeserializerTests.cs | 1 - .../Scraper/Metrics/AzureMetricConfigurationValidatorTest.cs | 3 --- 4 files changed, 6 deletions(-) diff --git a/src/Promitor.Core.Scraping/AzureMonitorScraper.cs b/src/Promitor.Core.Scraping/AzureMonitorScraper.cs index 54b187b82..240efe524 100644 --- a/src/Promitor.Core.Scraping/AzureMonitorScraper.cs +++ b/src/Promitor.Core.Scraping/AzureMonitorScraper.cs @@ -118,7 +118,6 @@ protected virtual List DetermineMetricDimensions(string metricName, TRes } return configuration.Dimensions?.Select(dimension => dimension.Name).Where(dimensionName => !string.IsNullOrWhiteSpace(dimensionName)).ToList(); - } /// diff --git a/src/Promitor.Core.Scraping/Configuration/Serialization/IDeserializer.cs b/src/Promitor.Core.Scraping/Configuration/Serialization/IDeserializer.cs index 09f583bdb..3d2296377 100644 --- a/src/Promitor.Core.Scraping/Configuration/Serialization/IDeserializer.cs +++ b/src/Promitor.Core.Scraping/Configuration/Serialization/IDeserializer.cs @@ -3,7 +3,6 @@ namespace Promitor.Core.Scraping.Configuration.Serialization { - /// /// An object that can deserialize a yaml node into an object. /// diff --git a/src/Promitor.Tests.Unit/Serialization/v1/Core/AzureMetricConfigurationDeserializerTests.cs b/src/Promitor.Tests.Unit/Serialization/v1/Core/AzureMetricConfigurationDeserializerTests.cs index d4379cbbc..7dd0db319 100644 --- a/src/Promitor.Tests.Unit/Serialization/v1/Core/AzureMetricConfigurationDeserializerTests.cs +++ b/src/Promitor.Tests.Unit/Serialization/v1/Core/AzureMetricConfigurationDeserializerTests.cs @@ -155,7 +155,6 @@ public void Deserialize_DimensionAndDimensionsSupplied_UsesDeserializer() var dimension = new MetricDimensionV1(); _dimensionDeserializer.Setup(d => d.Deserialize(dimensionNode, _errorReporter.Object)).Returns(dimension); - var dimensions = new List { new(), new() }; _dimensionDeserializer.Setup(d => d.Deserialize(dimensionsNode, _errorReporter.Object)).Returns(dimensions); diff --git a/src/Promitor.Tests.Unit/Validation/Scraper/Metrics/AzureMetricConfigurationValidatorTest.cs b/src/Promitor.Tests.Unit/Validation/Scraper/Metrics/AzureMetricConfigurationValidatorTest.cs index afcf32afd..13998fda2 100644 --- a/src/Promitor.Tests.Unit/Validation/Scraper/Metrics/AzureMetricConfigurationValidatorTest.cs +++ b/src/Promitor.Tests.Unit/Validation/Scraper/Metrics/AzureMetricConfigurationValidatorTest.cs @@ -15,7 +15,6 @@ public void DimensionsAndDimension_Fails() var metricConfig = new AzureMetricConfiguration { MetricName = "testMetric", - }; metricConfig.Dimensions = new List { new(), new() }; @@ -36,7 +35,6 @@ public void OnlyDimension_Succeeds() var metricConfig = new AzureMetricConfiguration { MetricName = "testMetric", - }; metricConfig.Dimension = new MetricDimension(); @@ -57,7 +55,6 @@ public void OnlyDimensions_Succeeds() var metricConfig = new AzureMetricConfiguration { MetricName = "testMetric", - }; metricConfig.Dimensions = new List { new(), new() }; From 19faf9af4929f008a7d5ac8d27ccdba4821398cd Mon Sep 17 00:00:00 2001 From: aaronweissler <46028218+aaronweissler@users.noreply.github.com> Date: Thu, 20 Oct 2022 15:17:45 +0200 Subject: [PATCH 30/53] Specify properties more exactly in changelog --- changelog/content/experimental/unreleased.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/changelog/content/experimental/unreleased.md b/changelog/content/experimental/unreleased.md index 6f9ebb1a1..71ab9143b 100644 --- a/changelog/content/experimental/unreleased.md +++ b/changelog/content/experimental/unreleased.md @@ -8,10 +8,10 @@ version: - {{% tag added %}} Provide Azure Log Analytics scraper ([docs](https://docs.promitor.io/v2.9/scraping/providers/log-analytics/) | [#2132](https://github.com/tomkerkhove/promitor/pull/2132)) -- {{% tag added %}} Provide capability to use multiple metric dimensions by using new configuration property `dimensions` ([#1820](https://github.com/tomkerkhove/promitor/issues/1820)) -- {{% tag added %}} Provide capability to use multiple metric dimensions by using new configuration property `dimensions` - ([#1820](https://github.com/tomkerkhove/promitor/issues/1820)) -- {{% tag deprecated %}} Old configuration property for metric dimension `dimension` ([#1820](https://github.com/tomkerkhove/promitor/issues/1820)) +- {{% tag added %}} Capability to use multiple metrics dimensions with new metrics configuration property + `metrics[x].azureMetricConfiguration.dimensions` ([#1820](https://github.com/tomkerkhove/promitor/issues/1820)) +- {{% tag deprecated %}} Old metrics configuration property for metric dimension `metrics[x].azureMetricConfiguration.dimension` + ([#1820](https://github.com/tomkerkhove/promitor/issues/1820)) #### Resource Discovery From e321e9f7ebfd9a17b9ba707c1324e1dc51c6a14a Mon Sep 17 00:00:00 2001 From: aaronweissler <46028218+aaronweissler@users.noreply.github.com> Date: Thu, 20 Oct 2022 16:44:56 +0200 Subject: [PATCH 31/53] Add Distinct to DetermineMetricDimensions --- src/Promitor.Core.Scraping/AzureMonitorScraper.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Promitor.Core.Scraping/AzureMonitorScraper.cs b/src/Promitor.Core.Scraping/AzureMonitorScraper.cs index 240efe524..edae805f0 100644 --- a/src/Promitor.Core.Scraping/AzureMonitorScraper.cs +++ b/src/Promitor.Core.Scraping/AzureMonitorScraper.cs @@ -117,7 +117,7 @@ protected virtual List DetermineMetricDimensions(string metricName, TRes return string.IsNullOrWhiteSpace(configuration.Dimension.Name) ? new List() : new List{ configuration.Dimension.Name }; } - return configuration.Dimensions?.Select(dimension => dimension.Name).Where(dimensionName => !string.IsNullOrWhiteSpace(dimensionName)).ToList(); + return configuration.Dimensions?.Select(dimension => dimension.Name).Where(dimensionName => !string.IsNullOrWhiteSpace(dimensionName)).Distinct().ToList(); } /// From 4bae988ebec1d75e46e77c80bc3b8d9601893b56 Mon Sep 17 00:00:00 2001 From: aaronweissler <46028218+aaronweissler@users.noreply.github.com> Date: Mon, 24 Oct 2022 12:34:48 +0200 Subject: [PATCH 32/53] Fix Resharper warnings --- .../Configuration/Model/AzureMetricConfiguration.cs | 2 +- .../v1/Core/AzureMetricConfigurationDeserializer.cs | 6 ------ .../Serialization/v1/Model/AzureMetricConfigurationV1.cs | 2 +- 3 files changed, 2 insertions(+), 8 deletions(-) diff --git a/src/Promitor.Core.Scraping/Configuration/Model/AzureMetricConfiguration.cs b/src/Promitor.Core.Scraping/Configuration/Model/AzureMetricConfiguration.cs index 73e94c42d..2a2937612 100644 --- a/src/Promitor.Core.Scraping/Configuration/Model/AzureMetricConfiguration.cs +++ b/src/Promitor.Core.Scraping/Configuration/Model/AzureMetricConfiguration.cs @@ -24,7 +24,7 @@ public class AzureMetricConfiguration /// /// Information about the dimension of an Azure Monitor metric /// - [Obsolete("Dimension is deprecated, please use Dimensions instead.")] + //[Obsolete("Dimension is deprecated, please use Dimensions instead.")] public MetricDimension Dimension { get; set; } /// diff --git a/src/Promitor.Core.Scraping/Configuration/Serialization/v1/Core/AzureMetricConfigurationDeserializer.cs b/src/Promitor.Core.Scraping/Configuration/Serialization/v1/Core/AzureMetricConfigurationDeserializer.cs index b66d4e438..f476db65a 100644 --- a/src/Promitor.Core.Scraping/Configuration/Serialization/v1/Core/AzureMetricConfigurationDeserializer.cs +++ b/src/Promitor.Core.Scraping/Configuration/Serialization/v1/Core/AzureMetricConfigurationDeserializer.cs @@ -7,10 +7,6 @@ namespace Promitor.Core.Scraping.Configuration.Serialization.v1.Core { public class AzureMetricConfigurationDeserializer : Deserializer { - private const string MultipleDimensionsTag = "dimensions"; - private const string SingleDimensionTag = "dimension"; - private readonly IDeserializer _dimensionDeserializer; - public AzureMetricConfigurationDeserializer(IDeserializer dimensionDeserializer, IDeserializer aggregationDeserializer, ILogger logger) : base(logger) { @@ -25,8 +21,6 @@ public AzureMetricConfigurationDeserializer(IDeserializer dim .MapUsingDeserializer(dimensionDeserializer); Map(config => config.Dimension) .MapUsingDeserializer(dimensionDeserializer); - - _dimensionDeserializer = dimensionDeserializer; } private object DetermineLimit(string rawLimit, KeyValuePair nodePair, IErrorReporter errorReporter) diff --git a/src/Promitor.Core.Scraping/Configuration/Serialization/v1/Model/AzureMetricConfigurationV1.cs b/src/Promitor.Core.Scraping/Configuration/Serialization/v1/Model/AzureMetricConfigurationV1.cs index c6c0cf2f7..ec7f762da 100644 --- a/src/Promitor.Core.Scraping/Configuration/Serialization/v1/Model/AzureMetricConfigurationV1.cs +++ b/src/Promitor.Core.Scraping/Configuration/Serialization/v1/Model/AzureMetricConfigurationV1.cs @@ -23,7 +23,7 @@ public class AzureMetricConfigurationV1 /// /// Information about the dimension of an Azure Monitor metric /// - [Obsolete("Dimension is deprecated, please use Dimensions instead.")] + //[Obsolete("Dimension is deprecated, please use Dimensions instead.")] public MetricDimensionV1 Dimension { get; set; } /// From dbb26c5f6f6fc0bfdc328f98f2159cb89a9618dd Mon Sep 17 00:00:00 2001 From: aaronweissler <46028218+aaronweissler@users.noreply.github.com> Date: Mon, 24 Oct 2022 13:23:06 +0200 Subject: [PATCH 33/53] Fix AzureMetricConfigurationValidator tests --- ...AnalyticsConfigurationDeserializerTests.cs | 2 +- .../AzureMetricConfigurationValidatorTest.cs | 22 ++++++++++++++++--- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/src/Promitor.Tests.Unit/Serialization/v1/Core/LogAnalyticsConfigurationDeserializerTests.cs b/src/Promitor.Tests.Unit/Serialization/v1/Core/LogAnalyticsConfigurationDeserializerTests.cs index 8de06d193..15f9e8e03 100644 --- a/src/Promitor.Tests.Unit/Serialization/v1/Core/LogAnalyticsConfigurationDeserializerTests.cs +++ b/src/Promitor.Tests.Unit/Serialization/v1/Core/LogAnalyticsConfigurationDeserializerTests.cs @@ -51,7 +51,7 @@ public void Deserialize_AggregationSupplied_UsesDeserializer() var aggregation = new AggregationV1(); _aggregationDeserializer.Setup( - d => d.DeserializeObject(aggregationNode, _errorReporter.Object)).Returns(aggregation); + d => d.Deserialize(aggregationNode, _errorReporter.Object)).Returns(aggregation); // Act var config = _deserializer.Deserialize(node, _errorReporter.Object); diff --git a/src/Promitor.Tests.Unit/Validation/Scraper/Metrics/AzureMetricConfigurationValidatorTest.cs b/src/Promitor.Tests.Unit/Validation/Scraper/Metrics/AzureMetricConfigurationValidatorTest.cs index 13998fda2..195ba2b79 100644 --- a/src/Promitor.Tests.Unit/Validation/Scraper/Metrics/AzureMetricConfigurationValidatorTest.cs +++ b/src/Promitor.Tests.Unit/Validation/Scraper/Metrics/AzureMetricConfigurationValidatorTest.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; using Promitor.Agents.Scraper.Validation.MetricDefinitions; using Promitor.Core.Scraping.Configuration.Model; +using Promitor.Core.Scraping.Configuration.Model.Metrics; using Xunit; using MetricDimension = Promitor.Core.Scraping.Configuration.Model.MetricDimension; @@ -17,12 +18,17 @@ public void DimensionsAndDimension_Fails() MetricName = "testMetric", }; + var metricDefinition = new MetricDefinition + { + AzureMetricConfiguration = metricConfig + }; + metricConfig.Dimensions = new List { new(), new() }; metricConfig.Dimension = new MetricDimension(); // Act var azureMetricConfigurationValidator = new AzureMetricConfigurationValidator( new MetricDefaults()); - var validationErrors = azureMetricConfigurationValidator.Validate(metricConfig); + var validationErrors = azureMetricConfigurationValidator.Validate(metricDefinition); // Assert Assert.NotEmpty(validationErrors); @@ -37,12 +43,17 @@ public void OnlyDimension_Succeeds() MetricName = "testMetric", }; + var metricDefinition = new MetricDefinition + { + AzureMetricConfiguration = metricConfig + }; + metricConfig.Dimension = new MetricDimension(); metricConfig.Dimensions = new List(); // Act var azureMetricConfigurationValidator = new AzureMetricConfigurationValidator( new MetricDefaults()); - var validationErrors = azureMetricConfigurationValidator.Validate(metricConfig); + var validationErrors = azureMetricConfigurationValidator.Validate(metricDefinition); // Assert Assert.Empty(validationErrors); @@ -57,11 +68,16 @@ public void OnlyDimensions_Succeeds() MetricName = "testMetric", }; + var metricDefinition = new MetricDefinition + { + AzureMetricConfiguration = metricConfig + }; + metricConfig.Dimensions = new List { new(), new() }; // Act var azureMetricConfigurationValidator = new AzureMetricConfigurationValidator( new MetricDefaults()); - var validationErrors = azureMetricConfigurationValidator.Validate(metricConfig); + var validationErrors = azureMetricConfigurationValidator.Validate(metricDefinition); // Assert Assert.Empty(validationErrors); From 35dce63771360e1e6b1ed75c2cee6b071b7f4e53 Mon Sep 17 00:00:00 2001 From: aaronweissler <46028218+aaronweissler@users.noreply.github.com> Date: Mon, 24 Oct 2022 14:12:55 +0200 Subject: [PATCH 34/53] Remove unneeded using --- .../Serialization/v1/Model/AzureMetricConfigurationV1.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Promitor.Core.Scraping/Configuration/Serialization/v1/Model/AzureMetricConfigurationV1.cs b/src/Promitor.Core.Scraping/Configuration/Serialization/v1/Model/AzureMetricConfigurationV1.cs index ec7f762da..35828a7df 100644 --- a/src/Promitor.Core.Scraping/Configuration/Serialization/v1/Model/AzureMetricConfigurationV1.cs +++ b/src/Promitor.Core.Scraping/Configuration/Serialization/v1/Model/AzureMetricConfigurationV1.cs @@ -1,5 +1,4 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; namespace Promitor.Core.Scraping.Configuration.Serialization.v1.Model { From 5d499ff5badd9db9bc0136634eb5486f85dc4d70 Mon Sep 17 00:00:00 2001 From: aaronweissler <46028218+aaronweissler@users.noreply.github.com> Date: Wed, 9 Nov 2022 16:29:19 +0100 Subject: [PATCH 35/53] Re-add obsolete and add exclusion for resharper --- src/Promitor.Agents.Scraper/Promitor.Agents.Scraper.csproj | 4 ++-- .../Configuration/Model/AzureMetricConfiguration.cs | 2 +- .../Serialization/v1/Model/AzureMetricConfigurationV1.cs | 5 +++-- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/Promitor.Agents.Scraper/Promitor.Agents.Scraper.csproj b/src/Promitor.Agents.Scraper/Promitor.Agents.Scraper.csproj index 90cd14b8b..0af070c90 100644 --- a/src/Promitor.Agents.Scraper/Promitor.Agents.Scraper.csproj +++ b/src/Promitor.Agents.Scraper/Promitor.Agents.Scraper.csproj @@ -12,11 +12,11 @@ - 1701;1702;1591 + 1701;1702;1591;618 - 1701;1702;1591 + 1701;1702;1591;618 diff --git a/src/Promitor.Core.Scraping/Configuration/Model/AzureMetricConfiguration.cs b/src/Promitor.Core.Scraping/Configuration/Model/AzureMetricConfiguration.cs index 2a2937612..73e94c42d 100644 --- a/src/Promitor.Core.Scraping/Configuration/Model/AzureMetricConfiguration.cs +++ b/src/Promitor.Core.Scraping/Configuration/Model/AzureMetricConfiguration.cs @@ -24,7 +24,7 @@ public class AzureMetricConfiguration /// /// Information about the dimension of an Azure Monitor metric /// - //[Obsolete("Dimension is deprecated, please use Dimensions instead.")] + [Obsolete("Dimension is deprecated, please use Dimensions instead.")] public MetricDimension Dimension { get; set; } /// diff --git a/src/Promitor.Core.Scraping/Configuration/Serialization/v1/Model/AzureMetricConfigurationV1.cs b/src/Promitor.Core.Scraping/Configuration/Serialization/v1/Model/AzureMetricConfigurationV1.cs index 35828a7df..c6c0cf2f7 100644 --- a/src/Promitor.Core.Scraping/Configuration/Serialization/v1/Model/AzureMetricConfigurationV1.cs +++ b/src/Promitor.Core.Scraping/Configuration/Serialization/v1/Model/AzureMetricConfigurationV1.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; namespace Promitor.Core.Scraping.Configuration.Serialization.v1.Model { @@ -22,7 +23,7 @@ public class AzureMetricConfigurationV1 /// /// Information about the dimension of an Azure Monitor metric /// - //[Obsolete("Dimension is deprecated, please use Dimensions instead.")] + [Obsolete("Dimension is deprecated, please use Dimensions instead.")] public MetricDimensionV1 Dimension { get; set; } /// From 85f069d1361029cc1c4fbfc9f300d797a3a75cd7 Mon Sep 17 00:00:00 2001 From: aaronweissler <46028218+aaronweissler@users.noreply.github.com> Date: Wed, 9 Nov 2022 17:09:45 +0100 Subject: [PATCH 36/53] Add warning exception to remaining projects --- src/Promitor.Core.Scraping/Promitor.Core.Scraping.csproj | 4 ++-- src/Promitor.Tests.Unit/Promitor.Tests.Unit.csproj | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Promitor.Core.Scraping/Promitor.Core.Scraping.csproj b/src/Promitor.Core.Scraping/Promitor.Core.Scraping.csproj index fdf3928d5..f3eef9711 100644 --- a/src/Promitor.Core.Scraping/Promitor.Core.Scraping.csproj +++ b/src/Promitor.Core.Scraping/Promitor.Core.Scraping.csproj @@ -7,11 +7,11 @@ - 1701;1702;1591 + 1701;1702;1591;618 - 1701;1702;1591 + 1701;1702;1591;618 diff --git a/src/Promitor.Tests.Unit/Promitor.Tests.Unit.csproj b/src/Promitor.Tests.Unit/Promitor.Tests.Unit.csproj index b7223cad7..6c0202c23 100644 --- a/src/Promitor.Tests.Unit/Promitor.Tests.Unit.csproj +++ b/src/Promitor.Tests.Unit/Promitor.Tests.Unit.csproj @@ -7,11 +7,11 @@ - 1701;1702;1591 + 1701;1702;1591;618 - 1701;1702;1591 + 1701;1702;1591;618 From af0370c0af2332fac773d53e80b0256e6588037f Mon Sep 17 00:00:00 2001 From: aaronweissler <46028218+aaronweissler@users.noreply.github.com> Date: Wed, 9 Nov 2022 22:29:19 +0100 Subject: [PATCH 37/53] Suppress warning for IDeserializer --- .../Serialization/FieldDeserializationInfoBuilder.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Promitor.Core.Scraping/Configuration/Serialization/FieldDeserializationInfoBuilder.cs b/src/Promitor.Core.Scraping/Configuration/Serialization/FieldDeserializationInfoBuilder.cs index b1e87c26b..aa1373d2b 100644 --- a/src/Promitor.Core.Scraping/Configuration/Serialization/FieldDeserializationInfoBuilder.cs +++ b/src/Promitor.Core.Scraping/Configuration/Serialization/FieldDeserializationInfoBuilder.cs @@ -71,8 +71,9 @@ public FieldDeserializationInfoBuilder MapUsing(Func - /// Specifies an to use to map the field. + /// Specifies an to use to map the field. /// /// The deserializer. /// The builder. From 7a3a1ba209749c63ee46cae8ea2eedfaaabcffe3 Mon Sep 17 00:00:00 2001 From: aaronweissler <46028218+aaronweissler@users.noreply.github.com> Date: Wed, 9 Nov 2022 22:29:40 +0100 Subject: [PATCH 38/53] Add test for dimensions --- .../PrometheusScrapeMetricSinkTests.cs | 32 ++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/src/Promitor.Tests.Integration/Services/Scraper/MetricSinks/PrometheusScrapeMetricSinkTests.cs b/src/Promitor.Tests.Integration/Services/Scraper/MetricSinks/PrometheusScrapeMetricSinkTests.cs index fc7f8dcb2..9edb53e6b 100644 --- a/src/Promitor.Tests.Integration/Services/Scraper/MetricSinks/PrometheusScrapeMetricSinkTests.cs +++ b/src/Promitor.Tests.Integration/Services/Scraper/MetricSinks/PrometheusScrapeMetricSinkTests.cs @@ -1,4 +1,6 @@ -using System.Net; +using System; +using System.Collections.Generic; +using System.Net; using System.Threading.Tasks; using Promitor.Agents.Core; using Promitor.Tests.Integration.Data; @@ -91,5 +93,33 @@ public async Task Prometheus_Scrape_Get_ReturnsVersionHeader() Assert.True(response.Headers.Contains(HttpHeaders.AgentVersion)); Assert.Equal(ExpectedVersion, response.Headers.GetFirstOrDefaultHeaderValue(HttpHeaders.AgentVersion)); } + + [Theory] + [MemberData(nameof(DimensionsData))] + public async Task Prometheus_Scrape_ExpectedDimensionsAreAvailable(string expectedMetricName, IReadOnlyCollection expectedDimensionNames) + { + // Arrange + var prometheusClient = PrometheusClientFactory.CreateForPrometheusScrapingEndpointInScraperAgent(Configuration); + + // Act + var gaugeMetric = await prometheusClient.WaitForPrometheusMetricAsync(expectedMetricName); + + // Assert + Assert.NotNull(gaugeMetric); + Assert.Equal(expectedMetricName, gaugeMetric.Name); + Assert.NotNull(gaugeMetric.Measurements); + Assert.False(gaugeMetric.Measurements.Count < 1); + + foreach (var expectedDimensionName in expectedDimensionNames) + { + Assert.True(gaugeMetric.Measurements[0].Labels.ContainsKey(expectedDimensionName.SanitizeForPrometheusLabelKey())); + Assert.NotEqual("unknown", gaugeMetric.Measurements[0].Labels[expectedDimensionName]); + } + } + + public static IEnumerable DimensionsData(){ + yield return new object[] { "promitor_demo_frontdoor_backend_health_per_backend_pool", new List{ "BackendPool" } }; + yield return new object[] { "promitor_demo_frontdoor_backend_health_per_backend_pool_and_backend", new List{ "BackendPool", "Backend" } }; + } } } From ec53834656fe833cbe6ac62b7fc0622576c8db7a Mon Sep 17 00:00:00 2001 From: aaronweissler <46028218+aaronweissler@users.noreply.github.com> Date: Wed, 9 Nov 2022 23:40:32 +0100 Subject: [PATCH 39/53] WIP disable new test --- .../Scraper/MetricSinks/PrometheusScrapeMetricSinkTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Promitor.Tests.Integration/Services/Scraper/MetricSinks/PrometheusScrapeMetricSinkTests.cs b/src/Promitor.Tests.Integration/Services/Scraper/MetricSinks/PrometheusScrapeMetricSinkTests.cs index 9edb53e6b..8af8909d4 100644 --- a/src/Promitor.Tests.Integration/Services/Scraper/MetricSinks/PrometheusScrapeMetricSinkTests.cs +++ b/src/Promitor.Tests.Integration/Services/Scraper/MetricSinks/PrometheusScrapeMetricSinkTests.cs @@ -94,7 +94,7 @@ public async Task Prometheus_Scrape_Get_ReturnsVersionHeader() Assert.Equal(ExpectedVersion, response.Headers.GetFirstOrDefaultHeaderValue(HttpHeaders.AgentVersion)); } - [Theory] + [Theory(Skip = "todo disabled because it causes infinite(?) loop")] [MemberData(nameof(DimensionsData))] public async Task Prometheus_Scrape_ExpectedDimensionsAreAvailable(string expectedMetricName, IReadOnlyCollection expectedDimensionNames) { From 69f0762bf5f29ccadb87673e7c45488ddb225253 Mon Sep 17 00:00:00 2001 From: aaronweissler <46028218+aaronweissler@users.noreply.github.com> Date: Thu, 10 Nov 2022 15:14:53 +0100 Subject: [PATCH 40/53] Apply suggestions from code review Co-authored-by: Tom Kerkhove --- changelog/content/experimental/unreleased.md | 6 ++---- .../Configuration/Model/AzureMetricConfiguration.cs | 2 +- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/changelog/content/experimental/unreleased.md b/changelog/content/experimental/unreleased.md index 71ab9143b..44d5939fc 100644 --- a/changelog/content/experimental/unreleased.md +++ b/changelog/content/experimental/unreleased.md @@ -8,10 +8,8 @@ version: - {{% tag added %}} Provide Azure Log Analytics scraper ([docs](https://docs.promitor.io/v2.9/scraping/providers/log-analytics/) | [#2132](https://github.com/tomkerkhove/promitor/pull/2132)) -- {{% tag added %}} Capability to use multiple metrics dimensions with new metrics configuration property - `metrics[x].azureMetricConfiguration.dimensions` ([#1820](https://github.com/tomkerkhove/promitor/issues/1820)) -- {{% tag deprecated %}} Old metrics configuration property for metric dimension `metrics[x].azureMetricConfiguration.dimension` - ([#1820](https://github.com/tomkerkhove/promitor/issues/1820)) +- {{% tag added %}} Provide support for scraping multiple metrics dimensions ([#1820](https://github.com/tomkerkhove/promitor/issues/1820)) +- {{% tag deprecated %}} Support for scraping single metric dimension by using `metrics[x].azureMetricConfiguration.dimension` ([#1820](https://github.com/tomkerkhove/promitor/issues/1820)) #### Resource Discovery diff --git a/src/Promitor.Core.Scraping/Configuration/Model/AzureMetricConfiguration.cs b/src/Promitor.Core.Scraping/Configuration/Model/AzureMetricConfiguration.cs index 73e94c42d..20b5625d3 100644 --- a/src/Promitor.Core.Scraping/Configuration/Model/AzureMetricConfiguration.cs +++ b/src/Promitor.Core.Scraping/Configuration/Model/AzureMetricConfiguration.cs @@ -43,7 +43,7 @@ public bool HasDimension(string dimensionName) { return Dimension.Name.Equals(dimensionName, StringComparison.InvariantCultureIgnoreCase); } - return Dimensions?.Where(dimension => dimension.Name.Equals(dimensionName, StringComparison.InvariantCultureIgnoreCase)).Any() ?? false; + return Dimensions?.Any(dimension => dimension.Name.Equals(dimensionName, StringComparison.InvariantCultureIgnoreCase)) ?? false; } } } \ No newline at end of file From c558f1a5cc20ac583d97cd5789b5ec16a4606c52 Mon Sep 17 00:00:00 2001 From: aaronweissler <46028218+aaronweissler@users.noreply.github.com> Date: Thu, 10 Nov 2022 15:15:44 +0100 Subject: [PATCH 41/53] Add suggestion --- .../Configuration/Model/AzureMetricConfiguration.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Promitor.Core.Scraping/Configuration/Model/AzureMetricConfiguration.cs b/src/Promitor.Core.Scraping/Configuration/Model/AzureMetricConfiguration.cs index 20b5625d3..d5d8e998d 100644 --- a/src/Promitor.Core.Scraping/Configuration/Model/AzureMetricConfiguration.cs +++ b/src/Promitor.Core.Scraping/Configuration/Model/AzureMetricConfiguration.cs @@ -41,7 +41,7 @@ public bool HasDimension(string dimensionName) { if (Dimension != null) { - return Dimension.Name.Equals(dimensionName, StringComparison.InvariantCultureIgnoreCase); + return Dimension?.Name?.Equals(dimensionName, StringComparison.InvariantCultureIgnoreCase) ?? false; } return Dimensions?.Any(dimension => dimension.Name.Equals(dimensionName, StringComparison.InvariantCultureIgnoreCase)) ?? false; } From d18362a779f7860b130257285251dbb7caf35fa6 Mon Sep 17 00:00:00 2001 From: aaronweissler <46028218+aaronweissler@users.noreply.github.com> Date: Thu, 10 Nov 2022 15:34:43 +0100 Subject: [PATCH 42/53] Simplify arrange of ConfigurationValidatorTests --- .../AzureMetricConfigurationValidatorTest.cs | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/Promitor.Tests.Unit/Validation/Scraper/Metrics/AzureMetricConfigurationValidatorTest.cs b/src/Promitor.Tests.Unit/Validation/Scraper/Metrics/AzureMetricConfigurationValidatorTest.cs index 195ba2b79..07721f57b 100644 --- a/src/Promitor.Tests.Unit/Validation/Scraper/Metrics/AzureMetricConfigurationValidatorTest.cs +++ b/src/Promitor.Tests.Unit/Validation/Scraper/Metrics/AzureMetricConfigurationValidatorTest.cs @@ -16,6 +16,8 @@ public void DimensionsAndDimension_Fails() var metricConfig = new AzureMetricConfiguration { MetricName = "testMetric", + Dimension = new MetricDimension(), + Dimensions = new List { new(), new() } }; var metricDefinition = new MetricDefinition @@ -23,9 +25,6 @@ public void DimensionsAndDimension_Fails() AzureMetricConfiguration = metricConfig }; - metricConfig.Dimensions = new List { new(), new() }; - metricConfig.Dimension = new MetricDimension(); - // Act var azureMetricConfigurationValidator = new AzureMetricConfigurationValidator( new MetricDefaults()); var validationErrors = azureMetricConfigurationValidator.Validate(metricDefinition); @@ -41,6 +40,8 @@ public void OnlyDimension_Succeeds() var metricConfig = new AzureMetricConfiguration { MetricName = "testMetric", + Dimension = new MetricDimension(), + Dimensions = new List() }; var metricDefinition = new MetricDefinition @@ -48,9 +49,6 @@ public void OnlyDimension_Succeeds() AzureMetricConfiguration = metricConfig }; - metricConfig.Dimension = new MetricDimension(); - metricConfig.Dimensions = new List(); - // Act var azureMetricConfigurationValidator = new AzureMetricConfigurationValidator( new MetricDefaults()); var validationErrors = azureMetricConfigurationValidator.Validate(metricDefinition); @@ -66,6 +64,7 @@ public void OnlyDimensions_Succeeds() var metricConfig = new AzureMetricConfiguration { MetricName = "testMetric", + Dimensions = new List { new(), new() } }; var metricDefinition = new MetricDefinition @@ -73,8 +72,6 @@ public void OnlyDimensions_Succeeds() AzureMetricConfiguration = metricConfig }; - metricConfig.Dimensions = new List { new(), new() }; - // Act var azureMetricConfigurationValidator = new AzureMetricConfigurationValidator( new MetricDefaults()); var validationErrors = azureMetricConfigurationValidator.Validate(metricDefinition); From 5fe7f980be2520cfdbc7e38fe15be03b2dbb4786 Mon Sep 17 00:00:00 2001 From: aaronweissler <46028218+aaronweissler@users.noreply.github.com> Date: Thu, 10 Nov 2022 16:04:32 +0100 Subject: [PATCH 43/53] Make return type of HasDimension nullable --- .../Configuration/Model/AzureMetricConfiguration.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Promitor.Core.Scraping/Configuration/Model/AzureMetricConfiguration.cs b/src/Promitor.Core.Scraping/Configuration/Model/AzureMetricConfiguration.cs index d5d8e998d..f1bac2974 100644 --- a/src/Promitor.Core.Scraping/Configuration/Model/AzureMetricConfiguration.cs +++ b/src/Promitor.Core.Scraping/Configuration/Model/AzureMetricConfiguration.cs @@ -37,13 +37,13 @@ public class AzureMetricConfiguration /// /// Dimension name to be checked for. /// true if the dimension name was found, false otherwise - public bool HasDimension(string dimensionName) + public bool? HasDimension(string dimensionName) { if (Dimension != null) { - return Dimension?.Name?.Equals(dimensionName, StringComparison.InvariantCultureIgnoreCase) ?? false; + return Dimension?.Name?.Equals(dimensionName, StringComparison.InvariantCultureIgnoreCase); } - return Dimensions?.Any(dimension => dimension.Name.Equals(dimensionName, StringComparison.InvariantCultureIgnoreCase)) ?? false; + return Dimensions?.Any(dimension => dimension.Name.Equals(dimensionName, StringComparison.InvariantCultureIgnoreCase)); } } } \ No newline at end of file From 4999b238b86e02783b38effb3980b30a08a220bf Mon Sep 17 00:00:00 2001 From: aaronweissler <46028218+aaronweissler@users.noreply.github.com> Date: Thu, 10 Nov 2022 16:09:29 +0100 Subject: [PATCH 44/53] Add dimension names to ConfigurationValidatorTest --- .../Metrics/AzureMetricConfigurationValidatorTest.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Promitor.Tests.Unit/Validation/Scraper/Metrics/AzureMetricConfigurationValidatorTest.cs b/src/Promitor.Tests.Unit/Validation/Scraper/Metrics/AzureMetricConfigurationValidatorTest.cs index 07721f57b..1170aa978 100644 --- a/src/Promitor.Tests.Unit/Validation/Scraper/Metrics/AzureMetricConfigurationValidatorTest.cs +++ b/src/Promitor.Tests.Unit/Validation/Scraper/Metrics/AzureMetricConfigurationValidatorTest.cs @@ -16,8 +16,8 @@ public void DimensionsAndDimension_Fails() var metricConfig = new AzureMetricConfiguration { MetricName = "testMetric", - Dimension = new MetricDimension(), - Dimensions = new List { new(), new() } + Dimension = new MetricDimension { Name = "testDimension1" }, + Dimensions = new List { new() {Name = "testDimension2"}, new() { Name = "testDimension3" } } }; var metricDefinition = new MetricDefinition @@ -40,7 +40,7 @@ public void OnlyDimension_Succeeds() var metricConfig = new AzureMetricConfiguration { MetricName = "testMetric", - Dimension = new MetricDimension(), + Dimension = new MetricDimension { Name = "testDimension1" }, Dimensions = new List() }; @@ -64,7 +64,7 @@ public void OnlyDimensions_Succeeds() var metricConfig = new AzureMetricConfiguration { MetricName = "testMetric", - Dimensions = new List { new(), new() } + Dimensions = new List { new() {Name = "testDimension1"}, new() { Name = "testDimension2" } } }; var metricDefinition = new MetricDefinition From 19faf8c201b1f44abb8e01be0451f073b3eb7381 Mon Sep 17 00:00:00 2001 From: aaronweissler <46028218+aaronweissler@users.noreply.github.com> Date: Mon, 14 Nov 2022 11:01:56 +0100 Subject: [PATCH 45/53] WIP add new metrics with dimensions in metrics.yaml --- config/promitor/scraper/metrics.yaml | 33 ++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/config/promitor/scraper/metrics.yaml b/config/promitor/scraper/metrics.yaml index 8a028a11e..f9b760f6f 100644 --- a/config/promitor/scraper/metrics.yaml +++ b/config/promitor/scraper/metrics.yaml @@ -271,6 +271,39 @@ metrics: # Application Insights with data in Log Analytics - name: promitor-automation-data-generation-we-telemetry resourceGroupName: promitor-automation-data-generation + - name: promitor_demo_application_insights_availability_per_name + description: "Availability (%) of promitor.io measured in Azure Application Insights per name" + resourceType: ApplicationInsights + azureMetricConfiguration: + metricName: availabilityResults/availabilityPercentage + aggregation: + type: Average + dimension: + name: availabilityResult/name + resources: + # Application Insights with data in the service itself (classic, deprecated) + - name: promitor-automation-data-generation-we-telemetry-classic + resourceGroupName: promitor-automation-data-generation + # Application Insights with data in Log Analytics + - name: promitor-automation-data-generation-we-telemetry + resourceGroupName: promitor-automation-data-generation + - name: promitor_demo_application_insights_availability_per_name_and_location + description: "Availability (%) of promitor.io measured in Azure Application Insights per name and location" + resourceType: ApplicationInsights + azureMetricConfiguration: + metricName: availabilityResults/availabilityPercentage + aggregation: + type: Average + dimensions: + - name: availabilityResult/name + - name: availabilityResult/location + resources: + # Application Insights with data in the service itself (classic, deprecated) + - name: promitor-automation-data-generation-we-telemetry-classic + resourceGroupName: promitor-automation-data-generation + # Application Insights with data in Log Analytics + - name: promitor-automation-data-generation-we-telemetry + resourceGroupName: promitor-automation-data-generation - name: promitor_demo_cdn_requests_discovered description: "Amount of requests sent to Azure CDN" resourceType: Cdn From b933ab855131c534a0e0cefb7c855a1289be3f33 Mon Sep 17 00:00:00 2001 From: aaronweissler <46028218+aaronweissler@users.noreply.github.com> Date: Mon, 14 Nov 2022 11:39:49 +0100 Subject: [PATCH 46/53] Remove old example of dimensions from metrics.yaml --- config/promitor/scraper/metrics.yaml | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/config/promitor/scraper/metrics.yaml b/config/promitor/scraper/metrics.yaml index f9b760f6f..d1f0d2571 100644 --- a/config/promitor/scraper/metrics.yaml +++ b/config/promitor/scraper/metrics.yaml @@ -185,20 +185,6 @@ metrics: type: Average resourceDiscoveryGroups: - name: front-door-landscape - - name: promitor_demo_frontdoor_backend_health_per_backend_pool_and_backend - description: "Health percentage for a backend in Azure Front Door" - resourceType: FrontDoor - labels: - app: promitor - azureMetricConfiguration: - metricName: BackendHealthPercentage - dimensions: - - name: BackendPool - - name: Backend - aggregation: - type: Average - resourceDiscoveryGroups: - - name: front-door-landscape - name: promitor_demo_sql_elastic_pool_cpu description: "CPU percentage used for a Azure SQL Elastic Pool" resourceType: SqlElasticPool From 9a3a4873323c6e4dc91f07269a26fb589f0861e7 Mon Sep 17 00:00:00 2001 From: aaronweissler <46028218+aaronweissler@users.noreply.github.com> Date: Mon, 14 Nov 2022 11:42:11 +0100 Subject: [PATCH 47/53] Modify and unskip dimensions integration test --- .../Scraper/MetricSinks/PrometheusScrapeMetricSinkTests.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Promitor.Tests.Integration/Services/Scraper/MetricSinks/PrometheusScrapeMetricSinkTests.cs b/src/Promitor.Tests.Integration/Services/Scraper/MetricSinks/PrometheusScrapeMetricSinkTests.cs index 8af8909d4..728e569b5 100644 --- a/src/Promitor.Tests.Integration/Services/Scraper/MetricSinks/PrometheusScrapeMetricSinkTests.cs +++ b/src/Promitor.Tests.Integration/Services/Scraper/MetricSinks/PrometheusScrapeMetricSinkTests.cs @@ -94,7 +94,7 @@ public async Task Prometheus_Scrape_Get_ReturnsVersionHeader() Assert.Equal(ExpectedVersion, response.Headers.GetFirstOrDefaultHeaderValue(HttpHeaders.AgentVersion)); } - [Theory(Skip = "todo disabled because it causes infinite(?) loop")] + [Theory] [MemberData(nameof(DimensionsData))] public async Task Prometheus_Scrape_ExpectedDimensionsAreAvailable(string expectedMetricName, IReadOnlyCollection expectedDimensionNames) { @@ -118,8 +118,8 @@ public async Task Prometheus_Scrape_ExpectedDimensionsAreAvailable(string expect } public static IEnumerable DimensionsData(){ - yield return new object[] { "promitor_demo_frontdoor_backend_health_per_backend_pool", new List{ "BackendPool" } }; - yield return new object[] { "promitor_demo_frontdoor_backend_health_per_backend_pool_and_backend", new List{ "BackendPool", "Backend" } }; + yield return new object[] { "promitor_demo_application_insights_availability_per_name", new List{ "availabilityResult/name" } }; + yield return new object[] { "promitor_demo_application_insights_availability_per_name_and_location", new List{ "availabilityResult/name", "availabilityResult/location" } }; } } } From 56f8efd51b27639724f660a6911bce62db4418f2 Mon Sep 17 00:00:00 2001 From: aaronweissler <46028218+aaronweissler@users.noreply.github.com> Date: Mon, 14 Nov 2022 11:45:40 +0100 Subject: [PATCH 48/53] Fix trailing space in metrics.yaml --- config/promitor/scraper/metrics.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/promitor/scraper/metrics.yaml b/config/promitor/scraper/metrics.yaml index d1f0d2571..dded7c244 100644 --- a/config/promitor/scraper/metrics.yaml +++ b/config/promitor/scraper/metrics.yaml @@ -264,7 +264,7 @@ metrics: metricName: availabilityResults/availabilityPercentage aggregation: type: Average - dimension: + dimension: name: availabilityResult/name resources: # Application Insights with data in the service itself (classic, deprecated) From fa4380ec812df7fa4f79a8bd45116f13027a09a3 Mon Sep 17 00:00:00 2001 From: aaronweissler <46028218+aaronweissler@users.noreply.github.com> Date: Mon, 14 Nov 2022 11:57:36 +0100 Subject: [PATCH 49/53] Add missing sanitization in dimensions integration test --- .../Scraper/MetricSinks/PrometheusScrapeMetricSinkTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Promitor.Tests.Integration/Services/Scraper/MetricSinks/PrometheusScrapeMetricSinkTests.cs b/src/Promitor.Tests.Integration/Services/Scraper/MetricSinks/PrometheusScrapeMetricSinkTests.cs index 728e569b5..e8ddace63 100644 --- a/src/Promitor.Tests.Integration/Services/Scraper/MetricSinks/PrometheusScrapeMetricSinkTests.cs +++ b/src/Promitor.Tests.Integration/Services/Scraper/MetricSinks/PrometheusScrapeMetricSinkTests.cs @@ -113,7 +113,7 @@ public async Task Prometheus_Scrape_ExpectedDimensionsAreAvailable(string expect foreach (var expectedDimensionName in expectedDimensionNames) { Assert.True(gaugeMetric.Measurements[0].Labels.ContainsKey(expectedDimensionName.SanitizeForPrometheusLabelKey())); - Assert.NotEqual("unknown", gaugeMetric.Measurements[0].Labels[expectedDimensionName]); + Assert.NotEqual("unknown", gaugeMetric.Measurements[0].Labels[expectedDimensionName.SanitizeForPrometheusLabelKey()]); } } From 2c4db50a877fe1c235899ce9e9d788b7ea139e0f Mon Sep 17 00:00:00 2001 From: aaronweissler <46028218+aaronweissler@users.noreply.github.com> Date: Mon, 14 Nov 2022 12:41:03 +0100 Subject: [PATCH 50/53] sanitize only once in dimensions integration test --- .../Scraper/MetricSinks/PrometheusScrapeMetricSinkTests.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Promitor.Tests.Integration/Services/Scraper/MetricSinks/PrometheusScrapeMetricSinkTests.cs b/src/Promitor.Tests.Integration/Services/Scraper/MetricSinks/PrometheusScrapeMetricSinkTests.cs index e8ddace63..540f81e7b 100644 --- a/src/Promitor.Tests.Integration/Services/Scraper/MetricSinks/PrometheusScrapeMetricSinkTests.cs +++ b/src/Promitor.Tests.Integration/Services/Scraper/MetricSinks/PrometheusScrapeMetricSinkTests.cs @@ -112,8 +112,9 @@ public async Task Prometheus_Scrape_ExpectedDimensionsAreAvailable(string expect foreach (var expectedDimensionName in expectedDimensionNames) { - Assert.True(gaugeMetric.Measurements[0].Labels.ContainsKey(expectedDimensionName.SanitizeForPrometheusLabelKey())); - Assert.NotEqual("unknown", gaugeMetric.Measurements[0].Labels[expectedDimensionName.SanitizeForPrometheusLabelKey()]); + var sanitizedDimensionName = expectedDimensionName.SanitizeForPrometheusLabelKey(); + Assert.True(gaugeMetric.Measurements[0].Labels.ContainsKey(sanitizedDimensionName)); + Assert.NotEqual("unknown", gaugeMetric.Measurements[0].Labels[sanitizedDimensionName]); } } From a350f8936021f083eaf983bf7747137bd82040c8 Mon Sep 17 00:00:00 2001 From: amirschw <24677563+amirschw@users.noreply.github.com> Date: Tue, 18 Jul 2023 20:42:51 +0300 Subject: [PATCH 51/53] Merge branch 'master' into feature/multiple-dimensions --- .github/workflows/ci-code.yml | 13 +- .github/workflows/pr-post-comment.yml | 24 +++ .github/workflows/publish-ci-test-report.yml | 32 ++++ .../workflows/templates-build-push-image.yml | 4 +- build/azure-devops/agents-ci-discovery.yml | 3 + build/azure-devops/agents-ci-scraper.yml | 9 +- ...ts-resource-discovery-release-official.yml | 4 + .../agents-scraper-release-official.yml | 18 ++- .../templates/build/install-sdk.yml | 4 +- .../templates/tests/run-integration-tests.yml | 3 + build/azure-devops/variables/build.yml | 2 +- build/azure-devops/variables/tests.yml | 2 + changelog/content/experimental/unreleased.md | 48 +----- .../released/v0.9.0-resource-discovery.md | 28 ++++ .../released/v0.9.1-resource-discovery.md | 10 ++ changelog/content/released/v2.9.0-scraper.md | 31 ++++ changelog/content/released/v2.9.1-scraper.md | 10 ++ .../collector-config.yaml | 4 +- .../resource-discovery-declaration.yaml | 10 +- .../promitor/resource-discovery/runtime.yaml | 2 +- config/promitor/scraper/metrics.yaml | 41 +++-- config/promitor/scraper/runtime.yaml | 2 +- src/Promitor.Agents.Core/AgentStartup.cs | 5 +- .../Configuration/RuntimeConfiguration.cs | 6 +- .../Telemetry/TelemetryConfiguration.cs | 4 +- .../IApplicationBuilderExtensions.cs | 32 ++-- .../Promitor.Agents.Core.csproj | 16 +- .../AgentRuntimeConfiguration.cs | 2 +- .../Configuration/ResourceCriteria.cs | 8 +- .../ResourceCriteriaDefinition.cs | 2 +- .../Configuration/ResourceDiscoveryGroup.cs | 2 +- .../Dockerfile.linux | 57 ++++++- .../Dockerfile.windows | 5 +- .../IServiceCollectionExtensions.cs | 11 +- .../Graph/AzureResourceGraph.cs | 88 +++++----- .../Graph/ResourceDiscoveryFactory.cs | 2 + .../TrafficManagerDiscoveryQuery.cs | 21 +++ .../Health/AzureResourceGraphHealthCheck.cs | 2 +- .../Promitor.Agents.ResourceDiscovery.csproj | 9 +- .../AzureMonitorClientFactory.cs | 6 +- .../ScraperRuntimeConfiguration.cs | 6 +- .../Discovery/ResourceDiscoveryClient.cs | 2 +- .../StubResourceDiscoveryRepository.cs | 4 +- src/Promitor.Agents.Scraper/Dockerfile.linux | 57 ++++++- .../Dockerfile.windows | 5 +- .../Health/ResourceDiscoveryHealthCheck.cs | 2 +- .../Promitor.Agents.Scraper.csproj | 11 +- .../Exceptions/ValidationFailedException.cs | 2 +- .../Factories/MetricValidatorFactory.cs | 2 + .../AzureMetricConfigurationValidator.cs | 2 +- .../MetricDefinitions/MetricsValidator.cs | 2 +- .../ResourceTypes/EventHubsMetricValidator.cs | 2 +- .../ServiceBusNamespaceMetricValidator.cs | 2 +- .../TrafficManagerMetricValidator.cs | 25 +++ .../Promitor.Core.Contracts.csproj | 2 +- src/Promitor.Core.Contracts/ResourceType.cs | 1 + .../TrafficManagerResourceDefinition.cs | 25 +++ .../Providers/MetricsDeclarationProvider.cs | 1 + .../Core/AzureResourceDeserializerFactory.cs | 3 + .../v1/Mapping/V1MappingProfile.cs | 2 + .../ResourceTypes/TrafficManagerResourceV1.cs | 13 ++ .../Providers/TrafficManagerDeserializer.cs | 14 ++ .../Factories/MetricScraperFactory.cs | 2 + .../Promitor.Core.Scraping.csproj | 4 +- .../ResourceTypes/TrafficManagerScraper.cs | 24 +++ .../Promitor.Core.Telemetry.csproj | 8 +- src/Promitor.Core/Metrics/MeasuredMetric.cs | 6 +- .../Metrics/MeasuredMetricDimension.cs | 2 +- src/Promitor.Core/Promitor.Core.csproj | 12 +- src/Promitor.Core/ScrapeResult.cs | 2 +- .../AzureAuthenticationFactory.cs | 7 +- .../Promitor.Integrations.Azure.csproj | 8 +- .../AzureMonitorClient.cs | 13 +- .../AzureMonitorConfiguration.cs | 4 +- .../AzureMonitorIntegrationConfiguration.cs | 2 +- .../Promitor.Integrations.AzureMonitor.csproj | 4 +- .../Promitor.Integrations.AzureStorage.csproj | 18 +-- .../LogAnalyticsClient.cs | 4 +- .../Promitor.Integrations.LogAnalytics.csproj | 24 +-- .../AtlassianStatusPageMetricSink.cs | 14 +- .../AtlassianStatusPageSinkConfiguration.cs | 2 +- ...grations.Sinks.Atlassian.Statuspage.csproj | 3 +- .../MetricSink.cs | 80 +++++++++ .../Promitor.Integrations.Sinks.Core.csproj | 20 +++ .../OpenTelemetryCollectorMetricSink.cs | 19 ++- ...or.Integrations.Sinks.OpenTelemetry.csproj | 7 +- .../AzureScrapingSystemMetricsPublisher.cs | 5 +- ...etheusScrapingEndpointSinkConfiguration.cs | 2 +- .../PrometheusScrapingEndpointMetricSink.cs | 59 +------ ...mitor.Integrations.Sinks.Prometheus.csproj | 3 +- .../Promitor.Integrations.Sinks.Statsd.csproj | 3 +- .../StatsdMetricSink.cs | 11 +- .../Clients/PrometheusClient.cs | 2 +- .../IntegrationTest.cs | 2 +- .../Promitor.Tests.Integration.csproj | 10 +- .../ResourceDiscoveryTests.cs | 14 +- .../PrometheusScrapeMetricSinkTests.cs | 2 +- .../AddRequiredYamlFileTests.cs | 2 +- ...sourceGroupsDiscoveryBackgroundJobTests.cs | 4 +- .../Metrics/v1/MetricsDeclarationBuilder.cs | 24 ++- .../Model/Metrics/MetricDefinitionTests.cs | 4 +- .../Config/RuntimeConfigurationGenerator.cs | 24 +-- .../Generators/ScrapeResultGenerator.cs | 2 +- .../Metrics/MetricSinkWriterTests.cs | 6 +- .../AtlassianStatuspageMetricSinkTests.cs | 23 ++- .../Metrics/Sinks/MetricSinkTest.cs | 37 +++++ ...ometheusScrapingEndpointMetricSinkTest.cs} | 33 +--- .../Metrics/Sinks/StatsDMetricSinkTests.cs | 25 +-- .../Promitor.Tests.Unit.csproj | 8 +- .../DeserializerTests/DeserializationTests.cs | 4 +- .../DeserializerTests/ValidationTests.cs | 4 +- .../Serialization/ErrorReporterTests.cs | 2 +- .../DefaultTests.cs | 3 +- .../MapUsingDeserializerTests.cs | 3 +- .../MapUsingTests.cs | 3 +- .../RequiredTests.cs | 3 +- .../SetPropertyTests.cs | 3 +- .../CronExpressionValidatorTests.cs | 2 +- ...ureMetricConfigurationDeserializerTests.cs | 12 +- ...AnalyticsConfigurationDeserializerTests.cs | 2 +- .../Core/MetricDefaultsDeserializerTests.cs | 2 +- .../Core/MetricDefinitionDeserializerTests.cs | 13 +- .../v1/Core/V1DeserializerTests.cs | 4 +- .../Providers/SqlDatabaseDeserializerTests.cs | 2 +- .../SqlElasticPoolDeserializerTests.cs | 2 +- .../StorageQueueDeserializerTests.cs | 2 +- ...SynapseApacheSparkPoolDeserializerTests.cs | 2 +- .../SynapseSqlPoolDeserializerTests.cs | 2 +- .../SynapseWorkspaceDeserializerTests.cs | 2 +- .../TrafficManagerDeserializerTests.cs | 45 ++++++ .../Serialization/v1/V1SerializationTests.cs | 6 +- .../AzureMetricConfigurationValidatorTest.cs | 4 +- ...erMetricsDeclarationValidationStepTests.cs | 152 ++++++++++++++++++ src/Promitor.sln | 9 +- src/Promitor.sln.DotSettings | 4 +- 135 files changed, 1151 insertions(+), 502 deletions(-) create mode 100644 .github/workflows/pr-post-comment.yml create mode 100644 .github/workflows/publish-ci-test-report.yml create mode 100644 changelog/content/released/v0.9.0-resource-discovery.md create mode 100644 changelog/content/released/v0.9.1-resource-discovery.md create mode 100644 changelog/content/released/v2.9.0-scraper.md create mode 100644 changelog/content/released/v2.9.1-scraper.md create mode 100644 src/Promitor.Agents.ResourceDiscovery/Graph/ResourceTypes/TrafficManagerDiscoveryQuery.cs create mode 100644 src/Promitor.Agents.Scraper/Validation/MetricDefinitions/ResourceTypes/TrafficManagerMetricValidator.cs create mode 100644 src/Promitor.Core.Contracts/ResourceTypes/TrafficManagerResourceDefinition.cs create mode 100644 src/Promitor.Core.Scraping/Configuration/Serialization/v1/Model/ResourceTypes/TrafficManagerResourceV1.cs create mode 100644 src/Promitor.Core.Scraping/Configuration/Serialization/v1/Providers/TrafficManagerDeserializer.cs create mode 100644 src/Promitor.Core.Scraping/ResourceTypes/TrafficManagerScraper.cs create mode 100644 src/Promitor.Integrations.Sinks.Core/MetricSink.cs create mode 100644 src/Promitor.Integrations.Sinks.Core/Promitor.Integrations.Sinks.Core.csproj create mode 100644 src/Promitor.Tests.Unit/Metrics/Sinks/MetricSinkTest.cs rename src/Promitor.Tests.Unit/Metrics/Sinks/{PrometheusScrapingEndpointMetricSinkTests.cs => PrometheusScrapingEndpointMetricSinkTest.cs} (94%) create mode 100644 src/Promitor.Tests.Unit/Serialization/v1/Providers/TrafficManagerDeserializerTests.cs create mode 100644 src/Promitor.Tests.Unit/Validation/Scraper/Metrics/ResourceTypes/TrafficManagerMetricsDeclarationValidationStepTests.cs diff --git a/.github/workflows/ci-code.yml b/.github/workflows/ci-code.yml index 78fc31d9f..ab8da1328 100644 --- a/.github/workflows/ci-code.yml +++ b/.github/workflows/ci-code.yml @@ -40,14 +40,13 @@ jobs: - name: Run Unit Tests run: dotnet test src/Promitor.Tests.Unit/Promitor.Tests.Unit.csproj --logger "trx;LogFileName=test-results.trx" - # Provide Unit Test Results - - name: Report Unit Test Results - uses: dorny/test-reporter@v1 + # Publish Unit Test Results + - name: Upload Test Results + uses: actions/upload-artifact@v3 if: success() || failure() with: - name: .NET Unit Tests + name: test-results path: src/**/test-results.trx - reporter: dotnet-trx code_quality: runs-on: ubuntu-latest # or macos-latest, windows-latest name: Code Quality (R#) @@ -64,7 +63,7 @@ jobs: run: dotnet restore src/Promitor.sln - name: R# Code Quality - uses: muno92/resharper_inspectcode@1.6.9 + uses: muno92/resharper_inspectcode@1.7.1 with: solutionPath: src/Promitor.sln - minimumSeverity: warning \ No newline at end of file + minimumSeverity: warning diff --git a/.github/workflows/pr-post-comment.yml b/.github/workflows/pr-post-comment.yml new file mode 100644 index 000000000..43accb595 --- /dev/null +++ b/.github/workflows/pr-post-comment.yml @@ -0,0 +1,24 @@ +name: PR Bot + +on: + pull_request_target: + types: [opened] + branches: + - 'master' + +jobs: + pr_bot: + name: PR Bot + runs-on: ubuntu-latest + steps: + - name: 'Comment on PR' + uses: actions/github-script@v6 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: ${{ github.event.number }}, + body: 'Thank you for your contribution! 🙏 We will review it as soon as possible.' + }); diff --git a/.github/workflows/publish-ci-test-report.yml b/.github/workflows/publish-ci-test-report.yml new file mode 100644 index 000000000..f0a534cb2 --- /dev/null +++ b/.github/workflows/publish-ci-test-report.yml @@ -0,0 +1,32 @@ +name: 'Test Report' +on: + workflow_run: + workflows: ['CI - Code'] + types: + - completed + +permissions: + statuses: write + checks: write + contents: write + pull-requests: write + actions: write + +jobs: + report: + runs-on: ubuntu-latest + steps: + - name: Download artifact + id: download-artifact + uses: dawidd6/action-download-artifact@v2 + with: + run_id: ${{ github.event.workflow_run.id }} + name: test-results + + - name: Publish CI Test Results + uses: dorny/test-reporter@v1 + with: + artifact: test-results + name: .NET Unit Tests + path: '**/*.trx' + reporter: dotnet-trx diff --git a/.github/workflows/templates-build-push-image.yml b/.github/workflows/templates-build-push-image.yml index 04ed22b54..0bea6e5c7 100644 --- a/.github/workflows/templates-build-push-image.yml +++ b/.github/workflows/templates-build-push-image.yml @@ -32,7 +32,7 @@ jobs: echo "image_latest_uri=${{ inputs.image_name }}:${{ inputs.version }}" >> $GITHUB_ENV - name: Determine container image metadata - uses: docker/metadata-action@v4.3.0 + uses: docker/metadata-action@v4.6.0 with: images: ${{ inputs.image_name }} @@ -44,7 +44,7 @@ jobs: password: ${{ secrets.GITHUB_TOKEN }} - name: Build and push preview image - uses: docker/build-push-action@v4.0.0 + uses: docker/build-push-action@v4.1.1 with: build-args: VERSION="${{ env.artifact_full_version }}" context: ./src/ diff --git a/build/azure-devops/agents-ci-discovery.yml b/build/azure-devops/agents-ci-discovery.yml index efc12c1eb..16f927303 100644 --- a/build/azure-devops/agents-ci-discovery.yml +++ b/build/azure-devops/agents-ci-discovery.yml @@ -10,6 +10,7 @@ pr: paths: include: - src/* + - config/promitor/* - build/azure-devops/templates/* - build/azure-devops/agents-ci-discovery.yml variables: @@ -104,6 +105,7 @@ stages: - template: templates/tests/run-integration-tests.yml parameters: agentName: 'Resource Discovery' + testRunTitle: 'resource-discovery-linux' dotnetVersion: '$(DotNet.Sdk.Version)' buildConfiguration: '$(DotNet.Configuration)' - template: templates/docker/show-container-logs.yml @@ -163,6 +165,7 @@ stages: - template: templates/tests/run-integration-tests.yml parameters: agentName: 'Resource Discovery' + testRunTitle: 'resource-discovery-windows' dotnetVersion: '$(DotNet.Sdk.Version)' buildConfiguration: '$(DotNet.Configuration)' - template: templates/docker/show-container-logs.yml diff --git a/build/azure-devops/agents-ci-scraper.yml b/build/azure-devops/agents-ci-scraper.yml index 3d0d3b615..88759a234 100644 --- a/build/azure-devops/agents-ci-scraper.yml +++ b/build/azure-devops/agents-ci-scraper.yml @@ -10,6 +10,7 @@ pr: paths: include: - src/* + - config/promitor/* - build/azure-devops/templates/* - build/azure-devops/agents-ci-scraper.yml variables: @@ -150,6 +151,7 @@ stages: - template: templates/tests/run-integration-tests.yml parameters: agentName: 'Scraper' + testRunTitle: 'scraper-linux' dotnetVersion: '$(DotNet.Sdk.Version)' buildConfiguration: '$(DotNet.Configuration)' - template: templates/docker/show-container-logs.yml @@ -166,6 +168,10 @@ stages: parameters: agentName: 'Resource Discovery' url: '$(Agent.ResourceDiscovery.BaseUrl)/$(Agent.ResourceDiscovery.Prometheus.ScrapeUri)' + - template: templates/prometheus/show-prometheus-metrics.yml + parameters: + agentName: 'OpenTelemetry' + url: '$(OpenTelemetry.Collector.Uri)/$(Agent.OpenTelemetry.Prometheus.ScrapeUri)' - ${{ if eq(variables['Build.Reason'], 'PullRequest') }}: - template: templates/docker/push-image.yml parameters: @@ -249,6 +255,7 @@ stages: - template: templates/tests/run-integration-tests.yml parameters: agentName: 'Scraper' + testRunTitle: 'scraper-windows' dotnetVersion: '$(DotNet.Sdk.Version)' buildConfiguration: '$(DotNet.Configuration)' - template: templates/docker/show-container-logs.yml @@ -268,4 +275,4 @@ stages: - ${{ if eq(variables['Build.Reason'], 'PullRequest') }}: - template: templates/docker/push-image.yml parameters: - imageName: '$(Image.TaggedName)' \ No newline at end of file + imageName: '$(Image.TaggedName)' diff --git a/build/azure-devops/agents-resource-discovery-release-official.yml b/build/azure-devops/agents-resource-discovery-release-official.yml index 09315024f..25eb5935e 100644 --- a/build/azure-devops/agents-resource-discovery-release-official.yml +++ b/build/azure-devops/agents-resource-discovery-release-official.yml @@ -55,6 +55,8 @@ variables: value: NOTUSED - name: Agent.ResourceDiscovery.Version value: $(Image.Version) + - name: OpenTelemetry.Collector.Uri + value: http://notused:8889 stages: - stage: Init @@ -116,6 +118,7 @@ stages: - template: templates/tests/run-integration-tests.yml parameters: agentName: 'Resource Discovery' + testRunTitle: 'resource-discovery-linux' dotnetVersion: '$(DotNet.Sdk.Version)' buildConfiguration: '$(DotNet.Configuration)' - template: templates/docker/show-container-logs.yml @@ -187,6 +190,7 @@ stages: - template: templates/tests/run-integration-tests.yml parameters: agentName: 'Resource Discovery' + testRunTitle: 'resource-discovery-windows' dotnetVersion: '$(DotNet.Sdk.Version)' buildConfiguration: '$(DotNet.Configuration)' - template: templates/docker/show-container-logs.yml diff --git a/build/azure-devops/agents-scraper-release-official.yml b/build/azure-devops/agents-scraper-release-official.yml index 9f4e46f35..fd44c7ed6 100644 --- a/build/azure-devops/agents-scraper-release-official.yml +++ b/build/azure-devops/agents-scraper-release-official.yml @@ -160,9 +160,10 @@ stages: - template: templates/docker/show-running-containers.yml - template: templates/tests/run-integration-tests.yml parameters: - agentName: 'Scraper' - dotnetVersion: '$(DotNet.Sdk.Version)' - buildConfiguration: '$(DotNet.Configuration)' + agentName: 'Scraper' + testRunTitle: 'scraper-linux' + dotnetVersion: '$(DotNet.Sdk.Version)' + buildConfiguration: '$(DotNet.Configuration)' - template: templates/docker/show-container-logs.yml parameters: containerName: '$(Container.Scraper.Name)' @@ -261,11 +262,12 @@ stages: networkName: '$(Container.Network.Name)' os: '$(OS.Name)' - template: templates/docker/show-running-containers.yml - #- template: templates/tests/run-integration-tests.yml - # parameters: - # agentName: 'Scraper' - # dotnetVersion: '$(DotNet.Sdk.Version)' - # buildConfiguration: '$(DotNet.Configuration)' + - template: templates/tests/run-integration-tests.yml + parameters: + agentName: 'Scraper' + testRunTitle: 'scraper-windows' + dotnetVersion: '$(DotNet.Sdk.Version)' + buildConfiguration: '$(DotNet.Configuration)' - template: templates/docker/show-container-logs.yml parameters: containerName: '$(Container.Scraper.Name)' diff --git a/build/azure-devops/templates/build/install-sdk.yml b/build/azure-devops/templates/build/install-sdk.yml index e40c2c499..7cdabf093 100644 --- a/build/azure-devops/templates/build/install-sdk.yml +++ b/build/azure-devops/templates/build/install-sdk.yml @@ -4,7 +4,7 @@ parameters: steps: - task: UseDotNet@2 - displayName: 'Install .Net Core SDK (${{ parameters.dotnetVersion }})' + displayName: 'Install .NET Core SDK (${{ parameters.dotnetVersion }})' inputs: packageType: 'sdk' - version: '${{ parameters.dotnetVersion }}' \ No newline at end of file + version: '${{ parameters.dotnetVersion }}' diff --git a/build/azure-devops/templates/tests/run-integration-tests.yml b/build/azure-devops/templates/tests/run-integration-tests.yml index 1d3fddf6b..9c188a9e0 100644 --- a/build/azure-devops/templates/tests/run-integration-tests.yml +++ b/build/azure-devops/templates/tests/run-integration-tests.yml @@ -1,6 +1,8 @@ parameters: - name: agentName type: string +- name: testRunTitle + type: string - name: dotnetVersion type: string - name: buildConfiguration @@ -30,4 +32,5 @@ steps: projects: 'src/Promitor.Tests.Integration/Promitor.Tests.Integration.csproj' feedsToUse: 'config' nugetConfigPath: 'src/NuGet.config' + testRunTitle: ${{ parameters.testRunTitle }} arguments: '--configuration ${{ parameters.buildConfiguration }} --filter "Agent=${{ parameters.agentName}}"' \ No newline at end of file diff --git a/build/azure-devops/variables/build.yml b/build/azure-devops/variables/build.yml index 0876c00ba..1fa6775ff 100644 --- a/build/azure-devops/variables/build.yml +++ b/build/azure-devops/variables/build.yml @@ -1,3 +1,3 @@ variables: - DotNet.Sdk.Version: '7.0.103' + DotNet.Sdk.Version: '7.0.305' DotNet.Configuration: 'release' diff --git a/build/azure-devops/variables/tests.yml b/build/azure-devops/variables/tests.yml index f0518b878..8f0417ee5 100644 --- a/build/azure-devops/variables/tests.yml +++ b/build/azure-devops/variables/tests.yml @@ -3,3 +3,5 @@ variables: value: metrics - name: Agent.ResourceDiscovery.Prometheus.ScrapeUri value: metrics +- name: Agent.OpenTelemetry.Prometheus.ScrapeUri + value: metrics diff --git a/changelog/content/experimental/unreleased.md b/changelog/content/experimental/unreleased.md index 3f3cbbef3..41ae7d210 100644 --- a/changelog/content/experimental/unreleased.md +++ b/changelog/content/experimental/unreleased.md @@ -6,46 +6,14 @@ version: #### Scraper -- {{% tag added %}} Provide custom formatting for emitting metrics using StatsD sink in Geneva format -- {{% tag added %}} Provide capability to read Azure AD service principal secret from a file -- {{% tag added %}} Provide support for scraping multiple metrics dimensions ([#1820](https://github.com/tomkerkhove/promitor/issues/1820)) -- {{% tag added %}} Provide Azure Log Analytics scraper ([docs](https://docs.promitor.io/unreleased/scraping/providers/log-analytics/) | [#2132](https://github.com/tomkerkhove/promitor/pull/2132)) -- {{% tag added %}} Provide support for Azure Data Explorer Clusters ([docs](https://docs.promitor.io/unreleased/scraping/providers/data-explorer-clusters.md)) -- {{% tag added %}} Provide support for Azure NAT Gateway ([docs](https://docs.promitor.io/unreleased/scraping/providers/nat-gateway.md)) -- {{% tag added %}} Provide container vulnerability scanning in CI -- {{% tag added %}} Provide option to use a User Assigned Managed Identity without specifying the Client ID -- {{% tag added %}} Provide support for Public IP Address ([docs](https://docs.promitor.io/unreleased/scraping/providers/public-ip-address.md)) -- {{% tag security %}} Patch for [CVE-2023-0286](https://github.com/advisories/GHSA-x4qr-2fvf-3mr5) (Critical | Base image) -- {{% tag security %}} Patch for [CVE-2023-0215](https://github.com/advisories/GHSA-x4qr-2fvf-3mr5) (Critical | Base image) -- {{% tag security %}} Patch for [CVE-2022-41032](https://github.com/advisories/GHSA-g3q9-xf95-8hp5) (High) -- {{% tag security %}} Patch for [CVE-2022-4450](https://github.com/advisories/GHSA-v5w6-wcm8-jm4q) (High | Base image) -- {{% tag security %}} Patch for [CVE-2023-0215](https://github.com/advisories/GHSA-r7jw-wp68-3xch) (High | Base image) -- {{% tag security %}} Patch for [CVE-2022-42898](https://access.redhat.com/security/cve/cve-2022-42898) (High | Base image) -- {{% tag security %}} Patch for [CVE-2022-4304](https://github.com/advisories/GHSA-p52g-cm5j-mjv4) (Moderate | Base image) -- {{% tag fixed %}} Fixed a bug where startup throws scheduling exception due to metric misconfiguration -- {{% tag fixed %}} Fixed a bug where resource discovery for Azure Container Instances was not working -- {{% tag fixed %}} Fixed a bug where Promitor was reported as `unknown_service:dotnet` job in OpenTelemetry Collector -- {{% tag fixed %}} Fixed a bug where OpenTelemetry sink had concurrency issues -- {{% tag changed %}} Migrate to .NET 7 -- {{% tag changed %}} Migrate Resharper code quality check to GitHub Actions -- {{% tag deprecated %}} Support for scraping single metric dimension by using `metrics[x].azureMetricConfiguration.dimension` ([#1820](https://github.com/tomkerkhove/promitor/issues/1820)) +- {{% tag added %}} Provide support for all label scenarios in StatsD & OpenTelemetry metric sink. This includes +dimensions, customer & default labels. +- {{% tag added %}} Provide support for scraping multiple metrics dimensions. +- {{% tag changed %}} Switch to Mariner distroless base images +- {{% tag security %}} Patch for [CVE-2023-29331](https://github.com/advisories/GHSA-555c-2p6r-68mm) (High) +- {{% tag deprecated %}} Support for scraping single metric dimension by using `metrics[x].azureMetricConfiguration.dimension`. #### Resource Discovery -- {{% tag added %}} Provide path to read app secret key from file -- {{% tag added %}} Provide container vulnerability scanning in CI -- {{% tag added %}} Provide support for Azure Data Explorer Clusters ([docs](https://docs.promitor.io/unreleased/scraping/providers/data-explorer-clusters.md)) -- {{% tag added %}} Provide support for Azure NAT Gateway ([docs](https://docs.promitor.io/unreleased/scraping/providers/nat-gateway.md)) -- {{% tag added %}} Provide option to use a User Assigned Managed Identity without specifying the Client ID -- {{% tag added %}} Provide support for Public IP Address ([docs](https://docs.promitor.io/unreleased/scraping/providers/public-ip-address.md)) -- {{% tag security %}} Patch for [CVE-2022-37434](https://github.com/advisories/GHSA-cfmr-vrgj-vqwv) (Critical | Base image) -- {{% tag security %}} Patch for [CVE-2021-42377](https://github.com/advisories/GHSA-phvg-gc27-gjwp) (Critical | Base image) -- {{% tag security %}} Patch for [CVE-2022-38013](https://github.com/advisories/GHSA-r8m2-4x37-6592) (High) -- {{% tag security %}} Patch for [CVE-2022-41032](https://github.com/advisories/GHSA-g3q9-xf95-8hp5) (High) -- {{% tag security %}} Patch for [CVE-2023-0215](https://github.com/advisories/GHSA-r7jw-wp68-3xch) (High | Base image) -- {{% tag security %}} Patch for [CVE-2022-2097](https://github.com/advisories/GHSA-3wx7-46ch-7rq2) (High | Base image) -- {{% tag security %}} Patch for [CVE-2021-42373](https://github.com/advisories/GHSA-6w3h-h7gw-72qf) (High | Base image) -- {{% tag security %}} Patch for [CVE-2022-34716](https://github.com/advisories/GHSA-2m65-m22p-9wjw) (Moderate) -- {{% tag security %}} Patch for [CVE-2022-4304](https://github.com/advisories/GHSA-p52g-cm5j-mjv4) (Moderate | Base image) -- {{% tag changed %}} Migrate to .NET 7 -- {{% tag changed %}} Migrate Resharper code quality check to GitHub Actions +- {{% tag changed %}} Switch to Mariner distroless base images +- {{% tag security %}} Patch for [CVE-2023-29331](https://github.com/advisories/GHSA-555c-2p6r-68mm) (High) diff --git a/changelog/content/released/v0.9.0-resource-discovery.md b/changelog/content/released/v0.9.0-resource-discovery.md new file mode 100644 index 000000000..6a4cdeca8 --- /dev/null +++ b/changelog/content/released/v0.9.0-resource-discovery.md @@ -0,0 +1,28 @@ +--- +subtitle: "released on 2023-03-24" +date: 2023-03-24T07:00:47+02:00 +weight: 1019 +version: Resource Discovery - v0.9.0 +--- + +- {{% tag added %}} Provide Public IP Address scraper ([docs](https://docs.promitor.io/unreleased/scraping/providers/public-ip-address.md)) +- {{% tag added %}} Provide Azure Traffic Manager scraper ([docs](https://docs.promitor.io/unreleased/scraping/providers/traffic-manager.md)) +- {{% tag added %}} Provide Azure Log Analytics scraper ([docs](https://docs.promitor.io/unreleased/scraping/providers/log-analytics/)) +- {{% tag added %}} Provide Azure Data Explorer Cluster scraper ([docs](https://docs.promitor.io/unreleased/scraping/providers/data-explorer-clusters.md)) +- {{% tag added %}} Provide Azure NAT Gateway scraper ([docs](https://docs.promitor.io/unreleased/scraping/providers/nat-gateway.md)) +- {{% tag added %}} Provide capability to read Azure AD service principal secret from a file ([docs](https://docs.promitor.io/v2.9/security/azure-authentication/#service-principle-authentication)) +- {{% tag added %}} Provide option to use a User Assigned Managed Identity without specifying the Client ID +- {{% tag added %}} Provide container vulnerability scanning in CI +- {{% tag security %}} Patch for [CVE-2022-37434](https://github.com/advisories/GHSA-cfmr-vrgj-vqwv) (Critical | Base image) +- {{% tag security %}} Patch for [CVE-2021-42377](https://github.com/advisories/GHSA-phvg-gc27-gjwp) (Critical | Base image) +- {{% tag security %}} Patch for [CVE-2022-38013](https://github.com/advisories/GHSA-r8m2-4x37-6592) (High) +- {{% tag security %}} Patch for [CVE-2022-41032](https://github.com/advisories/GHSA-g3q9-xf95-8hp5) (High) +- {{% tag security %}} Patch for [CVE-2023-0215](https://github.com/advisories/GHSA-r7jw-wp68-3xch) (High | Base image) +- {{% tag security %}} Patch for [CVE-2022-2097](https://github.com/advisories/GHSA-3wx7-46ch-7rq2) (High | Base image) +- {{% tag security %}} Patch for [CVE-2021-42373](https://github.com/advisories/GHSA-6w3h-h7gw-72qf) (High | Base image) +- {{% tag security %}} Patch for [CVE-2022-34716](https://github.com/advisories/GHSA-2m65-m22p-9wjw) (Moderate) +- {{% tag security %}} Patch for [CVE-2022-4304](https://github.com/advisories/GHSA-p52g-cm5j-mjv4) (Moderate | Base image) +- {{% tag changed %}} Migrate to .NET 7 +- {{% tag changed %}} Migrate Resharper code quality check to GitHub Actions + +Full release notes can be found [here](https://github.com/tomkerkhove/promitor/releases/tag/ResourceDiscovery-v0.9.0). diff --git a/changelog/content/released/v0.9.1-resource-discovery.md b/changelog/content/released/v0.9.1-resource-discovery.md new file mode 100644 index 000000000..de97f2cf2 --- /dev/null +++ b/changelog/content/released/v0.9.1-resource-discovery.md @@ -0,0 +1,10 @@ +--- +subtitle: "released on 2023-03-20" +date: 2023-05-20T07:00:47+02:00 +weight: 1021 +version: Resource Discovery - v0.9.1 +--- + +- {{% tag security %}} Patch for [CVE-2023-28260](https://github.com/advisories/GHSA-w4m3-43gp-x8hx) (High | Base image) + +Full release notes can be found [here](https://github.com/tomkerkhove/promitor/releases/tag/ResourceDiscovery-v0.9.1). diff --git a/changelog/content/released/v2.9.0-scraper.md b/changelog/content/released/v2.9.0-scraper.md new file mode 100644 index 000000000..7e214739c --- /dev/null +++ b/changelog/content/released/v2.9.0-scraper.md @@ -0,0 +1,31 @@ +--- +subtitle: "released on 2023-03-24" +date: 2023-03-24T07:00:47+02:00 +weight: 1020 +version: Scraper - v2.9.0 +--- + +- {{% tag added %}} Provide Public IP Address scraper ([docs](https://docs.promitor.io/unreleased/scraping/providers/public-ip-address.md)) +- {{% tag added %}} Provide Azure Traffic Manager scraper ([docs](https://docs.promitor.io/unreleased/scraping/providers/traffic-manager.md)) +- {{% tag added %}} Provide Azure Log Analytics scraper ([docs](https://docs.promitor.io/unreleased/scraping/providers/log-analytics/)) +- {{% tag added %}} Provide Azure Data Explorer Cluster scraper ([docs](https://docs.promitor.io/unreleased/scraping/providers/data-explorer-clusters.md)) +- {{% tag added %}} Provide Azure NAT Gateway scraper ([docs](https://docs.promitor.io/unreleased/scraping/providers/nat-gateway.md)) +- {{% tag added %}} Provide capability to read Azure AD service principal secret from a file ([docs](https://docs.promitor.io/v2.9/security/azure-authentication/#service-principle-authentication)) +- {{% tag added %}} Provide option to use a User Assigned Managed Identity without specifying the Client ID +- {{% tag added %}} Provide custom formatting for emitting metrics using StatsD sink in Geneva format +- {{% tag added %}} Provide container vulnerability scanning in CI +- {{% tag security %}} Patch for [CVE-2023-0286](https://github.com/advisories/GHSA-x4qr-2fvf-3mr5) (Critical | Base image) +- {{% tag security %}} Patch for [CVE-2023-0215](https://github.com/advisories/GHSA-x4qr-2fvf-3mr5) (Critical | Base image) +- {{% tag security %}} Patch for [CVE-2022-41032](https://github.com/advisories/GHSA-g3q9-xf95-8hp5) (High) +- {{% tag security %}} Patch for [CVE-2022-4450](https://github.com/advisories/GHSA-v5w6-wcm8-jm4q) (High | Base image) +- {{% tag security %}} Patch for [CVE-2023-0215](https://github.com/advisories/GHSA-r7jw-wp68-3xch) (High | Base image) +- {{% tag security %}} Patch for [CVE-2022-42898](https://access.redhat.com/security/cve/cve-2022-42898) (High | Base image) +- {{% tag security %}} Patch for [CVE-2022-4304](https://github.com/advisories/GHSA-p52g-cm5j-mjv4) (Moderate | Base image) +- {{% tag fixed %}} Fixed a bug where startup throws scheduling exception due to metric misconfiguration +- {{% tag fixed %}} Fixed a bug where resource discovery for Azure Container Instances was not working +- {{% tag fixed %}} Fixed a bug where Promitor was reported as `unknown_service:dotnet` job in OpenTelemetry Collector +- {{% tag fixed %}} Fixed a bug where OpenTelemetry sink had concurrency issues +- {{% tag changed %}} Migrate to .NET 7 +- {{% tag changed %}} Migrate Resharper code quality check to GitHub Actions + +Full release notes can be found [here](https://github.com/tomkerkhove/promitor/releases/tag/Scraper-v2.9.0). diff --git a/changelog/content/released/v2.9.1-scraper.md b/changelog/content/released/v2.9.1-scraper.md new file mode 100644 index 000000000..afc4ca4d4 --- /dev/null +++ b/changelog/content/released/v2.9.1-scraper.md @@ -0,0 +1,10 @@ +--- +subtitle: "released on 2023-03-20" +date: 2023-05-20T07:00:47+02:00 +weight: 1022 +version: Scraper - v2.9.1 +--- + +- {{% tag security %}} Patch for [CVE-2023-28260](https://github.com/advisories/GHSA-w4m3-43gp-x8hx) (High | Base image) + +Full release notes can be found [here](https://github.com/tomkerkhove/promitor/releases/tag/Scraper-v2.9.1). diff --git a/config/opentelemetry-collector/collector-config.yaml b/config/opentelemetry-collector/collector-config.yaml index 7ae5ffe67..5efc22f2a 100644 --- a/config/opentelemetry-collector/collector-config.yaml +++ b/config/opentelemetry-collector/collector-config.yaml @@ -8,7 +8,7 @@ exporters: endpoint: "0.0.0.0:8889" namespace: otel const_labels: - app: promitor + source_app: promitor send_timestamps: true processors: @@ -22,4 +22,4 @@ service: metrics: receivers: [otlp] processors: [batch] - exporters: [prometheus] \ No newline at end of file + exporters: [prometheus] diff --git a/config/promitor/resource-discovery/resource-discovery-declaration.yaml b/config/promitor/resource-discovery/resource-discovery-declaration.yaml index 2a3139fb2..448b02acb 100644 --- a/config/promitor/resource-discovery/resource-discovery-declaration.yaml +++ b/config/promitor/resource-discovery/resource-discovery-declaration.yaml @@ -1,8 +1,8 @@ version: v1 azureLandscape: - tenantId: e0372f7f-a362-47fb-9631-74a5c4ba8bbf + tenantId: 56c6cf98-bd87-4684-ad83-f3b41dfdcb21 subscriptions: - - 63c590b6-4947-4898-92a3-cae91a31b5e4 + - 3566a5fa-878c-40fd-ac37-ef0ba0eee29d cloud: Global resourceDiscoveryGroups: - name: service-bus-landscape @@ -75,6 +75,8 @@ resourceDiscoveryGroups: type: SynapseSqlPool - name: synapse-workspaces type: SynapseWorkspace +- name: traffic-managers + type: TrafficManager - name: virtual-machines type: VirtualMachine - name: virtual-machine-scale-sets @@ -137,7 +139,7 @@ resourceDiscoveryGroups: criteria: include: subscriptions: - - 63c590b6-4947-4898-92a3-cae91a31b5e4 + - 3566a5fa-878c-40fd-ac37-ef0ba0eee29d - name: one-tag-scenario type: LogicApp criteria: @@ -171,4 +173,4 @@ resourceDiscoveryGroups: include: regions: - northeurope - - westeurope \ No newline at end of file + - westeurope diff --git a/config/promitor/resource-discovery/runtime.yaml b/config/promitor/resource-discovery/runtime.yaml index 1d39b50f3..a0a06f35b 100644 --- a/config/promitor/resource-discovery/runtime.yaml +++ b/config/promitor/resource-discovery/runtime.yaml @@ -2,7 +2,7 @@ server: httpPort: 88 authentication: mode: ServicePrincipal - identityId: bcb00b1d-7cde-4d05-b0fc-23a287697fa2 + identityId: 90a927a2-fa24-414a-a961-70f574d14df9 telemetry: applicationInsights: instrumentationKey: ABC diff --git a/config/promitor/scraper/metrics.yaml b/config/promitor/scraper/metrics.yaml index f0cadf569..09685c94d 100644 --- a/config/promitor/scraper/metrics.yaml +++ b/config/promitor/scraper/metrics.yaml @@ -1,7 +1,7 @@ version: v1 azureMetadata: - tenantId: e0372f7f-a362-47fb-9631-74a5c4ba8bbf - subscriptionId: 63c590b6-4947-4898-92a3-cae91a31b5e4 + tenantId: 56c6cf98-bd87-4684-ad83-f3b41dfdcb21 + subscriptionId: 3566a5fa-878c-40fd-ac37-ef0ba0eee29d resourceGroupName: promitor-testing-infrastructure-europe metricDefaults: aggregation: @@ -252,11 +252,11 @@ metrics: type: Average resources: # Application Insights with data in the service itself (classic, deprecated) - - name: promitor-automation-data-generation-we-telemetry-classic - resourceGroupName: promitor-automation-data-generation + - name: promitor-testing-resource-eu-telemetry-classic + resourceGroupName: promitor-testing-infrastructure-europe # Application Insights with data in Log Analytics - - name: promitor-automation-data-generation-we-telemetry - resourceGroupName: promitor-automation-data-generation + - name: promitor-testing-resource-eu-telemetry + resourceGroupName: promitor-testing-infrastructure-europe - name: promitor_demo_application_insights_availability_per_name description: "Availability (%) of promitor.io measured in Azure Application Insights per name" resourceType: ApplicationInsights @@ -268,11 +268,11 @@ metrics: name: availabilityResult/name resources: # Application Insights with data in the service itself (classic, deprecated) - - name: promitor-automation-data-generation-we-telemetry-classic - resourceGroupName: promitor-automation-data-generation + - name: promitor-testing-resource-eu-telemetry-classic + resourceGroupName: promitor-testing-infrastructure-europe # Application Insights with data in Log Analytics - - name: promitor-automation-data-generation-we-telemetry - resourceGroupName: promitor-automation-data-generation + - name: promitor-testing-infrastructure-europe-we-telemetry + resourceGroupName: promitor-testing-infrastructure-europe - name: promitor_demo_application_insights_availability_per_name_and_location description: "Availability (%) of promitor.io measured in Azure Application Insights per name and location" resourceType: ApplicationInsights @@ -285,11 +285,11 @@ metrics: - name: availabilityResult/location resources: # Application Insights with data in the service itself (classic, deprecated) - - name: promitor-automation-data-generation-we-telemetry-classic - resourceGroupName: promitor-automation-data-generation - # Application Insights with data in Log Analytics - - name: promitor-automation-data-generation-we-telemetry - resourceGroupName: promitor-automation-data-generation + - name: promitor-testing-resource-eu-telemetry-classic + resourceGroupName: promitor-testing-infrastructure-europe + # Application Insights with data in Log Analytics + - name: promitor-testing-resource-eu-telemetry + resourceGroupName: promitor-testing-infrastructure-europe - name: promitor_demo_cdn_requests_discovered description: "Amount of requests sent to Azure CDN" resourceType: Cdn @@ -343,7 +343,7 @@ metrics: aggregation: interval: 7:00:00:00 resources: - - workspaceId: 1cf05fe4-96a8-4e14-9b57-13e7a200ecbb + - workspaceId: 7f07e0fe-36e7-44c8-b79c-7c7f65cb81a2 workspaceName: promitor-testing-resource-eu-logs - name: azure_container_instance_cpu_usage_discovered description: "Average cpu usage of our container instance" @@ -381,6 +381,15 @@ metrics: type: Maximum resourceDiscoveryGroups: - name: public-ip-addresses + - name: azure_traffic_manager_endpoint_qps + description: Number of times a Traffic Manager endpoint was returned in the given time frame + resourceType: TrafficManager + azureMetricConfiguration: + metricName: QpsByEndpoint + aggregation: + type: Total + resourceDiscoveryGroups: + - name: traffic-managers # This uses our large-scale data set containing 1000+ Azure Logic App instances # Uncomment if you want to test with this scale diff --git a/config/promitor/scraper/runtime.yaml b/config/promitor/scraper/runtime.yaml index dade38a1a..8c236eb45 100644 --- a/config/promitor/scraper/runtime.yaml +++ b/config/promitor/scraper/runtime.yaml @@ -2,7 +2,7 @@ server: httpPort: 88 authentication: mode: ServicePrincipal - identityId: 65351cf0-33f8-4f26-9b6f-3380cf910b50 + identityId: bd16d14f-7161-432b-86ad-0c31dfef44ac metricSinks: atlassianStatuspage: pageId: 4mwc0ny6bgw1 diff --git a/src/Promitor.Agents.Core/AgentStartup.cs b/src/Promitor.Agents.Core/AgentStartup.cs index cc5c73d10..831000d02 100644 --- a/src/Promitor.Agents.Core/AgentStartup.cs +++ b/src/Promitor.Agents.Core/AgentStartup.cs @@ -6,6 +6,7 @@ using Promitor.Agents.Core.Observability; using Serilog; using Serilog.Configuration; +using Serilog.Events; namespace Promitor.Agents.Core { @@ -53,7 +54,9 @@ protected virtual LoggerConfiguration CreateSerilogConfiguration(string componen { var defaultLogLevel = SerilogFactory.DetermineSinkLogLevel(telemetryConfiguration.DefaultVerbosity); var loggerConfiguration = new LoggerConfiguration() - .MinimumLevel.Is(defaultLogLevel); + .MinimumLevel.Is(defaultLogLevel) + .MinimumLevel.Override("Microsoft", LogEventLevel.Warning) + .MinimumLevel.Override("Microsoft.AspNetCore", LogEventLevel.Warning); loggerConfiguration = EnrichTelemetry(componentName, serviceProvider, loggerConfiguration); loggerConfiguration = FilterTelemetry(loggerConfiguration); diff --git a/src/Promitor.Agents.Core/Configuration/RuntimeConfiguration.cs b/src/Promitor.Agents.Core/Configuration/RuntimeConfiguration.cs index 00bd8d4ee..c5ffbbe51 100644 --- a/src/Promitor.Agents.Core/Configuration/RuntimeConfiguration.cs +++ b/src/Promitor.Agents.Core/Configuration/RuntimeConfiguration.cs @@ -6,8 +6,8 @@ namespace Promitor.Agents.Core.Configuration { public class RuntimeConfiguration { - public ServerConfiguration Server { get; set; } = new ServerConfiguration(); - public AuthenticationConfiguration Authentication { get; set; } = new AuthenticationConfiguration(); - public TelemetryConfiguration Telemetry { get; set; } = new TelemetryConfiguration(); + public ServerConfiguration Server { get; set; } = new(); + public AuthenticationConfiguration Authentication { get; set; } = new(); + public TelemetryConfiguration Telemetry { get; set; } = new(); } } \ No newline at end of file diff --git a/src/Promitor.Agents.Core/Configuration/Telemetry/TelemetryConfiguration.cs b/src/Promitor.Agents.Core/Configuration/Telemetry/TelemetryConfiguration.cs index 9d7b689fa..b95fdd04a 100644 --- a/src/Promitor.Agents.Core/Configuration/Telemetry/TelemetryConfiguration.cs +++ b/src/Promitor.Agents.Core/Configuration/Telemetry/TelemetryConfiguration.cs @@ -6,7 +6,7 @@ namespace Promitor.Agents.Core.Configuration.Telemetry public class TelemetryConfiguration { public LogLevel? DefaultVerbosity { get; set; } = Defaults.Telemetry.DefaultVerbosity; - public ContainerLogConfiguration ContainerLogs { get; set; } = new ContainerLogConfiguration(); - public ApplicationInsightsConfiguration ApplicationInsights { get; set; } = new ApplicationInsightsConfiguration(); + public ContainerLogConfiguration ContainerLogs { get; set; } = new(); + public ApplicationInsightsConfiguration ApplicationInsights { get; set; } = new(); } } diff --git a/src/Promitor.Agents.Core/Extensions/IApplicationBuilderExtensions.cs b/src/Promitor.Agents.Core/Extensions/IApplicationBuilderExtensions.cs index e93954ace..cb6bca2b6 100644 --- a/src/Promitor.Agents.Core/Extensions/IApplicationBuilderExtensions.cs +++ b/src/Promitor.Agents.Core/Extensions/IApplicationBuilderExtensions.cs @@ -62,24 +62,18 @@ public static IApplicationBuilder UseVersionMiddleware(this IApplicationBuilder /// Action to configure Open API public static IApplicationBuilder ExposeOpenApiUi(this IApplicationBuilder app, string apiName, Action openApiUiConfigurationAction = null, Action openApiConfigurationAction = null) { - if (openApiConfigurationAction == null) + openApiConfigurationAction ??= setupAction => { - openApiConfigurationAction = setupAction => - { - setupAction.RouteTemplate = "api/{documentName}/docs.json"; - setupAction.PreSerializeFilters.Add((swagger, request) => AutomaticallyBuildApiServerUrl(request, swagger)); - }; - } + setupAction.RouteTemplate = "api/{documentName}/docs.json"; + setupAction.PreSerializeFilters.Add((swagger, request) => AutomaticallyBuildApiServerUrl(request, swagger)); + }; - if (openApiUiConfigurationAction == null) + openApiUiConfigurationAction ??= swaggerUiOptions => { - openApiUiConfigurationAction = swaggerUiOptions => - { - swaggerUiOptions.ConfigureDefaultOptions(apiName); - swaggerUiOptions.SwaggerEndpoint("../v1/docs.json", apiName); - swaggerUiOptions.RoutePrefix = "api/docs"; - }; - } + swaggerUiOptions.ConfigureDefaultOptions(apiName); + swaggerUiOptions.SwaggerEndpoint("../v1/docs.json", apiName); + swaggerUiOptions.RoutePrefix = "api/docs"; + }; // New Swagger UI app.UseSwagger(openApiConfigurationAction); @@ -91,12 +85,12 @@ public static IApplicationBuilder ExposeOpenApiUi(this IApplicationBuilder app, private static void AutomaticallyBuildApiServerUrl(HttpRequest request, OpenApiDocument swagger) { // Default to simple scenario - string serverUrl = $"{request.Scheme}://{request.Host}"; + var serverUrl = $"{request.Scheme}://{request.Host}"; // If request forwarding is used, we need to see if we need to adapt // Here we need to use the host and prefix, when specified // This is required when using reverse proxies such as Azure API Management, Traefik, NGINX, etc. - if (request.Headers.ContainsKey("X-Forwarded-Host")) + if (request.Headers.TryGetValue("X-Forwarded-Host", out var forwardedHost)) { var urlPrefix = string.Empty; var prefixFromHeaders = request.Headers["X-Forwarded-Prefix"]; @@ -110,10 +104,10 @@ private static void AutomaticallyBuildApiServerUrl(HttpRequest request, OpenApiD } } - serverUrl = $"{request.Scheme}://{request.Headers["X-Forwarded-Host"]}{urlPrefix}"; + serverUrl = $"{request.Scheme}://{forwardedHost}{urlPrefix}"; } - swagger.Servers = new List {new OpenApiServer {Url = serverUrl}}; + swagger.Servers = new List {new() {Url = serverUrl}}; } } } diff --git a/src/Promitor.Agents.Core/Promitor.Agents.Core.csproj b/src/Promitor.Agents.Core/Promitor.Agents.Core.csproj index 29bb4101d..70ba4183c 100644 --- a/src/Promitor.Agents.Core/Promitor.Agents.Core.csproj +++ b/src/Promitor.Agents.Core/Promitor.Agents.Core.csproj @@ -1,8 +1,8 @@ - + net7.0 - 7.0.3 + 7.0.8 @@ -21,17 +21,17 @@ - - + + - + - + - + - + diff --git a/src/Promitor.Agents.ResourceDiscovery/Configuration/AgentRuntimeConfiguration.cs b/src/Promitor.Agents.ResourceDiscovery/Configuration/AgentRuntimeConfiguration.cs index 6a04dd289..fcc7d6f91 100644 --- a/src/Promitor.Agents.ResourceDiscovery/Configuration/AgentRuntimeConfiguration.cs +++ b/src/Promitor.Agents.ResourceDiscovery/Configuration/AgentRuntimeConfiguration.cs @@ -4,6 +4,6 @@ namespace Promitor.Agents.ResourceDiscovery.Configuration { public class AgentRuntimeConfiguration : RuntimeConfiguration { - public CacheConfiguration Cache { get; set; } = new CacheConfiguration(); + public CacheConfiguration Cache { get; set; } = new(); } } diff --git a/src/Promitor.Agents.ResourceDiscovery/Configuration/ResourceCriteria.cs b/src/Promitor.Agents.ResourceDiscovery/Configuration/ResourceCriteria.cs index 2c7825d95..e15b0a36e 100644 --- a/src/Promitor.Agents.ResourceDiscovery/Configuration/ResourceCriteria.cs +++ b/src/Promitor.Agents.ResourceDiscovery/Configuration/ResourceCriteria.cs @@ -4,9 +4,9 @@ namespace Promitor.Agents.ResourceDiscovery.Configuration { public class ResourceCriteria { - public Dictionary Tags { get; set; } = new Dictionary(); - public List Subscriptions { get; set; } = new List(); - public List ResourceGroups { get; set; } = new List(); - public List Regions { get; set; } = new List(); + public Dictionary Tags { get; set; } = new(); + public List Subscriptions { get; set; } = new(); + public List ResourceGroups { get; set; } = new(); + public List Regions { get; set; } = new(); } } \ No newline at end of file diff --git a/src/Promitor.Agents.ResourceDiscovery/Configuration/ResourceCriteriaDefinition.cs b/src/Promitor.Agents.ResourceDiscovery/Configuration/ResourceCriteriaDefinition.cs index 18dcc26df..acc2d2651 100644 --- a/src/Promitor.Agents.ResourceDiscovery/Configuration/ResourceCriteriaDefinition.cs +++ b/src/Promitor.Agents.ResourceDiscovery/Configuration/ResourceCriteriaDefinition.cs @@ -2,6 +2,6 @@ { public class ResourceCriteriaDefinition { - public ResourceCriteria Include { get; set; } = new ResourceCriteria(); + public ResourceCriteria Include { get; set; } = new(); } } \ No newline at end of file diff --git a/src/Promitor.Agents.ResourceDiscovery/Configuration/ResourceDiscoveryGroup.cs b/src/Promitor.Agents.ResourceDiscovery/Configuration/ResourceDiscoveryGroup.cs index 59c9cb085..bcb70dea2 100644 --- a/src/Promitor.Agents.ResourceDiscovery/Configuration/ResourceDiscoveryGroup.cs +++ b/src/Promitor.Agents.ResourceDiscovery/Configuration/ResourceDiscoveryGroup.cs @@ -6,6 +6,6 @@ public class ResourceDiscoveryGroup { public string Name { get; set; } public ResourceType Type { get; set; } - public ResourceCriteriaDefinition Criteria { get; set; } = new ResourceCriteriaDefinition(); + public ResourceCriteriaDefinition Criteria { get; set; } = new(); } } \ No newline at end of file diff --git a/src/Promitor.Agents.ResourceDiscovery/Dockerfile.linux b/src/Promitor.Agents.ResourceDiscovery/Dockerfile.linux index 3a48a4bf0..3c24c0a56 100644 --- a/src/Promitor.Agents.ResourceDiscovery/Dockerfile.linux +++ b/src/Promitor.Agents.ResourceDiscovery/Dockerfile.linux @@ -1,4 +1,4 @@ -FROM mcr.microsoft.com/dotnet/sdk:7.0.103-alpine3.16 AS build +FROM mcr.microsoft.com/dotnet/sdk:7.0.305-cbl-mariner2.0 AS build WORKDIR /src ARG VERSION="UNSET-VERSION" COPY Promitor.Agents.ResourceDiscovery/* Promitor.Agents.ResourceDiscovery/ @@ -10,16 +10,65 @@ COPY Promitor.Integrations.Azure/* Promitor.Integrations.Azure/ COPY Promitor.Integrations.AzureMonitor/* Promitor.Integrations.AzureMonitor/ COPY Promitor.Integrations.AzureStorage/* Promitor.Integrations.AzureStorage/ COPY Promitor.Integrations.LogAnalytics/* Promitor.Integrations.LogAnalytics/ +COPY Promitor.Integrations.Sinks.Core/* Promitor.Integrations.Sinks.Core/ COPY Promitor.Integrations.Sinks.Prometheus/* Promitor.Integrations.Sinks.Prometheus/ RUN dotnet publish Promitor.Agents.ResourceDiscovery/Promitor.Agents.ResourceDiscovery.csproj --configuration release --output /app /p:Version=$VERSION -FROM mcr.microsoft.com/dotnet/aspnet:7.0.3-alpine3.16 AS runtime +FROM mcr.microsoft.com/dotnet/aspnet:7.0.8-cbl-mariner2.0-distroless AS runtime-base + +FROM mcr.microsoft.com/cbl-mariner/base/core:2.0 AS installer + +RUN tdnf install -y fdupes \ + && tdnf clean all + +COPY --from=runtime-base / /staging1 +COPY --from=runtime-base / /staging2 + +# See https://docs.microsoft.com/en-us/dotnet/core/runtime-config/globalization +RUN tdnf install -y --releasever=2.0 --installroot /staging2 icu \ + && tdnf clean all --releasever=2.0 --installroot /staging2 + +# Prepare the staging2 directory to be copied to the final stage by removing unnecessary files +# that will only cause extra image bloat. +RUN \ + # Remove duplicates from staging2 that exist in staging1 + fdupes /staging1 /staging2 -rdpN \ + \ + # Delete duplicate symlinks + # Function to find and format symlinks w/o including root dir (format: /path/to/symlink /path/to/target) + && getsymlinks() { find $1 -type l -printf '%p %l\n' | sed -n "s/^\\$1\\(.*\\)/\\1/p"; } \ + # Combine set of symlinks between staging1 and staging2 + && (getsymlinks "/staging1"; getsymlinks "/staging2") \ + # Sort them + | sort \ + # Find the duplicates + | uniq -d \ + # Extract just the path to the symlink + | cut -d' ' -f1 \ + # Prepend the staging2 directory to the paths + | sed -e 's/^/\/staging2/' \ + # Delete the files + | xargs rm \ + \ + # General cleanup + && rm -rf /staging2/etc/tdnf \ + && rm -rf /staging2/run/* \ + && rm -rf /staging2/var/cache/tdnf \ + && rm -rf /staging2/var/lib/rpm \ + && rm -rf /staging2/usr/share/doc \ + && rm -rf /staging2/usr/share/man \ + && find /staging2/var/log -type f -size +0 -delete \ + \ + # Delete empty directories + && find /staging2 -type d -empty -delete + +FROM runtime-base AS runtime +COPY --from=installer /staging2/ / + WORKDIR /app ENV PROMITOR_CONFIG_FOLDER="/config/" COPY --from=build /app . -# See https://docs.microsoft.com/en-us/dotnet/core/runtime-config/globalization -RUN apk add --no-cache icu-libs ENV DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=false ENTRYPOINT ["dotnet", "Promitor.Agents.ResourceDiscovery.dll"] diff --git a/src/Promitor.Agents.ResourceDiscovery/Dockerfile.windows b/src/Promitor.Agents.ResourceDiscovery/Dockerfile.windows index f40155df5..a1033e32c 100644 --- a/src/Promitor.Agents.ResourceDiscovery/Dockerfile.windows +++ b/src/Promitor.Agents.ResourceDiscovery/Dockerfile.windows @@ -1,4 +1,4 @@ -FROM mcr.microsoft.com/dotnet/sdk:7.0.103 AS build +FROM mcr.microsoft.com/dotnet/sdk:7.0.305 AS build WORKDIR /src ARG VERSION="UNSET-VERSION" COPY Promitor.Agents.ResourceDiscovery/* Promitor.Agents.ResourceDiscovery/ @@ -10,10 +10,11 @@ COPY Promitor.Integrations.Azure/* Promitor.Integrations.Azure/ COPY Promitor.Integrations.AzureMonitor/* Promitor.Integrations.AzureMonitor/ COPY Promitor.Integrations.AzureStorage/* Promitor.Integrations.AzureStorage/ COPY Promitor.Integrations.LogAnalytics/* Promitor.Integrations.LogAnalytics/ +COPY Promitor.Integrations.Sinks.Core/* Promitor.Integrations.Sinks.Core/ COPY Promitor.Integrations.Sinks.Prometheus/* Promitor.Integrations.Sinks.Prometheus/ RUN dotnet publish Promitor.Agents.ResourceDiscovery/Promitor.Agents.ResourceDiscovery.csproj --configuration release --output /app /p:Version=%VERSION% -FROM mcr.microsoft.com/dotnet/aspnet:7.0.3 AS runtime +FROM mcr.microsoft.com/dotnet/aspnet:7.0.8 AS runtime WORKDIR /app ENV PROMITOR_CONFIG_FOLDER="c:/config/" COPY --from=build /app . diff --git a/src/Promitor.Agents.ResourceDiscovery/Extensions/IServiceCollectionExtensions.cs b/src/Promitor.Agents.ResourceDiscovery/Extensions/IServiceCollectionExtensions.cs index e3702ab48..bf063982f 100644 --- a/src/Promitor.Agents.ResourceDiscovery/Extensions/IServiceCollectionExtensions.cs +++ b/src/Promitor.Agents.ResourceDiscovery/Extensions/IServiceCollectionExtensions.cs @@ -78,13 +78,10 @@ public static IServiceCollection AddBackgroundJobs(this IServiceCollection servi { var jobName = "Azure Resource Group Discovery"; builder.AddJob( - jobServices => - { - return new AzureResourceGroupsDiscoveryBackgroundJob(jobName, - jobServices.GetRequiredService(), - jobServices.GetRequiredService(), - jobServices.GetRequiredService>()); - }, + jobServices => new AzureResourceGroupsDiscoveryBackgroundJob(jobName, + jobServices.GetRequiredService(), + jobServices.GetRequiredService(), + jobServices.GetRequiredService>()), schedulerOptions => { schedulerOptions.CronSchedule = "*/15 * * * *"; diff --git a/src/Promitor.Agents.ResourceDiscovery/Graph/AzureResourceGraph.cs b/src/Promitor.Agents.ResourceDiscovery/Graph/AzureResourceGraph.cs index 85eedc348..9883b3303 100644 --- a/src/Promitor.Agents.ResourceDiscovery/Graph/AzureResourceGraph.cs +++ b/src/Promitor.Agents.ResourceDiscovery/Graph/AzureResourceGraph.cs @@ -116,66 +116,64 @@ private async Task InteractWithAzureResourceGraphAsync(str { var graphClient = await GetOrCreateClient(); - bool isSuccessfulDependency = false; - using (var dependencyMeasurement = DurationMeasurement.Start()) + var isSuccessfulDependency = false; + using var dependencyMeasurement = DurationMeasurement.Start(); + try { - try - { - var response = await interactionFunc(graphClient); - isSuccessfulDependency = true; + var response = await interactionFunc(graphClient); + isSuccessfulDependency = true; - return response; - } - catch (ErrorResponseException responseException) + return response; + } + catch (ErrorResponseException responseException) + { + if (responseException.Response != null) { - if (responseException.Response != null) + if (responseException.Response.StatusCode == HttpStatusCode.Forbidden) { - if (responseException.Response.StatusCode == HttpStatusCode.Forbidden) - { - var unauthorizedException = CreateUnauthorizedException(targetSubscriptions); + var unauthorizedException = CreateUnauthorizedException(targetSubscriptions); - throw unauthorizedException; - } + throw unauthorizedException; + } - if (responseException.Response.StatusCode == HttpStatusCode.BadRequest) + if (responseException.Response.StatusCode == HttpStatusCode.BadRequest) + { + var response = JToken.Parse(responseException.Response.Content); + var errorDetails = response["error"]?["details"]; + if (errorDetails != null) { - var response = JToken.Parse(responseException.Response.Content); - var errorDetails = response["error"]?["details"]; - if (errorDetails != null) + var errorCodes = new List(); + foreach (var detailEntry in errorDetails) + { + errorCodes.Add(detailEntry["code"]?.ToString()); + } + + if (errorCodes.Any(errorCode => errorCode.Equals("NoValidSubscriptionsInQueryRequest", StringComparison.InvariantCultureIgnoreCase))) { - var errorCodes = new List(); - foreach (var detailEntry in errorDetails) - { - errorCodes.Add(detailEntry["code"]?.ToString()); - } - - if (errorCodes.Any(errorCode => errorCode.Equals("NoValidSubscriptionsInQueryRequest", StringComparison.InvariantCultureIgnoreCase))) - { - var invalidSubscriptionException = new QueryContainsInvalidSubscriptionException(targetSubscriptions); - _logger.LogCritical(invalidSubscriptionException, "Unable to query Azure Resource Graph"); - throw invalidSubscriptionException; - } + var invalidSubscriptionException = new QueryContainsInvalidSubscriptionException(targetSubscriptions); + _logger.LogCritical(invalidSubscriptionException, "Unable to query Azure Resource Graph"); + throw invalidSubscriptionException; } } } - - throw; } - finally - { - var contextualInformation = new Dictionary - { - {"Query", query}, - {"QueryName", queryName} - }; - if (targetSubscriptions?.Any() == true) - { - contextualInformation.Add("Subscriptions", targetSubscriptions); - } + throw; + } + finally + { + var contextualInformation = new Dictionary + { + {"Query", query}, + {"QueryName", queryName} + }; - _logger.LogDependency("Azure Resource Graph", query, "Query", isSuccessfulDependency, dependencyMeasurement, contextualInformation); + if (targetSubscriptions?.Any() == true) + { + contextualInformation.Add("Subscriptions", targetSubscriptions); } + + _logger.LogDependency("Azure Resource Graph", query, "Query", isSuccessfulDependency, dependencyMeasurement, contextualInformation); } }); } diff --git a/src/Promitor.Agents.ResourceDiscovery/Graph/ResourceDiscoveryFactory.cs b/src/Promitor.Agents.ResourceDiscovery/Graph/ResourceDiscoveryFactory.cs index 740436c21..83e4c7318 100644 --- a/src/Promitor.Agents.ResourceDiscovery/Graph/ResourceDiscoveryFactory.cs +++ b/src/Promitor.Agents.ResourceDiscovery/Graph/ResourceDiscoveryFactory.cs @@ -90,6 +90,8 @@ public static ResourceDiscoveryQuery UseResourceDiscoveryFor(ResourceType resour return new SynapseSqlPoolDiscoveryQuery(); case ResourceType.SynapseWorkspace: return new SynapseWorkspaceDiscoveryQuery(); + case ResourceType.TrafficManager: + return new TrafficManagerDiscoveryQuery(); case ResourceType.VirtualMachine: return new VirtualMachineDiscoveryQuery(); case ResourceType.VirtualMachineScaleSet: diff --git a/src/Promitor.Agents.ResourceDiscovery/Graph/ResourceTypes/TrafficManagerDiscoveryQuery.cs b/src/Promitor.Agents.ResourceDiscovery/Graph/ResourceTypes/TrafficManagerDiscoveryQuery.cs new file mode 100644 index 000000000..e39d59b41 --- /dev/null +++ b/src/Promitor.Agents.ResourceDiscovery/Graph/ResourceTypes/TrafficManagerDiscoveryQuery.cs @@ -0,0 +1,21 @@ +using GuardNet; +using Newtonsoft.Json.Linq; +using Promitor.Core.Contracts; +using Promitor.Core.Contracts.ResourceTypes; + +namespace Promitor.Agents.ResourceDiscovery.Graph.ResourceTypes +{ + public class TrafficManagerDiscoveryQuery : ResourceDiscoveryQuery + { + public override string[] ResourceTypes => new[] { "microsoft.network/trafficmanagerprofiles" }; + public override string[] ProjectedFieldNames => new[] { "subscriptionId", "resourceGroup", "type", "name" }; + + public override AzureResourceDefinition ParseResults(JToken resultRowEntry) + { + Guard.NotNull(resultRowEntry, nameof(resultRowEntry)); + + var resource = new TrafficManagerResourceDefinition(resultRowEntry[0]?.ToString(), resultRowEntry[1]?.ToString(), resultRowEntry[3]?.ToString()); + return resource; + } + } +} diff --git a/src/Promitor.Agents.ResourceDiscovery/Health/AzureResourceGraphHealthCheck.cs b/src/Promitor.Agents.ResourceDiscovery/Health/AzureResourceGraphHealthCheck.cs index 3c5184eb0..a7be6b252 100644 --- a/src/Promitor.Agents.ResourceDiscovery/Health/AzureResourceGraphHealthCheck.cs +++ b/src/Promitor.Agents.ResourceDiscovery/Health/AzureResourceGraphHealthCheck.cs @@ -31,7 +31,7 @@ public AzureResourceGraphHealthCheck(IAzureResourceGraph azureResourceGraph, IOp _resourceDeclarationMonitor = resourceDeclarationMonitor; } - public async Task CheckHealthAsync(HealthCheckContext context, CancellationToken cancellationToken = new CancellationToken()) + public async Task CheckHealthAsync(HealthCheckContext context, CancellationToken cancellationToken = new()) { var query = GraphQueryBuilder.ForResourceType("microsoft.logic/workflows") .Project("subscriptionId", "resourceGroup", "type", "name", "id") diff --git a/src/Promitor.Agents.ResourceDiscovery/Promitor.Agents.ResourceDiscovery.csproj b/src/Promitor.Agents.ResourceDiscovery/Promitor.Agents.ResourceDiscovery.csproj index 365d85568..a9c30e09a 100644 --- a/src/Promitor.Agents.ResourceDiscovery/Promitor.Agents.ResourceDiscovery.csproj +++ b/src/Promitor.Agents.ResourceDiscovery/Promitor.Agents.ResourceDiscovery.csproj @@ -3,7 +3,7 @@ net7.0 ..\docker-compose.dcproj - 7.0.3 + 7.0.8 true Docs\Open-Api.xml 159d036b-3697-40d4-bdc4-7d9736521375 @@ -36,12 +36,13 @@ - - - + + + + diff --git a/src/Promitor.Agents.Scraper/AzureMonitorClientFactory.cs b/src/Promitor.Agents.Scraper/AzureMonitorClientFactory.cs index 9bfb06b52..5937f947d 100644 --- a/src/Promitor.Agents.Scraper/AzureMonitorClientFactory.cs +++ b/src/Promitor.Agents.Scraper/AzureMonitorClientFactory.cs @@ -14,7 +14,7 @@ namespace Promitor.Agents.Scraper { public class AzureMonitorClientFactory { - private readonly Dictionary _azureMonitorClients = new Dictionary(); + private readonly Dictionary _azureMonitorClients = new(); /// /// Provides an Azure Monitor client @@ -31,9 +31,9 @@ public class AzureMonitorClientFactory /// Factory to create loggers with public AzureMonitorClient CreateIfNotExists(AzureEnvironment cloud, string tenantId, string subscriptionId, MetricSinkWriter metricSinkWriter, IAzureScrapingSystemMetricsPublisher azureScrapingSystemMetricsPublisher, IMemoryCache resourceMetricDefinitionMemoryCache, IConfiguration configuration, IOptions azureMonitorIntegrationConfiguration, IOptions azureMonitorLoggingConfiguration, ILoggerFactory loggerFactory) { - if (_azureMonitorClients.ContainsKey(subscriptionId)) + if (_azureMonitorClients.TryGetValue(subscriptionId, out var value)) { - return _azureMonitorClients[subscriptionId]; + return value; } var azureMonitorClient = CreateNewAzureMonitorClient(cloud, tenantId, subscriptionId, metricSinkWriter, azureScrapingSystemMetricsPublisher, resourceMetricDefinitionMemoryCache, configuration, azureMonitorIntegrationConfiguration, azureMonitorLoggingConfiguration, loggerFactory); diff --git a/src/Promitor.Agents.Scraper/Configuration/ScraperRuntimeConfiguration.cs b/src/Promitor.Agents.Scraper/Configuration/ScraperRuntimeConfiguration.cs index 48fd3f71d..54976f37b 100644 --- a/src/Promitor.Agents.Scraper/Configuration/ScraperRuntimeConfiguration.cs +++ b/src/Promitor.Agents.Scraper/Configuration/ScraperRuntimeConfiguration.cs @@ -7,9 +7,9 @@ namespace Promitor.Agents.Scraper.Configuration { public class ScraperRuntimeConfiguration : RuntimeConfiguration { - public AzureMonitorConfiguration AzureMonitor { get; set; } = new AzureMonitorConfiguration(); - public MetricsConfiguration MetricsConfiguration { get; set; } = new MetricsConfiguration(); - public MetricSinkConfiguration MetricSinks { get; set; } = new MetricSinkConfiguration(); + public AzureMonitorConfiguration AzureMonitor { get; set; } = new(); + public MetricsConfiguration MetricsConfiguration { get; set; } = new(); + public MetricSinkConfiguration MetricSinks { get; set; } = new(); public ResourceDiscoveryConfiguration ResourceDiscovery { get; set; } } } \ No newline at end of file diff --git a/src/Promitor.Agents.Scraper/Discovery/ResourceDiscoveryClient.cs b/src/Promitor.Agents.Scraper/Discovery/ResourceDiscoveryClient.cs index 447f59dd2..e490e146f 100644 --- a/src/Promitor.Agents.Scraper/Discovery/ResourceDiscoveryClient.cs +++ b/src/Promitor.Agents.Scraper/Discovery/ResourceDiscoveryClient.cs @@ -16,7 +16,7 @@ namespace Promitor.Agents.Scraper.Discovery { public class ResourceDiscoveryClient { - private readonly JsonSerializerSettings _serializerSettings = new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.Objects }; + private readonly JsonSerializerSettings _serializerSettings = new() { TypeNameHandling = TypeNameHandling.Objects }; private readonly IOptionsMonitor _configuration; private readonly ILogger _logger; private readonly HttpClient _httpClient; diff --git a/src/Promitor.Agents.Scraper/Discovery/StubResourceDiscoveryRepository.cs b/src/Promitor.Agents.Scraper/Discovery/StubResourceDiscoveryRepository.cs index a2c582f98..0295f8d6e 100644 --- a/src/Promitor.Agents.Scraper/Discovery/StubResourceDiscoveryRepository.cs +++ b/src/Promitor.Agents.Scraper/Discovery/StubResourceDiscoveryRepository.cs @@ -8,8 +8,8 @@ namespace Promitor.Agents.Scraper.Discovery { public class StubResourceDiscoveryRepository : IResourceDiscoveryRepository { - private static readonly List emptyResourceDefinitions = new List(); - private static readonly AgentHealthReport healthReport = new AgentHealthReport(); + private static readonly List emptyResourceDefinitions = new(); + private static readonly AgentHealthReport healthReport = new(); public Task> GetResourceDiscoveryGroupAsync(string resourceDiscoveryGroupName) { diff --git a/src/Promitor.Agents.Scraper/Dockerfile.linux b/src/Promitor.Agents.Scraper/Dockerfile.linux index 0fcdd43bf..093ca6b39 100644 --- a/src/Promitor.Agents.Scraper/Dockerfile.linux +++ b/src/Promitor.Agents.Scraper/Dockerfile.linux @@ -1,4 +1,4 @@ -FROM mcr.microsoft.com/dotnet/sdk:7.0.103-alpine3.16 AS build +FROM mcr.microsoft.com/dotnet/sdk:7.0.305-cbl-mariner2.0 AS build WORKDIR /src ARG VERSION="UNSET-VERSION" COPY Promitor.Core/* Promitor.Core/ @@ -10,6 +10,7 @@ COPY Promitor.Integrations.Azure/* Promitor.Integrations.Azure/ COPY Promitor.Integrations.AzureMonitor/* Promitor.Integrations.AzureMonitor/ COPY Promitor.Integrations.AzureStorage/* Promitor.Integrations.AzureStorage/ COPY Promitor.Integrations.LogAnalytics/* Promitor.Integrations.LogAnalytics/ +COPY Promitor.Integrations.Sinks.Core/* Promitor.Integrations.Sinks.Core/ COPY Promitor.Integrations.Sinks.Atlassian.Statuspage/* Promitor.Integrations.Sinks.Atlassian.Statuspage/ COPY Promitor.Integrations.Sinks.OpenTelemetry/* Promitor.Integrations.Sinks.OpenTelemetry/ COPY Promitor.Integrations.Sinks.Prometheus/* Promitor.Integrations.Sinks.Prometheus/ @@ -17,12 +18,60 @@ COPY Promitor.Integrations.Sinks.Statsd/* Promitor.Integrations.Sinks.Statsd/ COPY Promitor.Agents.Scraper/* Promitor.Agents.Scraper/ RUN dotnet publish Promitor.Agents.Scraper/Promitor.Agents.Scraper.csproj --configuration release --output app /p:Version=$VERSION -FROM mcr.microsoft.com/dotnet/aspnet:7.0.3-alpine3.16 as runtime +FROM mcr.microsoft.com/dotnet/aspnet:7.0.8-cbl-mariner2.0-distroless AS runtime-base + +FROM mcr.microsoft.com/cbl-mariner/base/core:2.0 AS installer + +RUN tdnf install -y fdupes \ + && tdnf clean all + +COPY --from=runtime-base / /staging1 +COPY --from=runtime-base / /staging2 + +# See https://docs.microsoft.com/en-us/dotnet/core/runtime-config/globalization +RUN tdnf install -y --releasever=2.0 --installroot /staging2 icu \ + && tdnf clean all --releasever=2.0 --installroot /staging2 + +# Prepare the staging2 directory to be copied to the final stage by removing unnecessary files +# that will only cause extra image bloat. +RUN \ + # Remove duplicates from staging2 that exist in staging1 + fdupes /staging1 /staging2 -rdpN \ + \ + # Delete duplicate symlinks + # Function to find and format symlinks w/o including root dir (format: /path/to/symlink /path/to/target) + && getsymlinks() { find $1 -type l -printf '%p %l\n' | sed -n "s/^\\$1\\(.*\\)/\\1/p"; } \ + # Combine set of symlinks between staging1 and staging2 + && (getsymlinks "/staging1"; getsymlinks "/staging2") \ + # Sort them + | sort \ + # Find the duplicates + | uniq -d \ + # Extract just the path to the symlink + | cut -d' ' -f1 \ + # Prepend the staging2 directory to the paths + | sed -e 's/^/\/staging2/' \ + # Delete the files + | xargs rm \ + \ + # General cleanup + && rm -rf /staging2/etc/tdnf \ + && rm -rf /staging2/run/* \ + && rm -rf /staging2/var/cache/tdnf \ + && rm -rf /staging2/var/lib/rpm \ + && rm -rf /staging2/usr/share/doc \ + && rm -rf /staging2/usr/share/man \ + && find /staging2/var/log -type f -size +0 -delete \ + \ + # Delete empty directories + && find /staging2 -type d -empty -delete + +FROM runtime-base AS runtime +COPY --from=installer /staging2/ / + WORKDIR /app ENV PROMITOR_CONFIG_FOLDER="/config/" -# See https://docs.microsoft.com/en-us/dotnet/core/runtime-config/globalization -RUN apk add --no-cache icu-libs ENV DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=false COPY --from=build /src/app . diff --git a/src/Promitor.Agents.Scraper/Dockerfile.windows b/src/Promitor.Agents.Scraper/Dockerfile.windows index 848880367..71e053d42 100644 --- a/src/Promitor.Agents.Scraper/Dockerfile.windows +++ b/src/Promitor.Agents.Scraper/Dockerfile.windows @@ -1,4 +1,4 @@ -FROM mcr.microsoft.com/dotnet/sdk:7.0.103 AS build +FROM mcr.microsoft.com/dotnet/sdk:7.0.305 AS build WORKDIR /src ARG VERSION="UNSET-VERSION" COPY Promitor.Core/* Promitor.Core/ @@ -10,6 +10,7 @@ COPY Promitor.Integrations.Azure/* Promitor.Integrations.Azure/ COPY Promitor.Integrations.AzureMonitor/* Promitor.Integrations.AzureMonitor/ COPY Promitor.Integrations.AzureStorage/* Promitor.Integrations.AzureStorage/ COPY Promitor.Integrations.LogAnalytics/* Promitor.Integrations.LogAnalytics/ +COPY Promitor.Integrations.Sinks.Core/* Promitor.Integrations.Sinks.Core/ COPY Promitor.Integrations.Sinks.Atlassian.Statuspage/* Promitor.Integrations.Sinks.Atlassian.Statuspage/ COPY Promitor.Integrations.Sinks.OpenTelemetry/* Promitor.Integrations.Sinks.OpenTelemetry/ COPY Promitor.Integrations.Sinks.Prometheus/* Promitor.Integrations.Sinks.Prometheus/ @@ -17,7 +18,7 @@ COPY Promitor.Integrations.Sinks.Statsd/* Promitor.Integrations.Sinks.Statsd/ COPY Promitor.Agents.Scraper/* Promitor.Agents.Scraper/ RUN dotnet publish Promitor.Agents.Scraper/Promitor.Agents.Scraper.csproj --configuration release --output app /p:Version=%VERSION% -FROM mcr.microsoft.com/dotnet/aspnet:7.0.3 as runtime +FROM mcr.microsoft.com/dotnet/aspnet:7.0.8 as runtime WORKDIR /app ENV PROMITOR_CONFIG_FOLDER="c:/config/" diff --git a/src/Promitor.Agents.Scraper/Health/ResourceDiscoveryHealthCheck.cs b/src/Promitor.Agents.Scraper/Health/ResourceDiscoveryHealthCheck.cs index dafcf6f11..f04ae6b5a 100644 --- a/src/Promitor.Agents.Scraper/Health/ResourceDiscoveryHealthCheck.cs +++ b/src/Promitor.Agents.Scraper/Health/ResourceDiscoveryHealthCheck.cs @@ -18,7 +18,7 @@ public ResourceDiscoveryHealthCheck(IResourceDiscoveryRepository resourceDiscove _resourceDiscoveryRepository = resourceDiscoveryRepository; } - public async Task CheckHealthAsync(HealthCheckContext context, CancellationToken cancellationToken = new CancellationToken()) + public async Task CheckHealthAsync(HealthCheckContext context, CancellationToken cancellationToken = new()) { try { diff --git a/src/Promitor.Agents.Scraper/Promitor.Agents.Scraper.csproj b/src/Promitor.Agents.Scraper/Promitor.Agents.Scraper.csproj index c6e0512c4..c83b51d61 100644 --- a/src/Promitor.Agents.Scraper/Promitor.Agents.Scraper.csproj +++ b/src/Promitor.Agents.Scraper/Promitor.Agents.Scraper.csproj @@ -3,7 +3,7 @@ net7.0 ..\docker-compose.dcproj - 7.0.3 + 7.0.8 @@ -36,14 +36,15 @@ - - - + + + - + + diff --git a/src/Promitor.Agents.Scraper/Validation/Exceptions/ValidationFailedException.cs b/src/Promitor.Agents.Scraper/Validation/Exceptions/ValidationFailedException.cs index 866fe52ed..c83580ad6 100644 --- a/src/Promitor.Agents.Scraper/Validation/Exceptions/ValidationFailedException.cs +++ b/src/Promitor.Agents.Scraper/Validation/Exceptions/ValidationFailedException.cs @@ -15,7 +15,7 @@ public ValidationFailedException(List validationResults) ValidationResults.AddRange(validationResults); } - public List ValidationResults { get; } = new List(); + public List ValidationResults { get; } = new(); private static string ListErrors(List validationResults) { diff --git a/src/Promitor.Agents.Scraper/Validation/Factories/MetricValidatorFactory.cs b/src/Promitor.Agents.Scraper/Validation/Factories/MetricValidatorFactory.cs index a59fe8dee..fa44b712b 100644 --- a/src/Promitor.Agents.Scraper/Validation/Factories/MetricValidatorFactory.cs +++ b/src/Promitor.Agents.Scraper/Validation/Factories/MetricValidatorFactory.cs @@ -103,6 +103,8 @@ internal static IMetricValidator GetValidatorFor(ResourceType resourceType) return new SynapseSqlPoolMetricValidator(); case ResourceType.SynapseWorkspace: return new SynapseWorkspaceMetricValidator(); + case ResourceType.TrafficManager: + return new TrafficManagerMetricValidator(); case ResourceType.VirtualMachineScaleSet: return new VirtualMachineScaleSetMetricValidator(); case ResourceType.VirtualNetwork: diff --git a/src/Promitor.Agents.Scraper/Validation/MetricDefinitions/AzureMetricConfigurationValidator.cs b/src/Promitor.Agents.Scraper/Validation/MetricDefinitions/AzureMetricConfigurationValidator.cs index 3b0fac393..bdf760d8f 100644 --- a/src/Promitor.Agents.Scraper/Validation/MetricDefinitions/AzureMetricConfigurationValidator.cs +++ b/src/Promitor.Agents.Scraper/Validation/MetricDefinitions/AzureMetricConfigurationValidator.cs @@ -56,7 +56,7 @@ private IEnumerable ValidateAzureMetricConfiguration(AzureMetricConfigur } if (azureMetricConfiguration.Dimension != null && azureMetricConfiguration.Dimensions.Any()) - { + { errorMessages.Add("Only one of 'dimensions' and 'dimension' is allowed. Please use 'dimensions'."); } diff --git a/src/Promitor.Agents.Scraper/Validation/MetricDefinitions/MetricsValidator.cs b/src/Promitor.Agents.Scraper/Validation/MetricDefinitions/MetricsValidator.cs index 03dddbcdf..6473211cb 100644 --- a/src/Promitor.Agents.Scraper/Validation/MetricDefinitions/MetricsValidator.cs +++ b/src/Promitor.Agents.Scraper/Validation/MetricDefinitions/MetricsValidator.cs @@ -22,7 +22,7 @@ public IList Validate(List metrics) Guard.NotNull(metrics, nameof(metrics)); var errorMessages = metrics - .SelectMany(metric => Validate(metric)) + .SelectMany(Validate) .AsParallel(); return errorMessages.ToList(); diff --git a/src/Promitor.Agents.Scraper/Validation/MetricDefinitions/ResourceTypes/EventHubsMetricValidator.cs b/src/Promitor.Agents.Scraper/Validation/MetricDefinitions/ResourceTypes/EventHubsMetricValidator.cs index ffe82dfa7..48d670b91 100644 --- a/src/Promitor.Agents.Scraper/Validation/MetricDefinitions/ResourceTypes/EventHubsMetricValidator.cs +++ b/src/Promitor.Agents.Scraper/Validation/MetricDefinitions/ResourceTypes/EventHubsMetricValidator.cs @@ -21,7 +21,7 @@ public IEnumerable Validate(MetricDefinition metricDefinition) { errorMessages.Add("At least one Dimension other than EntityName is defined."); } - + var isEntityNameDimensionConfigured = metricDefinition.AzureMetricConfiguration?.HasDimension(EntityNameDimension) ?? false; foreach (var resourceDefinition in metricDefinition.Resources.Cast()) diff --git a/src/Promitor.Agents.Scraper/Validation/MetricDefinitions/ResourceTypes/ServiceBusNamespaceMetricValidator.cs b/src/Promitor.Agents.Scraper/Validation/MetricDefinitions/ResourceTypes/ServiceBusNamespaceMetricValidator.cs index e2961043b..60602d6dd 100644 --- a/src/Promitor.Agents.Scraper/Validation/MetricDefinitions/ResourceTypes/ServiceBusNamespaceMetricValidator.cs +++ b/src/Promitor.Agents.Scraper/Validation/MetricDefinitions/ResourceTypes/ServiceBusNamespaceMetricValidator.cs @@ -23,7 +23,7 @@ public IEnumerable Validate(MetricDefinition metricDefinition) } var isEntityNameDimensionConfigured = metricDefinition.AzureMetricConfiguration?.HasDimension(EntityNameDimension) ?? false; - + foreach (var resourceDefinition in metricDefinition.Resources.Cast()) { if (string.IsNullOrWhiteSpace(resourceDefinition.Namespace)) diff --git a/src/Promitor.Agents.Scraper/Validation/MetricDefinitions/ResourceTypes/TrafficManagerMetricValidator.cs b/src/Promitor.Agents.Scraper/Validation/MetricDefinitions/ResourceTypes/TrafficManagerMetricValidator.cs new file mode 100644 index 000000000..ebec4f9ab --- /dev/null +++ b/src/Promitor.Agents.Scraper/Validation/MetricDefinitions/ResourceTypes/TrafficManagerMetricValidator.cs @@ -0,0 +1,25 @@ +using System.Collections.Generic; +using System.Linq; +using GuardNet; +using Promitor.Core.Scraping.Configuration.Model.Metrics; +using Promitor.Agents.Scraper.Validation.MetricDefinitions.Interfaces; +using Promitor.Core.Contracts.ResourceTypes; + +namespace Promitor.Agents.Scraper.Validation.MetricDefinitions.ResourceTypes +{ + internal class TrafficManagerMetricValidator : IMetricValidator + { + public IEnumerable Validate(MetricDefinition metricDefinition) + { + Guard.NotNull(metricDefinition, nameof(metricDefinition)); + + foreach (var resourceDefinition in metricDefinition.Resources.Cast()) + { + if (string.IsNullOrWhiteSpace(resourceDefinition.Name)) + { + yield return "No Azure Traffic Manager profile name is configured"; + } + } + } + } +} \ No newline at end of file diff --git a/src/Promitor.Core.Contracts/Promitor.Core.Contracts.csproj b/src/Promitor.Core.Contracts/Promitor.Core.Contracts.csproj index 18425f2e5..9882dce64 100644 --- a/src/Promitor.Core.Contracts/Promitor.Core.Contracts.csproj +++ b/src/Promitor.Core.Contracts/Promitor.Core.Contracts.csproj @@ -2,7 +2,7 @@ net7.0 - 7.0.3 + 7.0.8 diff --git a/src/Promitor.Core.Contracts/ResourceType.cs b/src/Promitor.Core.Contracts/ResourceType.cs index 708b03824..7f1eda278 100644 --- a/src/Promitor.Core.Contracts/ResourceType.cs +++ b/src/Promitor.Core.Contracts/ResourceType.cs @@ -53,5 +53,6 @@ public enum ResourceType DataExplorerCluster = 48, NatGateway = 49, PublicIpAddress = 50, + TrafficManager = 51, } } \ No newline at end of file diff --git a/src/Promitor.Core.Contracts/ResourceTypes/TrafficManagerResourceDefinition.cs b/src/Promitor.Core.Contracts/ResourceTypes/TrafficManagerResourceDefinition.cs new file mode 100644 index 000000000..d6ed3a19b --- /dev/null +++ b/src/Promitor.Core.Contracts/ResourceTypes/TrafficManagerResourceDefinition.cs @@ -0,0 +1,25 @@ +namespace Promitor.Core.Contracts.ResourceTypes +{ + /// + /// Represents an Azure Traffic manager profile resource. + /// + public class TrafficManagerResourceDefinition : AzureResourceDefinition + { + /// + /// Initializes a new instance of the class. + /// + /// Specify a subscription to scrape that defers from the default subscription. + /// The name of the resource group the server is in. + /// The name of the Azure Traffic manager profile resource. + public TrafficManagerResourceDefinition(string subscriptionId, string resourceGroupName, string name) + : base(ResourceType.TrafficManager, subscriptionId, resourceGroupName, name) + { + Name = name; + } + + /// + /// The name of the Azure Traffic manager profile resource. + /// + public string Name { get; } + } +} \ No newline at end of file diff --git a/src/Promitor.Core.Scraping/Configuration/Providers/MetricsDeclarationProvider.cs b/src/Promitor.Core.Scraping/Configuration/Providers/MetricsDeclarationProvider.cs index bf41497fb..93faf3a81 100644 --- a/src/Promitor.Core.Scraping/Configuration/Providers/MetricsDeclarationProvider.cs +++ b/src/Promitor.Core.Scraping/Configuration/Providers/MetricsDeclarationProvider.cs @@ -69,6 +69,7 @@ public virtual MetricsDeclaration Get(bool applyDefaults = false, IErrorReporter metric.LogAnalyticsConfiguration.Aggregation.Interval ??= config.MetricDefaults.Aggregation?.Interval; } } + return config; } diff --git a/src/Promitor.Core.Scraping/Configuration/Serialization/v1/Core/AzureResourceDeserializerFactory.cs b/src/Promitor.Core.Scraping/Configuration/Serialization/v1/Core/AzureResourceDeserializerFactory.cs index 884408c08..051b74063 100644 --- a/src/Promitor.Core.Scraping/Configuration/Serialization/v1/Core/AzureResourceDeserializerFactory.cs +++ b/src/Promitor.Core.Scraping/Configuration/Serialization/v1/Core/AzureResourceDeserializerFactory.cs @@ -159,6 +159,9 @@ public IDeserializer GetDeserializerFor(ResourceType case ResourceType.SynapseWorkspace: var synapseWorkspaceLogger = _loggerFactory.CreateLogger(); return new SynapseWorkspaceDeserializer(synapseWorkspaceLogger); + case ResourceType.TrafficManager: + var trafficManagerLogger = _loggerFactory.CreateLogger(); + return new TrafficManagerDeserializer(trafficManagerLogger); case ResourceType.VirtualMachine: var virtualMachineLogger = _loggerFactory.CreateLogger(); return new VirtualMachineDeserializer(virtualMachineLogger); diff --git a/src/Promitor.Core.Scraping/Configuration/Serialization/v1/Mapping/V1MappingProfile.cs b/src/Promitor.Core.Scraping/Configuration/Serialization/v1/Mapping/V1MappingProfile.cs index 1636fe310..08ec48dee 100644 --- a/src/Promitor.Core.Scraping/Configuration/Serialization/v1/Mapping/V1MappingProfile.cs +++ b/src/Promitor.Core.Scraping/Configuration/Serialization/v1/Mapping/V1MappingProfile.cs @@ -71,6 +71,7 @@ public V1MappingProfile() CreateMap(); CreateMap(); CreateMap(); + CreateMap(); CreateMap(); CreateMap(); CreateMap(); @@ -128,6 +129,7 @@ public V1MappingProfile() .Include() .Include() .Include() + .Include() .Include() .Include() .Include() diff --git a/src/Promitor.Core.Scraping/Configuration/Serialization/v1/Model/ResourceTypes/TrafficManagerResourceV1.cs b/src/Promitor.Core.Scraping/Configuration/Serialization/v1/Model/ResourceTypes/TrafficManagerResourceV1.cs new file mode 100644 index 000000000..0e1a4cc80 --- /dev/null +++ b/src/Promitor.Core.Scraping/Configuration/Serialization/v1/Model/ResourceTypes/TrafficManagerResourceV1.cs @@ -0,0 +1,13 @@ +namespace Promitor.Core.Scraping.Configuration.Serialization.v1.Model.ResourceTypes +{ + /// + /// Contains the configuration required to scrape an Azure Traffic Manager Profile. + /// + public class TrafficManagerResourceV1 : AzureResourceDefinitionV1 + { + /// + /// The name of the Azure Traffic Manager Profile to get metrics for. + /// + public string Name { get; set; } + } +} diff --git a/src/Promitor.Core.Scraping/Configuration/Serialization/v1/Providers/TrafficManagerDeserializer.cs b/src/Promitor.Core.Scraping/Configuration/Serialization/v1/Providers/TrafficManagerDeserializer.cs new file mode 100644 index 000000000..a1f74d24d --- /dev/null +++ b/src/Promitor.Core.Scraping/Configuration/Serialization/v1/Providers/TrafficManagerDeserializer.cs @@ -0,0 +1,14 @@ +using Microsoft.Extensions.Logging; +using Promitor.Core.Scraping.Configuration.Serialization.v1.Model.ResourceTypes; + +namespace Promitor.Core.Scraping.Configuration.Serialization.v1.Providers +{ + public class TrafficManagerDeserializer : ResourceDeserializer + { + public TrafficManagerDeserializer(ILogger logger) : base(logger) + { + Map(resource => resource.Name) + .IsRequired(); + } + } +} diff --git a/src/Promitor.Core.Scraping/Factories/MetricScraperFactory.cs b/src/Promitor.Core.Scraping/Factories/MetricScraperFactory.cs index 460ce3665..32ec3200f 100644 --- a/src/Promitor.Core.Scraping/Factories/MetricScraperFactory.cs +++ b/src/Promitor.Core.Scraping/Factories/MetricScraperFactory.cs @@ -129,6 +129,8 @@ public IScraper CreateScraper(ResourceType metricDefin return new SynapseSqlPoolScraper(scraperConfiguration); case ResourceType.SynapseWorkspace: return new SynapseWorkspaceScraper(scraperConfiguration); + case ResourceType.TrafficManager: + return new TrafficManagerScraper(scraperConfiguration); case ResourceType.VirtualMachine: return new VirtualMachineScraper(scraperConfiguration); case ResourceType.VirtualMachineScaleSet: diff --git a/src/Promitor.Core.Scraping/Promitor.Core.Scraping.csproj b/src/Promitor.Core.Scraping/Promitor.Core.Scraping.csproj index 811980ab2..5c74f5bd6 100644 --- a/src/Promitor.Core.Scraping/Promitor.Core.Scraping.csproj +++ b/src/Promitor.Core.Scraping/Promitor.Core.Scraping.csproj @@ -2,7 +2,7 @@ net7.0 - 7.0.3 + 7.0.8 8 @@ -21,7 +21,7 @@ - + diff --git a/src/Promitor.Core.Scraping/ResourceTypes/TrafficManagerScraper.cs b/src/Promitor.Core.Scraping/ResourceTypes/TrafficManagerScraper.cs new file mode 100644 index 000000000..913fa9a3f --- /dev/null +++ b/src/Promitor.Core.Scraping/ResourceTypes/TrafficManagerScraper.cs @@ -0,0 +1,24 @@ +using Promitor.Core.Contracts; +using Promitor.Core.Contracts.ResourceTypes; +using Promitor.Core.Scraping.Configuration.Model.Metrics; + +namespace Promitor.Core.Scraping.ResourceTypes +{ + /// + /// Scrapes an Azure Traffic manager profile. + /// + public class TrafficManagerScraper : AzureMonitorScraper + { + private const string ResourceUriTemplate = "subscriptions/{0}/resourceGroups/{1}/providers/Microsoft.Network/trafficmanagerprofiles/{2}"; + + public TrafficManagerScraper(ScraperConfiguration scraperConfiguration) + : base(scraperConfiguration) + { + } + + protected override string BuildResourceUri(string subscriptionId, ScrapeDefinition scrapeDefinition, TrafficManagerResourceDefinition resource) + { + return string.Format(ResourceUriTemplate, subscriptionId, scrapeDefinition.ResourceGroupName, resource.Name); + } + } +} \ No newline at end of file diff --git a/src/Promitor.Core.Telemetry/Promitor.Core.Telemetry.csproj b/src/Promitor.Core.Telemetry/Promitor.Core.Telemetry.csproj index 75325b8dd..be025a62a 100644 --- a/src/Promitor.Core.Telemetry/Promitor.Core.Telemetry.csproj +++ b/src/Promitor.Core.Telemetry/Promitor.Core.Telemetry.csproj @@ -1,8 +1,8 @@ - + net7.0 - 7.0.3 + 7.0.4 @@ -15,8 +15,8 @@ - - + + diff --git a/src/Promitor.Core/Metrics/MeasuredMetric.cs b/src/Promitor.Core/Metrics/MeasuredMetric.cs index 4807c2705..21634f194 100644 --- a/src/Promitor.Core/Metrics/MeasuredMetric.cs +++ b/src/Promitor.Core/Metrics/MeasuredMetric.cs @@ -59,13 +59,13 @@ public static MeasuredMetric CreateForDimensions(double? value, List dim Guard.NotNull(timeseries, nameof(timeseries)); Guard.For(() => timeseries.Metadatavalues.Any() == false); - var dimensions = new List(); + var dimensions = new List(); foreach (var dimensionName in dimensionNames) { var dimensionValue = timeseries.Metadatavalues.Single(metadataValue => metadataValue.Name?.Value.Equals(dimensionName, StringComparison.InvariantCultureIgnoreCase) == true).Value; dimensions.Add(new MeasuredMetricDimension(dimensionName, dimensionValue)); } - + return new MeasuredMetric(value, dimensions); } @@ -78,7 +78,7 @@ public static MeasuredMetric CreateForDimensions(List dimensionNames) Guard.NotAny(dimensionNames, nameof(dimensionNames)); var dimensions = dimensionNames.Select(name => new MeasuredMetricDimension(name, "unknown")).ToList(); - + return new MeasuredMetric(null, dimensions); } } diff --git a/src/Promitor.Core/Metrics/MeasuredMetricDimension.cs b/src/Promitor.Core/Metrics/MeasuredMetricDimension.cs index 1a106d06e..80ddcfb34 100644 --- a/src/Promitor.Core/Metrics/MeasuredMetricDimension.cs +++ b/src/Promitor.Core/Metrics/MeasuredMetricDimension.cs @@ -13,7 +13,7 @@ public class MeasuredMetricDimension /// Value of dimension /// public string Value { get; } - + public MeasuredMetricDimension(string dimensionName, string dimensionValue) { Guard.NotNullOrWhitespace(dimensionName, nameof(dimensionName)); diff --git a/src/Promitor.Core/Promitor.Core.csproj b/src/Promitor.Core/Promitor.Core.csproj index e829de33d..42526d54a 100644 --- a/src/Promitor.Core/Promitor.Core.csproj +++ b/src/Promitor.Core/Promitor.Core.csproj @@ -2,7 +2,7 @@ net7.0 - 7.0.3 + 7.0.8 @@ -14,18 +14,14 @@ - + - + - - - - - + diff --git a/src/Promitor.Core/ScrapeResult.cs b/src/Promitor.Core/ScrapeResult.cs index df7cfaa5a..0c4e6521b 100644 --- a/src/Promitor.Core/ScrapeResult.cs +++ b/src/Promitor.Core/ScrapeResult.cs @@ -95,6 +95,6 @@ public ScrapeResult(string subscriptionId, string resourceGroupName, string inst /// /// Labels that are related to the metric /// - public Dictionary Labels { get; } = new Dictionary(); + public Dictionary Labels { get; } = new(); } } \ No newline at end of file diff --git a/src/Promitor.Integrations.Azure/Authentication/AzureAuthenticationFactory.cs b/src/Promitor.Integrations.Azure/Authentication/AzureAuthenticationFactory.cs index 0c3cd7a36..19b89146c 100644 --- a/src/Promitor.Integrations.Azure/Authentication/AzureAuthenticationFactory.cs +++ b/src/Promitor.Integrations.Azure/Authentication/AzureAuthenticationFactory.cs @@ -21,14 +21,9 @@ public class AzureAuthenticationFactory /// Application configuration public static AzureAuthenticationInfo GetConfiguredAzureAuthentication(IConfiguration configuration) { - var authenticationConfiguration = configuration.GetSection("authentication").Get(); - // To be still compatible with existing infrastructure using previous version of Promitor, we need to check if the authentication section exists. // If not, we should use a default value - if (authenticationConfiguration == null) - { - authenticationConfiguration = new AuthenticationConfiguration(); - } + var authenticationConfiguration = configuration.GetSection("authentication").Get() ?? new AuthenticationConfiguration(); string applicationKey; diff --git a/src/Promitor.Integrations.Azure/Promitor.Integrations.Azure.csproj b/src/Promitor.Integrations.Azure/Promitor.Integrations.Azure.csproj index a63d53c9b..c0985813e 100644 --- a/src/Promitor.Integrations.Azure/Promitor.Integrations.Azure.csproj +++ b/src/Promitor.Integrations.Azure/Promitor.Integrations.Azure.csproj @@ -1,8 +1,8 @@ - + net7.0 - 7.0.3 + 7.0.8 @@ -15,10 +15,10 @@ - + - + diff --git a/src/Promitor.Integrations.AzureMonitor/AzureMonitorClient.cs b/src/Promitor.Integrations.AzureMonitor/AzureMonitorClient.cs index 2d26ecb6b..5dcd3672d 100644 --- a/src/Promitor.Integrations.AzureMonitor/AzureMonitorClient.cs +++ b/src/Promitor.Integrations.AzureMonitor/AzureMonitorClient.cs @@ -30,7 +30,7 @@ public class AzureMonitorClient private readonly IOptions _azureMonitorIntegrationConfiguration; private readonly TimeSpan _metricDefinitionCacheDuration = TimeSpan.FromHours(1); private readonly IAzure _authenticatedAzureSubscription; - private readonly AzureCredentialsFactory _azureCredentialsFactory = new AzureCredentialsFactory(); + private readonly AzureCredentialsFactory _azureCredentialsFactory = new(); private readonly IMemoryCache _resourceMetricDefinitionMemoryCache; private readonly ILogger _logger; @@ -189,8 +189,7 @@ private async Task GetRelevantMetric(string metricName, AggregationType private MetricValue GetMostRecentMetricValue(string metricName, TimeSeriesElement timeSeries, DateTime recordDateTime) { var relevantMetricValue = timeSeries.Data.Where(metricValue => metricValue.TimeStamp < recordDateTime) - .OrderByDescending(metricValue => metricValue.TimeStamp) - .FirstOrDefault(); + .MaxBy(metricValue => metricValue.TimeStamp); if (relevantMetricValue == null) { @@ -220,7 +219,7 @@ private MetricValue GetMostRecentMetricValue(string metricName, TimeSeriesElemen throw new Exception($"Unable to determine the metrics value for aggregator '{metricAggregation}'"); } } - + private IWithMetricsQueryExecute CreateMetricsQuery(AggregationType metricAggregation, TimeSpan metricsInterval, string metricFilter, List metricDimensions, int? metricLimit, IMetricDefinition metricDefinition, DateTime recordDateTime) { @@ -238,14 +237,14 @@ private IWithMetricsQueryExecute CreateMetricsQuery(AggregationType metricAggreg metricQuery.WithOdataFilter(filter); metricQuery.SelectTop(queryLimit); } - + if (metricDimensions.Any()) { string metricDimensionsFilter = string.Join(" and ", metricDimensions.Select(metricDimension => $"{metricDimension} eq '*'")); metricQuery.WithOdataFilter(metricDimensionsFilter); metricQuery.SelectTop(queryLimit); } - + return metricQuery; } @@ -257,7 +256,7 @@ private IAzure CreateAzureClient(AzureEnvironment azureCloud, string tenantId, s var azureClientConfiguration = Microsoft.Azure.Management.Fluent.Azure.Configure() .WithDelegatingHandler(monitorHandler); - + var azureMonitorLogging = azureMonitorLoggingConfiguration.Value; if (azureMonitorLogging.IsEnabled) { diff --git a/src/Promitor.Integrations.AzureMonitor/Configuration/AzureMonitorConfiguration.cs b/src/Promitor.Integrations.AzureMonitor/Configuration/AzureMonitorConfiguration.cs index e413909f5..ebf177f83 100644 --- a/src/Promitor.Integrations.AzureMonitor/Configuration/AzureMonitorConfiguration.cs +++ b/src/Promitor.Integrations.AzureMonitor/Configuration/AzureMonitorConfiguration.cs @@ -2,7 +2,7 @@ { public class AzureMonitorConfiguration { - public AzureMonitorIntegrationConfiguration Integration { get; set; } = new AzureMonitorIntegrationConfiguration(); - public AzureMonitorLoggingConfiguration Logging { get; set; } = new AzureMonitorLoggingConfiguration(); + public AzureMonitorIntegrationConfiguration Integration { get; set; } = new(); + public AzureMonitorLoggingConfiguration Logging { get; set; } = new(); } } \ No newline at end of file diff --git a/src/Promitor.Integrations.AzureMonitor/Configuration/AzureMonitorIntegrationConfiguration.cs b/src/Promitor.Integrations.AzureMonitor/Configuration/AzureMonitorIntegrationConfiguration.cs index 2919c39c7..52daf0f65 100644 --- a/src/Promitor.Integrations.AzureMonitor/Configuration/AzureMonitorIntegrationConfiguration.cs +++ b/src/Promitor.Integrations.AzureMonitor/Configuration/AzureMonitorIntegrationConfiguration.cs @@ -2,6 +2,6 @@ { public class AzureMonitorIntegrationConfiguration { - public AzureMonitorHistoryConfiguration History { get; set; } = new AzureMonitorHistoryConfiguration(); + public AzureMonitorHistoryConfiguration History { get; set; } = new(); } } \ No newline at end of file diff --git a/src/Promitor.Integrations.AzureMonitor/Promitor.Integrations.AzureMonitor.csproj b/src/Promitor.Integrations.AzureMonitor/Promitor.Integrations.AzureMonitor.csproj index c77a64cdf..8d8dcffb3 100644 --- a/src/Promitor.Integrations.AzureMonitor/Promitor.Integrations.AzureMonitor.csproj +++ b/src/Promitor.Integrations.AzureMonitor/Promitor.Integrations.AzureMonitor.csproj @@ -2,7 +2,7 @@ net7.0 - 7.0.3 + 7.0.8 @@ -17,7 +17,7 @@ - + diff --git a/src/Promitor.Integrations.AzureStorage/Promitor.Integrations.AzureStorage.csproj b/src/Promitor.Integrations.AzureStorage/Promitor.Integrations.AzureStorage.csproj index b6bb46211..6a71ffe8e 100644 --- a/src/Promitor.Integrations.AzureStorage/Promitor.Integrations.AzureStorage.csproj +++ b/src/Promitor.Integrations.AzureStorage/Promitor.Integrations.AzureStorage.csproj @@ -1,14 +1,14 @@  - - net7.0 - 7.0.3 - + + net7.0 + 7.0.8 + - - - - - + + + + + diff --git a/src/Promitor.Integrations.LogAnalytics/LogAnalyticsClient.cs b/src/Promitor.Integrations.LogAnalytics/LogAnalyticsClient.cs index 965793c0c..c4f921a27 100644 --- a/src/Promitor.Integrations.LogAnalytics/LogAnalyticsClient.cs +++ b/src/Promitor.Integrations.LogAnalytics/LogAnalyticsClient.cs @@ -13,8 +13,8 @@ public class LogAnalyticsClient { private readonly ILogger _logger; public readonly string ColumnNameResult = "result"; - private readonly Uri _defaultEndpoint = new Uri("https://api.loganalytics.io"); - private readonly Uri _govEndpoint = new Uri("https://api.loganalytics.us"); + private readonly Uri _defaultEndpoint = new("https://api.loganalytics.io"); + private readonly Uri _govEndpoint = new("https://api.loganalytics.us"); private readonly LogsQueryClient _logsQueryClient; diff --git a/src/Promitor.Integrations.LogAnalytics/Promitor.Integrations.LogAnalytics.csproj b/src/Promitor.Integrations.LogAnalytics/Promitor.Integrations.LogAnalytics.csproj index 1f94034cd..c5c56133d 100644 --- a/src/Promitor.Integrations.LogAnalytics/Promitor.Integrations.LogAnalytics.csproj +++ b/src/Promitor.Integrations.LogAnalytics/Promitor.Integrations.LogAnalytics.csproj @@ -1,17 +1,17 @@  - - net7.0 - 6.0.9 - + + net7.0 + 7.0.8 + - - - - - - - - + + + + + + + + diff --git a/src/Promitor.Integrations.Sinks.Atlassian.Statuspage/AtlassianStatusPageMetricSink.cs b/src/Promitor.Integrations.Sinks.Atlassian.Statuspage/AtlassianStatusPageMetricSink.cs index 8a59ec0ff..155539350 100644 --- a/src/Promitor.Integrations.Sinks.Atlassian.Statuspage/AtlassianStatusPageMetricSink.cs +++ b/src/Promitor.Integrations.Sinks.Atlassian.Statuspage/AtlassianStatusPageMetricSink.cs @@ -6,28 +6,28 @@ using Microsoft.Extensions.Options; using Promitor.Core; using Promitor.Core.Metrics.Sinks; +using Promitor.Core.Scraping.Configuration.Providers.Interfaces; using Promitor.Integrations.Sinks.Atlassian.Statuspage.Configuration; +using Promitor.Integrations.Sinks.Core; namespace Promitor.Integrations.Sinks.Atlassian.Statuspage { - public class AtlassianStatuspageMetricSink : IMetricSink + public class AtlassianStatuspageMetricSink : MetricSink, IMetricSink { - private readonly ILogger _logger; private readonly IAtlassianStatuspageClient _atlassianStatusPageClient; private readonly IOptionsMonitor _sinkConfiguration; - public MetricSinkType Type { get; } = MetricSinkType.AtlassianStatuspage; + public MetricSinkType Type => MetricSinkType.AtlassianStatuspage; - public AtlassianStatuspageMetricSink(IAtlassianStatuspageClient atlassianStatusPageClient, IOptionsMonitor sinkConfiguration, ILogger logger) + public AtlassianStatuspageMetricSink(IAtlassianStatuspageClient atlassianStatusPageClient, IMetricsDeclarationProvider metricsDeclarationProvider, IOptionsMonitor sinkConfiguration, ILogger logger) + : base(metricsDeclarationProvider, logger) { Guard.NotNull(atlassianStatusPageClient, nameof(atlassianStatusPageClient)); Guard.NotNull(sinkConfiguration, nameof(sinkConfiguration)); Guard.NotNull(sinkConfiguration.CurrentValue, nameof(sinkConfiguration.CurrentValue)); - Guard.NotNull(logger, nameof(logger)); _atlassianStatusPageClient = atlassianStatusPageClient; _sinkConfiguration = sinkConfiguration; - _logger = logger; } public async Task ReportMetricAsync(string metricName, string metricDescription, ScrapeResult scrapeResult) @@ -59,7 +59,7 @@ public async Task ReportMetricAsync(string metricName, string metricDescription, await _atlassianStatusPageClient.ReportMetricAsync(systemMetricMapping.Id, metricValue); } - _logger.LogTrace("Metric {MetricName} with value {MetricValue} was written to Atlassian Statuspage", metricName, metricValue); + Logger.LogTrace("Metric {MetricName} with value {MetricValue} was written to Atlassian Statuspage", metricName, metricValue); } } } diff --git a/src/Promitor.Integrations.Sinks.Atlassian.Statuspage/Configuration/AtlassianStatusPageSinkConfiguration.cs b/src/Promitor.Integrations.Sinks.Atlassian.Statuspage/Configuration/AtlassianStatusPageSinkConfiguration.cs index ecebf8930..de28d606a 100644 --- a/src/Promitor.Integrations.Sinks.Atlassian.Statuspage/Configuration/AtlassianStatusPageSinkConfiguration.cs +++ b/src/Promitor.Integrations.Sinks.Atlassian.Statuspage/Configuration/AtlassianStatusPageSinkConfiguration.cs @@ -5,6 +5,6 @@ namespace Promitor.Integrations.Sinks.Atlassian.Statuspage.Configuration public class AtlassianStatusPageSinkConfiguration { public string PageId { get; set; } - public List SystemMetricMapping { get; set; } = new List(); + public List SystemMetricMapping { get; set; } = new(); } } \ No newline at end of file diff --git a/src/Promitor.Integrations.Sinks.Atlassian.Statuspage/Promitor.Integrations.Sinks.Atlassian.Statuspage.csproj b/src/Promitor.Integrations.Sinks.Atlassian.Statuspage/Promitor.Integrations.Sinks.Atlassian.Statuspage.csproj index fa6bb0164..52a94e8da 100644 --- a/src/Promitor.Integrations.Sinks.Atlassian.Statuspage/Promitor.Integrations.Sinks.Atlassian.Statuspage.csproj +++ b/src/Promitor.Integrations.Sinks.Atlassian.Statuspage/Promitor.Integrations.Sinks.Atlassian.Statuspage.csproj @@ -2,7 +2,7 @@ net7.0 - 7.0.3 + 7.0.8 @@ -20,6 +20,7 @@ + diff --git a/src/Promitor.Integrations.Sinks.Core/MetricSink.cs b/src/Promitor.Integrations.Sinks.Core/MetricSink.cs new file mode 100644 index 000000000..a86846bf4 --- /dev/null +++ b/src/Promitor.Integrations.Sinks.Core/MetricSink.cs @@ -0,0 +1,80 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using GuardNet; +using Microsoft.Extensions.Logging; +using Promitor.Core; +using Promitor.Core.Metrics; +using Promitor.Core.Scraping.Configuration.Providers.Interfaces; + +namespace Promitor.Integrations.Sinks.Core +{ + public class MetricSink + { + protected ILogger Logger { get; } + protected IMetricsDeclarationProvider MetricsDeclarationProvider { get; } + + protected MetricSink(IMetricsDeclarationProvider metricsDeclarationProvider, ILogger logger) + { + Guard.NotNull(metricsDeclarationProvider, nameof(metricsDeclarationProvider)); + Guard.NotNull(logger, nameof(logger)); + + MetricsDeclarationProvider = metricsDeclarationProvider; + Logger = logger; + } + + public Dictionary DetermineLabels(string metricName, ScrapeResult scrapeResult, MeasuredMetric measuredMetric, Func mutateLabelName = null) + { + var metricDefinition = MetricsDeclarationProvider.GetPrometheusDefinition(metricName); + var defaultLabels = MetricsDeclarationProvider.GetDefaultLabels(); + + var labels = new Dictionary(scrapeResult.Labels.Select(label => + { + var labelName = DetermineLabelName(label.Key, mutateLabelName); + return new KeyValuePair(labelName, label.Value); + })); + + if (measuredMetric.IsDimensional) + { + foreach (var dimension in measuredMetric.Dimensions) + { + labels.Add(DetermineLabelName(dimension.Name, mutateLabelName), dimension.Value); + } + } + + if (metricDefinition?.Labels?.Any() == true) + { + foreach (var customLabel in metricDefinition.Labels) + { + var customLabelKey = DetermineLabelName(customLabel.Key, mutateLabelName); + if (labels.TryGetValue(customLabelKey, out var label)) + { + Logger.LogWarning("Custom label {CustomLabelName} was already specified with value '{LabelValue}' instead of '{CustomLabelValue}'. Ignoring...", customLabel.Key, label, customLabel.Value); + continue; + } + + labels.Add(customLabelKey, customLabel.Value); + } + } + + foreach (var defaultLabel in defaultLabels) + { + var defaultLabelKey = DetermineLabelName(defaultLabel.Key, mutateLabelName); + labels.TryAdd(defaultLabelKey, defaultLabel.Value); + } + + // Add the tenant id + var metricsDeclaration = MetricsDeclarationProvider.Get(applyDefaults: true); + labels.TryAdd("tenant_id", metricsDeclaration.AzureMetadata.TenantId); + + var orderedLabels = labels.OrderBy(kvp => kvp.Key).ToDictionary(kvp => kvp.Key, kvp => kvp.Value); + + return orderedLabels; + } + + private static string DetermineLabelName(string originalLabelName, Func mutateLabelName) + { + return mutateLabelName!= null ? mutateLabelName.Invoke(originalLabelName) : originalLabelName; + } + } +} \ No newline at end of file diff --git a/src/Promitor.Integrations.Sinks.Core/Promitor.Integrations.Sinks.Core.csproj b/src/Promitor.Integrations.Sinks.Core/Promitor.Integrations.Sinks.Core.csproj new file mode 100644 index 000000000..95fec7114 --- /dev/null +++ b/src/Promitor.Integrations.Sinks.Core/Promitor.Integrations.Sinks.Core.csproj @@ -0,0 +1,20 @@ + + + + net7.0 + 7.0.7 + + + + 1701;1702;1591 + + + + 1701;1702;1591 + + + + + + + diff --git a/src/Promitor.Integrations.Sinks.OpenTelemetry/OpenTelemetryCollectorMetricSink.cs b/src/Promitor.Integrations.Sinks.OpenTelemetry/OpenTelemetryCollectorMetricSink.cs index a45b289af..03ddf8df3 100644 --- a/src/Promitor.Integrations.Sinks.OpenTelemetry/OpenTelemetryCollectorMetricSink.cs +++ b/src/Promitor.Integrations.Sinks.OpenTelemetry/OpenTelemetryCollectorMetricSink.cs @@ -9,17 +9,20 @@ using Microsoft.Extensions.Logging; using Promitor.Core; using Promitor.Core.Metrics.Sinks; +using Promitor.Core.Scraping.Configuration.Providers.Interfaces; +using Promitor.Integrations.Sinks.Core; namespace Promitor.Integrations.Sinks.OpenTelemetry { - public class OpenTelemetryCollectorMetricSink : IMetricSink + public class OpenTelemetryCollectorMetricSink : MetricSink, IMetricSink { private readonly ILogger _logger; - private static readonly Meter azureMonitorMeter = new Meter("Promitor.Scraper.Metrics.AzureMonitor", "1.0"); + private static readonly Meter azureMonitorMeter = new("Promitor.Scraper.Metrics.AzureMonitor", "1.0"); public MetricSinkType Type => MetricSinkType.OpenTelemetryCollector; - public OpenTelemetryCollectorMetricSink(ILogger logger) + public OpenTelemetryCollectorMetricSink(IMetricsDeclarationProvider metricsDeclarationProvider, ILogger logger) + : base(metricsDeclarationProvider, logger) { Guard.NotNull(logger, nameof(logger)); @@ -38,15 +41,17 @@ public async Task ReportMetricAsync(string metricName, string metricDescription, { var metricValue = measuredMetric.Value ?? 0; - var reportMetricTask = ReportMetricAsync(metricName, metricDescription, metricValue, scrapeResult.Labels); + var metricLabels = DetermineLabels(metricName, scrapeResult, measuredMetric); + + var reportMetricTask = ReportMetricAsync(metricName, metricDescription, metricValue, metricLabels); reportMetricTasks.Add(reportMetricTask); } await Task.WhenAll(reportMetricTasks); } - private readonly ConcurrentDictionary> _gauges = new ConcurrentDictionary>(); - private readonly ConcurrentDictionary>> _measurements = new ConcurrentDictionary>>(); + private readonly ConcurrentDictionary> _gauges = new(); + private readonly ConcurrentDictionary>> _measurements = new(); public async Task ReportMetricAsync(string metricName, string metricDescription, double metricValue, Dictionary labels) { @@ -68,7 +73,7 @@ public async Task ReportMetricAsync(string metricName, string metricDescription, private void InitializeNewMetric(string metricName, string metricDescription) { - var gauge = azureMonitorMeter.CreateObservableGauge(metricName, description: metricDescription, observeValues: () => ReportMeasurementsForMetricAsync(metricName).Result); + var gauge = azureMonitorMeter.CreateObservableGauge(metricName, description: metricDescription, observeValues: () => ReportMeasurementsForMetricAsync(metricName).Result); _gauges.TryAdd(metricName, gauge); _measurements.TryAdd(metricName, CreateNewMeasurementChannel()); diff --git a/src/Promitor.Integrations.Sinks.OpenTelemetry/Promitor.Integrations.Sinks.OpenTelemetry.csproj b/src/Promitor.Integrations.Sinks.OpenTelemetry/Promitor.Integrations.Sinks.OpenTelemetry.csproj index fe1423a2a..386e9e41a 100644 --- a/src/Promitor.Integrations.Sinks.OpenTelemetry/Promitor.Integrations.Sinks.OpenTelemetry.csproj +++ b/src/Promitor.Integrations.Sinks.OpenTelemetry/Promitor.Integrations.Sinks.OpenTelemetry.csproj @@ -2,7 +2,7 @@ net7.0 - 6.0.0 + 7.0.8 @@ -14,12 +14,13 @@ - - + + + diff --git a/src/Promitor.Integrations.Sinks.Prometheus/Collectors/AzureScrapingSystemMetricsPublisher.cs b/src/Promitor.Integrations.Sinks.Prometheus/Collectors/AzureScrapingSystemMetricsPublisher.cs index 3d0bc3591..c5e46b75c 100644 --- a/src/Promitor.Integrations.Sinks.Prometheus/Collectors/AzureScrapingSystemMetricsPublisher.cs +++ b/src/Promitor.Integrations.Sinks.Prometheus/Collectors/AzureScrapingSystemMetricsPublisher.cs @@ -37,10 +37,7 @@ public async Task WriteGaugeMeasurementAsync(string name, string description, do var enableMetricTimestamps = _prometheusConfiguration.CurrentValue.EnableMetricTimestamps; var metricsDeclaration = _metricsDeclarationProvider.Get(applyDefaults: true); - if (labels.ContainsKey("tenant_id") == false) - { - labels.Add("tenant_id", metricsDeclaration.AzureMetadata.TenantId); - } + labels.TryAdd("tenant_id", metricsDeclaration.AzureMetadata.TenantId); var orderedLabels = labels.OrderByDescending(kvp => kvp.Key).ToDictionary(kvp => kvp.Key, kvp => kvp.Value); diff --git a/src/Promitor.Integrations.Sinks.Prometheus/Configuration/PrometheusScrapingEndpointSinkConfiguration.cs b/src/Promitor.Integrations.Sinks.Prometheus/Configuration/PrometheusScrapingEndpointSinkConfiguration.cs index 17c33d64d..8739b9e50 100644 --- a/src/Promitor.Integrations.Sinks.Prometheus/Configuration/PrometheusScrapingEndpointSinkConfiguration.cs +++ b/src/Promitor.Integrations.Sinks.Prometheus/Configuration/PrometheusScrapingEndpointSinkConfiguration.cs @@ -5,6 +5,6 @@ public class PrometheusScrapingEndpointSinkConfiguration public string BaseUriPath { get; set; } = Defaults.Prometheus.ScrapeEndpointBaseUri; public double? MetricUnavailableValue { get; set; } = Defaults.Prometheus.MetricUnavailableValue; public bool EnableMetricTimestamps { get; set; } = Defaults.Prometheus.EnableMetricTimestamps; - public LabelConfiguration Labels { get; set; } = new LabelConfiguration(); + public LabelConfiguration Labels { get; set; } = new(); } } diff --git a/src/Promitor.Integrations.Sinks.Prometheus/PrometheusScrapingEndpointMetricSink.cs b/src/Promitor.Integrations.Sinks.Prometheus/PrometheusScrapingEndpointMetricSink.cs index 758f8502c..e21cd7d39 100644 --- a/src/Promitor.Integrations.Sinks.Prometheus/PrometheusScrapingEndpointMetricSink.cs +++ b/src/Promitor.Integrations.Sinks.Prometheus/PrometheusScrapingEndpointMetricSink.cs @@ -9,30 +9,26 @@ using Promitor.Core; using Promitor.Core.Metrics; using Promitor.Core.Metrics.Sinks; -using Promitor.Core.Scraping.Configuration.Model.Metrics; using Promitor.Core.Scraping.Configuration.Providers.Interfaces; +using Promitor.Integrations.Sinks.Core; using Promitor.Integrations.Sinks.Prometheus.Configuration; using Promitor.Integrations.Sinks.Prometheus.Labels; namespace Promitor.Integrations.Sinks.Prometheus { - public class PrometheusScrapingEndpointMetricSink : IMetricSink + public class PrometheusScrapingEndpointMetricSink : MetricSink, IMetricSink { private readonly IMetricFactory _metricFactory; - private readonly ILogger _logger; - private readonly IMetricsDeclarationProvider _metricsDeclarationProvider; private readonly IOptionsMonitor _prometheusConfiguration; public PrometheusScrapingEndpointMetricSink(IMetricFactory metricFactory, IMetricsDeclarationProvider metricsDeclarationProvider, IOptionsMonitor prometheusConfiguration, ILogger logger) + : base(metricsDeclarationProvider, logger) { Guard.NotNull(metricFactory, nameof(metricFactory)); Guard.NotNull(prometheusConfiguration, nameof(prometheusConfiguration)); - Guard.NotNull(logger, nameof(logger)); _metricFactory = metricFactory; - _metricsDeclarationProvider = metricsDeclarationProvider; _prometheusConfiguration = prometheusConfiguration; - _logger = logger; } public MetricSinkType Type => MetricSinkType.PrometheusScrapingEndpoint; @@ -48,10 +44,8 @@ public async Task ReportMetricAsync(string metricName, string metricDescription, foreach (var measuredMetric in scrapeResult.MetricValues) { var metricValue = DetermineMetricMeasurement(measuredMetric); - var metricDefinition = _metricsDeclarationProvider.GetPrometheusDefinition(metricName); - var defaultLabels = _metricsDeclarationProvider.GetDefaultLabels(); - var metricLabels = DetermineLabels(metricDefinition, scrapeResult, measuredMetric, defaultLabels); + var metricLabels = DetermineLabels(metricName, scrapeResult, measuredMetric); var reportMetricTask = ReportMetricAsync(metricName, metricDescription, metricValue, metricLabels); reportMetricTasks.Add(reportMetricTask); @@ -77,7 +71,7 @@ public Task ReportMetricAsync(string metricName, string metricDescription, doubl var gauge = CreateGauge(metricName, metricDescription, orderedLabels, enableMetricTimestamps); gauge.WithLabels(orderedLabels.Values.ToArray()).Set(metricValue); - _logger.LogTrace("Metric {MetricName} with value {MetricValue} was written to StatsD server", metricName, metricValue); + Logger.LogTrace("Metric {MetricName} with value {MetricValue} was written to StatsD server", metricName, metricValue); return Task.CompletedTask; } @@ -88,48 +82,9 @@ private IMetricFamily CreateGauge(string metricName, string metricDescri return gauge; } - private Dictionary DetermineLabels(PrometheusMetricDefinition metricDefinition, ScrapeResult scrapeResult, MeasuredMetric measuredMetric, Dictionary defaultLabels) + private Dictionary DetermineLabels(string metricName, ScrapeResult scrapeResult, MeasuredMetric measuredMetric) { - var labels = new Dictionary(scrapeResult.Labels.Select(label => new KeyValuePair(label.Key.SanitizeForPrometheusLabelKey(), label.Value))); - - if (measuredMetric.IsDimensional) - { - foreach (var dimension in measuredMetric.Dimensions) - { - labels.Add(dimension.Name.SanitizeForPrometheusLabelKey(), dimension.Value); - } - } - - if (metricDefinition?.Labels?.Any() == true) - { - foreach (var customLabel in metricDefinition.Labels) - { - var customLabelKey = customLabel.Key.SanitizeForPrometheusLabelKey(); - if (labels.ContainsKey(customLabelKey)) - { - _logger.LogWarning("Custom label {CustomLabelName} was already specified with value '{LabelValue}' instead of '{CustomLabelValue}'. Ignoring...", customLabel.Key, labels[customLabelKey], customLabel.Value); - continue; - } - - labels.Add(customLabelKey, customLabel.Value); - } - } - - foreach (var defaultLabel in defaultLabels) - { - var defaultLabelKey = defaultLabel.Key.SanitizeForPrometheusLabelKey(); - if (labels.ContainsKey(defaultLabelKey) == false) - { - labels.Add(defaultLabelKey, defaultLabel.Value); - } - } - - // Add the tenant id - var metricsDeclaration = _metricsDeclarationProvider.Get(applyDefaults: true); - if (labels.ContainsKey("tenant_id") == false) - { - labels.Add("tenant_id", metricsDeclaration.AzureMetadata.TenantId); - } + var labels = base.DetermineLabels(metricName, scrapeResult, measuredMetric, originalLabelName => originalLabelName.SanitizeForPrometheusLabelKey()); // Transform labels, if need be if (_prometheusConfiguration.CurrentValue.Labels != null) diff --git a/src/Promitor.Integrations.Sinks.Prometheus/Promitor.Integrations.Sinks.Prometheus.csproj b/src/Promitor.Integrations.Sinks.Prometheus/Promitor.Integrations.Sinks.Prometheus.csproj index eaf6f014a..07ab64ea4 100644 --- a/src/Promitor.Integrations.Sinks.Prometheus/Promitor.Integrations.Sinks.Prometheus.csproj +++ b/src/Promitor.Integrations.Sinks.Prometheus/Promitor.Integrations.Sinks.Prometheus.csproj @@ -2,7 +2,7 @@ net7.0 - 7.0.3 + 7.0.8 @@ -19,6 +19,7 @@ + diff --git a/src/Promitor.Integrations.Sinks.Statsd/Promitor.Integrations.Sinks.Statsd.csproj b/src/Promitor.Integrations.Sinks.Statsd/Promitor.Integrations.Sinks.Statsd.csproj index c4504804d..ab53883f9 100644 --- a/src/Promitor.Integrations.Sinks.Statsd/Promitor.Integrations.Sinks.Statsd.csproj +++ b/src/Promitor.Integrations.Sinks.Statsd/Promitor.Integrations.Sinks.Statsd.csproj @@ -2,7 +2,7 @@ net7.0 - 7.0.3 + 7.0.8 @@ -19,6 +19,7 @@ + diff --git a/src/Promitor.Integrations.Sinks.Statsd/StatsdMetricSink.cs b/src/Promitor.Integrations.Sinks.Statsd/StatsdMetricSink.cs index f20e5d47e..66f43fe83 100644 --- a/src/Promitor.Integrations.Sinks.Statsd/StatsdMetricSink.cs +++ b/src/Promitor.Integrations.Sinks.Statsd/StatsdMetricSink.cs @@ -9,17 +9,19 @@ using Newtonsoft.Json; using Promitor.Core; using Promitor.Core.Metrics.Sinks; +using Promitor.Core.Scraping.Configuration.Providers.Interfaces; +using Promitor.Integrations.Sinks.Core; using Promitor.Integrations.Sinks.Statsd.Configuration; namespace Promitor.Integrations.Sinks.Statsd { - public class StatsdMetricSink : IMetricSink + public class StatsdMetricSink : MetricSink, IMetricSink { - private readonly ILogger _logger; private readonly IStatsDPublisher _statsDPublisher; private readonly IOptionsMonitor _statsDConfiguration; - public StatsdMetricSink(IStatsDPublisher statsDPublisher, IOptionsMonitor configuration, ILogger logger) + public StatsdMetricSink(IStatsDPublisher statsDPublisher, IMetricsDeclarationProvider metricsDeclarationProvider, IOptionsMonitor configuration, ILogger logger) + : base(metricsDeclarationProvider, logger) { Guard.NotNull(statsDPublisher, nameof(statsDPublisher)); Guard.NotNull(logger, nameof(logger)); @@ -27,7 +29,6 @@ public StatsdMetricSink(IStatsDPublisher statsDPublisher, IOptionsMonitor MetricSinkType.StatsD; @@ -96,7 +97,7 @@ private Task ReportMetricWithGenevaFormattingAsync(string metricName, string met private void LogMetricWritten(string metricName, double metricValue) { - _logger.LogTrace("Metric {MetricName} with value {MetricValue} was written to StatsD server", metricName, metricValue); + Logger.LogTrace("Metric {MetricName} with value {MetricValue} was written to StatsD server", metricName, metricValue); } } } \ No newline at end of file diff --git a/src/Promitor.Tests.Integration/Clients/PrometheusClient.cs b/src/Promitor.Tests.Integration/Clients/PrometheusClient.cs index 6a717f61d..64e8703b6 100644 --- a/src/Promitor.Tests.Integration/Clients/PrometheusClient.cs +++ b/src/Promitor.Tests.Integration/Clients/PrometheusClient.cs @@ -88,7 +88,7 @@ private async Task WaitForPrometheusMetricAsync(Predicate filter) if (gauge == null) { - Logger.LogInformation($"No matching gauge was found."); + Logger.LogInformation("No matching gauge was found."); if (foundMetrics.Any()) { Logger.LogInformation($"Found metrics are: {string.Join(", ", foundMetrics.Select(x => x.Name))}"); diff --git a/src/Promitor.Tests.Integration/IntegrationTest.cs b/src/Promitor.Tests.Integration/IntegrationTest.cs index de8029638..b2bd139fe 100644 --- a/src/Promitor.Tests.Integration/IntegrationTest.cs +++ b/src/Promitor.Tests.Integration/IntegrationTest.cs @@ -12,7 +12,7 @@ public class IntegrationTest { protected IConfiguration Configuration { get; } protected XunitTestLogger Logger { get; } - public PrometheusClientFactory PrometheusClientFactory => new PrometheusClientFactory(Logger); + public PrometheusClientFactory PrometheusClientFactory => new(Logger); public IntegrationTest(ITestOutputHelper testOutput) { diff --git a/src/Promitor.Tests.Integration/Promitor.Tests.Integration.csproj b/src/Promitor.Tests.Integration/Promitor.Tests.Integration.csproj index 0deeff58a..978644482 100644 --- a/src/Promitor.Tests.Integration/Promitor.Tests.Integration.csproj +++ b/src/Promitor.Tests.Integration/Promitor.Tests.Integration.csproj @@ -2,7 +2,7 @@ net7.0 - 7.0.3 + 7.0.8 true @@ -18,12 +18,12 @@ - + - + - - + + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/src/Promitor.Tests.Integration/Services/ResourceDiscovery/ResourceDiscoveryTests.cs b/src/Promitor.Tests.Integration/Services/ResourceDiscovery/ResourceDiscoveryTests.cs index f1a688efa..a4a73f9c2 100644 --- a/src/Promitor.Tests.Integration/Services/ResourceDiscovery/ResourceDiscoveryTests.cs +++ b/src/Promitor.Tests.Integration/Services/ResourceDiscovery/ResourceDiscoveryTests.cs @@ -18,7 +18,7 @@ namespace Promitor.Tests.Integration.Services.ResourceDiscovery { public class ResourceDiscoveryTests : ResourceDiscoveryIntegrationTest { - private readonly Faker _bogusGenerator = new Faker(); + private readonly Faker _bogusGenerator = new(); public ResourceDiscoveryTests(ITestOutputHelper testOutput) : base(testOutput) @@ -104,7 +104,7 @@ public async Task ResourceDiscoveryV2_GetAllPerResourceTypeWithoutFilters_Return // Arrange const string resourceDiscoveryGroupName = "logic-apps-unfiltered"; const int pageSize = 1000; - const int expectedTotalResourceCount = 1012; + const int expectedTotalResourceCount = 1009; var resourceDiscoveryClient = new ResourceDiscoveryClient(Configuration, Logger); // Act & Assert @@ -135,7 +135,7 @@ public async Task ResourceDiscoveryV2_GetAllPerResourceTypeWithoutFiltersAndSpec { // Arrange const string resourceDiscoveryGroupName = "logic-apps-unfiltered"; - const int expectedTotalResources = 1012; + const int expectedTotalResources = 1009; const int pageSize = 500; int expectedResourceCount = pageSize; var resourceDiscoveryClient = new ResourceDiscoveryClient(Configuration, Logger); @@ -287,7 +287,7 @@ public async Task ResourceDiscoveryV2_GetWithFilterOnTwoRegions_ReturnsExpectedA { // Arrange const string resourceDiscoveryGroupName = "two-region-scenario"; - const int expectedResourceCount = 409; + const int expectedResourceCount = 406; var resourceDiscoveryClient = new ResourceDiscoveryClient(Configuration, Logger); // Act @@ -303,7 +303,7 @@ public async Task ResourceDiscoveryV1_GetAllPerResourceTypeWithoutFilters_Return // Arrange const string resourceDiscoveryGroupName = "logic-apps-unfiltered"; const int pageSize = 1000; - const int expectedTotalResourceCount = 1012; + const int expectedTotalResourceCount = 1009; var resourceDiscoveryClient = new ResourceDiscoveryClient(Configuration, Logger); // Act & Assert @@ -337,7 +337,7 @@ public async Task ResourceDiscoveryV1_GetAllPerResourceTypeWithoutFiltersAndSpec { // Arrange const string resourceDiscoveryGroupName = "logic-apps-unfiltered"; - const int expectedTotalAmount = 1012; + const int expectedTotalAmount = 1009; const int pageSize = 500; var expectedResourceCount = pageSize; var resourceDiscoveryClient = new ResourceDiscoveryClient(Configuration, Logger); @@ -489,7 +489,7 @@ public async Task ResourceDiscoveryV1_GetWithFilterOnTwoRegions_ReturnsExpectedA { // Arrange const string resourceDiscoveryGroupName = "two-region-scenario"; - const int expectedResourceCount = 409; + const int expectedResourceCount = 406; var resourceDiscoveryClient = new ResourceDiscoveryClient(Configuration, Logger); // Act diff --git a/src/Promitor.Tests.Integration/Services/Scraper/MetricSinks/PrometheusScrapeMetricSinkTests.cs b/src/Promitor.Tests.Integration/Services/Scraper/MetricSinks/PrometheusScrapeMetricSinkTests.cs index 540f81e7b..c20c45718 100644 --- a/src/Promitor.Tests.Integration/Services/Scraper/MetricSinks/PrometheusScrapeMetricSinkTests.cs +++ b/src/Promitor.Tests.Integration/Services/Scraper/MetricSinks/PrometheusScrapeMetricSinkTests.cs @@ -117,7 +117,7 @@ public async Task Prometheus_Scrape_ExpectedDimensionsAreAvailable(string expect Assert.NotEqual("unknown", gaugeMetric.Measurements[0].Labels[sanitizedDimensionName]); } } - + public static IEnumerable DimensionsData(){ yield return new object[] { "promitor_demo_application_insights_availability_per_name", new List{ "availabilityResult/name" } }; yield return new object[] { "promitor_demo_application_insights_availability_per_name_and_location", new List{ "availabilityResult/name", "availabilityResult/location" } }; diff --git a/src/Promitor.Tests.Unit/Agents/Core/Extensions/ConfigurationBuilder/AddRequiredYamlFileTests.cs b/src/Promitor.Tests.Unit/Agents/Core/Extensions/ConfigurationBuilder/AddRequiredYamlFileTests.cs index 062965b60..af42c7fac 100644 --- a/src/Promitor.Tests.Unit/Agents/Core/Extensions/ConfigurationBuilder/AddRequiredYamlFileTests.cs +++ b/src/Promitor.Tests.Unit/Agents/Core/Extensions/ConfigurationBuilder/AddRequiredYamlFileTests.cs @@ -11,7 +11,7 @@ namespace Promitor.Tests.Unit.Agents.Core.Extensions.ConfigurationBuilder public class AddRequiredYamlFileTests : IDisposable { - private readonly List _tempFiles = new List(); + private readonly List _tempFiles = new(); [Fact] public void AddRequiredYamlFile_FileExists_AddsFile() diff --git a/src/Promitor.Tests.Unit/Agents/ResourceDiscovery/AzureResourceGroupsDiscoveryBackgroundJobTests.cs b/src/Promitor.Tests.Unit/Agents/ResourceDiscovery/AzureResourceGroupsDiscoveryBackgroundJobTests.cs index a3c2b7afa..a05445ec4 100644 --- a/src/Promitor.Tests.Unit/Agents/ResourceDiscovery/AzureResourceGroupsDiscoveryBackgroundJobTests.cs +++ b/src/Promitor.Tests.Unit/Agents/ResourceDiscovery/AzureResourceGroupsDiscoveryBackgroundJobTests.cs @@ -27,12 +27,12 @@ public AzureResourceGroupsDiscoveryBackgroundJobTests() _firstPage = new Promitor.Core.Contracts.PagedPayload() { PageInformation = new Promitor.Core.Contracts.PageInformation { CurrentPage = 1, PageSize = 1, TotalRecords = 1 }, - Result = new List() { new AzureSubscriptionInformation { TenantId = "TenantId", Id = "ID", Name = "Name" } } + Result = new List() { new() { TenantId = "TenantId", Id = "ID", Name = "Name" } } }; var secondPage = new Promitor.Core.Contracts.PagedPayload() { PageInformation = new Promitor.Core.Contracts.PageInformation { CurrentPage = 2, PageSize = 1, TotalRecords = 1 }, - Result = new List() { new AzureSubscriptionInformation { TenantId = "TenantId", Id = "ID", Name = "Name" } } + Result = new List() { new() { TenantId = "TenantId", Id = "ID", Name = "Name" } } }; azureResourceRepository.Setup(r => r.DiscoverAzureSubscriptionsAsync(1000, 1)).ReturnsAsync(_firstPage); azureResourceRepository.Setup(r => r.DiscoverAzureSubscriptionsAsync(1000, 2)).ReturnsAsync(secondPage); diff --git a/src/Promitor.Tests.Unit/Builders/Metrics/v1/MetricsDeclarationBuilder.cs b/src/Promitor.Tests.Unit/Builders/Metrics/v1/MetricsDeclarationBuilder.cs index e0e4bd649..9f821f1e3 100644 --- a/src/Promitor.Tests.Unit/Builders/Metrics/v1/MetricsDeclarationBuilder.cs +++ b/src/Promitor.Tests.Unit/Builders/Metrics/v1/MetricsDeclarationBuilder.cs @@ -19,9 +19,9 @@ namespace Promitor.Tests.Unit.Builders.Metrics.v1 public class MetricsDeclarationBuilder { private readonly AzureMetadataV1 _azureMetadata; - private readonly List _metrics = new List(); + private readonly List _metrics = new(); - private MetricDefaultsV1 _metricDefaults = new MetricDefaultsV1 + private MetricDefaultsV1 _metricDefaults = new() { Scraping = new ScrapingV1 { Schedule = @"0 * * ? * *" } }; @@ -974,6 +974,24 @@ public MetricsDeclarationBuilder WithSynapseWorkspaceMetric( return this; } + public MetricsDeclarationBuilder WithTrafficManagerMetric(string metricName = "promitor", + string metricDescription = "Description for a metric", + string name = "promitor-traffic-manager", + string azureMetricName = "QpsByEndpoint", + string resourceDiscoveryGroupName = "", + int? azureMetricLimit = null, + bool omitResource = false) + { + var resource = new TrafficManagerResourceV1 + { + Name = name + }; + + CreateAndAddMetricDefinition(ResourceType.TrafficManager, metricName, metricDescription, resourceDiscoveryGroupName, omitResource, azureMetricName, azureMetricLimit, resource); + + return this; + } + public MetricsDeclarationBuilder WithVirtualMachineMetric(string metricName = "promitor-virtual-machine", string metricDescription = "Description for a metric", string virtualMachineName = "promitor-virtual-machine-name", @@ -1058,7 +1076,7 @@ private void CreateAndAddMetricDefinition(ResourceType resourceType, string metr { var azureMetricConfiguration = CreateAzureMetricConfiguration(azureMetricName, azureMetricLimit, metricDimensions); var logAnalyticsConfiguration = CreateLogAnalyticsConfiguration(query, interval); - + var metric = new MetricDefinitionV1 { Name = metricName, diff --git a/src/Promitor.Tests.Unit/Core/Scraping/Configuration/Model/Metrics/MetricDefinitionTests.cs b/src/Promitor.Tests.Unit/Core/Scraping/Configuration/Model/Metrics/MetricDefinitionTests.cs index e0cf15cf8..efa82e491 100644 --- a/src/Promitor.Tests.Unit/Core/Scraping/Configuration/Model/Metrics/MetricDefinitionTests.cs +++ b/src/Promitor.Tests.Unit/Core/Scraping/Configuration/Model/Metrics/MetricDefinitionTests.cs @@ -12,9 +12,9 @@ namespace Promitor.Tests.Unit.Core.Scraping.Configuration.Model.Metrics public class MetricDefinitionTests { private readonly PrometheusMetricDefinition _prometheusMetricDefinition = - new PrometheusMetricDefinition("promitor_test", "test", new Dictionary()); + new("promitor_test", "test", new Dictionary()); - private readonly AzureMetadata _azureMetadata = new AzureMetadata { ResourceGroupName = "global-resource-group", SubscriptionId = "global-subscription-id"}; + private readonly AzureMetadata _azureMetadata = new() { ResourceGroupName = "global-resource-group", SubscriptionId = "global-subscription-id"}; [Fact] public void CreateScrapeDefinition_ResourceOverridesResourceGroupName_UsesOverriddenName() diff --git a/src/Promitor.Tests.Unit/Generators/Config/RuntimeConfigurationGenerator.cs b/src/Promitor.Tests.Unit/Generators/Config/RuntimeConfigurationGenerator.cs index 1aa14eddf..cbcab7220 100644 --- a/src/Promitor.Tests.Unit/Generators/Config/RuntimeConfigurationGenerator.cs +++ b/src/Promitor.Tests.Unit/Generators/Config/RuntimeConfigurationGenerator.cs @@ -20,7 +20,7 @@ namespace Promitor.Tests.Unit.Generators.Config { internal class RuntimeConfigurationGenerator { - private readonly ScraperRuntimeConfiguration _runtimeConfiguration = new ScraperRuntimeConfiguration(); + private readonly ScraperRuntimeConfiguration _runtimeConfiguration = new(); private RuntimeConfigurationGenerator(ServerConfiguration serverConfiguration) { @@ -200,12 +200,8 @@ public RuntimeConfigurationGenerator WithContainerTelemetry(LogLevel? verbosity Verbosity = verbosity }; - if (_runtimeConfiguration.Telemetry == null) - { - _runtimeConfiguration.Telemetry = new TelemetryConfiguration(); - } - - _runtimeConfiguration.Telemetry.ContainerLogs = containerLogConfiguration; + _runtimeConfiguration.Telemetry ??= new TelemetryConfiguration(); +_runtimeConfiguration.Telemetry.ContainerLogs = containerLogConfiguration; return this; } @@ -221,11 +217,7 @@ public RuntimeConfigurationGenerator WithApplicationInsightsTelemetry(string ins Verbosity = verbosity }; - if (_runtimeConfiguration.Telemetry == null) - { - _runtimeConfiguration.Telemetry = new TelemetryConfiguration(); - } - + _runtimeConfiguration.Telemetry ??= new TelemetryConfiguration(); _runtimeConfiguration.Telemetry.ApplicationInsights = applicationInsightsTelemetry; return this; @@ -233,11 +225,7 @@ public RuntimeConfigurationGenerator WithApplicationInsightsTelemetry(string ins public RuntimeConfigurationGenerator WithAzureMonitorLogging(bool isEnabled = true, HttpLoggingDelegatingHandler.Level informationLevel = HttpLoggingDelegatingHandler.Level.Headers) { - if (_runtimeConfiguration.AzureMonitor == null) - { - _runtimeConfiguration.AzureMonitor = new AzureMonitorConfiguration(); - } - + _runtimeConfiguration.AzureMonitor ??= new AzureMonitorConfiguration(); _runtimeConfiguration.AzureMonitor.Logging = new AzureMonitorLoggingConfiguration { IsEnabled = isEnabled, @@ -292,7 +280,7 @@ public async Task GenerateAsync() configurationBuilder.AppendLine($" metricFormat: {_runtimeConfiguration?.MetricSinks.Statsd.MetricFormat}"); if (_runtimeConfiguration?.MetricSinks.Statsd.Geneva != null) { - configurationBuilder.AppendLine($" geneva:"); + configurationBuilder.AppendLine(" geneva:"); configurationBuilder.AppendLine($" account: {_runtimeConfiguration?.MetricSinks.Statsd.Geneva.Account}"); configurationBuilder.AppendLine($" namespace: {_runtimeConfiguration?.MetricSinks.Statsd.Geneva.Namespace}"); } diff --git a/src/Promitor.Tests.Unit/Generators/ScrapeResultGenerator.cs b/src/Promitor.Tests.Unit/Generators/ScrapeResultGenerator.cs index e46f3b72c..9248c0723 100644 --- a/src/Promitor.Tests.Unit/Generators/ScrapeResultGenerator.cs +++ b/src/Promitor.Tests.Unit/Generators/ScrapeResultGenerator.cs @@ -7,7 +7,7 @@ namespace Promitor.Tests.Unit.Generators { public class ScrapeResultGenerator { - private static readonly Faker bogus = new Faker(); + private static readonly Faker bogus = new(); public static ScrapeResult GenerateFromMetric(MeasuredMetric measuredMetric) { diff --git a/src/Promitor.Tests.Unit/Metrics/MetricSinkWriterTests.cs b/src/Promitor.Tests.Unit/Metrics/MetricSinkWriterTests.cs index 6d7b3bdcb..379e14f2c 100644 --- a/src/Promitor.Tests.Unit/Metrics/MetricSinkWriterTests.cs +++ b/src/Promitor.Tests.Unit/Metrics/MetricSinkWriterTests.cs @@ -11,13 +11,14 @@ using Promitor.Integrations.Sinks.Statsd; using Promitor.Integrations.Sinks.Statsd.Configuration; using Promitor.Tests.Unit.Generators; +using Promitor.Tests.Unit.Metrics.Sinks; using Promitor.Tests.Unit.Stubs; using Xunit; namespace Promitor.Tests.Unit.Metrics { [Category("Unit")] - public class MetricSinkWriterTests : UnitTest + public class MetricSinkWriterTests : MetricSinkTest { [Theory] [InlineData("")] @@ -159,9 +160,10 @@ public async Task ReportMetricAsync_WriteToStatsDSink_Succeeds() var metricDescription = BogusGenerator.Lorem.Sentence(); var metricValue = BogusGenerator.Random.Double(); var scrapeResult = ScrapeResultGenerator.Generate(metricValue); + var metricsDeclarationProvider = CreateMetricsDeclarationProvider(metricName); var statsDPublisherMock = new Mock(); var statsDSinkConfiguration = CreateStatsDConfiguration(); - var statsdMetricSink = new StatsdMetricSink(statsDPublisherMock.Object, statsDSinkConfiguration, NullLogger.Instance); + var statsdMetricSink = new StatsdMetricSink(statsDPublisherMock.Object, metricsDeclarationProvider, statsDSinkConfiguration, NullLogger.Instance); var metricSinkWriter = new MetricSinkWriter(new List { statsdMetricSink }, NullLogger.Instance); // Act diff --git a/src/Promitor.Tests.Unit/Metrics/Sinks/AtlassianStatuspageMetricSinkTests.cs b/src/Promitor.Tests.Unit/Metrics/Sinks/AtlassianStatuspageMetricSinkTests.cs index 4e180de85..35407f823 100644 --- a/src/Promitor.Tests.Unit/Metrics/Sinks/AtlassianStatuspageMetricSinkTests.cs +++ b/src/Promitor.Tests.Unit/Metrics/Sinks/AtlassianStatuspageMetricSinkTests.cs @@ -12,7 +12,7 @@ namespace Promitor.Tests.Unit.Metrics.Sinks { [Category("Unit")] - public class AtlassianStatuspageMetricSinkTests : UnitTest + public class AtlassianStatuspageMetricSinkTests : MetricSinkTest { [Theory] [InlineData("")] @@ -25,7 +25,8 @@ public async Task ReportMetricAsync_InputDoesNotContainMetricName_ThrowsExceptio var scrapeResult = ScrapeResultGenerator.Generate(metricValue); var systemMetricConfigOptions = BogusAtlassianStatuspageMetricSinkConfigurationGenerator.GetSinkConfiguration(); var atlassianStatuspageClientMock = new Mock(); - var metricSink = new AtlassianStatuspageMetricSink(atlassianStatuspageClientMock.Object, systemMetricConfigOptions, NullLogger.Instance); + var metricsDeclarationProvider = CreateMetricsDeclarationProvider(metricName); + var metricSink = new AtlassianStatuspageMetricSink(atlassianStatuspageClientMock.Object, metricsDeclarationProvider, systemMetricConfigOptions, NullLogger.Instance); // Act & Assert // ReSharper disable once ExpressionIsAlwaysNull @@ -44,7 +45,8 @@ public async Task ReportMetricAsync_InputDoesNotContainMetricDescription_Succeed var scrapeResult = ScrapeResultGenerator.GenerateFromMetric(measuredMetric); var systemMetricConfigOptions = BogusAtlassianStatuspageMetricSinkConfigurationGenerator.GetSinkConfiguration(); var atlassianStatuspageClientMock = new Mock(); - var metricSink = new AtlassianStatuspageMetricSink(atlassianStatuspageClientMock.Object, systemMetricConfigOptions, NullLogger.Instance); + var metricsDeclarationProvider = CreateMetricsDeclarationProvider(metricName); + var metricSink = new AtlassianStatuspageMetricSink(atlassianStatuspageClientMock.Object, metricsDeclarationProvider, systemMetricConfigOptions, NullLogger.Instance); // Act & Assert // ReSharper disable once ExpressionIsAlwaysNull @@ -59,7 +61,8 @@ public async Task ReportMetricAsync_InputDoesNotContainMeasuredMetric_ThrowsExce var metricDescription = BogusGenerator.Lorem.Sentence(); var systemMetricConfigOptions = BogusAtlassianStatuspageMetricSinkConfigurationGenerator.GetSinkConfiguration(); var atlassianStatuspageClientMock = new Mock(); - var metricSink = new AtlassianStatuspageMetricSink(atlassianStatuspageClientMock.Object, systemMetricConfigOptions, NullLogger.Instance); + var metricsDeclarationProvider = CreateMetricsDeclarationProvider(metricName); + var metricSink = new AtlassianStatuspageMetricSink(atlassianStatuspageClientMock.Object, metricsDeclarationProvider, systemMetricConfigOptions, NullLogger.Instance); // Act & Assert // ReSharper disable once ExpressionIsAlwaysNull @@ -74,11 +77,13 @@ public async Task ReportMetricAsync_GetsValidInputWithMetricValueAndPromitorToSy var systemMetricId = BogusGenerator.Name.FirstName(); var metricDescription = BogusGenerator.Lorem.Sentence(); var metricValue = BogusGenerator.Random.Double(); + var metricName = BogusGenerator.Name.FirstName(); var measuredMetric = MeasuredMetric.CreateWithoutDimensions(metricValue); var scrapeResult = ScrapeResultGenerator.GenerateFromMetric(measuredMetric); var systemMetricConfigOptions = BogusAtlassianStatuspageMetricSinkConfigurationGenerator.GetSinkConfiguration(systemMetricId: systemMetricId, promitorMetricName: promitorMetricName); var atlassianStatuspageClientMock = new Mock(); - var metricSink = new AtlassianStatuspageMetricSink(atlassianStatuspageClientMock.Object, systemMetricConfigOptions, NullLogger.Instance); + var metricsDeclarationProvider = CreateMetricsDeclarationProvider(metricName); + var metricSink = new AtlassianStatuspageMetricSink(atlassianStatuspageClientMock.Object, metricsDeclarationProvider, systemMetricConfigOptions, NullLogger.Instance); // Act await metricSink.ReportMetricAsync(promitorMetricName, metricDescription, scrapeResult); @@ -95,13 +100,15 @@ public async Task ReportMetricAsync_GetsValidInputWithoutMetricValueButWithPromi var promitorMetricName = BogusGenerator.Name.FirstName(); var systemMetricId = BogusGenerator.Name.FirstName(); var metricDescription = BogusGenerator.Lorem.Sentence(); + var metricName = BogusGenerator.Name.FirstName(); double? metricValue = null; // ReSharper disable once ExpressionIsAlwaysNull var measuredMetric = MeasuredMetric.CreateWithoutDimensions(metricValue); var scrapeResult = ScrapeResultGenerator.GenerateFromMetric(measuredMetric); var systemMetricConfigOptions = BogusAtlassianStatuspageMetricSinkConfigurationGenerator.GetSinkConfiguration(systemMetricId: systemMetricId, promitorMetricName: promitorMetricName); var atlassianStatuspageClientMock = new Mock(); - var metricSink = new AtlassianStatuspageMetricSink(atlassianStatuspageClientMock.Object, systemMetricConfigOptions, NullLogger.Instance); + var metricsDeclarationProvider = CreateMetricsDeclarationProvider(metricName); + var metricSink = new AtlassianStatuspageMetricSink(atlassianStatuspageClientMock.Object, metricsDeclarationProvider, systemMetricConfigOptions, NullLogger.Instance); // Act await metricSink.ReportMetricAsync(promitorMetricName, metricDescription, scrapeResult); @@ -118,13 +125,15 @@ public async Task ReportMetricAsync_GetsValidInputWithPromitorMetricThatIsNotMap var promitorMetricName = BogusGenerator.Name.FirstName(); var systemMetricId = BogusGenerator.Name.FirstName(); var metricDescription = BogusGenerator.Lorem.Sentence(); + var metricName = BogusGenerator.Name.FirstName(); double? metricValue = null; // ReSharper disable once ExpressionIsAlwaysNull var measuredMetric = MeasuredMetric.CreateWithoutDimensions(metricValue); var scrapeResult = ScrapeResultGenerator.GenerateFromMetric(measuredMetric); var systemMetricConfigOptions = BogusAtlassianStatuspageMetricSinkConfigurationGenerator.GetSinkConfiguration(promitorMetricName: promitorMetricName); var atlassianStatuspageClientMock = new Mock(); - var metricSink = new AtlassianStatuspageMetricSink(atlassianStatuspageClientMock.Object, systemMetricConfigOptions, NullLogger.Instance); + var metricsDeclarationProvider = CreateMetricsDeclarationProvider(metricName); + var metricSink = new AtlassianStatuspageMetricSink(atlassianStatuspageClientMock.Object, metricsDeclarationProvider, systemMetricConfigOptions, NullLogger.Instance); // Act await metricSink.ReportMetricAsync(promitorMetricName, metricDescription, scrapeResult); diff --git a/src/Promitor.Tests.Unit/Metrics/Sinks/MetricSinkTest.cs b/src/Promitor.Tests.Unit/Metrics/Sinks/MetricSinkTest.cs new file mode 100644 index 000000000..57564d629 --- /dev/null +++ b/src/Promitor.Tests.Unit/Metrics/Sinks/MetricSinkTest.cs @@ -0,0 +1,37 @@ +using System.Collections.Generic; +using System.ComponentModel; +using AutoMapper; +using Promitor.Core.Scraping.Configuration.Serialization.v1.Mapping; +using Promitor.Core.Scraping.Configuration.Serialization.v1.Model; +using Promitor.Tests.Unit.Builders.Metrics.v1; +using Promitor.Tests.Unit.Stubs; + +namespace Promitor.Tests.Unit.Metrics.Sinks +{ + [Category("Unit")] + public class MetricSinkTest : UnitTest + { + protected MetricsDeclarationProviderStub CreateMetricsDeclarationProvider(string metricName, Dictionary labels = null, Dictionary defaultLabels = null) + { + var mapperConfiguration = new MapperConfiguration(c => c.AddProfile()); + var mapper = mapperConfiguration.CreateMapper(); + var metricBuilder = MetricsDeclarationBuilder.WithMetadata(); + + if (defaultLabels != null) + { + var defaults = new MetricDefaultsV1 + { + Labels = defaultLabels + }; + + metricBuilder.WithDefaults(defaults); + } + + var rawDeclaration = metricBuilder.WithServiceBusMetric(metricName, labels: labels) + .Build(mapper); + + var metricsDeclarationProvider = new MetricsDeclarationProviderStub(rawDeclaration, mapper); + return metricsDeclarationProvider; + } + } +} diff --git a/src/Promitor.Tests.Unit/Metrics/Sinks/PrometheusScrapingEndpointMetricSinkTests.cs b/src/Promitor.Tests.Unit/Metrics/Sinks/PrometheusScrapingEndpointMetricSinkTest.cs similarity index 94% rename from src/Promitor.Tests.Unit/Metrics/Sinks/PrometheusScrapingEndpointMetricSinkTests.cs rename to src/Promitor.Tests.Unit/Metrics/Sinks/PrometheusScrapingEndpointMetricSinkTest.cs index e0381fc10..ee621e100 100644 --- a/src/Promitor.Tests.Unit/Metrics/Sinks/PrometheusScrapingEndpointMetricSinkTests.cs +++ b/src/Promitor.Tests.Unit/Metrics/Sinks/PrometheusScrapingEndpointMetricSinkTest.cs @@ -3,18 +3,14 @@ using System.ComponentModel; using System.Linq; using System.Threading.Tasks; -using AutoMapper; using Microsoft.Azure.Management.Monitor.Fluent.Models; using Microsoft.Extensions.Logging.Abstractions; using Microsoft.Extensions.Options; using Moq; using Prometheus.Client; using Promitor.Core.Metrics; -using Promitor.Core.Scraping.Configuration.Serialization.v1.Mapping; -using Promitor.Core.Scraping.Configuration.Serialization.v1.Model; using Promitor.Integrations.Sinks.Prometheus; using Promitor.Integrations.Sinks.Prometheus.Configuration; -using Promitor.Tests.Unit.Builders.Metrics.v1; using Promitor.Tests.Unit.Generators; using Promitor.Tests.Unit.Stubs; using Xunit; @@ -22,7 +18,7 @@ namespace Promitor.Tests.Unit.Metrics.Sinks { [Category("Unit")] - public class PrometheusScrapingEndpointMetricSinkTests : UnitTest + public class PrometheusScrapingEndpointMetricSinkTest : MetricSinkTest { [Theory] [InlineData("")] @@ -144,7 +140,7 @@ public async Task ReportMetricAsync_GetsValidInputWithTwoMetricValuesOfWhichOneI var expectedDimensionName = dimensionName.ToLower(); var timeSeries = new TimeSeriesElement { - Metadatavalues = new List { new MetadataValue(name: new LocalizableString(dimensionName), value: dimensionValue) } + Metadatavalues = new List { new(name: new LocalizableString(dimensionName), value: dimensionValue) } }; var firstMetric = MeasuredMetric.CreateForDimensions(firstMetricValue, new List{ dimensionName.ToUpper() }, timeSeries); var secondMetric = MeasuredMetric.CreateWithoutDimensions(secondMetricValue); @@ -256,7 +252,7 @@ public async Task ReportMetricAsync_GetsValidInputWithOneDimensions_Successfully var expectedDimensionName = dimensionName.ToLower(); var timeSeries = new TimeSeriesElement { - Metadatavalues = new List { new MetadataValue(name: new LocalizableString(dimensionName), value: dimensionValue) } + Metadatavalues = new List { new(name: new LocalizableString(dimensionName), value: dimensionValue) } }; var measuredMetric = MeasuredMetric.CreateForDimensions(metricValue, new List{ dimensionName.ToUpper() }, timeSeries); var scrapeResult = ScrapeResultGenerator.GenerateFromMetric(measuredMetric); @@ -394,29 +390,6 @@ private IOptionsMonitor CreateProme return new OptionsMonitorStub(prometheusScrapingEndpointSinkConfiguration); } - private MetricsDeclarationProviderStub CreateMetricsDeclarationProvider(string metricName, Dictionary labels = null, Dictionary defaultLabels = null) - { - var mapperConfiguration = new MapperConfiguration(c => c.AddProfile()); - var mapper = mapperConfiguration.CreateMapper(); - var metricBuilder = MetricsDeclarationBuilder.WithMetadata(); - - if (defaultLabels != null) - { - var defaults = new MetricDefaultsV1 - { - Labels = defaultLabels - }; - - metricBuilder.WithDefaults(defaults); - } - - var rawDeclaration = metricBuilder.WithServiceBusMetric(metricName, labels: labels) - .Build(mapper); - - var metricsDeclarationProvider = new MetricsDeclarationProviderStub(rawDeclaration, mapper); - return metricsDeclarationProvider; - } - private static (Mock Factory, Mock> MetricFamily, Mock Gauge) CreatePrometheusMetricFactoryMock() { var gaugeMock = new Mock(); diff --git a/src/Promitor.Tests.Unit/Metrics/Sinks/StatsDMetricSinkTests.cs b/src/Promitor.Tests.Unit/Metrics/Sinks/StatsDMetricSinkTests.cs index 4b04cec93..670fc3239 100644 --- a/src/Promitor.Tests.Unit/Metrics/Sinks/StatsDMetricSinkTests.cs +++ b/src/Promitor.Tests.Unit/Metrics/Sinks/StatsDMetricSinkTests.cs @@ -16,7 +16,7 @@ namespace Promitor.Tests.Unit.Metrics.Sinks { [Category("Unit")] - public class StatsDMetricSinkTests : UnitTest + public class StatsDMetricSinkTests : MetricSinkTest { [Theory] [InlineData("")] @@ -28,8 +28,9 @@ public async Task ReportMetricAsync_InputDoesNotContainMetricName_ThrowsExceptio var metricValue = BogusGenerator.Random.Double(); var scrapeResult = ScrapeResultGenerator.Generate(metricValue); var statsDPublisherMock = new Mock(); + var metricsDeclarationProvider = CreateMetricsDeclarationProvider(metricName); var statsDSinkConfiguration = CreateStatsDConfiguration(); - var metricSink = new StatsdMetricSink(statsDPublisherMock.Object, statsDSinkConfiguration, NullLogger.Instance); + var metricSink = new StatsdMetricSink(statsDPublisherMock.Object, metricsDeclarationProvider, statsDSinkConfiguration, NullLogger.Instance); // Act & Assert // ReSharper disable once ExpressionIsAlwaysNull @@ -47,8 +48,9 @@ public async Task ReportMetricAsync_InputDoesNotContainMetricDescription_Succeed var measuredMetric = MeasuredMetric.CreateWithoutDimensions(metricValue); var scrapeResult = ScrapeResultGenerator.GenerateFromMetric(measuredMetric); var statsDPublisherMock = new Mock(); + var metricsDeclarationProvider = CreateMetricsDeclarationProvider(metricName); var statsDSinkConfiguration = CreateStatsDConfiguration(); - var metricSink = new StatsdMetricSink(statsDPublisherMock.Object, statsDSinkConfiguration, NullLogger.Instance); + var metricSink = new StatsdMetricSink(statsDPublisherMock.Object, metricsDeclarationProvider, statsDSinkConfiguration, NullLogger.Instance); // Act & Assert // ReSharper disable once ExpressionIsAlwaysNull @@ -62,8 +64,9 @@ public async Task ReportMetricAsync_InputDoesNotContainMeasuredMetric_ThrowsExce var metricName = BogusGenerator.Name.FirstName(); var metricDescription = BogusGenerator.Lorem.Sentence(); var statsDPublisherMock = new Mock(); + var metricsDeclarationProvider = CreateMetricsDeclarationProvider(metricName); var statsDSinkConfiguration = CreateStatsDConfiguration(); - var metricSink = new StatsdMetricSink(statsDPublisherMock.Object, statsDSinkConfiguration, NullLogger.Instance); + var metricSink = new StatsdMetricSink(statsDPublisherMock.Object, metricsDeclarationProvider, statsDSinkConfiguration, NullLogger.Instance); // Act & Assert // ReSharper disable once ExpressionIsAlwaysNull @@ -80,8 +83,9 @@ public async Task ReportMetricAsync_GetsValidInputWithMetricValue_SuccessfullyWr var measuredMetric = MeasuredMetric.CreateWithoutDimensions(metricValue); var scrapeResult = ScrapeResultGenerator.GenerateFromMetric(measuredMetric); var statsDPublisherMock = new Mock(); + var metricsDeclarationProvider = CreateMetricsDeclarationProvider(metricName); var statsDSinkConfiguration = CreateStatsDConfiguration(); - var metricSink = new StatsdMetricSink(statsDPublisherMock.Object, statsDSinkConfiguration, NullLogger.Instance); + var metricSink = new StatsdMetricSink(statsDPublisherMock.Object, metricsDeclarationProvider, statsDSinkConfiguration, NullLogger.Instance); // Act await metricSink.ReportMetricAsync(metricName, metricDescription, scrapeResult); @@ -102,8 +106,9 @@ public async Task ReportMetricAsync_GetsValidInputWithoutMetricValue_Successfull var measuredMetric = MeasuredMetric.CreateWithoutDimensions(metricValue); var scrapeResult = ScrapeResultGenerator.GenerateFromMetric(measuredMetric); var statsDPublisherMock = new Mock(); + var metricsDeclarationProvider = CreateMetricsDeclarationProvider(metricName); var statsDSinkConfiguration = CreateStatsDConfiguration(); - var metricSink = new StatsdMetricSink(statsDPublisherMock.Object, statsDSinkConfiguration, NullLogger.Instance); + var metricSink = new StatsdMetricSink(statsDPublisherMock.Object, metricsDeclarationProvider, statsDSinkConfiguration, NullLogger.Instance); // Act await metricSink.ReportMetricAsync(metricName, metricDescription, scrapeResult); @@ -122,8 +127,9 @@ public async Task ReportMetricAsync_InputDoesNotContainGenevaSettingsUsingGeneva var metricFormat = StatsdFormatterTypesEnum.Geneva; var scrapeResult = ScrapeResultGenerator.Generate(metricValue); var statsDPublisherMock = new Mock(); + var metricsDeclarationProvider = CreateMetricsDeclarationProvider(metricName); var statsDSinkConfiguration = CreateStatsDConfiguration(metricFormat); - var metricSink = new StatsdMetricSink(statsDPublisherMock.Object, statsDSinkConfiguration, NullLogger.Instance); + var metricSink = new StatsdMetricSink(statsDPublisherMock.Object, metricsDeclarationProvider, statsDSinkConfiguration, NullLogger.Instance); // Act & Assert // ReSharper disable once ExpressionIsAlwaysNull @@ -139,11 +145,12 @@ public async Task ReportMetricAsync_UsesValidInputWithGenevaFormat_SuccessfullyW var metricValue = BogusGenerator.Random.Double(); var metricFormat = StatsdFormatterTypesEnum.Geneva; var genevaConfiguration = GenerateGenevaConfiguration(); - var measuredMetric = MeasuredMetric.CreateWithoutDimension(metricValue); + var measuredMetric = MeasuredMetric.CreateWithoutDimensions(metricValue); var scrapeResult = ScrapeResultGenerator.GenerateFromMetric(measuredMetric); var statsDPublisherMock = new Mock(); + var metricsDeclarationProvider = CreateMetricsDeclarationProvider(metricName); var statsDSinkConfiguration = CreateStatsDConfiguration(metricFormat, genevaConfiguration); - var metricSink = new StatsdMetricSink(statsDPublisherMock.Object, statsDSinkConfiguration, NullLogger.Instance); + var metricSink = new StatsdMetricSink(statsDPublisherMock.Object, metricsDeclarationProvider, statsDSinkConfiguration, NullLogger.Instance); var expectedMetricValue = Math.Round(metricValue, MidpointRounding.AwayFromZero); var bucket = JsonConvert.SerializeObject(new diff --git a/src/Promitor.Tests.Unit/Promitor.Tests.Unit.csproj b/src/Promitor.Tests.Unit/Promitor.Tests.Unit.csproj index 53bf95a3e..91f186f8b 100644 --- a/src/Promitor.Tests.Unit/Promitor.Tests.Unit.csproj +++ b/src/Promitor.Tests.Unit/Promitor.Tests.Unit.csproj @@ -2,7 +2,7 @@ net7.0 - 7.0.3 + 7.0.8 true @@ -38,10 +38,10 @@ - + - - + + diff --git a/src/Promitor.Tests.Unit/Serialization/DeserializerTests/DeserializationTests.cs b/src/Promitor.Tests.Unit/Serialization/DeserializerTests/DeserializationTests.cs index 5ff8e3903..14c3e9869 100644 --- a/src/Promitor.Tests.Unit/Serialization/DeserializerTests/DeserializationTests.cs +++ b/src/Promitor.Tests.Unit/Serialization/DeserializerTests/DeserializationTests.cs @@ -12,8 +12,8 @@ public class DeserializationTests : UnitTest { private static readonly TimeSpan defaultInterval = TimeSpan.FromMinutes(5); - private readonly Mock _errorReporter = new Mock(); - private readonly Mock> _childDeserializer = new Mock>(); + private readonly Mock _errorReporter = new(); + private readonly Mock> _childDeserializer = new(); private readonly RegistrationConfigDeserializer _deserializer; public DeserializationTests() diff --git a/src/Promitor.Tests.Unit/Serialization/DeserializerTests/ValidationTests.cs b/src/Promitor.Tests.Unit/Serialization/DeserializerTests/ValidationTests.cs index 7ee1cdce2..8159d8e2c 100644 --- a/src/Promitor.Tests.Unit/Serialization/DeserializerTests/ValidationTests.cs +++ b/src/Promitor.Tests.Unit/Serialization/DeserializerTests/ValidationTests.cs @@ -12,8 +12,8 @@ namespace Promitor.Tests.Unit.Serialization.DeserializerTests { public class ValidationTests : UnitTest { - private readonly Mock _errorReporter = new Mock(); - private readonly TestDeserializer _deserializer = new TestDeserializer(); + private readonly Mock _errorReporter = new(); + private readonly TestDeserializer _deserializer = new(); [Fact] public void Deserialize_RequiredFieldMissing_ReportsError() diff --git a/src/Promitor.Tests.Unit/Serialization/ErrorReporterTests.cs b/src/Promitor.Tests.Unit/Serialization/ErrorReporterTests.cs index b2e2cbb44..589089647 100644 --- a/src/Promitor.Tests.Unit/Serialization/ErrorReporterTests.cs +++ b/src/Promitor.Tests.Unit/Serialization/ErrorReporterTests.cs @@ -8,7 +8,7 @@ namespace Promitor.Tests.Unit.Serialization [Category("Unit")] public class ErrorReporterTests : UnitTest { - private readonly ErrorReporter _errorReporter = new ErrorReporter(); + private readonly ErrorReporter _errorReporter = new(); [Fact] public void ReportError_AfterErrorReported_AddsError() diff --git a/src/Promitor.Tests.Unit/Serialization/FieldDeserializationInfoBuilderTests/DefaultTests.cs b/src/Promitor.Tests.Unit/Serialization/FieldDeserializationInfoBuilderTests/DefaultTests.cs index d31e4863d..120c9a873 100644 --- a/src/Promitor.Tests.Unit/Serialization/FieldDeserializationInfoBuilderTests/DefaultTests.cs +++ b/src/Promitor.Tests.Unit/Serialization/FieldDeserializationInfoBuilderTests/DefaultTests.cs @@ -5,8 +5,7 @@ namespace Promitor.Tests.Unit.Serialization.FieldDeserializationInfoBuilderTests { public class DefaultTests : UnitTest { - private readonly FieldDeserializationInfoBuilder _builder = - new FieldDeserializationInfoBuilder(); + private readonly FieldDeserializationInfoBuilder _builder = new(); public DefaultTests() { diff --git a/src/Promitor.Tests.Unit/Serialization/FieldDeserializationInfoBuilderTests/MapUsingDeserializerTests.cs b/src/Promitor.Tests.Unit/Serialization/FieldDeserializationInfoBuilderTests/MapUsingDeserializerTests.cs index 7d0110b4d..a7ed0f377 100644 --- a/src/Promitor.Tests.Unit/Serialization/FieldDeserializationInfoBuilderTests/MapUsingDeserializerTests.cs +++ b/src/Promitor.Tests.Unit/Serialization/FieldDeserializationInfoBuilderTests/MapUsingDeserializerTests.cs @@ -6,8 +6,7 @@ namespace Promitor.Tests.Unit.Serialization.FieldDeserializationInfoBuilderTests { public class MapUsingDeserializerTests : UnitTest { - private readonly FieldDeserializationInfoBuilder _builder = - new FieldDeserializationInfoBuilder(); + private readonly FieldDeserializationInfoBuilder _builder = new(); public MapUsingDeserializerTests() { diff --git a/src/Promitor.Tests.Unit/Serialization/FieldDeserializationInfoBuilderTests/MapUsingTests.cs b/src/Promitor.Tests.Unit/Serialization/FieldDeserializationInfoBuilderTests/MapUsingTests.cs index 359155e93..428363c06 100644 --- a/src/Promitor.Tests.Unit/Serialization/FieldDeserializationInfoBuilderTests/MapUsingTests.cs +++ b/src/Promitor.Tests.Unit/Serialization/FieldDeserializationInfoBuilderTests/MapUsingTests.cs @@ -7,8 +7,7 @@ namespace Promitor.Tests.Unit.Serialization.FieldDeserializationInfoBuilderTests { public class MapUsingTests : UnitTest { - private readonly FieldDeserializationInfoBuilder _builder = - new FieldDeserializationInfoBuilder(); + private readonly FieldDeserializationInfoBuilder _builder = new(); public MapUsingTests() { diff --git a/src/Promitor.Tests.Unit/Serialization/FieldDeserializationInfoBuilderTests/RequiredTests.cs b/src/Promitor.Tests.Unit/Serialization/FieldDeserializationInfoBuilderTests/RequiredTests.cs index ee1b35847..666d00183 100644 --- a/src/Promitor.Tests.Unit/Serialization/FieldDeserializationInfoBuilderTests/RequiredTests.cs +++ b/src/Promitor.Tests.Unit/Serialization/FieldDeserializationInfoBuilderTests/RequiredTests.cs @@ -5,8 +5,7 @@ namespace Promitor.Tests.Unit.Serialization.FieldDeserializationInfoBuilderTests { public class RequiredTests : UnitTest { - private readonly FieldDeserializationInfoBuilder _builder = - new FieldDeserializationInfoBuilder(); + private readonly FieldDeserializationInfoBuilder _builder = new(); public RequiredTests() { diff --git a/src/Promitor.Tests.Unit/Serialization/FieldDeserializationInfoBuilderTests/SetPropertyTests.cs b/src/Promitor.Tests.Unit/Serialization/FieldDeserializationInfoBuilderTests/SetPropertyTests.cs index 3895f0216..1a7098654 100644 --- a/src/Promitor.Tests.Unit/Serialization/FieldDeserializationInfoBuilderTests/SetPropertyTests.cs +++ b/src/Promitor.Tests.Unit/Serialization/FieldDeserializationInfoBuilderTests/SetPropertyTests.cs @@ -6,8 +6,7 @@ namespace Promitor.Tests.Unit.Serialization.FieldDeserializationInfoBuilderTests { public class SetPropertyTests : UnitTest { - private readonly FieldDeserializationInfoBuilder _builder = - new FieldDeserializationInfoBuilder(); + private readonly FieldDeserializationInfoBuilder _builder = new(); [Fact] public void SetProperty_SetsPropertyInfo_WhenBuilding() diff --git a/src/Promitor.Tests.Unit/Serialization/FieldValidators/CronExpressionValidatorTests.cs b/src/Promitor.Tests.Unit/Serialization/FieldValidators/CronExpressionValidatorTests.cs index 603a30bd9..853fc10a5 100644 --- a/src/Promitor.Tests.Unit/Serialization/FieldValidators/CronExpressionValidatorTests.cs +++ b/src/Promitor.Tests.Unit/Serialization/FieldValidators/CronExpressionValidatorTests.cs @@ -9,7 +9,7 @@ namespace Promitor.Tests.Unit.Serialization.FieldValidators { public class CronExpressionValidatorTests : UnitTest { - private readonly CronExpressionValidator _validator = new CronExpressionValidator(); + private readonly CronExpressionValidator _validator = new(); [Fact] public void Validate_InvalidExpression_ReportsError() diff --git a/src/Promitor.Tests.Unit/Serialization/v1/Core/AzureMetricConfigurationDeserializerTests.cs b/src/Promitor.Tests.Unit/Serialization/v1/Core/AzureMetricConfigurationDeserializerTests.cs index 7dd0db319..23bc8417c 100644 --- a/src/Promitor.Tests.Unit/Serialization/v1/Core/AzureMetricConfigurationDeserializerTests.cs +++ b/src/Promitor.Tests.Unit/Serialization/v1/Core/AzureMetricConfigurationDeserializerTests.cs @@ -16,7 +16,7 @@ public class AzureMetricConfigurationDeserializerTests : UnitTest private readonly AzureMetricConfigurationDeserializer _deserializer; private readonly Mock> _dimensionDeserializer; private readonly Mock> _aggregationDeserializer; - private readonly Mock _errorReporter = new Mock(); + private readonly Mock _errorReporter = new(); public AzureMetricConfigurationDeserializerTests() { @@ -113,7 +113,7 @@ public void Deserialize_DimensionSupplied_UsesDeserializer() // Act var config = _deserializer.Deserialize(node, _errorReporter.Object); - + // Assert Assert.Equal(dimension, config.Dimension); } @@ -128,7 +128,7 @@ public void Deserialize_DimensionsSupplied_UsesDeserializer() - name: Test"; var node = YamlUtils.CreateYamlNode(yamlText); var dimensionsNode = (YamlSequenceNode)node.Children["dimensions"]; - + var dimensions = new List { new(), new() }; _dimensionDeserializer.Setup(d => d.Deserialize(dimensionsNode, _errorReporter.Object)).Returns(dimensions); @@ -155,13 +155,13 @@ public void Deserialize_DimensionAndDimensionsSupplied_UsesDeserializer() var dimension = new MetricDimensionV1(); _dimensionDeserializer.Setup(d => d.Deserialize(dimensionNode, _errorReporter.Object)).Returns(dimension); - + var dimensions = new List { new(), new() }; _dimensionDeserializer.Setup(d => d.Deserialize(dimensionsNode, _errorReporter.Object)).Returns(dimensions); - + // Act var config = _deserializer.Deserialize(node, _errorReporter.Object); - + // Assert Assert.Equal(dimension, config.Dimension); Assert.Same(dimensions, config.Dimensions); diff --git a/src/Promitor.Tests.Unit/Serialization/v1/Core/LogAnalyticsConfigurationDeserializerTests.cs b/src/Promitor.Tests.Unit/Serialization/v1/Core/LogAnalyticsConfigurationDeserializerTests.cs index 15f9e8e03..a75f1b3e7 100644 --- a/src/Promitor.Tests.Unit/Serialization/v1/Core/LogAnalyticsConfigurationDeserializerTests.cs +++ b/src/Promitor.Tests.Unit/Serialization/v1/Core/LogAnalyticsConfigurationDeserializerTests.cs @@ -14,7 +14,7 @@ public class LogAnalyticsConfigurationDeserializerTests : UnitTest { private readonly LogAnalyticsConfigurationDeserializer _deserializer; private readonly Mock> _aggregationDeserializer; - private readonly Mock _errorReporter = new Mock(); + private readonly Mock _errorReporter = new(); public LogAnalyticsConfigurationDeserializerTests() { diff --git a/src/Promitor.Tests.Unit/Serialization/v1/Core/MetricDefaultsDeserializerTests.cs b/src/Promitor.Tests.Unit/Serialization/v1/Core/MetricDefaultsDeserializerTests.cs index d388ee386..ff92bf820 100644 --- a/src/Promitor.Tests.Unit/Serialization/v1/Core/MetricDefaultsDeserializerTests.cs +++ b/src/Promitor.Tests.Unit/Serialization/v1/Core/MetricDefaultsDeserializerTests.cs @@ -15,7 +15,7 @@ public class MetricDefaultsDeserializerTests : UnitTest private readonly MetricDefaultsDeserializer _deserializer; private readonly Mock> _aggregationDeserializer; private readonly Mock> _scrapingDeserializer; - private readonly Mock _errorReporter = new Mock(); + private readonly Mock _errorReporter = new(); public MetricDefaultsDeserializerTests() { diff --git a/src/Promitor.Tests.Unit/Serialization/v1/Core/MetricDefinitionDeserializerTests.cs b/src/Promitor.Tests.Unit/Serialization/v1/Core/MetricDefinitionDeserializerTests.cs index 3c24d247a..d7f81a650 100644 --- a/src/Promitor.Tests.Unit/Serialization/v1/Core/MetricDefinitionDeserializerTests.cs +++ b/src/Promitor.Tests.Unit/Serialization/v1/Core/MetricDefinitionDeserializerTests.cs @@ -17,11 +17,10 @@ public class MetricDefinitionDeserializerTests : UnitTest private readonly Mock> _azureMetricConfigurationDeserializer; private readonly Mock> _scrapingDeserializer; private readonly Mock _resourceDeserializerFactory; - private readonly Mock _errorReporter = new Mock(); - private readonly Mock> _logAnalyticsConfigurationDeserializer = - new Mock>(); + private readonly Mock _errorReporter = new(); + private readonly Mock> _logAnalyticsConfigurationDeserializer = new(); private readonly Mock> _resourceDiscoveryGroupDeserializer = - new Mock>(); + new(); private readonly MetricDefinitionDeserializer _deserializer; @@ -313,7 +312,7 @@ public void Deserialize_ResourcesSupplied_UsesDeserializer() var resources = new List { - new AzureResourceDefinitionV1 { ResourceGroupName = "promitor-group" } + new() { ResourceGroupName = "promitor-group" } }; resourceDeserializer.Setup( d => d.Deserialize((YamlSequenceNode)node.Children["resources"], _errorReporter.Object)) @@ -474,7 +473,7 @@ public void Deserialize_ResourcesSupplied_DoesNotReportError() - resourceUri: Microsoft.ServiceBus/namespaces/promitor-messaging-2"; var node = YamlUtils.CreateYamlNode(yamlText); - SetupResourceDeserializer(node, new List { new AzureResourceDefinitionV1() }); + SetupResourceDeserializer(node, new List { new() }); // Act _deserializer.Deserialize(node, _errorReporter.Object); @@ -514,7 +513,7 @@ public void Deserialize_ResourceDiscoveryGroupsSupplied_DoesNotReportError() var node = YamlUtils.CreateYamlNode(yamlText); var resourceDiscoveryGroups = new List { - new AzureResourceDiscoveryGroupDefinitionV1() + new() }; _resourceDiscoveryGroupDeserializer.Setup( d => d.Deserialize(It.IsAny(), It.IsAny())).Returns(resourceDiscoveryGroups); diff --git a/src/Promitor.Tests.Unit/Serialization/v1/Core/V1DeserializerTests.cs b/src/Promitor.Tests.Unit/Serialization/v1/Core/V1DeserializerTests.cs index 220d2806d..3eee06a70 100644 --- a/src/Promitor.Tests.Unit/Serialization/v1/Core/V1DeserializerTests.cs +++ b/src/Promitor.Tests.Unit/Serialization/v1/Core/V1DeserializerTests.cs @@ -17,7 +17,7 @@ public class V1DeserializerTests : UnitTest private readonly Mock> _metadataDeserializer; private readonly Mock> _defaultsDeserializer; private readonly Mock> _metricsDeserializer; - private readonly Mock _errorReporter = new Mock(); + private readonly Mock _errorReporter = new(); private readonly V1Deserializer _deserializer; public V1DeserializerTests() @@ -160,7 +160,7 @@ public void Deserialize_Metrics_UsesMetricsDeserializer() metrics: - name: promitor_metrics_total"; var yamlNode = YamlUtils.CreateYamlNode(config); - var metrics = new List { new MetricDefinitionV1 { Name = "test_metric" } }; + var metrics = new List { new() { Name = "test_metric" } }; _metricsDeserializer.Setup( d => d.Deserialize(It.IsAny(), It.IsAny())).Returns(metrics); diff --git a/src/Promitor.Tests.Unit/Serialization/v1/Providers/SqlDatabaseDeserializerTests.cs b/src/Promitor.Tests.Unit/Serialization/v1/Providers/SqlDatabaseDeserializerTests.cs index 9dfa1383b..4cffee3e9 100644 --- a/src/Promitor.Tests.Unit/Serialization/v1/Providers/SqlDatabaseDeserializerTests.cs +++ b/src/Promitor.Tests.Unit/Serialization/v1/Providers/SqlDatabaseDeserializerTests.cs @@ -11,7 +11,7 @@ namespace Promitor.Tests.Unit.Serialization.v1.Providers [Category("Unit")] public class SqlDatabaseDeserializerTests : ResourceDeserializerTest { - private readonly SqlDatabaseDeserializer _deserializer = new SqlDatabaseDeserializer(NullLogger.Instance); + private readonly SqlDatabaseDeserializer _deserializer = new(NullLogger.Instance); [Fact] public void Deserialize_ServerNameSupplied_SetsServerName() diff --git a/src/Promitor.Tests.Unit/Serialization/v1/Providers/SqlElasticPoolDeserializerTests.cs b/src/Promitor.Tests.Unit/Serialization/v1/Providers/SqlElasticPoolDeserializerTests.cs index 8902174bc..6de117ca8 100644 --- a/src/Promitor.Tests.Unit/Serialization/v1/Providers/SqlElasticPoolDeserializerTests.cs +++ b/src/Promitor.Tests.Unit/Serialization/v1/Providers/SqlElasticPoolDeserializerTests.cs @@ -11,7 +11,7 @@ namespace Promitor.Tests.Unit.Serialization.v1.Providers [Category("Unit")] public class SqlElasticPoolDeserializerTests : ResourceDeserializerTest { - private readonly SqlElasticPoolDeserializer _deserializer = new SqlElasticPoolDeserializer(NullLogger.Instance); + private readonly SqlElasticPoolDeserializer _deserializer = new(NullLogger.Instance); [Fact] public void Deserialize_ServerNameSupplied_SetsServerName() diff --git a/src/Promitor.Tests.Unit/Serialization/v1/Providers/StorageQueueDeserializerTests.cs b/src/Promitor.Tests.Unit/Serialization/v1/Providers/StorageQueueDeserializerTests.cs index f0f986e8c..4dd63acea 100644 --- a/src/Promitor.Tests.Unit/Serialization/v1/Providers/StorageQueueDeserializerTests.cs +++ b/src/Promitor.Tests.Unit/Serialization/v1/Providers/StorageQueueDeserializerTests.cs @@ -11,7 +11,7 @@ namespace Promitor.Tests.Unit.Serialization.v1.Providers public class StorageQueueDeserializerTests : ResourceDeserializerTest { private readonly Mock> _secretDeserializer; - private readonly Mock _errorReporter = new Mock(); + private readonly Mock _errorReporter = new(); private readonly StorageQueueDeserializer _deserializer; diff --git a/src/Promitor.Tests.Unit/Serialization/v1/Providers/SynapseApacheSparkPoolDeserializerTests.cs b/src/Promitor.Tests.Unit/Serialization/v1/Providers/SynapseApacheSparkPoolDeserializerTests.cs index 92c2b0d10..76d0aa476 100644 --- a/src/Promitor.Tests.Unit/Serialization/v1/Providers/SynapseApacheSparkPoolDeserializerTests.cs +++ b/src/Promitor.Tests.Unit/Serialization/v1/Providers/SynapseApacheSparkPoolDeserializerTests.cs @@ -11,7 +11,7 @@ namespace Promitor.Tests.Unit.Serialization.v1.Providers [Category("Unit")] public class SynapseApacheSparkPoolDeserializerTests : ResourceDeserializerTest { - private readonly SynapseApacheSparkPoolDeserializer _deserializer = new SynapseApacheSparkPoolDeserializer(NullLogger.Instance); + private readonly SynapseApacheSparkPoolDeserializer _deserializer = new(NullLogger.Instance); [Fact] public void Deserialize_PoolNameSupplied_SetsPoolName() diff --git a/src/Promitor.Tests.Unit/Serialization/v1/Providers/SynapseSqlPoolDeserializerTests.cs b/src/Promitor.Tests.Unit/Serialization/v1/Providers/SynapseSqlPoolDeserializerTests.cs index aeb118b46..e7e1215b9 100644 --- a/src/Promitor.Tests.Unit/Serialization/v1/Providers/SynapseSqlPoolDeserializerTests.cs +++ b/src/Promitor.Tests.Unit/Serialization/v1/Providers/SynapseSqlPoolDeserializerTests.cs @@ -11,7 +11,7 @@ namespace Promitor.Tests.Unit.Serialization.v1.Providers [Category("Unit")] public class SynapseSqlPoolDeserializerTests : ResourceDeserializerTest { - private readonly SynapseSqlPoolDeserializer _deserializer = new SynapseSqlPoolDeserializer(NullLogger.Instance); + private readonly SynapseSqlPoolDeserializer _deserializer = new(NullLogger.Instance); [Fact] public void Deserialize_PoolNameSupplied_SetsPoolName() diff --git a/src/Promitor.Tests.Unit/Serialization/v1/Providers/SynapseWorkspaceDeserializerTests.cs b/src/Promitor.Tests.Unit/Serialization/v1/Providers/SynapseWorkspaceDeserializerTests.cs index 3ecf9ebde..d8100d93c 100644 --- a/src/Promitor.Tests.Unit/Serialization/v1/Providers/SynapseWorkspaceDeserializerTests.cs +++ b/src/Promitor.Tests.Unit/Serialization/v1/Providers/SynapseWorkspaceDeserializerTests.cs @@ -11,7 +11,7 @@ namespace Promitor.Tests.Unit.Serialization.v1.Providers [Category("Unit")] public class SynapseWorkspaceDeserializerTests : ResourceDeserializerTest { - private readonly SynapseWorkspaceDeserializer _deserializer = new SynapseWorkspaceDeserializer(NullLogger.Instance); + private readonly SynapseWorkspaceDeserializer _deserializer = new(NullLogger.Instance); [Fact] public void Deserialize_WorkspaceNameSupplied_SetsWorkspace() diff --git a/src/Promitor.Tests.Unit/Serialization/v1/Providers/TrafficManagerDeserializerTests.cs b/src/Promitor.Tests.Unit/Serialization/v1/Providers/TrafficManagerDeserializerTests.cs new file mode 100644 index 000000000..c3ab4beae --- /dev/null +++ b/src/Promitor.Tests.Unit/Serialization/v1/Providers/TrafficManagerDeserializerTests.cs @@ -0,0 +1,45 @@ +using System.ComponentModel; +using Promitor.Core.Scraping.Configuration.Serialization; +using Promitor.Core.Scraping.Configuration.Serialization.v1.Model; +using Promitor.Core.Scraping.Configuration.Serialization.v1.Model.ResourceTypes; +using Promitor.Core.Scraping.Configuration.Serialization.v1.Providers; +using Xunit; + +namespace Promitor.Tests.Unit.Serialization.v1.Providers +{ + [Category("Unit")] + public class TrafficManagerDeserializerTests : ResourceDeserializerTest + { + private readonly TrafficManagerDeserializer _deserializer; + + public TrafficManagerDeserializerTests() + { + _deserializer = new TrafficManagerDeserializer(Logger); + } + + [Fact] + public void Deserialize_NameSupplied_SetsName() + { + const string name = "promitor-traffic-manager"; + YamlAssert.PropertySet( + _deserializer, + $"name: {name}", + name, + r => r.Name); + } + + [Fact] + public void Deserialize_NameNotSupplied_Null() + { + YamlAssert.PropertyNull( + _deserializer, + "resourceGroupName: promitor-group", + r => r.Name); + } + + protected override IDeserializer CreateDeserializer() + { + return new TrafficManagerDeserializer(Logger); + } + } +} \ No newline at end of file diff --git a/src/Promitor.Tests.Unit/Serialization/v1/V1SerializationTests.cs b/src/Promitor.Tests.Unit/Serialization/v1/V1SerializationTests.cs index a20faf454..890fe1b25 100644 --- a/src/Promitor.Tests.Unit/Serialization/v1/V1SerializationTests.cs +++ b/src/Promitor.Tests.Unit/Serialization/v1/V1SerializationTests.cs @@ -62,7 +62,7 @@ public V1SerializationTests() }, Metrics = new List { - new MetricDefinitionV1 + new() { Name = "promitor_demo_generic_queue_size", Description = "Amount of active messages of the 'orders' queue (determined with Generic provider)", @@ -93,7 +93,7 @@ public V1SerializationTests() } } }, - new MetricDefinitionV1 + new() { Name = "promitor_demo_servicebusqueue_queue_size", Description = "Amount of active messages of the 'orders' queue (determined with ServiceBusNamespace provider)", @@ -122,7 +122,7 @@ public V1SerializationTests() }, ResourceDiscoveryGroups = new List { - new AzureResourceDiscoveryGroupDefinitionV1 + new() { Name="example-resource-collection" } diff --git a/src/Promitor.Tests.Unit/Validation/Scraper/Metrics/AzureMetricConfigurationValidatorTest.cs b/src/Promitor.Tests.Unit/Validation/Scraper/Metrics/AzureMetricConfigurationValidatorTest.cs index 1170aa978..b785ba8ef 100644 --- a/src/Promitor.Tests.Unit/Validation/Scraper/Metrics/AzureMetricConfigurationValidatorTest.cs +++ b/src/Promitor.Tests.Unit/Validation/Scraper/Metrics/AzureMetricConfigurationValidatorTest.cs @@ -32,7 +32,7 @@ public void DimensionsAndDimension_Fails() // Assert Assert.NotEmpty(validationErrors); } - + [Fact] public void OnlyDimension_Succeeds() { @@ -56,7 +56,7 @@ public void OnlyDimension_Succeeds() // Assert Assert.Empty(validationErrors); } - + [Fact] public void OnlyDimensions_Succeeds() { diff --git a/src/Promitor.Tests.Unit/Validation/Scraper/Metrics/ResourceTypes/TrafficManagerMetricsDeclarationValidationStepTests.cs b/src/Promitor.Tests.Unit/Validation/Scraper/Metrics/ResourceTypes/TrafficManagerMetricsDeclarationValidationStepTests.cs new file mode 100644 index 000000000..e4ffc3867 --- /dev/null +++ b/src/Promitor.Tests.Unit/Validation/Scraper/Metrics/ResourceTypes/TrafficManagerMetricsDeclarationValidationStepTests.cs @@ -0,0 +1,152 @@ +using System.ComponentModel; +using Microsoft.Extensions.Logging.Abstractions; +using Promitor.Agents.Scraper.Validation.Steps; +using Promitor.Tests.Unit.Builders.Metrics.v1; +using Promitor.Tests.Unit.Stubs; +using Xunit; + +namespace Promitor.Tests.Unit.Validation.Scraper.Metrics.ResourceTypes +{ + [Category("Unit")] + public class TrafficManagerMetricsDeclarationValidationStepTests : MetricsDeclarationValidationStepsTests + { + [Fact] + public void TrafficManagerMetricsDeclaration_DeclarationWithoutAzureMetricName_Fails() + { + // Arrange + var rawDeclaration = MetricsDeclarationBuilder.WithMetadata() + .WithTrafficManagerMetric(azureMetricName: string.Empty) + .Build(Mapper); + var metricsDeclarationProvider = new MetricsDeclarationProviderStub(rawDeclaration, Mapper); + + // Act + var scrapingScheduleValidationStep = new MetricsDeclarationValidationStep(metricsDeclarationProvider, NullLogger.Instance); + var validationResult = scrapingScheduleValidationStep.Run(); + + // Assert + PromitorAssert.ValidationFailed(validationResult); + } + + [Theory] + [InlineData(-1)] + [InlineData(0)] + [InlineData(10001)] + public void TrafficManagerMetricsDeclaration_DeclarationWithInvalidMetricLimit_Fails(int metricLimit) + { + // Arrange + var rawDeclaration = MetricsDeclarationBuilder.WithMetadata() + .WithTrafficManagerMetric(azureMetricLimit: metricLimit) + .Build(Mapper); + var metricsDeclarationProvider = new MetricsDeclarationProviderStub(rawDeclaration, Mapper); + + // Act + var scrapingScheduleValidationStep = new MetricsDeclarationValidationStep(metricsDeclarationProvider, NullLogger.Instance); + var validationResult = scrapingScheduleValidationStep.Run(); + + // Assert + PromitorAssert.ValidationFailed(validationResult); + } + + [Fact] + public void TrafficManagerMetricsDeclaration_DeclarationWithoutMetricDescription_Succeeded() + { + // Arrange + var rawDeclaration = MetricsDeclarationBuilder.WithMetadata() + .WithTrafficManagerMetric(metricDescription: string.Empty) + .Build(Mapper); + var metricsDeclarationProvider = new MetricsDeclarationProviderStub(rawDeclaration, Mapper); + + // Act + var scrapingScheduleValidationStep = new MetricsDeclarationValidationStep(metricsDeclarationProvider, NullLogger.Instance); + var validationResult = scrapingScheduleValidationStep.Run(); + + // Assert + PromitorAssert.ValidationIsSuccessful(validationResult); + } + + [Fact] + public void TrafficManagerMetricsDeclaration_DeclarationWithoutMetricName_Fails() + { + // Arrange + var rawDeclaration = MetricsDeclarationBuilder.WithMetadata() + .WithTrafficManagerMetric(string.Empty) + .Build(Mapper); + var metricsDeclarationProvider = new MetricsDeclarationProviderStub(rawDeclaration, Mapper); + + // Act + var scrapingScheduleValidationStep = new MetricsDeclarationValidationStep(metricsDeclarationProvider, NullLogger.Instance); + var validationResult = scrapingScheduleValidationStep.Run(); + + // Assert + PromitorAssert.ValidationFailed(validationResult); + } + + [Fact] + public void TrafficManagerMetricsDeclaration_DeclarationWithoutTrafficManagerName_Fails() + { + // Arrange + var rawDeclaration = MetricsDeclarationBuilder.WithMetadata() + .WithTrafficManagerMetric(name: string.Empty) + .Build(Mapper); + var metricsDeclarationProvider = new MetricsDeclarationProviderStub(rawDeclaration, Mapper); + + // Act + var scrapingScheduleValidationStep = new MetricsDeclarationValidationStep(metricsDeclarationProvider, NullLogger.Instance); + var validationResult = scrapingScheduleValidationStep.Run(); + + // Assert + PromitorAssert.ValidationFailed(validationResult); + } + + [Fact] + public void TrafficManagerMetricsDeclaration_DeclarationWithoutResourceAndResourceDiscoveryGroupInfo_Fails() + { + // Arrange + var rawMetricsDeclaration = MetricsDeclarationBuilder.WithMetadata() + .WithTrafficManagerMetric(omitResource: true) + .Build(Mapper); + var metricsDeclarationProvider = new MetricsDeclarationProviderStub(rawMetricsDeclaration, Mapper); + + // Act + var scrapingScheduleValidationStep = new MetricsDeclarationValidationStep(metricsDeclarationProvider, NullLogger.Instance); + var validationResult = scrapingScheduleValidationStep.Run(); + + // Assert + PromitorAssert.ValidationFailed(validationResult); + } + + [Fact] + public void TrafficManagerMetricsDeclaration_DeclarationWithoutResourceButWithResourceDiscoveryGroupInfo_Succeeds() + { + // Arrange + var rawMetricsDeclaration = MetricsDeclarationBuilder.WithMetadata() + .WithTrafficManagerMetric(omitResource: true, resourceDiscoveryGroupName:"sample-collection") + .Build(Mapper); + var metricsDeclarationProvider = new MetricsDeclarationProviderStub(rawMetricsDeclaration, Mapper); + + // Act + var scrapingScheduleValidationStep = new MetricsDeclarationValidationStep(metricsDeclarationProvider, NullLogger.Instance); + var validationResult = scrapingScheduleValidationStep.Run(); + + // Assert + PromitorAssert.ValidationIsSuccessful(validationResult); + } + + [Fact] + public void TrafficManagerMetricsDeclaration_ValidDeclaration_Succeeds() + { + // Arrange + var rawMetricsDeclaration = MetricsDeclarationBuilder.WithMetadata() + .WithTrafficManagerMetric() + .Build(Mapper); + var metricsDeclarationProvider = new MetricsDeclarationProviderStub(rawMetricsDeclaration, Mapper); + + // Act + var scrapingScheduleValidationStep = new MetricsDeclarationValidationStep(metricsDeclarationProvider, NullLogger.Instance); + var validationResult = scrapingScheduleValidationStep.Run(); + + // Assert + PromitorAssert.ValidationIsSuccessful(validationResult); + } + } +} \ No newline at end of file diff --git a/src/Promitor.sln b/src/Promitor.sln index f509e1a75..fb5c14376 100644 --- a/src/Promitor.sln +++ b/src/Promitor.sln @@ -82,7 +82,9 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "OpenTelemetry", "OpenTeleme ..\config\opentelemetry-collector\collector-config.yaml = ..\config\opentelemetry-collector\collector-config.yaml EndProjectSection EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Promitor.Integrations.LogAnalytics", "Promitor.Integrations.LogAnalytics\Promitor.Integrations.LogAnalytics.csproj", "{2427547B-090A-460D-A631-A41D71545281}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Promitor.Integrations.LogAnalytics", "Promitor.Integrations.LogAnalytics\Promitor.Integrations.LogAnalytics.csproj", "{2427547B-090A-460D-A631-A41D71545281}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Promitor.Integrations.Sinks.Core", "Promitor.Integrations.Sinks.Core\Promitor.Integrations.Sinks.Core.csproj", "{25F056A7-481E-48E1-A22B-1D13BB4F4239}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -157,6 +159,10 @@ Global {2427547B-090A-460D-A631-A41D71545281}.Debug|Any CPU.Build.0 = Debug|Any CPU {2427547B-090A-460D-A631-A41D71545281}.Release|Any CPU.ActiveCfg = Release|Any CPU {2427547B-090A-460D-A631-A41D71545281}.Release|Any CPU.Build.0 = Release|Any CPU + {25F056A7-481E-48E1-A22B-1D13BB4F4239}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {25F056A7-481E-48E1-A22B-1D13BB4F4239}.Debug|Any CPU.Build.0 = Debug|Any CPU + {25F056A7-481E-48E1-A22B-1D13BB4F4239}.Release|Any CPU.ActiveCfg = Release|Any CPU + {25F056A7-481E-48E1-A22B-1D13BB4F4239}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -186,6 +192,7 @@ Global {614F1E5A-0E5C-4189-9B1C-FD596A959CBF} = {1C184DB7-C5E5-41F4-9E0C-8A798B9ED0CA} {F6988AF7-6E1E-431B-B2A4-C485D5E8CF64} = {1C184DB7-C5E5-41F4-9E0C-8A798B9ED0CA} {2427547B-090A-460D-A631-A41D71545281} = {59D7FFBC-3929-48AD-8C9C-242280D01CBD} + {25F056A7-481E-48E1-A22B-1D13BB4F4239} = {59D7FFBC-3929-48AD-8C9C-242280D01CBD} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {B47A777A-C793-453F-8F4F-7703551DFC4C} diff --git a/src/Promitor.sln.DotSettings b/src/Promitor.sln.DotSettings index 4cd99c4e6..3d0d9403a 100644 --- a/src/Promitor.sln.DotSettings +++ b/src/Promitor.sln.DotSettings @@ -83,6 +83,7 @@ True True True + False True True True @@ -93,8 +94,9 @@ True True True - True + False True + True True True True From fb4d6b88c468a8c0fe3149e300a7b65b4009f50b Mon Sep 17 00:00:00 2001 From: amirschw <24677563+amirschw@users.noreply.github.com> Date: Tue, 18 Jul 2023 22:32:02 +0300 Subject: [PATCH 52/53] fix integration tests --- config/promitor/scraper/metrics.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/promitor/scraper/metrics.yaml b/config/promitor/scraper/metrics.yaml index 09685c94d..4a947b444 100644 --- a/config/promitor/scraper/metrics.yaml +++ b/config/promitor/scraper/metrics.yaml @@ -271,7 +271,7 @@ metrics: - name: promitor-testing-resource-eu-telemetry-classic resourceGroupName: promitor-testing-infrastructure-europe # Application Insights with data in Log Analytics - - name: promitor-testing-infrastructure-europe-we-telemetry + - name: promitor-testing-resource-eu-telemetry resourceGroupName: promitor-testing-infrastructure-europe - name: promitor_demo_application_insights_availability_per_name_and_location description: "Availability (%) of promitor.io measured in Azure Application Insights per name and location" From 439d6cc8880e95c1598b66d9c19d2440057c4f22 Mon Sep 17 00:00:00 2001 From: amirschw <24677563+amirschw@users.noreply.github.com> Date: Wed, 19 Jul 2023 10:48:27 +0300 Subject: [PATCH 53/53] fix integration tests failing due to otel name length limit --- config/promitor/scraper/metrics.yaml | 6 +++--- .../Scraper/MetricSinks/PrometheusScrapeMetricSinkTests.cs | 4 ++-- src/Promitor.Tests.Integration/appsettings.json | 6 +++--- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/config/promitor/scraper/metrics.yaml b/config/promitor/scraper/metrics.yaml index 4a947b444..fae8f91e8 100644 --- a/config/promitor/scraper/metrics.yaml +++ b/config/promitor/scraper/metrics.yaml @@ -243,7 +243,7 @@ metrics: type: Total resourceDiscoveryGroups: - name: data-factory-landscape - - name: promitor_demo_application_insights_availability + - name: application_insights_availability description: "Availability (%) of promitor.io measured in Azure Application Insights" resourceType: ApplicationInsights azureMetricConfiguration: @@ -257,7 +257,7 @@ metrics: # Application Insights with data in Log Analytics - name: promitor-testing-resource-eu-telemetry resourceGroupName: promitor-testing-infrastructure-europe - - name: promitor_demo_application_insights_availability_per_name + - name: application_insights_availability_per_name description: "Availability (%) of promitor.io measured in Azure Application Insights per name" resourceType: ApplicationInsights azureMetricConfiguration: @@ -273,7 +273,7 @@ metrics: # Application Insights with data in Log Analytics - name: promitor-testing-resource-eu-telemetry resourceGroupName: promitor-testing-infrastructure-europe - - name: promitor_demo_application_insights_availability_per_name_and_location + - name: application_insights_availability_per_name_and_location description: "Availability (%) of promitor.io measured in Azure Application Insights per name and location" resourceType: ApplicationInsights azureMetricConfiguration: diff --git a/src/Promitor.Tests.Integration/Services/Scraper/MetricSinks/PrometheusScrapeMetricSinkTests.cs b/src/Promitor.Tests.Integration/Services/Scraper/MetricSinks/PrometheusScrapeMetricSinkTests.cs index c20c45718..ad9a28f8e 100644 --- a/src/Promitor.Tests.Integration/Services/Scraper/MetricSinks/PrometheusScrapeMetricSinkTests.cs +++ b/src/Promitor.Tests.Integration/Services/Scraper/MetricSinks/PrometheusScrapeMetricSinkTests.cs @@ -119,8 +119,8 @@ public async Task Prometheus_Scrape_ExpectedDimensionsAreAvailable(string expect } public static IEnumerable DimensionsData(){ - yield return new object[] { "promitor_demo_application_insights_availability_per_name", new List{ "availabilityResult/name" } }; - yield return new object[] { "promitor_demo_application_insights_availability_per_name_and_location", new List{ "availabilityResult/name", "availabilityResult/location" } }; + yield return new object[] { "application_insights_availability_per_name", new List{ "availabilityResult/name" } }; + yield return new object[] { "application_insights_availability_per_name_and_location", new List{ "availabilityResult/name", "availabilityResult/location" } }; } } } diff --git a/src/Promitor.Tests.Integration/appsettings.json b/src/Promitor.Tests.Integration/appsettings.json index 43dd7fc3c..a33028a74 100644 --- a/src/Promitor.Tests.Integration/appsettings.json +++ b/src/Promitor.Tests.Integration/appsettings.json @@ -22,7 +22,7 @@ "OpenTelemetry": { "Collector": { "Uri": "#{OpenTelemetry.Collector.Uri}#", - "MetricNamespace": "otel" - } - } + "MetricNamespace": "otel" + } + } } \ No newline at end of file