Skip to content

Commit fe9e62d

Browse files
[OTLP] Fix NullReferenceException when no bucket boundaries configured for a view (#6773)
1 parent 1080291 commit fe9e62d

File tree

7 files changed

+54
-7
lines changed

7 files changed

+54
-7
lines changed

src/OpenTelemetry.Exporter.OpenTelemetryProtocol/CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ Notes](../../RELEASENOTES.md).
2323
* Added support for `Meter.TelemetrySchemaUrl` property.
2424
([#6731](https://github.com/open-telemetry/opentelemetry-dotnet/pull/6731))
2525

26+
* Fix `NullReferenceException` when no bucket boundaries configured for a view.
27+
([#6773](https://github.com/open-telemetry/opentelemetry-dotnet/pull/6773))
28+
2629
## 1.14.0
2730

2831
Released 2025-Nov-12

src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/Serializer/ProtobufOtlpMetricSerializer.cs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -409,7 +409,7 @@ private static int WriteNumberDataPoint(byte[] buffer, int writePosition, int fi
409409
writePosition,
410410
in exemplar,
411411
ProtobufOtlpMetricFieldNumberConstants.NumberDataPoint_Exemplars,
412-
static (byte[] buffer, int writePosition, in Exemplar exemplar) => ProtobufSerializer.WriteFixed64WithTag(buffer, writePosition, ProtobufOtlpMetricFieldNumberConstants.Exemplar_Value_As_Int, (ulong)exemplar.LongValue));
412+
static (buffer, writePosition, in exemplar) => ProtobufSerializer.WriteFixed64WithTag(buffer, writePosition, ProtobufOtlpMetricFieldNumberConstants.Exemplar_Value_As_Int, (ulong)exemplar.LongValue));
413413
}
414414
}
415415

@@ -472,7 +472,7 @@ private static int WriteDoubleExemplars(byte[] buffer, int writePosition, int fi
472472
writePosition,
473473
in exemplar,
474474
fieldNumber,
475-
static (byte[] buffer, int writePosition, in Exemplar exemplar) => ProtobufSerializer.WriteDoubleWithTag(buffer, writePosition, ProtobufOtlpMetricFieldNumberConstants.Exemplar_Value_As_Double, exemplar.DoubleValue));
475+
static (buffer, writePosition, in exemplar) => ProtobufSerializer.WriteDoubleWithTag(buffer, writePosition, ProtobufOtlpMetricFieldNumberConstants.Exemplar_Value_As_Double, exemplar.DoubleValue));
476476
}
477477
}
478478

@@ -516,7 +516,10 @@ private static int WriteHistogramBuckets(byte[] buffer, int writePosition, Histo
516516
{
517517
writePosition = WriteBucketCounts(buffer, writePosition, buckets.BucketCounts);
518518

519-
writePosition = WriteExplicitBounds(buffer, writePosition, buckets.ExplicitBounds!);
519+
if (buckets.ExplicitBounds is { } explicitBounds)
520+
{
521+
writePosition = WriteExplicitBounds(buffer, writePosition, explicitBounds);
522+
}
520523

521524
return writePosition;
522525

src/OpenTelemetry/Metrics/View/ExplicitBucketHistogramConfiguration.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ public double[]? Boundaries
3838
throw new ArgumentException($"Histogram boundaries are invalid. Histogram boundaries must be in ascending order with distinct values.", nameof(value));
3939
}
4040

41-
this.CopiedBoundaries = value.ToArray();
41+
this.CopiedBoundaries = [.. value];
4242
}
4343
else
4444
{

test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/Implementation/Serializer/ProtobufOtlpMetricSerializerTests.cs

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,51 @@ namespace OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests.Implementation.Seri
1313

1414
public static class ProtobufOtlpMetricSerializerTests
1515
{
16+
private const string HistogramName = "histogram";
17+
1618
[Fact]
1719
public static async Task WriteMetricsData_Serializes_Metrics_Correctly()
1820
{
1921
// Arrange
2022
var metrics = GenerateMetrics();
2123

24+
// Act and Assert
25+
await WriteMetricsAndAssertSnapshot(metrics);
26+
}
27+
28+
[Fact]
29+
public static async Task WriteMetricsData_Serializes_Metrics_With_Explicit_Boundaries()
30+
{
31+
// Arrange
32+
var metrics = GenerateMetrics((builder) =>
33+
{
34+
builder.AddView(
35+
instrumentName: HistogramName,
36+
new ExplicitBucketHistogramConfiguration { Boundaries = [1, 2, 4, 8, 16] });
37+
});
38+
39+
// Act and Assert
40+
await WriteMetricsAndAssertSnapshot(metrics);
41+
}
42+
43+
[Fact]
44+
public static async Task WriteMetricsData_Serializes_Metrics_With_No_Boundaries()
45+
{
46+
// Arrange
47+
var metrics = GenerateMetrics((builder) =>
48+
{
49+
builder.AddView(
50+
instrumentName: HistogramName,
51+
new ExplicitBucketHistogramConfiguration { Boundaries = [] });
52+
});
53+
54+
// Act and Assert
55+
await WriteMetricsAndAssertSnapshot(metrics);
56+
}
57+
58+
private static async Task WriteMetricsAndAssertSnapshot(Batch<Metric> metrics)
59+
{
60+
// Arrange
2261
var attributes = new Dictionary<string, object>
2362
{
2463
["service.name"] = "OpenTelemetry-DotNet",
@@ -54,7 +93,7 @@ await Verify(stream, "bin")
5493
.UseDirectory("snapshots");
5594
}
5695

57-
private static Batch<Metric> GenerateMetrics()
96+
private static Batch<Metric> GenerateMetrics(Action<MeterProviderBuilder>? configure = null)
5897
{
5998
// Arrange
6099
Batch<Metric> metrics = default;
@@ -94,6 +133,8 @@ private static Batch<Metric> GenerateMetrics()
94133
experimentalOptions,
95134
configureExporterInstance: (_) => exporter));
96135

136+
configure?.Invoke(builder);
137+
97138
using var meterProvider = builder.Build();
98139
using var meter = new Meter(meterName);
99140

@@ -103,7 +144,7 @@ private static Batch<Metric> GenerateMetrics()
103144
var gauge = meter.CreateGauge<int>("gauge");
104145
gauge.Record(42);
105146

106-
var histogram = meter.CreateHistogram<int>("histogram");
147+
var histogram = meter.CreateHistogram<int>(HistogramName);
107148
histogram.Record(100);
108149

109150
Assert.True(meterProvider.ForceFlush());

test/OpenTelemetry.Tests/Shared/EventSourceTestHelper.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ private static void VerifyEventMessage(MethodInfo eventMethod, EventWrittenEvent
102102
string expectedMessage = eventArguments.Length == 0
103103
? GetEventAttribute(eventMethod).Message!
104104
: string.Format(CultureInfo.InvariantCulture, GetEventAttribute(eventMethod).Message!, eventArguments);
105-
string actualMessage = string.Format(CultureInfo.InvariantCulture, actualEvent.Message!, actualEvent.Payload!.ToArray());
105+
string actualMessage = string.Format(CultureInfo.InvariantCulture, actualEvent.Message!, [.. actualEvent.Payload!]);
106106
AssertEqual(nameof(VerifyEventMessage), expectedMessage, actualMessage);
107107
}
108108

0 commit comments

Comments
 (0)