internal static Proto.Trace.V1.Span ToProtoSpan(this Trace.Span otelSpan) { try { // 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]; otelSpan.Context.TraceId.CopyTo(traceIdBytes); otelSpan.Context.SpanId.CopyTo(spanIdBytes); var parentSpanIdString = ByteString.Empty; if (otelSpan.ParentSpanId != default) { Span <byte> parentSpanIdBytes = stackalloc byte[8]; otelSpan.ParentSpanId.CopyTo(parentSpanIdBytes); parentSpanIdString = ByteString.CopyFrom(parentSpanIdBytes.ToArray()); } return(new Proto.Trace.V1.Span { Name = new TruncatableString { Value = otelSpan.Name }, // TODO: Utilize new Span.Types.SpanKind below when updated protos are incorporated, also confirm default for SpanKind.Internal Kind = otelSpan.Kind == SpanKind.Client || otelSpan.Kind == SpanKind.Producer ? Proto.Trace.V1.Span.Types.SpanKind.Client : Proto.Trace.V1.Span.Types.SpanKind.Server, TraceId = ByteString.CopyFrom(traceIdBytes.ToArray()), SpanId = ByteString.CopyFrom(spanIdBytes.ToArray()), ParentSpanId = parentSpanIdString, StartTime = otelSpan.StartTimestamp.ToTimestamp(), EndTime = otelSpan.EndTimestamp.ToTimestamp(), Status = !otelSpan.Status.IsValid ? null : new OpenTelemetry.Proto.Trace.V1.Status { Code = (int)otelSpan.Status.CanonicalCode, Message = otelSpan.Status.Description ?? string.Empty, }, SameProcessAsParentSpan = otelSpan.ParentSpanId != default, ChildSpanCount = null, Attributes = FromAttributes(otelSpan.Attributes), TimeEvents = FromITimeEvents(otelSpan.Events), Links = new Proto.Trace.V1.Span.Types.Links { Link = { otelSpan.Links.Select(FromILink), }, }, }); }
/// <summary> /// Translating <see cref="Trace.Span"/> to Stackdriver's Span /// According to <see href="https://cloud.google.com/trace/docs/reference/v2/rpc/google.devtools.cloudtrace.v2"/> specifications. /// </summary> /// <param name="spanData">Span in OpenTelemetry format.</param> /// <param name="projectId">Google Cloud Platform Project Id.</param> /// <returns><see cref="ISpan"/>.</returns> public static Google.Cloud.Trace.V2.Span ToSpan(this Trace.Span spanData, string projectId) { var spanId = spanData.Context.SpanId.ToHexString(); // Base span settings var span = new Google.Cloud.Trace.V2.Span { SpanName = new SpanName(projectId, spanData.Context.TraceId.ToHexString(), spanId), SpanId = spanId, DisplayName = new TruncatableString { Value = spanData.Name }, StartTime = spanData.StartTimestamp.ToTimestamp(), EndTime = spanData.EndTimestamp.ToTimestamp(), ChildSpanCount = null, }; if (spanData.ParentSpanId != null) { var parentSpanId = spanData.ParentSpanId.ToHexString(); if (!string.IsNullOrEmpty(parentSpanId)) { span.ParentSpanId = parentSpanId; } } // Span Links if (spanData.Links != null) { span.Links = new Google.Cloud.Trace.V2.Span.Types.Links { Link = { spanData.Links.Select(l => l.ToLink()) }, }; } // Span Attributes if (spanData.Attributes != null) { span.Attributes = new Google.Cloud.Trace.V2.Span.Types.Attributes { AttributeMap = { spanData.Attributes?.ToDictionary( s => FormatLabel(s.Key), s => s.Value?.ToAttributeValue()), }, }; } return(span); }
internal static Proto.Trace.V1.Span ToProtoSpan(this Trace.Span otelSpan) { try { // 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]; otelSpan.Context.TraceId.CopyTo(traceIdBytes); otelSpan.Context.SpanId.CopyTo(spanIdBytes); var parentSpanIdString = ByteString.Empty; if (otelSpan.ParentSpanId != default) { Span <byte> parentSpanIdBytes = stackalloc byte[8]; otelSpan.ParentSpanId.CopyTo(parentSpanIdBytes); parentSpanIdString = ByteString.CopyFrom(parentSpanIdBytes.ToArray()); } return(new Proto.Trace.V1.Span { Name = otelSpan.Name, // TODO: Utilize new Span.Types.SpanKind below when updated protos are incorporated, also confirm default for SpanKind.Internal Kind = otelSpan.Kind == SpanKind.Client || otelSpan.Kind == SpanKind.Producer ? Proto.Trace.V1.Span.Types.SpanKind.Client : Proto.Trace.V1.Span.Types.SpanKind.Server, TraceId = ByteString.CopyFrom(traceIdBytes.ToArray()), SpanId = ByteString.CopyFrom(spanIdBytes.ToArray()), ParentSpanId = parentSpanIdString, StartTime = otelSpan.StartTimestamp.ToTimestamp(), EndTime = otelSpan.EndTimestamp.ToTimestamp(), Status = !otelSpan.Status.IsValid ? null : new Opentelemetry.Proto.Trace.V1.Status { Code = (int)otelSpan.Status.CanonicalCode, Message = otelSpan.Status.Description ?? string.Empty, }, ChildSpanCount = null, Attributes = FromAttributes(otelSpan.Attributes), TimeEvents = FromITimeEvents(otelSpan.Events), Links = new Proto.Trace.V1.Span.Types.Links { Link = { otelSpan.Links.Select(FromILink), }, }, }); } catch (Exception e) { // TODO: Is there a way to handle this better? // This type of error processing is very aggressive and doesn't follow the // error handling practices when smart defaults should be used when possible. // See: https://github.com/open-telemetry/OpenTelemetry-dotnet/blob/master/docs/error-handling.md ExporterEventSource.Log.FailedToConvertToProtoDefinitionError(e); } return(null); }