33
44using System . Diagnostics ;
55using System . Diagnostics . CodeAnalysis ;
6+ using System . Globalization ;
67using OpenTelemetry . Exporter . OpenTelemetryProtocol . Implementation ;
78using OpenTelemetry . Exporter . OpenTelemetryProtocol . Implementation . Serializer ;
89using OtlpCommon = OpenTelemetry . Proto . Common . V1 ;
@@ -278,6 +279,81 @@ public void KvListAttributeTriggersMainBufferResize()
278279 Assert . Equal ( largeString , values [ 0 ] . Value . StringValue ) ;
279280 }
280281
282+ [ Fact ]
283+ public void RecursionHasMaxDepthAndRecursionDepthIsReset ( )
284+ {
285+ var tags = new ActivityTagsCollection
286+ {
287+ new ( "kvList" , SelfReferencingKvList ( ) ) ,
288+ new ( "kvList1" , SelfReferencingKvList ( ) ) ,
289+ } ;
290+
291+ using var activitySource = new ActivitySource ( nameof ( this . RecursionHasMaxDepthAndRecursionDepthIsReset ) ) ;
292+ using var activity = activitySource . StartActivity ( "test" , ActivityKind . Server , default ( ActivityContext ) , tags ) ;
293+
294+ Assert . NotNull ( activity ) ;
295+
296+ var buffer = new byte [ 1_000_000 ] ;
297+
298+ var writePosition = ProtobufOtlpTraceSerializer . WriteSpan ( buffer , 0 , new SdkLimitOptions ( ) , activity ) ;
299+
300+ using var stream = new MemoryStream ( buffer , 0 , writePosition ) ;
301+ var scopeSpans = OtlpTrace . ScopeSpans . Parser . ParseFrom ( stream ) ;
302+ Assert . Single ( scopeSpans . Spans ) ;
303+ var span = scopeSpans . Spans . FirstOrDefault ( ) ;
304+
305+ Assert . NotNull ( span ) ;
306+ Assert . Equal ( 2 , span . Attributes . Count ) ;
307+
308+ var attribute = span . Attributes [ 0 ] ;
309+ Assert . Equal ( "kvList" , attribute . Key ) ;
310+
311+ var attributeValue = attribute . Value ;
312+ for ( var i = 0 ; i < 3 ; i ++ )
313+ {
314+ Assert . Equal ( OtlpCommon . AnyValue . ValueOneofCase . KvlistValue , attributeValue . ValueCase ) ;
315+ Assert . Equal ( 2 , attributeValue . KvlistValue . Values . Count ) ;
316+
317+ Assert . Equal ( "int" , attributeValue . KvlistValue . Values [ 0 ] . Key ) ;
318+ Assert . Equal ( OtlpCommon . AnyValue . ValueOneofCase . IntValue , attributeValue . KvlistValue . Values [ 0 ] . Value . ValueCase ) ;
319+
320+ Assert . Equal ( "self" , attributeValue . KvlistValue . Values [ 1 ] . Key ) ;
321+ if ( i < 2 )
322+ {
323+ Assert . Equal ( OtlpCommon . AnyValue . ValueOneofCase . KvlistValue , attributeValue . KvlistValue . Values [ 1 ] . Value . ValueCase ) ;
324+ attributeValue = attributeValue . KvlistValue . Values [ 1 ] . Value ;
325+ continue ;
326+ }
327+
328+ Assert . Equal ( OtlpCommon . AnyValue . ValueOneofCase . StringValue , attributeValue . KvlistValue . Values [ 1 ] . Value . ValueCase ) ;
329+ Assert . Equal ( Convert . ToString ( SelfReferencingKvList ( ) , CultureInfo . InvariantCulture ) , attributeValue . KvlistValue . Values [ 1 ] . Value . StringValue ) ;
330+ }
331+
332+ attribute = span . Attributes [ 1 ] ;
333+ Assert . Equal ( "kvList1" , attribute . Key ) ;
334+
335+ attributeValue = attribute . Value ;
336+ for ( var i = 0 ; i < 3 ; i ++ )
337+ {
338+ Assert . Equal ( OtlpCommon . AnyValue . ValueOneofCase . KvlistValue , attributeValue . ValueCase ) ;
339+ Assert . Equal ( 2 , attributeValue . KvlistValue . Values . Count ) ;
340+
341+ Assert . Equal ( "int" , attributeValue . KvlistValue . Values [ 0 ] . Key ) ;
342+ Assert . Equal ( OtlpCommon . AnyValue . ValueOneofCase . IntValue , attributeValue . KvlistValue . Values [ 0 ] . Value . ValueCase ) ;
343+
344+ Assert . Equal ( "self" , attributeValue . KvlistValue . Values [ 1 ] . Key ) ;
345+ if ( i < 2 )
346+ {
347+ Assert . Equal ( OtlpCommon . AnyValue . ValueOneofCase . KvlistValue , attributeValue . KvlistValue . Values [ 1 ] . Value . ValueCase ) ;
348+ attributeValue = attributeValue . KvlistValue . Values [ 1 ] . Value ;
349+ continue ;
350+ }
351+
352+ Assert . Equal ( OtlpCommon . AnyValue . ValueOneofCase . StringValue , attributeValue . KvlistValue . Values [ 1 ] . Value . ValueCase ) ;
353+ Assert . Equal ( Convert . ToString ( SelfReferencingKvList ( ) , CultureInfo . InvariantCulture ) , attributeValue . KvlistValue . Values [ 1 ] . Value . StringValue ) ;
354+ }
355+ }
356+
281357 public void Dispose ( )
282358 {
283359 this . activityListener . Dispose ( ) ;
@@ -289,6 +365,14 @@ public void Dispose()
289365 throw new InvalidOperationException ( "simulated failure" ) ;
290366 }
291367
368+ private static List < KeyValuePair < string , object ? > > SelfReferencingKvList ( )
369+ {
370+ var list = new List < KeyValuePair < string , object ? > > ( ) ;
371+ list . Add ( new ( "int" , 1 ) ) ;
372+ list . Add ( new ( "self" , list ) ) ;
373+ return list ;
374+ }
375+
292376 private static bool TryTransformTag ( KeyValuePair < string , object ? > tag , [ NotNullWhen ( true ) ] out OtlpCommon . KeyValue ? attribute )
293377 {
294378 ProtobufOtlpTagWriter . OtlpTagWriterState otlpTagWriterState = new ProtobufOtlpTagWriter . OtlpTagWriterState
0 commit comments