public void TracerProviderSdkSamplerAttributesAreAppliedToActivity(SamplingDecision sampling) { var testSampler = new TestSampler(); testSampler.SamplingAction = (samplingParams) => { var attributes = new Dictionary <string, object>(); attributes.Add("tagkeybysampler", "tagvalueaddedbysampler"); return(new SamplingResult(sampling, attributes)); }; using var activitySource = new ActivitySource(ActivitySourceName); using var sdk = Sdk.CreateTracerProviderBuilder() .AddSource(ActivitySourceName) .SetSampler(testSampler) .Build(); using (var rootActivity = activitySource.StartActivity("root")) { Assert.NotNull(rootActivity); Assert.Equal(rootActivity.TraceId, testSampler.LatestSamplingParameters.TraceId); if (sampling != SamplingDecision.Drop) { Assert.Contains(new KeyValuePair <string, object>("tagkeybysampler", "tagvalueaddedbysampler"), rootActivity.TagObjects); } } }
public void SdkSamplesLegacyActivityWithCustomSampler(SamplingDecision samplingDecision, bool isAllDataRequested, bool hasRecordedFlag) { var operationNameForLegacyActivity = "TestOperationName"; var sampler = new TestSampler() { SamplingAction = (samplingParameters) => new SamplingResult(samplingDecision) }; using var tracerProvider = Sdk.CreateTracerProviderBuilder() .SetSampler(sampler) .AddLegacySource(operationNameForLegacyActivity) .Build(); Activity activity = new Activity(operationNameForLegacyActivity); activity.Start(); Assert.Equal(isAllDataRequested, activity.IsAllDataRequested); Assert.Equal(hasRecordedFlag, activity.ActivityTraceFlags.HasFlag(ActivityTraceFlags.Recorded)); // Validating ActivityTraceFlags is not enough as it does not get reflected on // Id, If the Id is accessed before the sampler runs. // https://github.com/open-telemetry/opentelemetry-dotnet/issues/2700 Assert.EndsWith(hasRecordedFlag ? "-01" : "-00", activity.Id); activity.Stop(); }
public async Task ExtractContextIrrespectiveOfSamplingDecision(SamplingDecision samplingDecision) { try { var expectedTraceId = ActivityTraceId.CreateRandom(); var expectedParentSpanId = ActivitySpanId.CreateRandom(); var expectedTraceState = "rojo=1,congo=2"; var activityContext = new ActivityContext(expectedTraceId, expectedParentSpanId, ActivityTraceFlags.Recorded, expectedTraceState); var expectedBaggage = Baggage.SetBaggage("key1", "value1").SetBaggage("key2", "value2"); Sdk.SetDefaultTextMapPropagator(new ExtractOnlyPropagator(activityContext, expectedBaggage)); // Arrange using (var testFactory = this.factory .WithWebHostBuilder(builder => builder.ConfigureTestServices(services => { this.tracerProvider = Sdk.CreateTracerProviderBuilder() .SetSampler(new TestSampler(samplingDecision)) .AddAspNetCoreInstrumentation() .Build(); }))) { using var client = testFactory.CreateClient(); // Test TraceContext Propagation var request = new HttpRequestMessage(HttpMethod.Get, "/api/GetChildActivityTraceContext"); var response = await client.SendAsync(request); var childActivityTraceContext = JsonConvert.DeserializeObject <Dictionary <string, string> >(response.Content.ReadAsStringAsync().Result); response.EnsureSuccessStatusCode(); Assert.Equal(expectedTraceId.ToString(), childActivityTraceContext["TraceId"]); Assert.Equal(expectedTraceState, childActivityTraceContext["TraceState"]); Assert.NotEqual(expectedParentSpanId.ToString(), childActivityTraceContext["ParentSpanId"]); // there is a new activity created in instrumentation therefore the ParentSpanId is different that what is provided in the headers // Test Baggage Context Propagation request = new HttpRequestMessage(HttpMethod.Get, "/api/GetChildActivityBaggageContext"); response = await client.SendAsync(request); var childActivityBaggageContext = JsonConvert.DeserializeObject <IReadOnlyDictionary <string, string> >(response.Content.ReadAsStringAsync().Result); response.EnsureSuccessStatusCode(); Assert.Single(childActivityBaggageContext, item => item.Key == "key1" && item.Value == "value1"); Assert.Single(childActivityBaggageContext, item => item.Key == "key2" && item.Value == "value2"); } } finally { Sdk.SetDefaultTextMapPropagator(new CompositeTextMapPropagator(new TextMapPropagator[] { new TraceContextPropagator(), new BaggagePropagator(), })); } }
/// <summary> /// Initializes a new instance of the <see cref="SamplingResult"/> struct. /// </summary> /// <param name="decision">indicates whether an activity object is recorded and sampled.</param> /// <param name="attributes">Attributes associated with the sampling decision. Attributes list passed to /// this method must be immutable. Mutations of the collection and/or attribute values may lead to unexpected behavior.</param> public SamplingResult(SamplingDecision decision, IEnumerable <KeyValuePair <string, object> > attributes) { this.Decision = decision; // Note: Decision object takes ownership of the collection. // Current implementation has no means to ensure the collection will not be modified by the caller. // If this behavior will be abused we must switch to cloning of the collection. this.Attributes = attributes; }
public void ActivitySourceAdapterPopulatesSamplingAttributesToActivity(SamplingDecision sampling) { this.testSampler.SamplingAction = (samplingParams) => { var attributes = new Dictionary <string, object>(); attributes.Add("tagkeybysampler", "tagvalueaddedbysampler"); return(new SamplingResult(sampling, attributes)); }; var activity = new Activity("test"); activity.Start(); this.activitySourceAdapter.Start(activity, ActivityKind.Internal); if (sampling != SamplingDecision.Drop) { Assert.Contains(new KeyValuePair <string, object>("tagkeybysampler", "tagvalueaddedbysampler"), activity.TagObjects); } activity.Stop(); }
public void ActivitySourceAdapterCallsStartStopActivityProcessor1(SamplingDecision decision) { this.testSampler.SamplingAction = (samplingParameters) => { return(new SamplingResult(decision)); }; bool startCalled = false; bool endCalled = false; this.testProcessor.StartAction = (a) => { startCalled = true; // If start is called, that means activity is sampled, // and TraceFlag is set to Recorded. Assert.Equal(decision == SamplingDecision.Record || decision == SamplingDecision.RecordAndSampled, a.IsAllDataRequested); Assert.Equal(decision == SamplingDecision.RecordAndSampled ? ActivityTraceFlags.Recorded : ActivityTraceFlags.None, a.ActivityTraceFlags); Assert.Equal(decision == SamplingDecision.RecordAndSampled, a.Recorded); }; this.testProcessor.EndAction = (a) => { endCalled = true; }; var activity = new Activity("test"); activity.Start(); this.activitySourceAdapter.Start(activity, ActivityKind.Producer); activity.Stop(); this.activitySourceAdapter.Stop(activity); Assert.Equal(ActivityKind.Producer, activity.Kind); Assert.Equal(activity.IsAllDataRequested, startCalled); Assert.Equal(activity.IsAllDataRequested, endCalled); }
public void SdkSamplesLegacyActivityWithCustomSampler(SamplingDecision samplingDecision, bool isAllDataRequested, bool hasRecordedFlag) { var operationNameForLegacyActivity = "TestOperationName"; var sampler = new TestSampler() { SamplingAction = (samplingParameters) => new SamplingResult(samplingDecision) }; using var tracerProvider = Sdk.CreateTracerProviderBuilder() .SetSampler(sampler) .AddLegacySource(operationNameForLegacyActivity) .Build(); Activity activity = new Activity(operationNameForLegacyActivity); activity.Start(); Assert.Equal(isAllDataRequested, activity.IsAllDataRequested); Assert.Equal(hasRecordedFlag, activity.ActivityTraceFlags.HasFlag(ActivityTraceFlags.Recorded)); activity.Stop(); }
public async Task ShouldMapMassTransitTagsWhenIntrumentationWhenSampled(SamplingDecision samplingDecision, bool isActivityExpected) { var activityProcessor = new Mock <BaseProcessor <Activity> >(); using (Sdk.CreateTracerProviderBuilder() .SetSampler(new TestSampler() { SamplingAction = (samplingParameters) => new SamplingResult(samplingDecision) }) .AddProcessor(activityProcessor.Object) .AddMassTransitInstrumentation() .Build()) { var harness = new InMemoryTestHarness(); var consumerHarness = harness.Consumer <TestConsumer>(); var handlerHarness = harness.Handler <TestMessage>(); await harness.Start(); try { await harness.InputQueueSendEndpoint.Send <TestMessage>(new { Text = "Hello, world!" }); Assert.True(await harness.Consumed.SelectAsync <TestMessage>().Any()); Assert.True(await consumerHarness.Consumed.SelectAsync <TestMessage>().Any()); Assert.True(await handlerHarness.Consumed.SelectAsync().Any()); } finally { await harness.Stop(); } var expectedMessageContext = harness.Sent.Select <TestMessage>().FirstOrDefault()?.Context; Assert.NotNull(expectedMessageContext); } Assert.Equal(isActivityExpected, activityProcessor.Invocations.Any(invo => invo.Method.Name == nameof(activityProcessor.Object.OnStart))); Assert.Equal(isActivityExpected, activityProcessor.Invocations.Any(invo => invo.Method.Name == nameof(activityProcessor.Object.OnEnd))); }
public async Task FilterAndEnrichAreOnlyCalledWhenSampled(SamplingDecision samplingDecision, bool shouldFilterBeCalled, bool shouldEnrichBeCalled) { bool filterCalled = false; bool enrichCalled = false; void ConfigureTestServices(IServiceCollection services) { this.tracerProvider = Sdk.CreateTracerProviderBuilder() .SetSampler(new TestSampler(samplingDecision)) .AddAspNetCoreInstrumentation(options => { options.Filter = (context) => { filterCalled = true; return(true); }; options.Enrich = (activity, methodName, request) => { enrichCalled = true; }; }) .Build(); } // Arrange using var client = this.factory .WithWebHostBuilder(builder => builder.ConfigureTestServices(ConfigureTestServices)) .CreateClient(); // Act var response = await client.GetAsync("/api/values"); // Assert Assert.Equal(shouldFilterBeCalled, filterCalled); Assert.Equal(shouldEnrichBeCalled, enrichCalled); }
public TestSampler(SamplingDecision samplingDecision) { this.samplingDecision = samplingDecision; }
/// <summary> /// Initializes a new instance of the <see cref="SamplingResult"/> struct. /// </summary> /// <param name="decision"> indicates whether an activity object is recorded and sampled.</param> public SamplingResult(SamplingDecision decision) { this.Decision = decision; this.Attributes = Enumerable.Empty <KeyValuePair <string, object> >(); }