Skip to content

Commit 90fbcf4

Browse files
committed
fix: enhance thread safety in Metrics library to prevent concurrent modification issues
1 parent b92cce3 commit 90fbcf4

File tree

8 files changed

+662
-73
lines changed

8 files changed

+662
-73
lines changed

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

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -535,9 +535,17 @@ private Dictionary<string, string> ListToDictionary(List<DimensionSet> dimension
535535
var dictionary = new Dictionary<string, string>();
536536
try
537537
{
538-
return dimensions != null
539-
? new Dictionary<string, string>(dimensions.SelectMany(x => x.Dimensions))
540-
: dictionary;
538+
if (dimensions != null)
539+
{
540+
foreach (var dimensionSet in dimensions)
541+
{
542+
foreach (var kvp in dimensionSet.Dimensions)
543+
{
544+
dictionary[kvp.Key] = kvp.Value;
545+
}
546+
}
547+
}
548+
return dictionary;
541549
}
542550
catch (Exception e)
543551
{
@@ -633,20 +641,34 @@ private static MetricDefinition GetExistingMetric(List<MetricDefinition> metrics
633641
{
634642
// Use a traditional for loop instead of LINQ to avoid enumeration issues
635643
// when the collection is modified concurrently
636-
for (int i = 0; i < metrics.Count; i++)
644+
if (metrics == null || string.IsNullOrEmpty(key))
645+
return null;
646+
647+
// Create a snapshot of the count to avoid issues with concurrent modifications
648+
var count = metrics.Count;
649+
for (int i = 0; i < count; i++)
637650
{
638651
try
639652
{
653+
// Check bounds again in case collection was modified
654+
if (i >= metrics.Count)
655+
break;
656+
640657
var metric = metrics[i];
641-
if (metric?.Name == key)
658+
if (metric != null && string.Equals(metric.Name, key, StringComparison.Ordinal))
642659
{
643660
return metric;
644661
}
645662
}
646663
catch (ArgumentOutOfRangeException)
647664
{
648665
// Collection was modified during iteration, return null to be safe
649-
return null;
666+
break;
667+
}
668+
catch (IndexOutOfRangeException)
669+
{
670+
// Collection was modified during iteration, return null to be safe
671+
break;
650672
}
651673
}
652674
return null;

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

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,5 +43,16 @@ public DimensionSet(string key, string value)
4343
/// Gets the dimension keys.
4444
/// </summary>
4545
/// <value>The dimension keys.</value>
46-
public List<string> DimensionKeys => Dimensions.Keys.ToList();
46+
public List<string> DimensionKeys
47+
{
48+
get
49+
{
50+
var keys = new List<string>();
51+
foreach (var key in Dimensions.Keys)
52+
{
53+
keys.Add(key);
54+
}
55+
return keys;
56+
}
57+
}
4758
}

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

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,10 @@ public Metadata()
5151
/// </summary>
5252
internal void ClearMetrics()
5353
{
54-
_metricDirective.Metrics.Clear();
54+
lock (_metricDirective._lockObj)
55+
{
56+
_metricDirective.Metrics.Clear();
57+
}
5558
CustomMetadata?.Clear();
5659
}
5760

@@ -60,7 +63,10 @@ internal void ClearMetrics()
6063
/// </summary>
6164
internal void ClearNonDefaultDimensions()
6265
{
63-
_metricDirective.Dimensions.Clear();
66+
lock (_metricDirective._lockObj)
67+
{
68+
_metricDirective.Dimensions.Clear();
69+
}
6470
}
6571

6672
/// <summary>
@@ -144,7 +150,11 @@ internal void SetDefaultDimensions(List<DimensionSet> defaultDimensionSets)
144150
/// <returns>List of metrics stored in memory</returns>
145151
internal List<MetricDefinition> GetMetrics()
146152
{
147-
return _metricDirective.Metrics;
153+
// Return a snapshot to avoid concurrent modification issues during serialization
154+
lock (_metricDirective._lockObj)
155+
{
156+
return new List<MetricDefinition>(_metricDirective.Metrics);
157+
}
148158
}
149159

150160
/// <summary>

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,9 @@ public MetricDefinition(string name, MetricUnit unit, List<double> values, Metri
9393
/// <param name="value">Metric value to add to existing key</param>
9494
public void AddValue(double value)
9595
{
96-
Values.Add(value);
96+
lock (Values)
97+
{
98+
Values.Add(value);
99+
}
97100
}
98101
}

0 commit comments

Comments
 (0)