private RequestTelemetry InitializeRequestTelemetry(HttpContext httpContext, Activity activity, long timestamp, string legacyRootId = null) { var requestTelemetry = new RequestTelemetry(); if (activity.IdFormat == ActivityIdFormat.W3C) { var traceId = activity.TraceId.ToHexString(); requestTelemetry.Id = activity.SpanId.ToHexString(); requestTelemetry.Context.Operation.Id = traceId; AspNetCoreEventSource.Instance.RequestTelemetryCreated("W3C", requestTelemetry.Id, traceId); } else { requestTelemetry.Context.Operation.Id = activity.RootId; requestTelemetry.Id = activity.Id; AspNetCoreEventSource.Instance.RequestTelemetryCreated("Hierarchical", requestTelemetry.Id, requestTelemetry.Context.Operation.Id); } if (this.proactiveSamplingEnabled && !activity.Recorded && this.configuration != null && !string.IsNullOrEmpty(requestTelemetry.Context.Operation.Id) && SamplingScoreGenerator.GetSamplingScore(requestTelemetry.Context.Operation.Id) >= this.configuration.GetLastObservedSamplingPercentage(requestTelemetry.ItemTypeFlag)) { requestTelemetry.ProactiveSamplingDecision = SamplingDecision.SampledOut; AspNetCoreEventSource.Instance.TelemetryItemWasSampledOutAtHead(requestTelemetry.Context.Operation.Id); } //// When the item is proactively sampled out, we can avoid heavy operations that do not have known dependency later in the pipeline. //// We mostly exclude operations that were deemed heavy as per the corresponding profiler trace of this code path. if (requestTelemetry.ProactiveSamplingDecision != SamplingDecision.SampledOut) { foreach (var prop in activity.Baggage) { if (!requestTelemetry.Properties.ContainsKey(prop.Key)) { requestTelemetry.Properties[prop.Key] = prop.Value; } } if (!string.IsNullOrEmpty(legacyRootId)) { requestTelemetry.Properties[LegacyRootIdProperty] = legacyRootId; } } this.client.InitializeInstrumentationKey(requestTelemetry); requestTelemetry.Source = this.GetAppIdFromRequestHeader(httpContext.Request.Headers, requestTelemetry.Context.InstrumentationKey); requestTelemetry.Start(timestamp); httpContext.Features.Set(requestTelemetry); return(requestTelemetry); }
private RequestTelemetry InitializeRequestTelemetry(HttpContext httpContext, Activity activity, long timestamp) { var requestTelemetry = new RequestTelemetry(); if (!this.enableW3CHeaders) { requestTelemetry.Context.Operation.Id = activity.RootId; requestTelemetry.Id = activity.Id; } else { activity.UpdateTelemetry(requestTelemetry, false); } if (this.proactiveSamplingEnabled && this.configuration != null && !string.IsNullOrEmpty(requestTelemetry.Context.Operation.Id) && SamplingScoreGenerator.GetSamplingScore(requestTelemetry.Context.Operation.Id) >= this.configuration.GetLastObservedSamplingPercentage(requestTelemetry.ItemTypeFlag)) { requestTelemetry.IsSampledOutAtHead = true; AspNetCoreEventSource.Instance.TelemetryItemWasSampledOutAtHead(requestTelemetry.Context.Operation.Id); } //// When the item is proactively sampled out, we can avoid heavy operations that do not have known dependency later in the pipeline. //// We mostly exclude operations that were deemed heavy as per the corresponding profiler trace of this code path. if (!requestTelemetry.IsSampledOutAtHead) { foreach (var prop in activity.Baggage) { if (!requestTelemetry.Properties.ContainsKey(prop.Key)) { requestTelemetry.Properties[prop.Key] = prop.Value; } } } this.client.InitializeInstrumentationKey(requestTelemetry); requestTelemetry.Source = GetAppIdFromRequestHeader(httpContext.Request.Headers, requestTelemetry.Context.InstrumentationKey); requestTelemetry.Start(timestamp); httpContext.Features.Set(requestTelemetry); return(requestTelemetry); }
private bool IsSampledIn(ITelemetry telemetry) { // check if telemetry supports sampling var samplingSupportingTelemetry = telemetry as ISupportSampling; if (samplingSupportingTelemetry == null) { return(true); } // check sampling < 100% is specified if (samplingSupportingTelemetry.SamplingPercentage >= 100.0) { return(true); } return(SamplingScoreGenerator.GetSamplingScore(telemetry) < samplingSupportingTelemetry.SamplingPercentage); }
public void ProactivelySampledInItemsPassAccordingToScoreIfCurrentRateIsHigherThanExpected() { var sentTelemetry = new List <ITelemetry>(); var tc = new TelemetryConfiguration { TelemetryChannel = new StubTelemetryChannel(), InstrumentationKey = Guid.NewGuid().ToString("D") }; var channelBuilder = new TelemetryProcessorChainBuilder(tc); channelBuilder.Use(next => new SamplingTelemetryProcessor(next) { SamplingPercentage = 50, ProactiveSamplingPercentage = 50 }); channelBuilder.Use(next => new StubTelemetryProcessor(next) { OnProcess = t => sentTelemetry.Add(t) }); channelBuilder.Build(); int count = 5000; for (int i = 0; i < count; i++) { var item = new RequestTelemetry(); item.Context.Operation.Id = ActivityTraceId.CreateRandom().ToHexString(); // generate a lot sampled-in items, only 1/CurrentProactiveSampledInRatioToTarget of them should pass through // and SamplingPercentage of sampled-out items if (SamplingScoreGenerator.GetSamplingScore(item.Context.Operation.Id) < 80) { item.ProactiveSamplingDecision = SamplingDecision.SampledIn; } tc.TelemetryProcessorChain.Process(item); } Assert.AreEqual(0, sentTelemetry.Count(i => ((ISupportAdvancedSampling)i).ProactiveSamplingDecision == SamplingDecision.None)); Assert.AreEqual(count / 2, sentTelemetry.Count(i => ((ISupportAdvancedSampling)i).ProactiveSamplingDecision == SamplingDecision.SampledIn), count / 2 / 10); }
public void ProactivelySampledInItemsAreNotGivenPriorityIfRatesAreNotSet() { var sentTelemetry = new List <ITelemetry>(); TelemetryProcessorChain telemetryProcessorChainWithSampling = CreateTelemetryProcessorChainWithSampling( sentTelemetry, 50); for (int i = 0; i < 1000; i++) { var item = new RequestTelemetry(); item.Context.Operation.Id = ActivityTraceId.CreateRandom().ToHexString(); // proactively sample in items with big score, so they should not be sampled in if (SamplingScoreGenerator.GetSamplingScore(item.Context.Operation.Id) > 50) { item.ProactiveSamplingDecision = SamplingDecision.SampledIn; } telemetryProcessorChainWithSampling.Process(item); } Assert.AreEqual(0, sentTelemetry.Count(i => ((ISupportAdvancedSampling)i).ProactiveSamplingDecision == SamplingDecision.SampledIn)); }
/// <summary> /// Process a collected telemetry item. /// </summary> /// <param name="item">A collected Telemetry item.</param> public void Process(ITelemetry item) { double samplingPercentage = this.SamplingPercentage; //// If sampling rate is 100% and we aren't distinguishing between evaluated/unevaluated items, there is nothing to do: if (samplingPercentage >= 100.0 - 1.0E-12 && this.SampledNext.Equals(this.UnsampledNext)) { this.HandlePossibleProactiveSampling(item, samplingPercentage); return; } //// So sampling rate is not 100%, or we must evaluate further var advancedSamplingSupportingTelemetry = item as ISupportAdvancedSampling; // If someone implemented ISupportSampling and hopes that SamplingTelemetryProcessor will continue to work for them: var samplingSupportingTelemetry = advancedSamplingSupportingTelemetry ?? item as ISupportSampling; //// If null was passed in as item or if sampling not supported in general, do nothing: if (samplingSupportingTelemetry == null) { this.UnsampledNext.Process(item); return; } //// If telemetry was excluded by type, do nothing: if (advancedSamplingSupportingTelemetry != null && !this.IsSamplingApplicable(advancedSamplingSupportingTelemetry.ItemTypeFlag)) { if (TelemetryChannelEventSource.IsVerboseEnabled) { TelemetryChannelEventSource.Log.SamplingSkippedByType(item.ToString()); } this.UnsampledNext.Process(item); return; } //// If telemetry was already sampled, do nothing: bool itemAlreadySampled = samplingSupportingTelemetry.SamplingPercentage.HasValue; if (itemAlreadySampled) { this.UnsampledNext.Process(item); return; } //// Ok, now we can actually sample: samplingSupportingTelemetry.SamplingPercentage = samplingPercentage; bool isSampledIn; // if this is executed in adaptive sampling processor (rate ratio has value), // and item supports proactive sampling and was sampled in before, we'll give it more weight if (this.ProactiveSamplingPercentage.HasValue && advancedSamplingSupportingTelemetry != null && advancedSamplingSupportingTelemetry.ProactiveSamplingDecision == SamplingDecision.SampledIn) { // if current rate of proactively sampled-in telemetry is too high, ProactiveSamplingPercentage is low: // we'll sample in as much proactively sampled in items as we can (based on their sampling score) // so that we still keep target rate. // if current rate of proactively sampled-in telemetry is less that configured, ProactiveSamplingPercentage // is high - it could be > 100 - and we'll sample in all items with proactive SampledIn decision (plus some more in else branch). isSampledIn = SamplingScoreGenerator.GetSamplingScore(item) < this.ProactiveSamplingPercentage; } else { isSampledIn = SamplingScoreGenerator.GetSamplingScore(item) < samplingPercentage; } if (isSampledIn) { if (advancedSamplingSupportingTelemetry != null) { this.HandlePossibleProactiveSampling(item, samplingPercentage, advancedSamplingSupportingTelemetry); } else { this.SampledNext.Process(item); } } else { if (TelemetryChannelEventSource.IsVerboseEnabled) { TelemetryChannelEventSource.Log.ItemSampledOut(item.ToString()); } TelemetryDebugWriter.WriteTelemetry(item, nameof(SamplingTelemetryProcessor)); } }
/// <summary> /// Process a collected telemetry item. /// </summary> /// <param name="item">A collected Telemetry item.</param> public void Process(ITelemetry item) { double samplingPercentage = this.SamplingPercentage; //// If sampling rate is 100% and we aren't distinguishing between evaluated/unevaluated items, there is nothing to do: if (this.SampledNext.Equals(this.UnsampledNext) && samplingPercentage >= 100.0 - 1.0E-12) { this.SampledNext.Process(item); return; } //// So sampling rate is not 100%, or we must evaluate further //// If null was passed in as item or if sampling not supported in general, do nothing: var samplingSupportingTelemetry = item as ISupportSampling; if (samplingSupportingTelemetry == null) { this.UnsampledNext.Process(item); return; } //// If telemetry was excluded by type, do nothing: if (!this.IsSamplingApplicable(item.GetType())) { if (TelemetryChannelEventSource.IsVerboseEnabled) { TelemetryChannelEventSource.Log.SamplingSkippedByType(item.ToString()); } this.UnsampledNext.Process(item); return; } //// If telemetry was already sampled, do nothing: bool itemAlreadySampled = samplingSupportingTelemetry.SamplingPercentage.HasValue; if (itemAlreadySampled) { this.UnsampledNext.Process(item); return; } //// Ok, now we can actually sample: samplingSupportingTelemetry.SamplingPercentage = samplingPercentage; bool isSampledIn = SamplingScoreGenerator.GetSamplingScore(item) < samplingPercentage; if (isSampledIn) { this.SampledNext.Process(item); } else { if (TelemetryChannelEventSource.IsVerboseEnabled) { TelemetryChannelEventSource.Log.ItemSampledOut(item.ToString()); } TelemetryDebugWriter.WriteTelemetry(item, this.GetType().Name); } }
/// <summary> /// Process a collected telemetry item. /// </summary> /// <param name="item">A collected Telemetry item.</param> public void Process(ITelemetry item) { double samplingPercentage = this.SamplingPercentage; //// If sampling rate is 100% and we aren't distinguishing between evaluated/unevaluated items, there is nothing to do: if (samplingPercentage >= 100.0 - 1.0E-12 && this.SampledNext.Equals(this.UnsampledNext)) { this.HandlePossibleProactiveSampling(item, samplingPercentage); return; } //// So sampling rate is not 100%, or we must evaluate further var advancedSamplingSupportingTelemetry = item as ISupportAdvancedSampling; // If someone implemented ISupportSampling and hopes that SamplingTelemetryProcessor will continue to work for them: var samplingSupportingTelemetry = advancedSamplingSupportingTelemetry ?? item as ISupportSampling; //// If null was passed in as item or if sampling not supported in general, do nothing: if (samplingSupportingTelemetry == null) { this.UnsampledNext.Process(item); return; } //// If telemetry was excluded by type, do nothing: if (advancedSamplingSupportingTelemetry != null && !this.IsSamplingApplicable(advancedSamplingSupportingTelemetry.ItemTypeFlag)) { if (TelemetryChannelEventSource.IsVerboseEnabled) { TelemetryChannelEventSource.Log.SamplingSkippedByType(item.ToString()); } this.UnsampledNext.Process(item); return; } //// If telemetry was already sampled, do nothing: bool itemAlreadySampled = samplingSupportingTelemetry.SamplingPercentage.HasValue; if (itemAlreadySampled) { this.UnsampledNext.Process(item); return; } //// Ok, now we can actually sample: samplingSupportingTelemetry.SamplingPercentage = samplingPercentage; bool isSampledIn = SamplingScoreGenerator.GetSamplingScore(item) < samplingPercentage; if (isSampledIn) { if (advancedSamplingSupportingTelemetry != null) { this.HandlePossibleProactiveSampling(item, samplingPercentage, advancedSamplingSupportingTelemetry); } else { this.SampledNext.Process(item); } } else { if (TelemetryChannelEventSource.IsVerboseEnabled) { TelemetryChannelEventSource.Log.ItemSampledOut(item.ToString()); } TelemetryDebugWriter.WriteTelemetry(item, nameof(SamplingTelemetryProcessor)); } }