|
1 | | -import type { PropagationContext, TraceparentData } from '../types-hoist'; |
| 1 | +import type { DynamicSamplingContext, PropagationContext, TraceparentData } from '../types-hoist'; |
2 | 2 |
|
3 | 3 | import { baggageHeaderToDynamicSamplingContext } from './baggage'; |
4 | 4 | import { generateSpanId, generateTraceId } from './propagationContext'; |
@@ -68,7 +68,7 @@ export function propagationContextFromHeaders( |
68 | 68 | parentSpanId, |
69 | 69 | sampled: parentSampled, |
70 | 70 | dsc: dynamicSamplingContext || {}, // If we have traceparent data but no DSC it means we are not head of trace and we must freeze it |
71 | | - sampleRand: parseSampleRandFromDsc(dynamicSamplingContext?.sample_rand), |
| 71 | + sampleRand: getSampleRandFromTraceparentAndDsc(traceparentData, dynamicSamplingContext), |
72 | 72 | }; |
73 | 73 | } |
74 | 74 |
|
@@ -101,3 +101,38 @@ export function parseSampleRandFromDsc(sampleRand: string | undefined): number { |
101 | 101 | return Math.random(); |
102 | 102 | } |
103 | 103 | } |
| 104 | + |
| 105 | +function getSampleRandFromTraceparentAndDsc( |
| 106 | + traceparentData: TraceparentData | undefined, |
| 107 | + dsc: Partial<DynamicSamplingContext> | undefined, |
| 108 | +): number { |
| 109 | + const parsedSampleRand = parseSamplingDscNumber(dsc?.sample_rand); |
| 110 | + if (parsedSampleRand !== undefined) { |
| 111 | + return parsedSampleRand; |
| 112 | + } |
| 113 | + |
| 114 | + const parsedSampleRate = parseSamplingDscNumber(dsc?.sample_rate); |
| 115 | + if (parsedSampleRate && traceparentData?.parentSampled !== undefined) { |
| 116 | + return traceparentData.parentSampled |
| 117 | + ? // Returns a sample rand with positive sampling decision [0, sampleRate) |
| 118 | + Math.random() * parsedSampleRate |
| 119 | + : // Returns a sample rand with negative sampling decision [sampleRate, 1] |
| 120 | + parsedSampleRate + Math.random() * (1 - parsedSampleRate); |
| 121 | + } else { |
| 122 | + return Math.random(); |
| 123 | + } |
| 124 | +} |
| 125 | + |
| 126 | +function parseSamplingDscNumber(sampleRand: string | undefined): number | undefined { |
| 127 | + try { |
| 128 | + const parsed = Number(sampleRand); // Number(undefined) will return NaN and fail the next check |
| 129 | + if (isNaN(parsed) || parsed < 0 || parsed > 1) { |
| 130 | + // This is probably an invariant but returning undefined seems sensible. |
| 131 | + return undefined; |
| 132 | + } else { |
| 133 | + return parsed; |
| 134 | + } |
| 135 | + } catch { |
| 136 | + return undefined; |
| 137 | + } |
| 138 | +} |
0 commit comments