DatadogHttpCodec.java 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. package datadog.opentracing.propagation;
  2. import static datadog.opentracing.propagation.HttpCodec.validateUInt64BitsID;
  3. import datadog.opentracing.DDSpanContext;
  4. import io.opentracing.SpanContext;
  5. import io.opentracing.propagation.TextMapExtract;
  6. import io.opentracing.propagation.TextMapInject;
  7. import java.math.BigInteger;
  8. import java.util.Collections;
  9. import java.util.HashMap;
  10. import java.util.Map;
  11. import lombok.extern.slf4j.Slf4j;
  12. /** A codec designed for HTTP transport via headers using Datadog headers */
  13. @Slf4j
  14. class DatadogHttpCodec {
  15. private static final String OT_BAGGAGE_PREFIX = "ot-baggage-";
  16. private static final String TRACE_ID_KEY = "x-datadog-trace-id";
  17. private static final String SPAN_ID_KEY = "x-datadog-parent-id";
  18. private static final String ORIGIN_KEY = "x-datadog-origin";
  19. private DatadogHttpCodec() {
  20. // This class should not be created. This also makes code coverage checks happy.
  21. }
  22. public static class Injector implements HttpCodec.Injector {
  23. @Override
  24. public void inject(final DDSpanContext context, final TextMapInject carrier) {
  25. carrier.put(TRACE_ID_KEY, context.getTraceId().toString());
  26. carrier.put(SPAN_ID_KEY, context.getSpanId().toString());
  27. final String origin = context.getOrigin();
  28. if (origin != null) {
  29. carrier.put(ORIGIN_KEY, origin);
  30. }
  31. for (final Map.Entry<String, String> entry : context.baggageItems()) {
  32. carrier.put(OT_BAGGAGE_PREFIX + entry.getKey(), HttpCodec.encode(entry.getValue()));
  33. }
  34. log.debug("{} - Datadog parent context injected", context.getTraceId());
  35. }
  36. }
  37. public static class Extractor implements HttpCodec.Extractor {
  38. private final Map<String, String> taggedHeaders;
  39. public Extractor(final Map<String, String> taggedHeaders) {
  40. this.taggedHeaders = new HashMap<>();
  41. for (final Map.Entry<String, String> mapping : taggedHeaders.entrySet()) {
  42. this.taggedHeaders.put(mapping.getKey().trim().toLowerCase(), mapping.getValue());
  43. }
  44. }
  45. @Override
  46. public SpanContext extract(final TextMapExtract carrier) {
  47. try {
  48. Map<String, String> baggage = Collections.emptyMap();
  49. Map<String, String> tags = Collections.emptyMap();
  50. BigInteger traceId = BigInteger.ZERO;
  51. BigInteger spanId = BigInteger.ZERO;
  52. String origin = null;
  53. for (final Map.Entry<String, String> entry : carrier) {
  54. final String key = entry.getKey().toLowerCase();
  55. final String value = entry.getValue();
  56. if (value == null) {
  57. continue;
  58. }
  59. if (TRACE_ID_KEY.equalsIgnoreCase(key)) {
  60. traceId = validateUInt64BitsID(value, 10);
  61. } else if (SPAN_ID_KEY.equalsIgnoreCase(key)) {
  62. spanId = validateUInt64BitsID(value, 10);
  63. } else if (ORIGIN_KEY.equalsIgnoreCase(key)) {
  64. origin = value;
  65. } else if (key.startsWith(OT_BAGGAGE_PREFIX)) {
  66. if (baggage.isEmpty()) {
  67. baggage = new HashMap<>();
  68. }
  69. baggage.put(key.replace(OT_BAGGAGE_PREFIX, ""), HttpCodec.decode(value));
  70. }
  71. if (taggedHeaders.containsKey(key)) {
  72. if (tags.isEmpty()) {
  73. tags = new HashMap<>();
  74. }
  75. tags.put(taggedHeaders.get(key), HttpCodec.decode(value));
  76. }
  77. }
  78. if (!BigInteger.ZERO.equals(traceId)) {
  79. final ExtractedContext context =
  80. new ExtractedContext(traceId, spanId, origin, baggage, tags);
  81. log.debug("{} - Parent context extracted", context.getTraceId());
  82. return context;
  83. } else if (origin != null || !tags.isEmpty()) {
  84. log.debug("Tags context extracted");
  85. return new TagContext(origin, tags);
  86. }
  87. } catch (final RuntimeException e) {
  88. log.debug("Exception when extracting context", e);
  89. }
  90. return null;
  91. }
  92. }
  93. }