Skip to content

Commit 6408dc4

Browse files
authored
Merge pull request #505 from hjgraca/fix-exception-addmetadata
fix: Metrics throws exception when using AddMetadata
2 parents 21aff1f + e921a7b commit 6408dc4

File tree

6 files changed

+149
-9
lines changed

6 files changed

+149
-9
lines changed

docs/core/metrics.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,9 @@ You can add high-cardinality data as part of your Metrics log with `AddMetadata`
311311
!!! info
312312
**This will not be available during metrics visualization** - Use **dimensions** for this purpose
313313

314+
!!! info
315+
Adding metadata with a key that is the same as an existing metric will be ignored
316+
314317
=== "Function.cs"
315318

316319
```csharp hl_lines="9"

libraries/src/AWS.Lambda.Powertools.Metrics/Model/Metadata.cs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
/*
22
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3-
*
3+
*
44
* Licensed under the Apache License, Version 2.0 (the "License").
55
* You may not use this file except in compliance with the License.
66
* A copy of the License is located at
7-
*
7+
*
88
* http://aws.amazon.com/apache2.0
9-
*
9+
*
1010
* or in the "license" file accompanying this file. This file is distributed
1111
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
1212
* express or implied. See the License for the specific language governing
@@ -29,7 +29,7 @@ public class Metadata
2929
/// </summary>
3030
public Metadata()
3131
{
32-
CloudWatchMetrics = new List<MetricDirective> {new()};
32+
CloudWatchMetrics = new List<MetricDirective> { new() };
3333
CustomMetadata = new Dictionary<string, object>();
3434
}
3535

@@ -66,6 +66,7 @@ public Metadata()
6666
internal void ClearMetrics()
6767
{
6868
_metricDirective.Metrics.Clear();
69+
CustomMetadata?.Clear();
6970
}
7071

7172
/// <summary>
@@ -158,7 +159,7 @@ internal List<MetricDefinition> GetMetrics()
158159
/// <param name="value">Metadata value</param>
159160
internal void AddMetadata(string key, object value)
160161
{
161-
CustomMetadata.Add(key, value);
162+
CustomMetadata.TryAdd(key, value);
162163
}
163164

164165
/// <summary>

libraries/src/AWS.Lambda.Powertools.Metrics/Model/RootNode.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,14 +43,14 @@ public Dictionary<string, object> MetricData
4343
var targetMembers = new Dictionary<string, object>();
4444

4545
foreach (var dimension in AWS.ExpandAllDimensionSets()) targetMembers.Add(dimension.Key, dimension.Value);
46-
47-
foreach (var metadata in AWS.CustomMetadata) targetMembers.Add(metadata.Key, metadata.Value);
48-
46+
4947
foreach (var metricDefinition in AWS.GetMetrics())
5048
{
5149
var values = metricDefinition.Values;
5250
targetMembers.Add(metricDefinition.Name, values.Count == 1 ? values[0] : values);
5351
}
52+
53+
foreach (var metadata in AWS.CustomMetadata) targetMembers.TryAdd(metadata.Key, metadata.Value);
5454

5555
return targetMembers;
5656
}

libraries/tests/AWS.Lambda.Powertools.Metrics.Tests/EMFValidationTests.cs

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -546,7 +546,47 @@ public void WhenMetricsAndMetadataAdded_ValidateOutput()
546546
var result = consoleOut.ToString();
547547

548548
// Assert
549-
Assert.Contains("CloudWatchMetrics\":[{\"Namespace\":\"dotnet-powertools-test\",\"Metrics\":[{\"Name\":\"Time\",\"Unit\":\"Milliseconds\"}],\"Dimensions\":[[\"Service\"],[\"functionVersion\"]]}]},\"Service\":\"testService\",\"functionVersion\":\"$LATEST\",\"env\":\"dev\",\"Time\":100.7}"
549+
Assert.Contains("CloudWatchMetrics\":[{\"Namespace\":\"dotnet-powertools-test\",\"Metrics\":[{\"Name\":\"Time\",\"Unit\":\"Milliseconds\"}],\"Dimensions\":[[\"Service\"],[\"functionVersion\"]]}]},\"Service\":\"testService\",\"functionVersion\":\"$LATEST\",\"Time\":100.7,\"env\":\"dev\"}"
550+
, result);
551+
552+
// Reset
553+
handler.ResetForTest();
554+
}
555+
556+
[Fact]
557+
public void When_Metrics_And_Metadata_Added_With_Same_Key_Should_Only_Write_Metrics()
558+
{
559+
// Arrange
560+
var methodName = Guid.NewGuid().ToString();
561+
var consoleOut = new StringWriter();
562+
Console.SetOut(consoleOut);
563+
var configurations = Substitute.For<IPowertoolsConfigurations>();
564+
565+
var metrics = new Metrics(
566+
configurations,
567+
nameSpace: "dotnet-powertools-test",
568+
service: "testService"
569+
);
570+
571+
var handler = new MetricsAspectHandler(
572+
metrics,
573+
false
574+
);
575+
576+
var eventArgs = new AspectEventArgs { Name = methodName };
577+
578+
// Act
579+
handler.OnEntry(eventArgs);
580+
Metrics.AddDimension("functionVersion", "$LATEST");
581+
Metrics.AddMetric("Time", 100.7, MetricUnit.Milliseconds);
582+
Metrics.AddMetadata("Time", "dev");
583+
handler.OnExit(eventArgs);
584+
585+
var result = consoleOut.ToString();
586+
587+
// Assert
588+
// No Metadata key was added
589+
Assert.Contains("CloudWatchMetrics\":[{\"Namespace\":\"dotnet-powertools-test\",\"Metrics\":[{\"Name\":\"Time\",\"Unit\":\"Milliseconds\"}],\"Dimensions\":[[\"Service\"],[\"functionVersion\"]]}]},\"Service\":\"testService\",\"functionVersion\":\"$LATEST\",\"Time\":100.7}"
550590
, result);
551591

552592
// Reset
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/*
2+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License").
5+
* You may not use this file except in compliance with the License.
6+
* A copy of the License is located at
7+
*
8+
* http://aws.amazon.com/apache2.0
9+
*
10+
* or in the "license" file accompanying this file. This file is distributed
11+
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12+
* express or implied. See the License for the specific language governing
13+
* permissions and limitations under the License.
14+
*/
15+
16+
using System.Globalization;
17+
using System.Threading.Tasks;
18+
19+
namespace AWS.Lambda.Powertools.Metrics.Tests.Handlers;
20+
21+
public class FunctionHandler
22+
{
23+
[Metrics(Namespace = "ns", Service = "svc")]
24+
public async Task<string> HandleSameKey(string input)
25+
{
26+
Metrics.AddMetric("MyMetric", 1);
27+
Metrics.AddMetadata("MyMetric", "meta");
28+
29+
await Task.Delay(1);
30+
31+
return input.ToUpper(CultureInfo.InvariantCulture);
32+
}
33+
34+
[Metrics(Namespace = "ns", Service = "svc")]
35+
public async Task<string> HandleTestSecondCall(string input)
36+
{
37+
Metrics.AddMetric("MyMetric", 1);
38+
Metrics.AddMetadata("MyMetadata", "meta");
39+
40+
await Task.Delay(1);
41+
42+
return input.ToUpper(CultureInfo.InvariantCulture);
43+
}
44+
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
/*
2+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License").
5+
* You may not use this file except in compliance with the License.
6+
* A copy of the License is located at
7+
*
8+
* http://aws.amazon.com/apache2.0
9+
*
10+
* or in the "license" file accompanying this file. This file is distributed
11+
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12+
* express or implied. See the License for the specific language governing
13+
* permissions and limitations under the License.
14+
*/
15+
16+
using System.Threading.Tasks;
17+
using Xunit;
18+
19+
namespace AWS.Lambda.Powertools.Metrics.Tests.Handlers;
20+
21+
[Collection("Sequential")]
22+
public class FunctionHandlerTests
23+
{
24+
[Fact]
25+
public async Task When_Metrics_Add_Metadata_Same_Key_Should_Ignore_Metadata()
26+
{
27+
// Arrange
28+
Metrics.ResetForTest();
29+
var handler = new FunctionHandler();
30+
31+
// Act
32+
var exception = await Record.ExceptionAsync( () => handler.HandleSameKey("whatever"));
33+
34+
// Assert
35+
Assert.Null(exception);
36+
}
37+
38+
[Fact]
39+
public async Task When_Metrics_Add_Metadata_Second_Invocation_Should_Not_Throw_Exception()
40+
{
41+
// Arrange
42+
Metrics.ResetForTest();
43+
var handler = new FunctionHandler();
44+
45+
// Act
46+
var exception = await Record.ExceptionAsync( () => handler.HandleTestSecondCall("whatever"));
47+
Assert.Null(exception);
48+
49+
exception = await Record.ExceptionAsync( () => handler.HandleTestSecondCall("whatever"));
50+
Assert.Null(exception);
51+
}
52+
}

0 commit comments

Comments
 (0)