private static void AssertOtlpAttributeValue(object originalValue, OtlpCommon.AttributeKeyValue akv) { switch (originalValue) { case string s: Assert.Equal(akv.StringValue, s); break; case bool b: Assert.Equal(akv.BoolValue, b); break; case long l: Assert.Equal(akv.IntValue, l); break; case double d: Assert.Equal(akv.DoubleValue, d); break; default: Assert.Equal(akv.StringValue, originalValue?.ToString()); break; } }
private static void AssertOtlpAttributeValue(object originalValue, OtlpCommon.AttributeKeyValue akv) { switch (originalValue) { case string s: Assert.Equal(s, akv.StringValue); Assert.Equal(OtlpCommon.AttributeKeyValue.Types.ValueType.String, akv.Type); break; case bool b: Assert.Equal(b, akv.BoolValue); Assert.Equal(OtlpCommon.AttributeKeyValue.Types.ValueType.Bool, akv.Type); break; case long l: Assert.Equal(l, akv.IntValue); Assert.Equal(OtlpCommon.AttributeKeyValue.Types.ValueType.Int, akv.Type); break; case double d: Assert.Equal(d, akv.DoubleValue); Assert.Equal(OtlpCommon.AttributeKeyValue.Types.ValueType.Double, akv.Type); break; default: Assert.Equal(originalValue.ToString(), akv.StringValue); Assert.Equal(OtlpCommon.AttributeKeyValue.Types.ValueType.String, akv.Type); break; } }
private static OtlpCommon.AttributeKeyValue ToOtlpAttribute(KeyValuePair <string, object> kvp) { if (kvp.Value == null) { return(null); } var attrib = new OtlpCommon.AttributeKeyValue { Key = kvp.Key }; switch (kvp.Value) { case string s: attrib.Type = OtlpCommon.AttributeKeyValue.Types.ValueType.String; attrib.StringValue = s; break; case bool b: attrib.Type = OtlpCommon.AttributeKeyValue.Types.ValueType.Bool; attrib.BoolValue = b; break; case int i: attrib.Type = OtlpCommon.AttributeKeyValue.Types.ValueType.Int; attrib.IntValue = i; break; case long l: attrib.Type = OtlpCommon.AttributeKeyValue.Types.ValueType.Int; attrib.IntValue = l; break; case double d: attrib.Type = OtlpCommon.AttributeKeyValue.Types.ValueType.Double; attrib.DoubleValue = d; break; default: attrib.Type = OtlpCommon.AttributeKeyValue.Types.ValueType.String; attrib.StringValue = kvp.Value.ToString(); break; } return(attrib); }
private static OtlpCommon.AttributeKeyValue ToOtlpAttribute(KeyValuePair <string, string> kvp) { // TODO: enforce no duplicate keys? // TODO: reverse? // To maintain full fidelity to downstream receivers convert to the proper attribute types if (kvp.Value == null) { return(null); } var attrib = new OtlpCommon.AttributeKeyValue { Key = kvp.Key }; if (long.TryParse(kvp.Value, out var longValue)) { attrib.Type = OtlpCommon.AttributeKeyValue.Types.ValueType.Int; attrib.IntValue = longValue; } else if (double.TryParse(kvp.Value, out var doubleValue)) { attrib.Type = OtlpCommon.AttributeKeyValue.Types.ValueType.Double; attrib.DoubleValue = doubleValue; } else if (bool.TryParse(kvp.Value, out var boolValue)) { attrib.Type = OtlpCommon.AttributeKeyValue.Types.ValueType.Bool; attrib.BoolValue = boolValue; } else { attrib.Type = OtlpCommon.AttributeKeyValue.Types.ValueType.String; attrib.StringValue = kvp.Value; } return(attrib); }
public void ToOtlpResourceSpansTest() { var spanProcessor = new Mock <SpanProcessor>(); var evenResource = new Resource(new [] { new KeyValuePair <string, object>("k0", "v0") }); var oddResource = new Resource(new [] { new KeyValuePair <string, object>("k1", "v1") }); var tracers = new[] { TracerFactory.Create(b => b.SetResource(evenResource) .AddProcessorPipeline(p => p.AddProcessor(_ => spanProcessor.Object))) .GetTracer("even", "2.4.6"), TracerFactory.Create(b => b.SetResource(oddResource) .AddProcessorPipeline(p => p.AddProcessor(_ => spanProcessor.Object))) .GetTracer("odd", "1.3.5"), }; TelemetrySpan span = null; const int numOfSpans = 10; for (var i = 0; i < numOfSpans; i++) { var isEven = i % 2 == 0; var tracer = tracers[i % 2]; var spanKind = isEven ? SpanKind.Client : SpanKind.Server; if (span == null) { span = tracer.StartRootSpan("span-0", spanKind, null); } else { span = tracer.StartSpan($"span-{i}", span.Context, spanKind, null); } span.End(); } var spanDataList = new List <SpanData>(); var invocations = spanProcessor.Invocations; for (var i = 0; i < invocations.Count; i += 2) // Just want one of the OnStart/OnEnd pair. { spanDataList.Add((SpanData)invocations[i].Arguments[0]); } spanDataList.Reverse(); var otlpResourceSpans = spanDataList.ToOtlpResourceSpans(); Assert.Equal(2, otlpResourceSpans.Count()); var evenAttribKeyValue = new OtlpCommon.AttributeKeyValue { Key = "k0" }; evenAttribKeyValue.StringValue = "v0"; foreach (var resourceSpans in otlpResourceSpans) { Assert.Single(resourceSpans.InstrumentationLibrarySpans); Assert.Equal(numOfSpans / 2, resourceSpans.InstrumentationLibrarySpans[0].Spans.Count); Assert.NotNull(resourceSpans.Resource); var expectedSpanNames = new List <string>(); var start = resourceSpans.Resource.Attributes.Contains(evenAttribKeyValue) ? 0 : 1; for (var i = start; i < numOfSpans; i += 2) { expectedSpanNames.Add($"span-{i}"); } var otlpSpans = resourceSpans.InstrumentationLibrarySpans[0].Spans; Assert.Equal(expectedSpanNames.Count, otlpSpans.Count); foreach (var otlpSpan in otlpSpans) { Assert.Contains(otlpSpan.Name, expectedSpanNames); } } }
internal static OtlpTrace.Span ToOtlpSpan(this Activity activity) { if (activity.IdFormat != ActivityIdFormat.W3C) { // Only ActivityIdFormat.W3C is supported, in principle this should never be // hit under the OpenTelemetry SDK. return(null); } // protobuf doesn't understand Span<T> yet: https://github.com/protocolbuffers/protobuf/issues/3431 Span <byte> traceIdBytes = stackalloc byte[16]; Span <byte> spanIdBytes = stackalloc byte[8]; activity.TraceId.CopyTo(traceIdBytes); activity.SpanId.CopyTo(spanIdBytes); var parentSpanIdString = ByteString.Empty; if (activity.ParentSpanId != default) { Span <byte> parentSpanIdBytes = stackalloc byte[8]; activity.ParentSpanId.CopyTo(parentSpanIdBytes); parentSpanIdString = ByteString.CopyFrom(parentSpanIdBytes.ToArray()); } var startTimeUnixNano = activity.StartTimeUtc.ToUnixTimeNanoseconds(); var otlpSpan = new OtlpTrace.Span { Name = activity.DisplayName, Kind = (OtlpTrace.Span.Types.SpanKind)(activity.Kind + 1), // TODO: there is an offset of 1 on the enum. TraceId = ByteString.CopyFrom(traceIdBytes.ToArray()), SpanId = ByteString.CopyFrom(spanIdBytes.ToArray()), ParentSpanId = parentSpanIdString, // TODO: Status is still pending, need to pursue OTEL spec change. StartTimeUnixNano = (ulong)startTimeUnixNano, EndTimeUnixNano = (ulong)(startTimeUnixNano + activity.Duration.ToNanoseconds()), }; foreach (var kvp in activity.Tags) { // TODO: attempt to convert to supported types? // TODO: enforce no duplicate keys? // TODO: drop if Value is null? // TODO: reverse? var attrib = new OtlpCommon.AttributeKeyValue { Key = kvp.Key, StringValue = kvp.Value }; otlpSpan.Attributes.Add(attrib); } otlpSpan.Events.AddRange(activity.Events.Select(ToOtlpEvent)); otlpSpan.Links.AddRange(activity.Links.Select(ToOtlpLink)); // Activity does not limit number of attributes, events, links, etc so drop counts are always zero. return(otlpSpan); }