From 056abbb66caafe81a840bedf648be01f4d1b40ce Mon Sep 17 00:00:00 2001 From: Mark Kuhn Date: Mon, 15 Aug 2022 13:02:25 -0700 Subject: [PATCH 1/2] fix: prevent duplicate dimensions --- .../Model/MetricDirective.cs | 19 ++++++++ .../Model/MetricsContext.cs | 4 +- .../Logger/MetricsLoggerTests.cs | 44 +++++++++++++++++++ 3 files changed, 65 insertions(+), 2 deletions(-) diff --git a/src/Amazon.CloudWatch.EMF/Model/MetricDirective.cs b/src/Amazon.CloudWatch.EMF/Model/MetricDirective.cs index 53c9387..9d8a6cb 100644 --- a/src/Amazon.CloudWatch.EMF/Model/MetricDirective.cs +++ b/src/Amazon.CloudWatch.EMF/Model/MetricDirective.cs @@ -80,6 +80,25 @@ internal List> AllDimensionKeys } } + internal void PutDimension(DimensionSet dimensionSet) + { + // Duplicate dimensions sets are removed before being added to the end of the collection. + // This ensures the latest dimension key-value is used as a target member on the root EMF node. + // This operation is O(n^2), but acceptable given sets are capped at 10 dimensions + List incomingDimensionSetKeys = dimensionSet.DimensionKeys; + CustomDimensionSets = CustomDimensionSets.Where(existingDimensionSet => + { + if (existingDimensionSet.DimensionKeys.Count != incomingDimensionSetKeys.Count) + { + return true; + } + + return !existingDimensionSet.DimensionKeys.All(existingDimensionSetKey => incomingDimensionSetKeys.Contains(existingDimensionSetKey)); + }).ToList(); + + CustomDimensionSets.Add(dimensionSet); + } + /// /// Overrides all existing dimensions, including suppressing any default dimensions. /// diff --git a/src/Amazon.CloudWatch.EMF/Model/MetricsContext.cs b/src/Amazon.CloudWatch.EMF/Model/MetricsContext.cs index b1d0ae8..44ab4a3 100644 --- a/src/Amazon.CloudWatch.EMF/Model/MetricsContext.cs +++ b/src/Amazon.CloudWatch.EMF/Model/MetricsContext.cs @@ -151,7 +151,7 @@ public object GetProperty(string name) /// the dimensions set to add. public void PutDimension(DimensionSet dimensionSet) { - _metricDirective.CustomDimensionSets.Add(dimensionSet); + _metricDirective.PutDimension(dimensionSet); } /// @@ -166,7 +166,7 @@ public void PutDimension(string dimension, string value) { var dimensionSet = new DimensionSet(); dimensionSet.AddDimension(dimension, value); - _metricDirective.CustomDimensionSets.Add(dimensionSet); + _metricDirective.PutDimension(dimensionSet); } /// diff --git a/tests/Amazon.CloudWatch.EMF.Tests/Logger/MetricsLoggerTests.cs b/tests/Amazon.CloudWatch.EMF.Tests/Logger/MetricsLoggerTests.cs index 1f6e57a..dd1efc0 100644 --- a/tests/Amazon.CloudWatch.EMF.Tests/Logger/MetricsLoggerTests.cs +++ b/tests/Amazon.CloudWatch.EMF.Tests/Logger/MetricsLoggerTests.cs @@ -93,6 +93,50 @@ public void TestOverridePreviousDimensions() Assert.Equal(dimensionValue, _sink.MetricsContext.GetAllDimensionSets()[0].GetDimensionValue(dimensionName)); } + [Fact] + public void TestPutDuplicateDimensions() + { + string dimensionName1 = "dim1"; + string dimensionName2 = "dim2"; + string dimensionValue1 = "dimValue1"; + string dimensionValue2 = "dimValue2"; + string dimensionValue3 = "dimValue3"; + string dimensionValue4 = "dimValue4"; + + _metricsLogger.PutDimensions(new DimensionSet(dimensionName1, dimensionValue1)); + _metricsLogger.PutDimensions(new DimensionSet(dimensionName2, dimensionValue2)); + _metricsLogger.PutDimensions(new DimensionSet(dimensionName1, dimensionValue3)); + _metricsLogger.PutDimensions(new DimensionSet(dimensionName2, dimensionValue4)); + _metricsLogger.Flush(); + + Assert.Equal(4, _sink.MetricsContext.GetAllDimensionSets()[0].DimensionKeys.Count); + Assert.Equal(dimensionValue3, _sink.MetricsContext.GetAllDimensionSets()[0].GetDimensionValue(dimensionName1)); + Assert.Equal(dimensionValue4, _sink.MetricsContext.GetAllDimensionSets()[0].GetDimensionValue(dimensionName2)); + } + + [Fact] + public void TestSetPutDuplicateDimensions() + { + string dimensionName1 = "dim1"; + string dimensionName2 = "dim2"; + string dimensionName3 = "dim3"; + string dimensionValue1 = "dimValue1"; + string dimensionValue2 = "dimValue2"; + string dimensionValue3 = "dimValue3"; + string dimensionValue4 = "dimValue4"; + + _metricsLogger.PutDimensions(new DimensionSet(dimensionName1, dimensionValue1)); + _metricsLogger.SetDimensions(new DimensionSet(dimensionName2, dimensionValue1)); + _metricsLogger.PutDimensions(new DimensionSet(dimensionName3, dimensionValue2)); + _metricsLogger.PutDimensions(new DimensionSet(dimensionName2, dimensionValue3)); + _metricsLogger.PutDimensions(new DimensionSet(dimensionName3, dimensionValue4)); + _metricsLogger.Flush(); + + Assert.Equal(2, _sink.MetricsContext.GetAllDimensionSets().Count); + Assert.Equal(dimensionValue3, _sink.MetricsContext.GetAllDimensionSets()[0].GetDimensionValue(dimensionName2)); + Assert.Equal(dimensionValue4, _sink.MetricsContext.GetAllDimensionSets()[1].GetDimensionValue(dimensionName3)); + } + [Fact] public void TestSetNameSpace() { From 8b2a9e41632e32e6909bedefb2658b9797034ae5 Mon Sep 17 00:00:00 2001 From: Mark Kuhn Date: Wed, 17 Aug 2022 11:20:44 -0700 Subject: [PATCH 2/2] fix comment --- src/Amazon.CloudWatch.EMF/Model/MetricDirective.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Amazon.CloudWatch.EMF/Model/MetricDirective.cs b/src/Amazon.CloudWatch.EMF/Model/MetricDirective.cs index 9d8a6cb..f72877f 100644 --- a/src/Amazon.CloudWatch.EMF/Model/MetricDirective.cs +++ b/src/Amazon.CloudWatch.EMF/Model/MetricDirective.cs @@ -84,7 +84,7 @@ internal void PutDimension(DimensionSet dimensionSet) { // Duplicate dimensions sets are removed before being added to the end of the collection. // This ensures the latest dimension key-value is used as a target member on the root EMF node. - // This operation is O(n^2), but acceptable given sets are capped at 10 dimensions + // This operation is O(n^2), but acceptable given sets are capped at 30 dimensions List incomingDimensionSetKeys = dimensionSet.DimensionKeys; CustomDimensionSets = CustomDimensionSets.Where(existingDimensionSet => {