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), }, }, }); }
private void AddTrace(HttpListenerContext _Context, bool _bNewSpan, Action <string> _ErrorMessageAction = null) { //Start if (_bNewSpan) { _Context.Request.Headers.Set("span-start-time", DateTime.Now.ToString()); } //End else { var TraceID = _Context.Request.Headers.Get("trace-id"); if (TraceID == null || TraceID.Length == 0) { //It is a new trace TraceID = Guid.NewGuid().ToString("N"); } string ParentSpanID = null; string SpanID = _Context.Request.Headers.Get("span-id"); if (SpanID != null && SpanID.Length > 0) { ParentSpanID = SpanID; } SpanID = GetRandomHexNumber(16); _Context.Request.Headers.Set("trace-id", TraceID); _Context.Request.Headers.Set("span-id", SpanID); var LegitSpanName = new SpanName(ProjectName.ProjectId, TraceID, SpanID); var TruncString = new TruncatableString { Value = _Context.Request.HttpMethod + "->" + _Context.Request.Url.AbsolutePath, TruncatedByteCount = 0 }; Timestamp StartTime = null; try { StartTime = Timestamp.FromDateTimeOffset(DateTime.Parse(_Context.Request.Headers.Get("span-start-time"))); } catch (Exception ex) { _ErrorMessageAction?.Invoke("BTracingServiceGC->AddTrace: " + ex.Message + ", Trace: " + ex.StackTrace); } var Span = new Span { SpanName = LegitSpanName, DisplayName = TruncString, SpanId = SpanID, StartTime = StartTime ?? Timestamp.FromDateTimeOffset(DateTime.Now), EndTime = Timestamp.FromDateTimeOffset(DateTime.Now), Attributes = new Span.Types.Attributes() }; if (ParentSpanID != null) { Span.ParentSpanId = ParentSpanID; } AddEntryToSpan(Span, "Service Name", ProgramUniqueID); AddEntryToSpan(Span, "HTTP Method", _Context.Request.HttpMethod); AddEntryToSpan(Span, "HTTP URL", _Context.Request.Url.AbsoluteUri); AddEntryToSpan(Span, "HTTP Path", _Context.Request.Url.AbsolutePath); lock (Spans) { Spans.Add(Span); } } }