Update sampling API according to the spec (#369)

* Update sampling API according to the spec

* clean up public surface of probability sampler
This commit is contained in:
Liudmila Molkova 2019-12-04 12:18:09 -08:00 committed by GitHub
parent d8e57fe561
commit 287f08fa74
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
26 changed files with 207 additions and 256 deletions

View File

@ -263,7 +263,7 @@ Configuration is done by user application: it should configure exporter and may
services.AddOpenTelemetry(builder =>
{
builder
.SetSampler(Samplers.AlwaysSample)
.SetSampler(new AlwaysSampleSampler())
.UseZipkin()
// you may also configure request and dependencies collectors
@ -287,7 +287,7 @@ Outgoing http calls to Redis made using StackExchange.Redis library can be autom
var connection = ConnectionMultiplexer.Connect("localhost:6379");
using (TracerFactory.Create(b => b
.SetSampler(Samplers.AlwaysSample)
.SetSampler(new AlwaysSampleSampler())
.UseZipkin()
.SetResource(new Resource(new Dictionary<string, string>() { { "service.name", "my-service" } }))
.AddCollector(t =>
@ -309,7 +309,7 @@ You may configure sampler of your choice
```csharp
using (TracerFactory.Create(b => b
.SetSampler(ProbabilitySampler.Create(0.1))
.SetSampler(new ProbabilitySampler(0.1))
.UseZipkin()
.SetResource(new Resource(new Dictionary<string, string>() { { "service.name", "my-service" } })))
{
@ -320,12 +320,12 @@ You may configure sampler of your choice
You can also implement custom sampler by implementing `ISampler` interface
```csharp
class MySampler : ISampler
class MySampler : Sampler
{
public string Description { get; } = "my custom sampler";
public override string Description { get; } = "my custom sampler";
public Decision ShouldSample(SpanContext parentContext, ActivityTraceId traceId, ActivitySpanId spanId, string name,
IEnumerable<Link> links)
public override Decision ShouldSample(SpanContext parentContext, ActivityTraceId traceId, ActivitySpanId spanId, string name,
IDictionary<string, object> attributes, IEnumerable<Link> links)
{
bool sampledIn;
if (parentContext != null && parentContext.IsValid)

View File

@ -19,7 +19,7 @@ using BenchmarkDotNet.Running;
using Benchmarks.Tracing;
using OpenTelemetry.Trace;
using OpenTelemetry.Trace.Configuration;
using OpenTelemetry.Trace.Sampler;
using OpenTelemetry.Trace.Samplers;
namespace Benchmarks
{
@ -33,10 +33,10 @@ namespace Benchmarks
public OpenTelemetrySdkBenchmarks()
{
this.alwaysSampleTracer = TracerFactory
.Create(b => b.SetSampler(Samplers.AlwaysSample))
.Create(b => b.SetSampler(new AlwaysSampleSampler()))
.GetTracer(null);
this.neverSampleTracer = TracerFactory
.Create(b => b.SetSampler(Samplers.NeverSample))
.Create(b => b.SetSampler(new NeverSampleSampler()))
.GetTracer(null);
this.noopTracer = TracerFactoryBase.Default.GetTracer(null);
}

View File

@ -15,7 +15,6 @@
// </copyright>
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using OpenTelemetry.Context;
using OpenTelemetry.Exporter.Prometheus;

View File

@ -35,6 +35,11 @@ namespace OpenTelemetry.Trace
/// </summary>
public IEnumerable<Link> Links { get; set; }
/// <summary>
/// Gets or sets attributes known prior to span creation.
/// </summary>
public IDictionary<string, object> Attributes { get; set; }
/// <summary>
/// Gets or sets Links factory. Use it to deserialize list of <see cref="Link"/> lazily
/// when application configures OpenTelemetry implementation that supports links.

View File

@ -31,7 +31,7 @@ namespace OpenTelemetry.Trace.Configuration
internal TracerConfiguration TracerConfigurationOptions { get; private set; }
internal ISampler Sampler { get; private set; }
internal Sampler Sampler { get; private set; }
internal Resource Resource { get; private set; } = Resource.Empty;
@ -47,7 +47,7 @@ namespace OpenTelemetry.Trace.Configuration
/// Configures sampler.
/// </summary>
/// <param name="sampler">Sampler instance.</param>
public TracerBuilder SetSampler(ISampler sampler)
public TracerBuilder SetSampler(Sampler sampler)
{
this.Sampler = sampler ?? throw new ArgumentNullException(nameof(sampler));
return this;

View File

@ -14,7 +14,6 @@
// limitations under the License.
// </copyright>
using System;
using OpenTelemetry.Trace.Sampler;
namespace OpenTelemetry.Trace.Configuration
{

View File

@ -21,7 +21,7 @@ using OpenTelemetry.Context.Propagation;
using OpenTelemetry.Resources;
using OpenTelemetry.Trace.Export;
using OpenTelemetry.Trace.Export.Internal;
using OpenTelemetry.Trace.Sampler;
using OpenTelemetry.Trace.Samplers;
namespace OpenTelemetry.Trace.Configuration
{
@ -31,7 +31,7 @@ namespace OpenTelemetry.Trace.Configuration
private readonly Dictionary<TracerRegistryKey, ITracer> tracerRegistry = new Dictionary<TracerRegistryKey, ITracer>();
private readonly List<object> collectors = new List<object>();
private readonly ISampler sampler;
private readonly Sampler sampler;
private readonly Resource defaultResource;
private readonly TracerConfiguration configurationOptions;
private readonly SpanProcessor spanProcessor;
@ -42,7 +42,7 @@ namespace OpenTelemetry.Trace.Configuration
private TracerFactory(TracerBuilder builder)
{
this.sampler = builder.Sampler ?? Samplers.AlwaysSample;
this.sampler = builder.Sampler ?? new AlwaysSampleSampler();
this.defaultResource = builder.Resource;
this.configurationOptions =

View File

@ -1,4 +1,4 @@
// <copyright file="ISampler.cs" company="OpenTelemetry Authors">
// <copyright file="Sampler.cs" company="OpenTelemetry Authors">
// Copyright 2018, OpenTelemetry Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
@ -21,12 +21,12 @@ namespace OpenTelemetry.Trace
/// <summary>
/// Sampler to reduce data volume. This sampler executes before Span object was created.
/// </summary>
public interface ISampler
public abstract class Sampler
{
/// <summary>
/// Gets the span description.
/// Gets the sampler description.
/// </summary>
string Description { get; }
public abstract string Description { get; }
/// <summary>
/// Checks whether span needs to be created and tracked.
@ -35,12 +35,13 @@ namespace OpenTelemetry.Trace
/// <param name="traceId">Trace ID of a span to be created.</param>
/// <param name="spanId">Span ID of a span to be created.</param>
/// <param name="name"> Name of a span to be created. Note, that the name of the span is settable.
/// So this name can be changed later and <see cref="ISampler"/> implementation should assume that.
/// So this name can be changed later and Sampler implementation should assume that.
/// Typical example of a name change is when <see cref="ISpan"/> representing incoming http request
/// has a name of url path and then being updated with route name when routing complete.
/// </param>
/// <param name="attributes">Initial set of Attributes for the Span being constructed.</param>
/// <param name="links">Links associated with the span.</param>
/// <returns>Sampling decision on whether Span needs to be sampled or not.</returns>
Decision ShouldSample(SpanContext parentContext, ActivityTraceId traceId, ActivitySpanId spanId, string name, IEnumerable<Link> links);
public abstract Decision ShouldSample(SpanContext parentContext, ActivityTraceId traceId, ActivitySpanId spanId, string name, IDictionary<string, object> attributes, IEnumerable<Link> links);
}
}

View File

@ -1,39 +0,0 @@
// <copyright file="Samplers.cs" company="OpenTelemetry Authors">
// Copyright 2018, OpenTelemetry Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// </copyright>
namespace OpenTelemetry.Trace.Sampler
{
/// <summary>
/// Factory of well-known samplers.
/// </summary>
public sealed class Samplers
{
/// <summary>
/// Gets the sampler that always sample.
/// </summary>
public static ISampler AlwaysSample { get; } = new Internal.AlwaysSampleSampler();
/// <summary>
/// Gets the sampler than never samples.
/// </summary>
public static ISampler NeverSample { get; } = new Internal.NeverSampleSampler();
/// <summary>
/// Gets the sampler than never samples.
/// </summary>
public static ISampler AlwaysParentSampler { get; } = new Internal.AlwaysParentSampler();
}
}

View File

@ -16,33 +16,21 @@
using System.Collections.Generic;
using System.Diagnostics;
namespace OpenTelemetry.Trace.Sampler.Internal
namespace OpenTelemetry.Trace.Samplers
{
internal sealed class AlwaysParentSampler : ISampler
public sealed class AlwaysParentSampler : Sampler
{
internal AlwaysParentSampler()
{
}
public string Description => this.ToString();
public override string Description { get; } = nameof(AlwaysParentSampler);
/// <inheritdoc />
public Decision ShouldSample(SpanContext parentContext, ActivityTraceId traceId, ActivitySpanId spanId, string name, IEnumerable<Link> parentLinks)
public override Decision ShouldSample(SpanContext parentContext, ActivityTraceId traceId, ActivitySpanId spanId, string name, IDictionary<string, object> attributes, IEnumerable<Link> parentLinks)
{
if ((parentContext != null) && parentContext.TraceOptions.HasFlag(ActivityTraceFlags.Recorded))
if (parentContext != null && parentContext.TraceOptions.HasFlag(ActivityTraceFlags.Recorded))
{
return new Decision(true);
}
else
{
return new Decision(false);
}
}
/// <inheritdoc/>
public override string ToString()
{
return nameof(AlwaysParentSampler);
return new Decision(false);
}
}
}

View File

@ -16,26 +16,16 @@
using System.Collections.Generic;
using System.Diagnostics;
namespace OpenTelemetry.Trace.Sampler.Internal
namespace OpenTelemetry.Trace.Samplers
{
internal sealed class AlwaysSampleSampler : ISampler
public sealed class AlwaysSampleSampler : Sampler
{
internal AlwaysSampleSampler()
{
}
public string Description => this.ToString();
public override string Description { get; } = nameof(AlwaysSampleSampler);
/// <inheritdoc />
public Decision ShouldSample(SpanContext parentContext, ActivityTraceId traceId, ActivitySpanId spanId, string name, IEnumerable<Link> parentLinks)
public override Decision ShouldSample(SpanContext parentContext, ActivityTraceId traceId, ActivitySpanId spanId, string name, IDictionary<string, object> attributes, IEnumerable<Link> parentLinks)
{
return new Decision(true);
}
/// <inheritdoc/>
public override string ToString()
{
return nameof(AlwaysSampleSampler);
}
}
}

View File

@ -16,27 +16,16 @@
using System.Collections.Generic;
using System.Diagnostics;
namespace OpenTelemetry.Trace.Sampler.Internal
namespace OpenTelemetry.Trace.Samplers
{
/// <inheritdoc />
internal sealed class NeverSampleSampler : ISampler
public sealed class NeverSampleSampler : Sampler
{
internal NeverSampleSampler()
{
}
public string Description => this.ToString();
public override string Description { get; } = nameof(NeverSampleSampler);
/// <inheritdoc />
public Decision ShouldSample(SpanContext parentContext, ActivityTraceId traceId, ActivitySpanId spanId, string name, IEnumerable<Link> links)
public override Decision ShouldSample(SpanContext parentContext, ActivityTraceId traceId, ActivitySpanId spanId, string name, IDictionary<string, object> attributes, IEnumerable<Link> links)
{
return new Decision(false);
}
/// <inheritdoc/>
public override string ToString()
{
return nameof(NeverSampleSampler);
}
}
}

View File

@ -16,57 +16,48 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using OpenTelemetry.Utils;
namespace OpenTelemetry.Trace.Sampler
namespace OpenTelemetry.Trace.Samplers
{
/// <inheritdoc />
public sealed class ProbabilitySampler : ISampler
public sealed class ProbabilitySampler : Sampler
{
private ProbabilitySampler(double probability, long idUpperBound)
{
this.Probability = probability;
this.IdUpperBound = idUpperBound;
}
private readonly long idUpperBound;
private readonly double probability;
/// <inheritdoc />
public string Description => $"ProbabilitySampler({this.Probability:F6})";
public double Probability { get; }
public long IdUpperBound { get; }
public static ProbabilitySampler Create(double probability)
public ProbabilitySampler(double probability)
{
if (probability < 0.0 || probability > 1.0)
{
throw new ArgumentOutOfRangeException(nameof(probability), "probability must be in range [0.0, 1.0]");
throw new ArgumentOutOfRangeException(nameof(probability), "Probability must be in range [0.0, 1.0]");
}
long idUpperBound;
this.probability = probability;
this.Description = $"ProbabilitySampler({this.probability:F6})";
// Special case the limits, to avoid any possible issues with lack of precision across
// double/long boundaries. For probability == 0.0, we use Long.MIN_VALUE as this guarantees
// that we will never sample a trace, even in the case where the id == Long.MIN_VALUE, since
// Math.Abs(Long.MIN_VALUE) == Long.MIN_VALUE.
if (probability == 0.0)
if (this.probability == 0.0)
{
idUpperBound = long.MinValue;
this.idUpperBound = long.MinValue;
}
else if (probability == 1.0)
else if (this.probability == 1.0)
{
idUpperBound = long.MaxValue;
this.idUpperBound = long.MaxValue;
}
else
{
idUpperBound = (long)(probability * long.MaxValue);
this.idUpperBound = (long)(probability * long.MaxValue);
}
return new ProbabilitySampler(probability, idUpperBound);
}
/// <inheritdoc />
public Decision ShouldSample(SpanContext parentContext, ActivityTraceId traceId, ActivitySpanId spanId, string name, IEnumerable<Link> links)
public override string Description { get; }
/// <inheritdoc />
public override Decision ShouldSample(SpanContext parentContext, ActivityTraceId traceId, ActivitySpanId spanId, string name, IDictionary<string, object> attributes, IEnumerable<Link> links)
{
// If the parent is sampled keep the sampling decision.
if (parentContext != null &&
@ -97,48 +88,10 @@ namespace OpenTelemetry.Trace.Sampler
// code is executed in-line for every Span creation).
Span<byte> traceIdBytes = stackalloc byte[16];
traceId.CopyTo(traceIdBytes);
return Math.Abs(this.GetLowerLong(traceIdBytes)) < this.IdUpperBound ? new Decision(true) : new Decision(false);
return Math.Abs(this.GetLowerLong(traceIdBytes)) < this.idUpperBound ? new Decision(true) : new Decision(false);
}
/// <inheritdoc/>
public override string ToString()
{
return nameof(ProbabilitySampler)
+ "{"
+ nameof(this.Probability) + "=" + this.Probability + ", "
+ nameof(this.IdUpperBound) + "=" + this.IdUpperBound
+ "}";
}
/// <inheritdoc/>
public override bool Equals(object o)
{
if (o == this)
{
return true;
}
if (o is ProbabilitySampler that)
{
return DoubleUtil.ToInt64(this.Probability) == DoubleUtil.ToInt64(that.Probability)
&& (this.IdUpperBound == that.IdUpperBound);
}
return false;
}
/// <inheritdoc/>
public override int GetHashCode()
{
long h = 1;
h *= 1000003;
h ^= (DoubleUtil.ToInt64(this.Probability) >> 32) ^ DoubleUtil.ToInt64(this.Probability);
h *= 1000003;
h ^= (this.IdUpperBound >> 32) ^ this.IdUpperBound;
return (int)h;
}
public long GetLowerLong(ReadOnlySpan<byte> bytes)
private long GetLowerLong(ReadOnlySpan<byte> bytes)
{
long result = 0;
for (var i = 0; i < 8; i++)

View File

@ -36,7 +36,7 @@ namespace OpenTelemetry.Trace
{
private static readonly ConditionalWeakTable<Activity, Span> ActivitySpanTable = new ConditionalWeakTable<Activity, Span>();
private readonly ISampler sampler;
private readonly Sampler sampler;
private readonly TracerConfiguration tracerConfiguration;
private readonly SpanProcessor spanProcessor;
private readonly object lck = new object();
@ -59,7 +59,7 @@ namespace OpenTelemetry.Trace
bool createdFromActivity,
SpanKind spanKind,
SpanCreationOptions spanCreationOptions,
ISampler sampler,
Sampler sampler,
TracerConfiguration tracerConfiguration,
SpanProcessor spanProcessor,
Resource libraryResource)
@ -90,6 +90,7 @@ namespace OpenTelemetry.Trace
this.IsRecording = MakeSamplingDecision(
parentSpanContext,
name,
spanCreationOptions?.Attributes,
links, // we'll enumerate again, but double enumeration over small collection is cheaper than allocation
this.Activity.TraceId,
this.Activity.SpanId,
@ -106,6 +107,15 @@ namespace OpenTelemetry.Trace
if (this.IsRecording)
{
this.SetLinks(links);
if (spanCreationOptions?.Attributes != null)
{
foreach (var attribute in spanCreationOptions.Attributes)
{
this.SetAttribute(attribute);
}
}
this.spanProcessor.OnStart(this);
}
}
@ -385,7 +395,7 @@ namespace OpenTelemetry.Trace
ISpan parentSpan,
SpanKind spanKind,
SpanCreationOptions spanCreationOptions,
ISampler sampler,
Sampler sampler,
TracerConfiguration tracerConfiguration,
SpanProcessor spanProcessor,
Resource libraryResource)
@ -442,7 +452,7 @@ namespace OpenTelemetry.Trace
SpanContext parentContext,
SpanKind spanKind,
SpanCreationOptions spanCreationOptions,
ISampler sampler,
Sampler sampler,
TracerConfiguration tracerConfiguration,
SpanProcessor spanProcessor,
Resource libraryResource)
@ -464,7 +474,7 @@ namespace OpenTelemetry.Trace
string name,
SpanKind spanKind,
SpanCreationOptions spanCreationOptions,
ISampler sampler,
Sampler sampler,
TracerConfiguration tracerConfiguration,
SpanProcessor spanProcessor,
Resource libraryResource)
@ -487,7 +497,7 @@ namespace OpenTelemetry.Trace
Activity activity,
SpanKind spanKind,
IEnumerable<Link> links,
ISampler sampler,
Sampler sampler,
TracerConfiguration tracerConfiguration,
SpanProcessor spanProcessor,
Resource libraryResource)
@ -535,12 +545,13 @@ namespace OpenTelemetry.Trace
private static bool MakeSamplingDecision(
SpanContext parent,
string name,
IDictionary<string, object> attributes,
IEnumerable<Link> parentLinks,
ActivityTraceId traceId,
ActivitySpanId spanId,
ISampler sampler)
Sampler sampler)
{
return sampler.ShouldSample(parent, traceId, spanId, name, parentLinks).IsSampled;
return sampler.ShouldSample(parent, traceId, spanId, name, attributes, parentLinks).IsSampled;
}
private static ActivityAndTracestate FromCurrentParentActivity(string spanName, Activity current)

View File

@ -29,7 +29,7 @@ namespace OpenTelemetry.Trace
{
private readonly SpanProcessor spanProcessor;
private readonly TracerConfiguration tracerConfiguration;
private readonly ISampler sampler;
private readonly Sampler sampler;
static Tracer()
{
@ -46,7 +46,7 @@ namespace OpenTelemetry.Trace
/// <param name="binaryFormat">Binary format context propagator.</param>
/// <param name="textFormat">Text format context propagator.</param>
/// <param name="libraryResource">Resource describing the instrumentation library.</param>
internal Tracer(SpanProcessor spanProcessor, ISampler sampler, TracerConfiguration tracerConfiguration, IBinaryFormat binaryFormat, ITextFormat textFormat, Resource libraryResource)
internal Tracer(SpanProcessor spanProcessor, Sampler sampler, TracerConfiguration tracerConfiguration, IBinaryFormat binaryFormat, ITextFormat textFormat, Resource libraryResource)
{
this.spanProcessor = spanProcessor ?? throw new ArgumentNullException(nameof(spanProcessor));
this.tracerConfiguration = tracerConfiguration ?? throw new ArgumentNullException(nameof(tracerConfiguration));

View File

@ -15,7 +15,6 @@
// </copyright>
using OpenTelemetry.Trace.Configuration;
using OpenTelemetry.Trace.Sampler;
using Xunit;
using Microsoft.AspNetCore.Mvc.Testing;
using TestApp.AspNetCore._2._0;
@ -31,6 +30,7 @@ using OpenTelemetry.Context.Propagation;
using Microsoft.AspNetCore.Http;
using System.Collections.Generic;
using System.Diagnostics;
using OpenTelemetry.Trace.Samplers;
namespace OpenTelemetry.Collector.AspNetCore.Tests
{
@ -62,7 +62,7 @@ namespace OpenTelemetry.Collector.AspNetCore.Tests
{
services.AddSingleton<TracerFactory>(_ =>
TracerFactory.Create(b => b
.SetSampler(Samplers.AlwaysSample)
.SetSampler(new AlwaysSampleSampler())
.AddProcessorPipeline(p => p.AddProcessor(n => spanProcessor.Object))
.AddRequestCollector()));
}
@ -112,7 +112,7 @@ namespace OpenTelemetry.Collector.AspNetCore.Tests
{
services.AddSingleton<TracerFactory>(_ =>
TracerFactory.Create(b => b
.SetSampler(Samplers.AlwaysSample)
.SetSampler(new AlwaysSampleSampler())
.SetTextFormat(tf.Object)
.AddProcessorPipeline(p => p.AddProcessor(n => spanProcessor.Object))
.AddRequestCollector()));
@ -160,7 +160,7 @@ namespace OpenTelemetry.Collector.AspNetCore.Tests
{
services.AddSingleton<TracerFactory>(_ =>
TracerFactory.Create(b => b
.SetSampler(Samplers.AlwaysSample)
.SetSampler(new AlwaysSampleSampler())
.AddProcessorPipeline(p => p.AddProcessor(n => spanProcessor.Object))
.AddRequestCollector(o => o.EventFilter = Filter)));
}

View File

@ -15,7 +15,6 @@
// </copyright>
using OpenTelemetry.Trace.Configuration;
using OpenTelemetry.Trace.Sampler;
using Xunit;
using Microsoft.AspNetCore.Mvc.Testing;
using TestApp.AspNetCore._2._0;
@ -27,6 +26,7 @@ using Moq;
using Microsoft.AspNetCore.TestHost;
using System;
using Microsoft.AspNetCore.Http;
using OpenTelemetry.Trace.Samplers;
namespace OpenTelemetry.Collector.AspNetCore.Tests
{
@ -65,7 +65,7 @@ namespace OpenTelemetry.Collector.AspNetCore.Tests
services.AddSingleton<CallbackMiddleware.CallbackMiddlewareImpl>(new TestCallbackMiddlewareImpl());
services.AddSingleton<TracerFactory>(_ =>
TracerFactory.Create(b => b
.SetSampler(Samplers.AlwaysSample)
.SetSampler(new AlwaysSampleSampler())
.AddProcessorPipeline(p => p.AddProcessor(e => spanProcessor.Object))
.AddRequestCollector()));
}))

View File

@ -14,7 +14,6 @@
// limitations under the License.
// </copyright>
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using OpenTelemetry.Metrics;

View File

@ -13,9 +13,9 @@
// See the License for the specific language governing permissions and
// limitations under the License.
// </copyright>
using System;
using OpenTelemetry.Trace.Configuration;
using OpenTelemetry.Trace.Sampler;
using Xunit;
namespace OpenTelemetry.Trace.Config.Test

View File

@ -22,7 +22,7 @@ using OpenTelemetry.Testing.Export;
using OpenTelemetry.Trace;
using OpenTelemetry.Trace.Configuration;
using OpenTelemetry.Trace.Export;
using OpenTelemetry.Trace.Sampler;
using OpenTelemetry.Trace.Samplers;
using Xunit;
namespace OpenTelemetry.Tests.Impl.Trace
@ -60,7 +60,7 @@ namespace OpenTelemetry.Tests.Impl.Trace
bool processorFactoryCalled = false;
bool collectorFactoryCalled = true;
var sampler = ProbabilitySampler.Create(0.1);
var sampler = new ProbabilitySampler(0.1);
var exporter = new TestExporter(_ => { });
var options = new TracerConfiguration(1, 1, 1);
var binaryFormat = new BinaryFormat();
@ -104,7 +104,7 @@ namespace OpenTelemetry.Tests.Impl.Trace
Assert.Equal("semver:" + typeof(TestCollector).Assembly.GetName().Version, collectorFactory.Version);
Assert.NotNull(collectorFactory.Factory);
collectorFactory.Factory(new Tracer(new SimpleSpanProcessor(exporter), Samplers.AlwaysSample, options, binaryFormat, textFormat,
collectorFactory.Factory(new Tracer(new SimpleSpanProcessor(exporter), new AlwaysSampleSampler(), options, binaryFormat, textFormat,
Resource.Empty));
Assert.True(collectorFactoryCalled);

View File

@ -14,7 +14,6 @@
// limitations under the License.
// </copyright>
using OpenTelemetry.Trace.Sampler;
using System;
using System.Collections.Generic;
using System.Diagnostics;
@ -23,6 +22,7 @@ using System.Threading;
using System.Threading.Tasks;
using OpenTelemetry.Testing.Export;
using OpenTelemetry.Trace.Configuration;
using OpenTelemetry.Trace.Samplers;
using Xunit;
namespace OpenTelemetry.Trace.Export.Test
@ -38,7 +38,7 @@ namespace OpenTelemetry.Trace.Export.Test
private Span CreateSampledEndedSpan(string spanName, SpanProcessor spanProcessor)
{
var tracer = TracerFactory.Create(b => b
.SetSampler(Samplers.AlwaysSample)
.SetSampler(new AlwaysSampleSampler())
.AddProcessorPipeline(p => p.AddProcessor(e => spanProcessor))
.SetTracerOptions(new TracerConfiguration())).GetTracer(null);
var context = new SpanContext(ActivityTraceId.CreateRandom(), ActivitySpanId.CreateRandom(), ActivityTraceFlags.Recorded);
@ -50,7 +50,7 @@ namespace OpenTelemetry.Trace.Export.Test
private Span CreateNotSampledEndedSpan(string spanName, SpanProcessor spanProcessor)
{
var tracer = TracerFactory.Create(b => b
.SetSampler(Samplers.NeverSample)
.SetSampler(new NeverSampleSampler())
.AddProcessorPipeline(p => p.AddProcessor(_ => spanProcessor))
.SetTracerOptions(new TracerConfiguration())).GetTracer(null);
var context = new SpanContext(ActivityTraceId.CreateRandom(), ActivitySpanId.CreateRandom(), ActivityTraceFlags.None);

View File

@ -20,7 +20,7 @@ using System.Threading;
using System.Threading.Tasks;
using OpenTelemetry.Testing.Export;
using OpenTelemetry.Trace.Configuration;
using OpenTelemetry.Trace.Sampler;
using OpenTelemetry.Trace.Samplers;
using Xunit;
namespace OpenTelemetry.Trace.Export.Test
@ -40,7 +40,7 @@ namespace OpenTelemetry.Trace.Export.Test
.AddProcessorPipeline(p => p
.SetExporter(spanExporter)
.SetExportingProcessor(e => new SimpleSpanProcessor(e)))
.SetSampler(Samplers.AlwaysParentSampler))
.SetSampler(new AlwaysParentSampler()))
.GetTracer(null);
}

View File

@ -16,14 +16,13 @@
using System;
using System.Diagnostics;
using System.Collections.Generic;
using System.Globalization;
using Xunit;
namespace OpenTelemetry.Trace.Sampler.Test
namespace OpenTelemetry.Trace.Samplers.Test
{
public class SamplersTest
{
private static readonly String SPAN_NAME = "MySpanName";
private static readonly string SpanName = "MySpanName";
private static readonly int NUM_SAMPLE_TRIES = 1000;
private readonly ActivityTraceId traceId;
private readonly ActivitySpanId parentSpanId;
@ -47,30 +46,32 @@ namespace OpenTelemetry.Trace.Sampler.Test
{
// Sampled parent.
Assert.True(
Samplers.AlwaysSample
new AlwaysSampleSampler()
.ShouldSample(
sampledSpanContext,
traceId,
spanId,
"Another name",
null,
null).IsSampled);
// Not sampled parent.
Assert.True(
Samplers.AlwaysSample
new AlwaysSampleSampler()
.ShouldSample(
notSampledSpanContext,
traceId,
spanId,
"Yet another name",
null,
null).IsSampled);
}
[Fact]
public void AlwaysSampleSampler_ToString()
public void AlwaysSampleSampler_GetDescription()
{
Assert.Equal("AlwaysSampleSampler", Samplers.AlwaysSample.ToString());
Assert.Equal("AlwaysSampleSampler", new AlwaysSampleSampler().Description);
}
[Fact]
@ -78,59 +79,61 @@ namespace OpenTelemetry.Trace.Sampler.Test
{
// Sampled parent.
Assert.False(
Samplers.NeverSample
new NeverSampleSampler()
.ShouldSample(
sampledSpanContext,
traceId,
spanId,
"bar",
null,
null).IsSampled);
// Not sampled parent.
Assert.False(
Samplers.NeverSample
new NeverSampleSampler()
.ShouldSample(
notSampledSpanContext,
traceId,
spanId,
"quux",
null,
null).IsSampled);
}
[Fact]
public void NeverSampleSampler_ToString()
public void NeverSampleSampler_GetDescription()
{
Assert.Equal("NeverSampleSampler", Samplers.NeverSample.ToString());
Assert.Equal("NeverSampleSampler", new NeverSampleSampler().Description);
}
[Fact]
public void ProbabilitySampler_OutOfRangeHighProbability()
{
Assert.Throws<ArgumentOutOfRangeException>(() => ProbabilitySampler.Create(1.01));
Assert.Throws<ArgumentOutOfRangeException>(() => new ProbabilitySampler(1.01));
}
[Fact]
public void ProbabilitySampler_OutOfRangeLowProbability()
{
Assert.Throws<ArgumentOutOfRangeException>(() => ProbabilitySampler.Create(-0.00001));
Assert.Throws<ArgumentOutOfRangeException>(() => new ProbabilitySampler(-0.00001));
}
[Fact]
public void ProbabilitySampler_DifferentProbabilities_NotSampledParent()
{
ISampler neverSample = ProbabilitySampler.Create(0.0);
Sampler neverSample = new ProbabilitySampler(0.0);
AssertSamplerSamplesWithProbability(
neverSample, notSampledSpanContext, null, 0.0);
ISampler alwaysSample = ProbabilitySampler.Create(1.0);
Sampler alwaysSample = new ProbabilitySampler(1.0);
AssertSamplerSamplesWithProbability(
alwaysSample, notSampledSpanContext, null, 1.0);
ISampler fiftyPercentSample = ProbabilitySampler.Create(0.5);
Sampler fiftyPercentSample = new ProbabilitySampler(0.5);
AssertSamplerSamplesWithProbability(
fiftyPercentSample, notSampledSpanContext, null, 0.5);
ISampler twentyPercentSample = ProbabilitySampler.Create(0.2);
Sampler twentyPercentSample = new ProbabilitySampler(0.2);
AssertSamplerSamplesWithProbability(
twentyPercentSample, notSampledSpanContext, null, 0.2);
ISampler twoThirdsSample = ProbabilitySampler.Create(2.0 / 3.0);
Sampler twoThirdsSample = new ProbabilitySampler(2.0 / 3.0);
AssertSamplerSamplesWithProbability(
twoThirdsSample, notSampledSpanContext, null, 2.0 / 3.0);
}
@ -138,19 +141,19 @@ namespace OpenTelemetry.Trace.Sampler.Test
[Fact]
public void ProbabilitySampler_DifferentProbabilities_SampledParent()
{
ISampler neverSample = ProbabilitySampler.Create(0.0);
Sampler neverSample = new ProbabilitySampler(0.0);
AssertSamplerSamplesWithProbability(
neverSample, sampledSpanContext, null, 1.0);
ISampler alwaysSample = ProbabilitySampler.Create(1.0);
Sampler alwaysSample = new ProbabilitySampler(1.0);
AssertSamplerSamplesWithProbability(
alwaysSample, sampledSpanContext, null, 1.0);
ISampler fiftyPercentSample = ProbabilitySampler.Create(0.5);
Sampler fiftyPercentSample = new ProbabilitySampler(0.5);
AssertSamplerSamplesWithProbability(
fiftyPercentSample, sampledSpanContext, null, 1.0);
ISampler twentyPercentSample = ProbabilitySampler.Create(0.2);
Sampler twentyPercentSample = new ProbabilitySampler(0.2);
AssertSamplerSamplesWithProbability(
twentyPercentSample, sampledSpanContext, null, 1.0);
ISampler twoThirdsSample = ProbabilitySampler.Create(2.0 / 3.0);
Sampler twoThirdsSample = new ProbabilitySampler(2.0 / 3.0);
AssertSamplerSamplesWithProbability(
twoThirdsSample, sampledSpanContext, null, 1.0);
}
@ -158,19 +161,19 @@ namespace OpenTelemetry.Trace.Sampler.Test
[Fact]
public void ProbabilitySampler_DifferentProbabilities_SampledParentLink()
{
ISampler neverSample = ProbabilitySampler.Create(0.0);
Sampler neverSample = new ProbabilitySampler(0.0);
AssertSamplerSamplesWithProbability(
neverSample, notSampledSpanContext, new List<Link>() { sampledLink }, 1.0);
ISampler alwaysSample = ProbabilitySampler.Create(1.0);
Sampler alwaysSample = new ProbabilitySampler(1.0);
AssertSamplerSamplesWithProbability(
alwaysSample, notSampledSpanContext, new List<Link>() { sampledLink }, 1.0);
ISampler fiftyPercentSample = ProbabilitySampler.Create(0.5);
Sampler fiftyPercentSample = new ProbabilitySampler(0.5);
AssertSamplerSamplesWithProbability(
fiftyPercentSample, notSampledSpanContext, new List<Link>() { sampledLink }, 1.0);
ISampler twentyPercentSample = ProbabilitySampler.Create(0.2);
Sampler twentyPercentSample = new ProbabilitySampler(0.2);
AssertSamplerSamplesWithProbability(
twentyPercentSample, notSampledSpanContext, new List<Link>() { sampledLink }, 1.0);
ISampler twoThirdsSample = ProbabilitySampler.Create(2.0 / 3.0);
Sampler twoThirdsSample = new ProbabilitySampler(2.0 / 3.0);
AssertSamplerSamplesWithProbability(
twoThirdsSample, notSampledSpanContext, new List<Link>() { sampledLink }, 1.0);
}
@ -178,7 +181,7 @@ namespace OpenTelemetry.Trace.Sampler.Test
[Fact]
public void ProbabilitySampler_SampleBasedOnTraceId()
{
ISampler defaultProbability = ProbabilitySampler.Create(0.0001);
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 =
@ -207,7 +210,8 @@ namespace OpenTelemetry.Trace.Sampler.Test
SpanContext.BlankLocal,
notSampledtraceId,
ActivitySpanId.CreateRandom(),
SPAN_NAME,
SpanName,
null,
null).IsSampled);
// This traceId will be sampled by the ProbabilitySampler because the first 8 bytes as long
// is less than probability * Long.MAX_VALUE;
@ -237,26 +241,20 @@ namespace OpenTelemetry.Trace.Sampler.Test
null,
sampledtraceId,
ActivitySpanId.CreateRandom(),
SPAN_NAME,
SpanName,
null,
null).IsSampled);
}
[Fact]
public void ProbabilitySampler_getDescription()
public void ProbabilitySampler_GetDescription()
{
Assert.Equal($"ProbabilitySampler({0.5:F6})", ProbabilitySampler.Create(0.5).Description);
}
[Fact]
public void ProbabilitySampler_ToString()
{
var result = ProbabilitySampler.Create(0.5).ToString();
Assert.Contains($"0{CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator}5", result);
Assert.Equal($"ProbabilitySampler({0.5:F6})", new ProbabilitySampler(0.5).Description);
}
// Applies the given sampler to NUM_SAMPLE_TRIES random traceId/spanId pairs.
private static void AssertSamplerSamplesWithProbability(
ISampler sampler, SpanContext parent, List<Link> links, double probability)
Sampler sampler, SpanContext parent, List<Link> links, double probability)
{
var count = 0; // Count of spans with sampling enabled
for (var i = 0; i < NUM_SAMPLE_TRIES; i++)
@ -265,7 +263,8 @@ namespace OpenTelemetry.Trace.Sampler.Test
parent,
ActivityTraceId.CreateRandom(),
ActivitySpanId.CreateRandom(),
SPAN_NAME,
SpanName,
null,
links).IsSampled)
{
count++;

View File

@ -1255,6 +1255,64 @@ namespace OpenTelemetry.Trace.Test
Assert.Same(BlankSpan.Instance, tracer.CurrentSpan);
}
[Fact]
public void StartSpan_WithAttributes_PassesAttributesToSampler_AndSetsOnSpan()
{
var samplerMock = new Mock<Sampler>();
var tracer = TracerFactory.Create(b => b
.SetSampler(samplerMock.Object)
.AddProcessorPipeline(p => p.AddProcessor(_ => spanProcessor)))
.GetTracer(null);
samplerMock.Setup(s => s.ShouldSample(
It.IsAny<SpanContext>(),
It.IsAny<ActivityTraceId>(),
It.IsAny<ActivitySpanId>(),
It.IsAny<string>(),
It.IsAny<IDictionary<string, object>>(),
It.IsAny<IEnumerable<Link>>())).Returns(new Decision(true));
var span = (Span)tracer.StartSpan("test", SpanKind.Client, new SpanCreationOptions { Attributes = this.attributes, });
span.Attributes.AssertAreSame(this.attributes);
samplerMock.Verify(o => o.ShouldSample(
It.IsAny<SpanContext>(),
It.IsAny<ActivityTraceId>(),
It.IsAny<ActivitySpanId>(),
It.IsAny<string>(),
It.Is<IDictionary<string, object>>(a => a == this.attributes),
It.IsAny<IEnumerable<Link>>()), Times.Once);
}
[Fact]
public void StartNotSampledSpan_WithAttributes_PassesAttributesToSampler_DoesNotSetAttributesOnSpan()
{
var samplerMock = new Mock<Sampler>();
var tracer = TracerFactory.Create(b => b
.SetSampler(samplerMock.Object)
.AddProcessorPipeline(p => p.AddProcessor(_ => spanProcessor)))
.GetTracer(null);
samplerMock.Setup(s => s.ShouldSample(
It.IsAny<SpanContext>(),
It.IsAny<ActivityTraceId>(),
It.IsAny<ActivitySpanId>(),
It.IsAny<string>(),
It.IsAny<IDictionary<string, object>>(),
It.IsAny<IEnumerable<Link>>())).Returns(new Decision(false));
var span = (Span)tracer.StartSpan("test", SpanKind.Client, new SpanCreationOptions { Attributes = this.attributes, });
Assert.Empty(span.Attributes);
samplerMock.Verify(o => o.ShouldSample(
It.IsAny<SpanContext>(),
It.IsAny<ActivityTraceId>(),
It.IsAny<ActivitySpanId>(),
It.IsAny<string>(),
It.Is<IDictionary<string, object>>(a => a == this.attributes),
It.IsAny<IEnumerable<Link>>()), Times.Once);
}
private void AssertApproxSameTimestamp(DateTimeOffset one, DateTimeOffset two)
{
var timeShift = Math.Abs((one - two).TotalMilliseconds);

View File

@ -21,13 +21,13 @@ using OpenTelemetry.Context.Propagation;
using OpenTelemetry.Resources;
using OpenTelemetry.Tests;
using OpenTelemetry.Utils;
using OpenTelemetry.Trace.Sampler;
using Xunit;
using System;
using System.Collections.Generic;
using OpenTelemetry.Testing.Export;
using OpenTelemetry.Trace.Configuration;
using OpenTelemetry.Trace.Export;
using OpenTelemetry.Trace.Samplers;
namespace OpenTelemetry.Trace.Test
{
@ -52,14 +52,14 @@ namespace OpenTelemetry.Trace.Test
public void BadConstructorArgumentsThrow()
{
var noopProc = new SimpleSpanProcessor(new TestExporter(null));
Assert.Throws<ArgumentNullException>(() => new Tracer(null, Samplers.AlwaysSample, new TracerConfiguration(), new BinaryFormat(), new TraceContextFormat(), Resource.Empty));
Assert.Throws<ArgumentNullException>(() => new Tracer(null, new AlwaysSampleSampler(), new TracerConfiguration(), new BinaryFormat(), new TraceContextFormat(), Resource.Empty));
Assert.Throws<ArgumentNullException>(() => new Tracer(noopProc, Samplers.AlwaysSample, null, new BinaryFormat(), new TraceContextFormat(), Resource.Empty));
Assert.Throws<ArgumentNullException>(() => new Tracer(noopProc, new AlwaysSampleSampler(), null, new BinaryFormat(), new TraceContextFormat(), Resource.Empty));
Assert.Throws<ArgumentNullException>(() => new Tracer(noopProc, Samplers.AlwaysSample, new TracerConfiguration(), null, new TraceContextFormat(), Resource.Empty));
Assert.Throws<ArgumentNullException>(() => new Tracer(noopProc, Samplers.AlwaysSample, new TracerConfiguration(), new BinaryFormat(), null, Resource.Empty));
Assert.Throws<ArgumentNullException>(() => new Tracer(noopProc, new AlwaysSampleSampler(), new TracerConfiguration(), null, new TraceContextFormat(), Resource.Empty));
Assert.Throws<ArgumentNullException>(() => new Tracer(noopProc, new AlwaysSampleSampler(), new TracerConfiguration(), new BinaryFormat(), null, Resource.Empty));
Assert.Throws<ArgumentNullException>(() => new Tracer(noopProc, Samplers.AlwaysSample, new TracerConfiguration(), new BinaryFormat(), new TraceContextFormat(), null));
Assert.Throws<ArgumentNullException>(() => new Tracer(noopProc, new AlwaysSampleSampler(), new TracerConfiguration(), new BinaryFormat(), new TraceContextFormat(), null));
}
[Fact]
@ -120,7 +120,7 @@ namespace OpenTelemetry.Trace.Test
public void CreateSpan_NotSampled()
{
var tracer = TracerFactory.Create(b => b
.SetSampler(Samplers.NeverSample)
.SetSampler(new NeverSampleSampler())
.AddProcessorPipeline(p => p.AddProcessor(n => spanProcessor)))
.GetTracer(null);
@ -163,7 +163,7 @@ namespace OpenTelemetry.Trace.Test
var tracer = TracerFactory.Create(b => b
.AddProcessorPipeline(p => p.AddProcessor(n => spanProcessor))
.SetTracerOptions(traceConfig)
.SetSampler(Samplers.AlwaysSample))
.SetSampler(new AlwaysSampleSampler()))
.GetTracer(null);
var span = (Span)tracer.StartRootSpan(SpanName);
@ -215,7 +215,7 @@ namespace OpenTelemetry.Trace.Test
var tracer = TracerFactory.Create(b => b
.AddProcessorPipeline(p => p.AddProcessor(n => spanProcessor))
.SetTracerOptions(traceConfig)
.SetSampler(Samplers.AlwaysSample))
.SetSampler(new AlwaysSampleSampler()))
.GetTracer(null);
var span = (Span)tracer.StartRootSpan(SpanName);
@ -254,7 +254,7 @@ namespace OpenTelemetry.Trace.Test
var tracer = TracerFactory.Create(b => b
.AddProcessorPipeline(p => p.AddProcessor(n => spanProcessor))
.SetTracerOptions(traceConfig)
.SetSampler(Samplers.AlwaysSample))
.SetSampler(new AlwaysSampleSampler()))
.GetTracer(null);
var overflowedLinks = new List<Link>();
@ -296,7 +296,7 @@ namespace OpenTelemetry.Trace.Test
var tracer = TracerFactory.Create(b => b
.AddProcessorPipeline(p => p.AddProcessor(n => spanProcessor))
.SetTracerOptions(traceConfig)
.SetSampler(Samplers.AlwaysSample))
.SetSampler(new AlwaysSampleSampler()))
.GetTracer(null);
var overflowedLinks = new List<Link>();
@ -335,7 +335,7 @@ namespace OpenTelemetry.Trace.Test
var tracer = TracerFactory.Create(b => b
.AddProcessorPipeline(p => p.AddProcessor(_ => this.spanProcessor))
.SetTracerOptions(traceConfig)
.SetSampler(Samplers.AlwaysSample))
.SetSampler(new AlwaysSampleSampler()))
.GetTracer(null);
var span = (Span)tracer.StartRootSpan(SpanName);

View File

@ -14,7 +14,6 @@
// limitations under the License.
// </copyright>
using OpenTelemetry.Trace.Configuration;
using OpenTelemetry.Trace.Sampler.Internal;
using Xunit;
namespace OpenTelemetry.Trace.Test