Skip to content

Commit eb2f998

Browse files
authored
[sdk-logs+traces] Add internal processor weight api (#5424)
1 parent 0820101 commit eb2f998

File tree

6 files changed

+346
-15
lines changed

6 files changed

+346
-15
lines changed

src/OpenTelemetry/BaseProcessor.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,18 @@ public BaseProcessor()
2727
/// </summary>
2828
public BaseProvider? ParentProvider { get; private set; }
2929

30+
/// <summary>
31+
/// Gets or sets the weight of the processor when added to the provider
32+
/// pipeline. Default value: <c>0</c>.
33+
/// </summary>
34+
/// <remarks>
35+
/// Note: Weight is used to order processors when building a provider
36+
/// pipeline. Lower weighted processors come before higher weighted
37+
/// processors. Changing the weight after a pipeline has been constructed
38+
/// has no effect.
39+
/// </remarks>
40+
internal int PipelineWeight { get; set; }
41+
3042
/// <summary>
3143
/// Called synchronously when a telemetry object is started.
3244
/// </summary>

src/OpenTelemetry/Logs/LoggerProviderSdk.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,8 @@ public LoggerProviderSdk(
5454
resourceBuilder.ServiceProvider = serviceProvider;
5555
this.Resource = resourceBuilder.Build();
5656

57-
foreach (var processor in state.Processors)
57+
// Note: Linq OrderBy performs a stable sort, which is a requirement here
58+
foreach (var processor in state.Processors.OrderBy(p => p.PipelineWeight))
5859
{
5960
this.AddProcessor(processor);
6061
}

src/OpenTelemetry/Trace/Builder/TracerProviderBuilderSdk.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -162,13 +162,13 @@ public TracerProviderBuilder ConfigureServices(Action<IServiceCollection> config
162162
throw new NotSupportedException("Services cannot be configured after ServiceProvider has been created.");
163163
}
164164

165-
public void AddExceptionProcessorIfEnabled()
165+
public void AddExceptionProcessorIfEnabled(ref IEnumerable<BaseProcessor<Activity>> processors)
166166
{
167167
if (this.ExceptionProcessorEnabled)
168168
{
169169
try
170170
{
171-
this.Processors.Insert(0, new ExceptionProcessor());
171+
processors = new BaseProcessor<Activity>[] { new ExceptionProcessor() }.Concat(processors);
172172
}
173173
catch (Exception ex)
174174
{

src/OpenTelemetry/Trace/TracerProviderSdk.cs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,6 @@ internal TracerProviderSdk(
5353
StringBuilder processorsAdded = new StringBuilder();
5454
StringBuilder instrumentationFactoriesAdded = new StringBuilder();
5555

56-
state.AddExceptionProcessorIfEnabled();
57-
5856
var resourceBuilder = state.ResourceBuilder ?? ResourceBuilder.CreateDefault();
5957
resourceBuilder.ServiceProvider = serviceProvider;
6058
this.Resource = resourceBuilder.Build();
@@ -74,7 +72,12 @@ internal TracerProviderSdk(
7472
}
7573
}
7674

77-
foreach (var processor in state.Processors)
75+
// Note: Linq OrderBy performs a stable sort, which is a requirement here
76+
IEnumerable<BaseProcessor<Activity>> processors = state.Processors.OrderBy(p => p.PipelineWeight);
77+
78+
state.AddExceptionProcessorIfEnabled(ref processors);
79+
80+
foreach (var processor in processors)
7881
{
7982
this.AddProcessor(processor);
8083
processorsAdded.Append(processor.GetType());

test/OpenTelemetry.Tests/Logs/LoggerProviderBuilderExtensionsTests.cs

Lines changed: 149 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -127,16 +127,65 @@ public void LoggerProviderBuilderConfigureResourceBuilderTests()
127127
Assert.Contains(provider.Resource.Attributes, value => value.Key == "key1" && (string)value.Value == "value1");
128128
}
129129

130+
[Fact]
131+
public void LoggerProviderBuilderUsingDependencyInjectionTest()
132+
{
133+
using var provider = Sdk.CreateLoggerProviderBuilder()
134+
.AddProcessor<CustomProcessor>()
135+
.AddProcessor<CustomProcessor>()
136+
.Build() as LoggerProviderSdk;
137+
138+
Assert.NotNull(provider);
139+
140+
var processors = ((IServiceProvider)provider.OwnedServiceProvider!).GetServices<CustomProcessor>();
141+
142+
// Note: Two "Add" calls but it is a singleton so only a single registration is produced
143+
Assert.Single(processors);
144+
145+
var processor = provider.Processor as CompositeProcessor<LogRecord>;
146+
147+
Assert.NotNull(processor);
148+
149+
// Note: Two "Add" calls due yield two processors added to provider, even though they are the same
150+
Assert.True(processor.Head.Value is CustomProcessor);
151+
Assert.True(processor.Head.Next?.Value is CustomProcessor);
152+
}
153+
130154
[Fact]
131155
public void LoggerProviderBuilderAddProcessorTest()
132156
{
133-
List<CustomProcessor> processors = new();
157+
List<CustomProcessor> processorsToAdd = new()
158+
{
159+
new CustomProcessor()
160+
{
161+
Name = "A",
162+
},
163+
new CustomProcessor()
164+
{
165+
Name = "B",
166+
},
167+
new CustomProcessor()
168+
{
169+
Name = "C",
170+
},
171+
};
134172

135-
using (var provider = Sdk.CreateLoggerProviderBuilder()
136-
.AddProcessor<CustomProcessor>()
137-
.AddProcessor(sp => new CustomProcessor())
138-
.AddProcessor(new CustomProcessor())
139-
.Build() as LoggerProviderSdk)
173+
var builder = Sdk.CreateLoggerProviderBuilder();
174+
foreach (var processor in processorsToAdd)
175+
{
176+
builder.AddProcessor(processor);
177+
}
178+
179+
List<CustomProcessor> expectedProcessors = new()
180+
{
181+
processorsToAdd.First(p => p.Name == "A"),
182+
processorsToAdd.First(p => p.Name == "B"),
183+
processorsToAdd.First(p => p.Name == "C"),
184+
};
185+
186+
List<CustomProcessor> actualProcessors = new();
187+
188+
using (var provider = builder.Build() as LoggerProviderSdk)
140189
{
141190
Assert.NotNull(provider);
142191
Assert.NotNull(provider.Processor);
@@ -151,16 +200,106 @@ public void LoggerProviderBuilderAddProcessorTest()
151200
var processor = current.Value as CustomProcessor;
152201
Assert.NotNull(processor);
153202

154-
processors.Add(processor);
203+
actualProcessors.Add(processor);
155204
Assert.False(processor.Disposed);
156205

157206
current = current.Next;
158207
}
208+
209+
Assert.Equal(expectedProcessors, actualProcessors);
210+
}
211+
212+
foreach (var processor in actualProcessors)
213+
{
214+
Assert.True(processor.Disposed);
215+
}
216+
}
217+
218+
[Fact]
219+
public void LoggerProviderBuilderAddProcessorWithWeightTest()
220+
{
221+
List<CustomProcessor> processorsToAdd = new()
222+
{
223+
new CustomProcessor()
224+
{
225+
Name = "C",
226+
PipelineWeight = 0,
227+
},
228+
new CustomProcessor()
229+
{
230+
Name = "E",
231+
PipelineWeight = 10_000,
232+
},
233+
new CustomProcessor()
234+
{
235+
Name = "B",
236+
PipelineWeight = -10_000,
237+
},
238+
new CustomProcessor()
239+
{
240+
Name = "F",
241+
PipelineWeight = int.MaxValue,
242+
},
243+
new CustomProcessor()
244+
{
245+
Name = "A",
246+
PipelineWeight = int.MinValue,
247+
},
248+
new CustomProcessor()
249+
{
250+
Name = "D",
251+
PipelineWeight = 0,
252+
},
253+
};
254+
255+
var builder = Sdk.CreateLoggerProviderBuilder();
256+
foreach (var processor in processorsToAdd)
257+
{
258+
builder.AddProcessor(processor);
159259
}
160260

161-
Assert.Equal(3, processors.Count);
261+
List<CustomProcessor> expectedProcessors = new()
262+
{
263+
processorsToAdd.First(p => p.Name == "A"),
264+
processorsToAdd.First(p => p.Name == "B"),
265+
processorsToAdd.First(p => p.Name == "C"),
266+
processorsToAdd.First(p => p.Name == "D"),
267+
processorsToAdd.First(p => p.Name == "E"),
268+
processorsToAdd.First(p => p.Name == "F"),
269+
};
270+
271+
List<CustomProcessor> actualProcessors = new();
272+
273+
using (var provider = builder.Build() as LoggerProviderSdk)
274+
{
275+
Assert.NotNull(provider);
276+
Assert.NotNull(provider.Processor);
277+
278+
var compositeProcessor = provider.Processor as CompositeProcessor<LogRecord>;
279+
280+
Assert.NotNull(compositeProcessor);
281+
282+
var lastWeight = int.MinValue;
283+
var current = compositeProcessor.Head;
284+
while (current != null)
285+
{
286+
var processor = current.Value as CustomProcessor;
287+
Assert.NotNull(processor);
288+
289+
actualProcessors.Add(processor);
290+
Assert.False(processor.Disposed);
291+
292+
Assert.True(processor.PipelineWeight >= lastWeight);
293+
294+
lastWeight = processor.PipelineWeight;
295+
296+
current = current.Next;
297+
}
298+
299+
Assert.Equal(expectedProcessors, actualProcessors);
300+
}
162301

163-
foreach (var processor in processors)
302+
foreach (var processor in actualProcessors)
164303
{
165304
Assert.True(processor.Disposed);
166305
}
@@ -187,6 +326,7 @@ public void Dispose()
187326

188327
private sealed class CustomProcessor : BaseProcessor<LogRecord>
189328
{
329+
public string? Name;
190330
public bool Disposed;
191331

192332
protected override void Dispose(bool disposing)

0 commit comments

Comments
 (0)