Skip to content

Instantly share code, notes, and snippets.

@cortex93
Created March 13, 2021 14:14
Show Gist options
  • Save cortex93/a910534ba8bd095428102a30d0ba4eb9 to your computer and use it in GitHub Desktop.
Save cortex93/a910534ba8bd095428102a30d0ba4eb9 to your computer and use it in GitHub Desktop.
JaegerProgator for OpenTelemetry (extract only)
using OpenTelemetry;
using OpenTelemetry.Context.Propagation;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
namespace ProperNamespace
{
internal class JaegerPropagator : TextMapPropagator
{
public override ISet<string> Fields => new HashSet<string> { PROPAGATION_HEADER };
private const string PROPAGATION_HEADER = "uber-trace-id";
private const string PROPAGATION_HEADER_DELIMITER = ":";
private const int MAX_TRACE_ID_LENGTH = 2 * 16;
private const int MAX_SPAN_ID_LENGTH = 2 * 8;
private const int MAX_FLAGS_LENGTH = 2;
public override PropagationContext Extract<T>(PropagationContext context, T carrier, Func<T, string, IEnumerable<string>> getter)
{
if (context.ActivityContext.IsValid())
{
// If a valid context has already been extracted, perform a noop.
return context;
}
if (carrier == null)
{
return context;
}
if (getter == null)
{
return context;
}
try
{
var traceparentCollection = getter(carrier, PROPAGATION_HEADER);
// There must be a single traceparent
if (traceparentCollection == null || traceparentCollection.Count() != 1)
{
return context;
}
var traceparent = traceparentCollection.First();
var traceparentParsed = TryExtractTraceparent(traceparent, out var traceId, out var spanId, out var traceoptions);
if (!traceparentParsed)
{
return context;
}
return new PropagationContext(
new ActivityContext(traceId, spanId, traceoptions, null, isRemote: true),
context.Baggage);
}
catch (Exception ex)
{
}
return context;
}
internal static bool TryExtractTraceparent(string traceparent, out ActivityTraceId traceId, out ActivitySpanId spanId, out ActivityTraceFlags traceOptions)
{
traceId = default;
spanId = default;
traceOptions = default;
var parts = traceparent.Split(PROPAGATION_HEADER_DELIMITER);
if (parts.Length != 4) return false;
if (!IsTraceIdValid(parts[0])) return false;
traceId = ActivityTraceId.CreateFromString(parts[0].AsSpan());
if (!IsSpanIdValid(parts[1])) return false;
spanId = ActivitySpanId.CreateFromString(parts[1].AsSpan());
// parts[2] is ignored
if (!IsFlagsValid(parts[3]) || !int.TryParse(parts[3], out int flags)) return false;
traceOptions = flags == 1 ? ActivityTraceFlags.Recorded : ActivityTraceFlags.None;
return true;
}
private static bool IsTraceIdValid(string value)
{
return !(string.IsNullOrWhiteSpace(value) || value.Length > MAX_TRACE_ID_LENGTH);
}
private static bool IsSpanIdValid(string value)
{
return !(string.IsNullOrWhiteSpace(value) || value.Length > MAX_SPAN_ID_LENGTH);
}
private static bool IsFlagsValid(string value)
{
return !(string.IsNullOrWhiteSpace(value) || value.Length > MAX_FLAGS_LENGTH);
}
public override void Inject<T>(PropagationContext context, T carrier, Action<T, string, string> setter)
{
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment