Skip to content

Commit 97e2ba5

Browse files
authored
Merge branch 'main' into main
2 parents 8a9639f + 1b555c1 commit 97e2ba5

File tree

44 files changed

+228
-303
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+228
-303
lines changed

Directory.Packages.props

+2-2
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@
109109
<PackageVersion Include="Microsoft.Extensions.Logging.Abstractions" Version="$(LatestRuntimeOutOfBandVer)" />
110110
<PackageVersion Include="Microsoft.Extensions.Telemetry.Abstractions" Version="[9.0.0,)" />
111111
<PackageVersion Include="Microsoft.NETFramework.ReferenceAssemblies" Version="[1.0.3,2.0)" />
112-
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="[17.11.0,18.0.0)" />
112+
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="[17.13.0,18.0.0)" />
113113
<PackageVersion Include="Microsoft.SourceLink.GitHub" Version="[8.0.0,9.0)" />
114114
<PackageVersion Include="MinVer" Version="[5.0.0,6.0)" />
115115
<PackageVersion Include="NuGet.Versioning" Version="6.11.0" />
@@ -121,7 +121,7 @@
121121
<PackageVersion Include="StyleCop.Analyzers" Version="[1.2.0-beta.556,2.0)" />
122122
<PackageVersion Include="Swashbuckle.AspNetCore" Version="[6.7.3,)" />
123123
<PackageVersion Include="System.Runtime.InteropServices.RuntimeInformation" Version="4.3.0" />
124-
<PackageVersion Include="xunit" Version="[2.9.0,3.0)" />
124+
<PackageVersion Include="xunit" Version="[2.9.3,3.0)" />
125125
<PackageVersion Include="xunit.runner.visualstudio" Version="[2.8.2,3.0)" />
126126
</ItemGroup>
127127

docs/metrics/customizing-the-sdk/Program.cs

+3-3
Original file line numberDiff line numberDiff line change
@@ -29,19 +29,19 @@ public static void Main()
2929
.AddView(instrumentName: "MyCounter", name: "MyCounterRenamed")
3030

3131
// Change Histogram boundaries using the Explicit Bucket Histogram aggregation.
32-
.AddView(instrumentName: "MyHistogram", new ExplicitBucketHistogramConfiguration() { Boundaries = new double[] { 10, 20 } })
32+
.AddView(instrumentName: "MyHistogram", new ExplicitBucketHistogramConfiguration() { Boundaries = [10.0, 20.0] })
3333

3434
// Change Histogram to use the Base2 Exponential Bucket Histogram aggregation.
3535
.AddView(instrumentName: "MyExponentialBucketHistogram", new Base2ExponentialBucketHistogramConfiguration())
3636

3737
// For the instrument "MyCounterCustomTags", aggregate with only the keys "tag1", "tag2".
38-
.AddView(instrumentName: "MyCounterCustomTags", new MetricStreamConfiguration() { TagKeys = new string[] { "tag1", "tag2" } })
38+
.AddView(instrumentName: "MyCounterCustomTags", new MetricStreamConfiguration() { TagKeys = ["tag1", "tag2"] })
3939

4040
// Drop the instrument "MyCounterDrop".
4141
.AddView(instrumentName: "MyCounterDrop", MetricStreamConfiguration.Drop)
4242

4343
// Configure the Explicit Bucket Histogram aggregation with custom boundaries and new name.
44-
.AddView(instrumentName: "histogramWithMultipleAggregations", new ExplicitBucketHistogramConfiguration() { Boundaries = new double[] { 10, 20 }, Name = "MyHistogramWithExplicitHistogram" })
44+
.AddView(instrumentName: "histogramWithMultipleAggregations", new ExplicitBucketHistogramConfiguration() { Boundaries = [10.0, 20.0], Name = "MyHistogramWithExplicitHistogram" })
4545

4646
// Use Base2 Exponential Bucket Histogram aggregation and new name.
4747
.AddView(instrumentName: "histogramWithMultipleAggregations", new Base2ExponentialBucketHistogramConfiguration() { Name = "MyHistogramWithBase2ExponentialBucketHistogram" })

examples/AspNetCore/Controllers/WeatherForecastController.cs

+4-4
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,10 @@ namespace Examples.AspNetCore.Controllers;
1212
[Route("[controller]")]
1313
public class WeatherForecastController : ControllerBase
1414
{
15-
private static readonly string[] Summaries = new[]
16-
{
17-
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching",
18-
};
15+
private static readonly string[] Summaries =
16+
[
17+
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
18+
];
1919

2020
private static readonly HttpClient HttpClient = new();
2121

examples/Console/TestPrometheusExporter.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ internal static int Run(PrometheusOptions options)
3535
.AddMeter(MyMeter.Name)
3636
.AddMeter(MyMeter2.Name)
3737
.AddPrometheusHttpListener(
38-
o => o.UriPrefixes = new string[] { $"http://localhost:{options.Port}/" })
38+
o => o.UriPrefixes = [$"http://localhost:{options.Port}/"])
3939
.Build();
4040

4141
var process = Process.GetCurrentProcess();

src/OpenTelemetry.Api/CHANGELOG.md

+4
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@ Notes](../../RELEASENOTES.md).
66

77
## Unreleased
88

9+
* Revert optimize performance of `TraceContextPropagator.Extract` introduced
10+
in #5749 to resolve #6158.
11+
([#6161](https://github.com/open-telemetry/opentelemetry-dotnet/pull/6161))
12+
913
## 1.11.1
1014

1115
Released 2025-Jan-22

src/OpenTelemetry.Api/Context/Propagation/B3Propagator.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ public sealed class B3Propagator : TextMapPropagator
3535
// "Debug" sampled value.
3636
internal const string FlagsValue = "1";
3737

38-
private static readonly HashSet<string> AllFields = new() { XB3TraceId, XB3SpanId, XB3ParentSpanId, XB3Sampled, XB3Flags };
38+
private static readonly HashSet<string> AllFields = [XB3TraceId, XB3SpanId, XB3ParentSpanId, XB3Sampled, XB3Flags];
3939

4040
private static readonly HashSet<string> SampledValues = new(StringComparer.Ordinal) { SampledValue, LegacySampledValue };
4141

src/OpenTelemetry.Api/Context/Propagation/BaggagePropagator.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@ public class BaggagePropagator : TextMapPropagator
2020
private const int MaxBaggageLength = 8192;
2121
private const int MaxBaggageItems = 180;
2222

23-
private static readonly char[] EqualSignSeparator = new[] { '=' };
24-
private static readonly char[] CommaSignSeparator = new[] { ',' };
23+
private static readonly char[] EqualSignSeparator = ['='];
24+
private static readonly char[] CommaSignSeparator = [','];
2525

2626
/// <inheritdoc/>
2727
public override ISet<string> Fields => new HashSet<string> { BaggageHeaderName };

src/OpenTelemetry.Api/Context/Propagation/TraceContextPropagator.cs

+24-112
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
// Copyright The OpenTelemetry Authors
22
// SPDX-License-Identifier: Apache-2.0
33

4-
using System.Buffers;
54
using System.Diagnostics;
65
using System.Runtime.CompilerServices;
6+
using System.Text;
77
using OpenTelemetry.Internal;
88

99
namespace OpenTelemetry.Context.Propagation;
@@ -76,7 +76,7 @@ public override PropagationContext Extract<T>(PropagationContext context, T carr
7676
var tracestateCollection = getter(carrier, TraceState);
7777
if (tracestateCollection?.Any() ?? false)
7878
{
79-
TryExtractTracestate(tracestateCollection, out tracestate);
79+
TryExtractTracestate(tracestateCollection.ToArray(), out tracestate);
8080
}
8181

8282
return new PropagationContext(
@@ -220,37 +220,31 @@ internal static bool TryExtractTraceparent(string traceparent, out ActivityTrace
220220
return true;
221221
}
222222

223-
internal static bool TryExtractTracestate(IEnumerable<string> tracestateCollection, out string tracestateResult)
223+
internal static bool TryExtractTracestate(string[] tracestateCollection, out string tracestateResult)
224224
{
225225
tracestateResult = string.Empty;
226226

227-
char[]? rentedArray = null;
228-
Span<char> traceStateBuffer = stackalloc char[128]; // 256B
229-
Span<char> keyLookupBuffer = stackalloc char[96]; // 192B (3x32 keys)
230-
int keys = 0;
231-
int charsWritten = 0;
232-
233-
try
227+
if (tracestateCollection != null)
234228
{
235-
foreach (var tracestateItem in tracestateCollection)
229+
var keySet = new HashSet<string>();
230+
var result = new StringBuilder();
231+
for (int i = 0; i < tracestateCollection.Length; ++i)
236232
{
237-
var tracestate = tracestateItem.AsSpan();
238-
int position = 0;
239-
240-
while (position < tracestate.Length)
233+
var tracestate = tracestateCollection[i].AsSpan();
234+
int begin = 0;
235+
while (begin < tracestate.Length)
241236
{
242-
int length = tracestate.Slice(position).IndexOf(',');
237+
int length = tracestate.Slice(begin).IndexOf(',');
243238
ReadOnlySpan<char> listMember;
244-
245239
if (length != -1)
246240
{
247-
listMember = tracestate.Slice(position, length).Trim();
248-
position += length + 1;
241+
listMember = tracestate.Slice(begin, length).Trim();
242+
begin += length + 1;
249243
}
250244
else
251245
{
252-
listMember = tracestate.Slice(position).Trim();
253-
position = tracestate.Length;
246+
listMember = tracestate.Slice(begin).Trim();
247+
begin = tracestate.Length;
254248
}
255249

256250
// https://github.com/w3c/trace-context/blob/master/spec/20-http_request_header_format.md#tracestate-header-field-values
@@ -261,7 +255,7 @@ internal static bool TryExtractTracestate(IEnumerable<string> tracestateCollecti
261255
continue;
262256
}
263257

264-
if (keys >= 32)
258+
if (keySet.Count >= 32)
265259
{
266260
// https://github.com/w3c/trace-context/blob/master/spec/20-http_request_header_format.md#list
267261
// test_tracestate_member_count_limit
@@ -292,107 +286,25 @@ internal static bool TryExtractTracestate(IEnumerable<string> tracestateCollecti
292286
}
293287

294288
// ValidateKey() call above has ensured the key does not contain upper case letters.
295-
296-
var duplicationCheckLength = Math.Min(key.Length, 3);
297-
298-
if (keys > 0)
299-
{
300-
// Fast path check of first three chars for potential duplicated keys
301-
var potentialMatchingKeyPosition = 1;
302-
var found = false;
303-
for (int i = 0; i < keys * 3; i += 3)
304-
{
305-
if (keyLookupBuffer.Slice(i, duplicationCheckLength).SequenceEqual(key.Slice(0, duplicationCheckLength)))
306-
{
307-
found = true;
308-
break;
309-
}
310-
311-
potentialMatchingKeyPosition++;
312-
}
313-
314-
// If the fast check has found a possible duplicate, we need to do a full check
315-
if (found)
316-
{
317-
var bufferToCompare = traceStateBuffer.Slice(0, charsWritten);
318-
319-
// We know which key is the first possible duplicate, so skip to that key
320-
// by slicing to the position after the appropriate comma.
321-
for (int i = 1; i < potentialMatchingKeyPosition; i++)
322-
{
323-
var commaIndex = bufferToCompare.IndexOf(',');
324-
325-
if (commaIndex > -1)
326-
{
327-
bufferToCompare.Slice(commaIndex);
328-
}
329-
}
330-
331-
int existingIndex = -1;
332-
while ((existingIndex = bufferToCompare.IndexOf(key)) > -1)
333-
{
334-
if ((existingIndex > 0 && bufferToCompare[existingIndex - 1] != ',') || bufferToCompare[existingIndex + key.Length] != '=')
335-
{
336-
continue; // this is not a key
337-
}
338-
339-
return false; // test_tracestate_duplicated_keys
340-
}
341-
}
342-
}
343-
344-
// Store up to the first three characters of the key for use in the duplicate lookup fast path
345-
var startKeyLookupIndex = keys > 0 ? keys * 3 : 0;
346-
key.Slice(0, duplicationCheckLength).CopyTo(keyLookupBuffer.Slice(startKeyLookupIndex));
347-
348-
// Check we have capacity to write the key and value
349-
var requiredCapacity = charsWritten > 0 ? listMember.Length + 1 : listMember.Length;
350-
351-
while (charsWritten + requiredCapacity > traceStateBuffer.Length)
289+
if (!keySet.Add(key.ToString()))
352290
{
353-
GrowBuffer(ref rentedArray, ref traceStateBuffer);
291+
// test_tracestate_duplicated_keys
292+
return false;
354293
}
355294

356-
if (charsWritten > 0)
295+
if (result.Length > 0)
357296
{
358-
traceStateBuffer[charsWritten++] = ',';
297+
result.Append(',');
359298
}
360299

361-
listMember.CopyTo(traceStateBuffer.Slice(charsWritten));
362-
charsWritten += listMember.Length;
363-
364-
keys++;
300+
result.Append(listMember.ToString());
365301
}
366302
}
367303

368-
tracestateResult = traceStateBuffer.Slice(0, charsWritten).ToString();
369-
370-
return true;
304+
tracestateResult = result.ToString();
371305
}
372-
finally
373-
{
374-
if (rentedArray is not null)
375-
{
376-
ArrayPool<char>.Shared.Return(rentedArray);
377-
rentedArray = null;
378-
}
379-
}
380-
381-
[MethodImpl(MethodImplOptions.AggressiveInlining)]
382-
static void GrowBuffer(ref char[]? array, ref Span<char> buffer)
383-
{
384-
var newBuffer = ArrayPool<char>.Shared.Rent(buffer.Length * 2);
385306

386-
buffer.CopyTo(newBuffer.AsSpan());
387-
388-
if (array is not null)
389-
{
390-
ArrayPool<char>.Shared.Return(array);
391-
}
392-
393-
array = newBuffer;
394-
buffer = array.AsSpan();
395-
}
307+
return true;
396308
}
397309

398310
private static byte HexCharToByte(char c)

src/OpenTelemetry.Api/Logs/LogRecordSeverityExtensions.cs

+4-4
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,8 @@ static class LogRecordSeverityExtensions
5757
internal const string Fatal3ShortName = FatalShortName + "3";
5858
internal const string Fatal4ShortName = FatalShortName + "4";
5959

60-
private static readonly string[] LogRecordSeverityShortNames = new string[]
61-
{
60+
private static readonly string[] LogRecordSeverityShortNames =
61+
[
6262
UnspecifiedShortName,
6363

6464
TraceShortName,
@@ -89,8 +89,8 @@ static class LogRecordSeverityExtensions
8989
FatalShortName,
9090
Fatal2ShortName,
9191
Fatal3ShortName,
92-
Fatal4ShortName,
93-
};
92+
Fatal4ShortName
93+
];
9494

9595
/// <summary>
9696
/// Returns the OpenTelemetry Specification short name for the <see

src/OpenTelemetry.Exporter.OpenTelemetryProtocol/CHANGELOG.md

-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ Notes](../../RELEASENOTES.md).
1818

1919
* Fixed incorrect log serialization of attributes with null values, causing
2020
some backends to reject logs.
21-
some backends to reject logs when using OTLP exporter to output protobuf.
2221
([#6149](https://github.com/open-telemetry/opentelemetry-dotnet/pull/6149))
2322

2423
## 1.11.1

src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/ExportClient/OtlpGrpcExportClient.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ public override ExportClientResponse SendExportRequest(byte[] buffer, int conten
9393
grpcStatusDetailsHeader = GrpcProtocolHelpers.GetHeaderValue(trailingHeaders, GrpcStatusDetailsHeader);
9494
}
9595

96-
OpenTelemetryProtocolExporterEventSource.Log.ExportFailure(this.Endpoint.ToString(), "Export failed due to unexpected status code.");
96+
OpenTelemetryProtocolExporterEventSource.Log.ExportFailure(this.Endpoint, "Export failed due to unexpected status code.", status);
9797

9898
return new ExportClientGrpcResponse(
9999
success: false,

src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/OpenTelemetryProtocolExporterEventSource.cs

+13-3
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
using System.Diagnostics.Tracing;
55
using Microsoft.Extensions.Configuration;
6+
using OpenTelemetry.Exporter.OpenTelemetryProtocol.Implementation.ExportClient.Grpc;
67
using OpenTelemetry.Internal;
78

89
namespace OpenTelemetry.Exporter.OpenTelemetryProtocol.Implementation;
@@ -94,6 +95,15 @@ public void GrpcRetryDelayParsingFailed(string? grpcStatusDetailsHeader, Excepti
9495
}
9596
}
9697

98+
[NonEvent]
99+
public void ExportFailure(Uri endpoint, string message, Status status)
100+
{
101+
if (Log.IsEnabled(EventLevel.Error, EventKeywords.All))
102+
{
103+
this.ExportFailure(endpoint.ToString(), message, status.ToString());
104+
}
105+
}
106+
97107
[Event(2, Message = "Exporter failed send data to collector to {0} endpoint. Data will not be sent. Exception: {1}", Level = EventLevel.Error)]
98108
public void FailedToReachCollector(string rawCollectorUri, string ex)
99109
{
@@ -208,10 +218,10 @@ public void GrpcStatusWarning(string endpoint, string statusCode)
208218
this.WriteEvent(22, endpoint, statusCode);
209219
}
210220

211-
[Event(23, Message = "Export failed for {0}. Message: {1}", Level = EventLevel.Error)]
212-
public void ExportFailure(string endpoint, string message)
221+
[Event(23, Message = "Export failed for {0}. Message: {1}. {2}.", Level = EventLevel.Error)]
222+
public void ExportFailure(string endpoint, string message, string statusString)
213223
{
214-
this.WriteEvent(23, endpoint, message);
224+
this.WriteEvent(23, endpoint, message, statusString);
215225
}
216226

217227
[Event(24, Message = "Failed to parse gRPC retry delay from header grpcStatusDetailsHeader: '{0}'. Exception: {1}", Level = EventLevel.Warning)]

src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OtlpExporterOptionsExtensions.cs

+3-3
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ public static THeaders GetHeaders<THeaders>(this OtlpExporterOptions options, Ac
8888
{
8989
// Specify the maximum number of substrings to return to 2
9090
// This treats everything that follows the first `=` in the string as the value to be added for the metadata key
91-
var keyValueData = pair.Split(new char[] { '=' }, 2);
91+
var keyValueData = pair.Split(['='], 2);
9292
if (keyValueData.Length != 2)
9393
{
9494
throw new ArgumentException("Headers provided in an invalid format.");
@@ -197,11 +197,11 @@ public static void TryEnableIHttpClientFactoryIntegration(this OtlpExporterOptio
197197
"CreateClient",
198198
BindingFlags.Public | BindingFlags.Instance,
199199
binder: null,
200-
new Type[] { typeof(string) },
200+
[typeof(string)],
201201
modifiers: null);
202202
if (createClientMethod != null)
203203
{
204-
HttpClient? client = (HttpClient?)createClientMethod.Invoke(httpClientFactory, new object[] { httpClientName });
204+
HttpClient? client = (HttpClient?)createClientMethod.Invoke(httpClientFactory, [httpClientName]);
205205

206206
if (client != null)
207207
{

0 commit comments

Comments
 (0)