public void SampleBasedOnTraceId() { Sampler defaultProbability = new TraceIdRatioBasedSampler(0.0001); // This traceId will not be sampled by the TraceIdRatioBasedSampler because the first 8 bytes as long // is not less than probability * Long.MAX_VALUE; var notSampledtraceId = ActivityTraceId.CreateFromBytes( new byte[] { 0x8F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0, 0, 0, 0, 0, 0, 0, 0, }); Assert.Equal( SamplingDecision.Drop, defaultProbability.ShouldSample(new SamplingParameters(default, notSampledtraceId, ActivityDisplayName, ActivityKindServer, null, null)).Decision);
public void ProbabilitySampler_SampleBasedOnTraceId() { Sampler defaultProbability = new ProbabilitySampler(0.0001); // This traceId will not be sampled by the ProbabilitySampler because the first 8 bytes as long // is not less than probability * Long.MAX_VALUE; var notSampledtraceId = ActivityTraceId.CreateFromBytes( new byte[] { 0x8F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0, 0, 0, 0, 0, 0, 0, 0, }); Assert.False( defaultProbability.ShouldSample(
public void CheckToOtlpLogRecordSpanIdTraceIdAndFlag() { var logRecords = new List <LogRecord>(); using var loggerFactory = LoggerFactory.Create(builder => { builder.AddOpenTelemetry(options => { options.AddInMemoryExporter(logRecords); }); }); var logger = loggerFactory.CreateLogger("OtlpLogExporterTests"); ActivityTraceId expectedTraceId = default; ActivitySpanId expectedSpanId = default; using (var activity = new Activity(Utils.GetCurrentMethodName()).Start()) { logger.LogInformation("Log within an activity."); expectedTraceId = activity.TraceId; expectedSpanId = activity.SpanId; } var logRecord = logRecords[0]; var otlpLogRecord = logRecord.ToOtlpLog(); Assert.Equal(expectedTraceId.ToString(), ActivityTraceId.CreateFromBytes(otlpLogRecord.TraceId.ToByteArray()).ToString()); Assert.Equal(expectedSpanId.ToString(), ActivitySpanId.CreateFromBytes(otlpLogRecord.SpanId.ToByteArray()).ToString()); Assert.Equal((uint)logRecord.TraceFlags, otlpLogRecord.Flags); }
public void Int128ConversionWorksAsExpected() { var id = ActivityTraceId.CreateFromBytes(new byte[] { 0x1a, 0x0f, 0x54, 0x63, 0x25, 0xa8, 0x56, 0x43, 0x1a, 0x4c, 0x24, 0xea, 0xa8, 0x60, 0xb0, 0xe8 }); var int128 = new Int128(id); Assert.Equal <long>(unchecked ((long)0x1a0f546325a85643), int128.High); Assert.Equal <long>(unchecked ((long)0x1a4c24eaa860b0e8), int128.Low); }
/// <inheritdoc /> public SpanContext FromByteArray(byte[] bytes) { if (bytes == null) { OpenTelemetryApiEventSource.Log.FailedToExtractSpanContext("null bytes"); return(SpanContext.BlankRemote); } if (bytes.Length != 29 || bytes[0] != VersionId) { OpenTelemetryApiEventSource.Log.FailedToExtractSpanContext("unexpected bytes length or version"); return(SpanContext.BlankRemote); } ActivityTraceId traceId = default; ActivitySpanId spanId = default; var traceOptions = ActivityTraceFlags.None; var traceparentBytes = new ReadOnlySpan <byte>(bytes); var pos = 1; try { if (bytes.Length > pos && bytes[pos] == TraceIdFieldId) { traceId = ActivityTraceId.CreateFromBytes(traceparentBytes.Slice(pos + IdSize, 16)); pos += IdSize + TraceIdSize; } if (bytes.Length > pos && bytes[pos] == SpanIdFieldId) { spanId = ActivitySpanId.CreateFromBytes(traceparentBytes.Slice(pos + IdSize, 8)); pos += IdSize + SpanIdSize; } if (bytes.Length > pos && bytes[pos] == TraceOptionsFieldId) { traceOptions = (ActivityTraceFlags)traceparentBytes[pos + IdSize]; } return(new SpanContext(traceId, spanId, traceOptions)); } catch (Exception ex) { OpenTelemetryApiEventSource.Log.SpanContextExtractException(ex); return(SpanContext.BlankRemote); } }
public void StartRemoteChildSpan_WithProbabilitySamplerDefaultSampler() { var configMock = Mock.Get <ITraceConfig>(traceConfig); configMock.Setup((c) => c.ActiveTraceParams).Returns(TraceParams.Default); // This traceId will not be sampled by the ProbabilitySampler because the first 8 bytes as long // is not less than probability * Long.MAX_VALUE; var traceId = ActivityTraceId.CreateFromBytes( new byte[] { 0x8F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0, 0, 0, 0, 0, 0, 0, 0, }); // If parent is sampled then the remote child must be sampled. var childSpan = new SpanBuilder(SpanName, spanBuilderOptions) .SetSpanKind(SpanKind.Internal) .SetParent(SpanContext.Create( traceId, ActivitySpanId.CreateRandom(), ActivityTraceFlags.Recorded, Tracestate.Empty)) .StartSpan(); Assert.True(childSpan.Context.IsValid); Assert.Equal(traceId, childSpan.Context.TraceId); Assert.True((childSpan.Context.TraceOptions & ActivityTraceFlags.Recorded) != 0); childSpan.End(); Assert.Equal(TraceParams.Default, traceConfig.ActiveTraceParams); // If parent is not sampled then the remote child must be not sampled. childSpan = new SpanBuilder(SpanName, spanBuilderOptions) .SetSpanKind(SpanKind.Internal) .SetParent(SpanContext.Create( traceId, ActivitySpanId.CreateRandom(), ActivityTraceFlags.None, Tracestate.Empty)) .StartSpan(); Assert.True(childSpan.Context.IsValid); Assert.Equal(traceId, childSpan.Context.TraceId); Assert.True((childSpan.Context.TraceOptions & ActivityTraceFlags.Recorded) == 0); childSpan.End(); }
public SpanContext FromByteArray(byte[] bytes) { if (bytes == null) { throw new ArgumentNullException(nameof(bytes)); } if (bytes.Length == 0 || bytes[0] != VersionId) { throw new SpanContextParseException("Unsupported version."); } ActivityTraceId traceId = default; ActivitySpanId spanId = default; var traceOptions = ActivityTraceFlags.None; var traceparentBytes = new ReadOnlySpan <byte>(bytes); var pos = 1; try { if (bytes.Length > pos && bytes[pos] == TraceIdFieldId) { traceId = ActivityTraceId.CreateFromBytes(traceparentBytes.Slice(pos + IdSize, 16)); pos += IdSize + TraceIdSize; } if (bytes.Length > pos && bytes[pos] == SpanIdFieldId) { spanId = ActivitySpanId.CreateFromBytes(traceparentBytes.Slice(pos + IdSize, 8)); pos += IdSize + SpanIdSize; } if (bytes.Length > pos && bytes[pos] == TraceOptionsFieldId) { traceOptions = (ActivityTraceFlags)traceparentBytes[pos + IdSize]; } return(SpanContext.Create(traceId, spanId, traceOptions, Tracestate.Empty)); } catch (Exception e) { throw new SpanContextParseException("Invalid input.", e); } }
public void VerifyHashAlgorithmCorrectness() { byte[] testBytes = new byte[] { 0x8F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0, 0, 0, 0, 0, 0, 0, 0, }; byte[] testBytes2 = new byte[] { 0x0F, 0x1F, 0x2F, 0x3F, 0x4F, 0x5F, 0x6F, 0x7F, 0x8F, 0x9F, 0xAF, 0xBF, 0xCF, 0xDF, 0xEF, 0xFF, }; ActivityTraceId testId = ActivityTraceId.CreateFromBytes(testBytes); ActivityTraceId testId2 = ActivityTraceId.CreateFromBytes(testBytes2); ActivityContext parentContext = default(ActivityContext); SamplingParameters testParams = new SamplingParameters(parentContext, testId, "TestActivity", ActivityKind.Internal); SamplingParameters testParams2 = new SamplingParameters(parentContext, testId2, "TestActivity", ActivityKind.Internal); var zeroSampler = new ApplicationInsightsSampler(0); ApplicationInsightsSampler oneSampler = new ApplicationInsightsSampler(1); // 0.86 is below the sample score for testId1, but strict enough to drop testId2 ApplicationInsightsSampler ratioSampler = new ApplicationInsightsSampler(0.86f); Assert.Equal(SamplingDecision.Drop, zeroSampler.ShouldSample(testParams).Decision); Assert.Equal(SamplingDecision.Drop, zeroSampler.ShouldSample(testParams2).Decision); Assert.Equal(SamplingDecision.RecordAndSample, oneSampler.ShouldSample(testParams).Decision); Assert.Equal(SamplingDecision.RecordAndSample, oneSampler.ShouldSample(testParams2).Decision); Assert.Equal(SamplingDecision.Drop, ratioSampler.ShouldSample(testParams).Decision); Assert.Equal(SamplingDecision.RecordAndSample, ratioSampler.ShouldSample(testParams2).Decision); }
public void ActivityTraceIdTests() { Span <byte> idBytes1 = stackalloc byte[16]; Span <byte> idBytes2 = stackalloc byte[16]; // Empty Constructor string zeros = "00000000000000000000000000000000"; ActivityTraceId emptyId = new ActivityTraceId(); Assert.Equal(zeros, emptyId.ToHexString()); emptyId.CopyTo(idBytes1); Assert.Equal(new byte[16], idBytes1.ToArray()); Assert.True(emptyId == new ActivityTraceId()); Assert.True(!(emptyId != new ActivityTraceId())); Assert.True(emptyId.Equals(new ActivityTraceId())); Assert.True(emptyId.Equals((object)new ActivityTraceId())); Assert.Equal(new ActivityTraceId().GetHashCode(), emptyId.GetHashCode()); // NewActivityTraceId ActivityTraceId newId1 = ActivityTraceId.CreateRandom(); Assert.True(IsLowerCaseHex(newId1.ToHexString())); Assert.Equal(32, newId1.ToHexString().Length); ActivityTraceId newId2 = ActivityTraceId.CreateRandom(); Assert.Equal(32, newId1.ToHexString().Length); Assert.NotEqual(newId1.ToHexString(), newId2.ToHexString()); // Test equality Assert.True(newId1 != newId2); Assert.True(!(newId1 == newId2)); Assert.True(!(newId1.Equals(newId2))); Assert.True(!(newId1.Equals((object)newId2))); Assert.NotEqual(newId1.GetHashCode(), newId2.GetHashCode()); ActivityTraceId newId3 = ActivityTraceId.CreateFromString("00000000000000000000000000000001".AsSpan()); Assert.True(newId3 != emptyId); Assert.True(!(newId3 == emptyId)); Assert.True(!(newId3.Equals(emptyId))); Assert.True(!(newId3.Equals((object)emptyId))); Assert.NotEqual(newId3.GetHashCode(), emptyId.GetHashCode()); // Use in Dictionary (this does assume we have no collisions in IDs over 100 tries (very good). var dict = new Dictionary <ActivityTraceId, string>(); for (int i = 0; i < 100; i++) { var newId7 = ActivityTraceId.CreateRandom(); dict[newId7] = newId7.ToHexString(); } int ctr = 0; foreach (string value in dict.Values) { string valueInDict; Assert.True(dict.TryGetValue(ActivityTraceId.CreateFromString(value.AsSpan()), out valueInDict)); Assert.Equal(value, valueInDict); ctr++; } Assert.Equal(100, ctr); // We got out what we put in. // AsBytes and Byte constructor. newId2.CopyTo(idBytes2); ActivityTraceId newId2Clone = ActivityTraceId.CreateFromBytes(idBytes2); Assert.Equal(newId2.ToHexString(), newId2Clone.ToHexString()); newId2Clone.CopyTo(idBytes1); Assert.Equal(idBytes2.ToArray(), idBytes1.ToArray()); Assert.True(newId2 == newId2Clone); Assert.True(newId2.Equals(newId2Clone)); Assert.True(newId2.Equals((object)newId2Clone)); Assert.Equal(newId2.GetHashCode(), newId2Clone.GetHashCode()); // String constructor and ToHexString(). string idStr = "0123456789abcdef0123456789abcdef"; ActivityTraceId id = ActivityTraceId.CreateFromString(idStr.AsSpan()); Assert.Equal(idStr, id.ToHexString()); // Utf8 Constructor. byte[] idUtf8 = Encoding.UTF8.GetBytes(idStr); ActivityTraceId id1 = ActivityTraceId.CreateFromUtf8String(idUtf8); Assert.Equal(idStr, id1.ToHexString()); // ToString Assert.Equal(idStr, id.ToString()); }
public void ProbabilitySampler_SampleBasedOnTraceId() { ISampler defaultProbability = ProbabilitySampler.Create(0.0001); // This traceId will not be sampled by the ProbabilitySampler because the first 8 bytes as long // is not less than probability * Long.MAX_VALUE; var notSampledtraceId = ActivityTraceId.CreateFromBytes( new byte[] { 0x8F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0, 0, 0, 0, 0, 0, 0, 0, }); Assert.False( defaultProbability.ShouldSample( null, notSampledtraceId, ActivitySpanId.CreateRandom(), SPAN_NAME, null).IsSampled); // This traceId will be sampled by the ProbabilitySampler because the first 8 bytes as long // is less than probability * Long.MAX_VALUE; var sampledtraceId = ActivityTraceId.CreateFromBytes( new byte[] { 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0, 0, 0, 0, 0, 0, 0, 0, }); Assert.True( defaultProbability.ShouldSample( null, sampledtraceId, ActivitySpanId.CreateRandom(), SPAN_NAME, null).IsSampled); }