Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rename ParentOrElse to ParentBased and generalize to support all cases #1577

Merged
merged 12 commits into from
Aug 28, 2020
154 changes: 136 additions & 18 deletions sdk/tracing/src/main/java/io/opentelemetry/sdk/trace/Samplers.java
Original file line number Diff line number Diff line change
Expand Up @@ -147,14 +147,27 @@ public static Sampler alwaysOff() {
* whether or not to sample. If there is no parent, the Sampler uses the provided Sampler delegate
* to determine the sampling decision.
*
* @param delegateSampler the {@code Sampler} which is used to make the sampling decisions if the
* parent does not exist.
* @param root the {@code Sampler} which is used to make the sampling decisions if the parent does
* not exist.
* @return a {@code Sampler} that follows the parent's sampling decision if one exists, otherwise
* following the delegate sampler's decision.
* following the root sampler's decision.
* @since 0.7.0
*/
public static Sampler parentOrElse(Sampler delegateSampler) {
return new ParentOrElse(delegateSampler);
public static Sampler parentBased(Sampler root) {
return newParentBasedBuilder(root).build();
}

/**
* Returns a {@link ParentBased.Builder} that follows the parent's sampling decision if one
* exists, otherwise following the root sampler and other optional sampler's decision.
*
* @param root the required {@code Sampler} which is used to make the sampling decisions if the
* parent does not exist.
* @return a {@code ParentBased.Builder}
* @since 0.8.0
*/
public static ParentBased.Builder newParentBasedBuilder(Sampler root) {
dengliming marked this conversation as resolved.
Show resolved Hide resolved
return new ParentBased.Builder(root);
}

/**
Expand Down Expand Up @@ -214,11 +227,26 @@ public String getDescription() {
}

@Immutable
static class ParentOrElse implements Sampler {
private final Sampler delegateSampler;

ParentOrElse(Sampler delegateSampler) {
this.delegateSampler = delegateSampler;
static class ParentBased implements Sampler {
private final Sampler root;
private final Sampler remoteParentSampled;
private final Sampler remoteParentNotSampled;
private final Sampler localParentSampled;
private final Sampler localParentNotSampled;

private ParentBased(
Sampler root,
Sampler remoteParentSampled,
Sampler remoteParentNotSampled,
Sampler localParentSampled,
Sampler localParentNotSampled) {
this.root = root;
this.remoteParentSampled = remoteParentSampled == null ? alwaysOn() : remoteParentSampled;
this.remoteParentNotSampled =
remoteParentNotSampled == null ? alwaysOff() : remoteParentNotSampled;
this.localParentSampled = localParentSampled == null ? alwaysOn() : localParentSampled;
this.localParentNotSampled =
localParentNotSampled == null ? alwaysOff() : localParentNotSampled;
}

// If a parent is set, always follows the same sampling decision as the parent.
Expand All @@ -231,19 +259,109 @@ public SamplingResult shouldSample(
Kind spanKind,
ReadableAttributes attributes,
List<Link> parentLinks) {
if (parentContext.isValid()) {
if (parentContext.getTraceFlags().isSampled()) {
return EMPTY_RECORDED_AND_SAMPLED_SAMPLING_RESULT;
}
return EMPTY_NOT_SAMPLED_OR_RECORDED_SAMPLING_RESULT;
if (!parentContext.isValid()) {
return this.root.shouldSample(
parentContext, traceId, name, spanKind, attributes, parentLinks);
}
return this.delegateSampler.shouldSample(
parentContext, traceId, name, spanKind, attributes, parentLinks);

if (parentContext.isRemote()) {
return parentContext.getTraceFlags().isSampled()
? this.remoteParentSampled.shouldSample(
parentContext, traceId, name, spanKind, attributes, parentLinks)
: this.remoteParentNotSampled.shouldSample(
parentContext, traceId, name, spanKind, attributes, parentLinks);
}
return parentContext.getTraceFlags().isSampled()
? this.localParentSampled.shouldSample(
parentContext, traceId, name, spanKind, attributes, parentLinks)
: this.localParentNotSampled.shouldSample(
parentContext, traceId, name, spanKind, attributes, parentLinks);
}

@Override
public String getDescription() {
return String.format("ParentOrElse{%s}", this.delegateSampler.getDescription());
return String.format(
"ParentBased{root:%s,remoteParentSampled:%s,remoteParentNotSampled:%s,"
+ "localParentSampled:%s,localParentNotSampled:%s}",
this.root.getDescription(),
this.remoteParentSampled.getDescription(),
this.remoteParentNotSampled.getDescription(),
this.localParentSampled.getDescription(),
this.localParentNotSampled.getDescription());
}

static class Builder {
private final Sampler root;
private Sampler remoteParentSampled;
private Sampler remoteParentNotSampled;
private Sampler localParentSampled;
private Sampler localParentNotSampled;

/**
* Sets the remoteParentSampled. Optional.
dengliming marked this conversation as resolved.
Show resolved Hide resolved
*
* @param remoteParentSampled used to make the sampling decisions if the remote parent exist
dengliming marked this conversation as resolved.
Show resolved Hide resolved
* and is sampled.
* @return this.
*/
public Builder withRemoteParentSampled(Sampler remoteParentSampled) {
dengliming marked this conversation as resolved.
Show resolved Hide resolved
this.remoteParentSampled = remoteParentSampled;
return this;
}

/**
* Sets the remoteParentNotSampled. Optional.
*
* @param remoteParentNotSampled used to make the sampling decisions if the remote parent
* exist and is not sampled.
* @return this.
*/
public Builder withRemoteParentNotSampled(Sampler remoteParentNotSampled) {
this.remoteParentNotSampled = remoteParentNotSampled;
return this;
}

/**
* Sets the localParentSampled. Optional.
*
* @param localParentSampled used to make the sampling decisions if the local parent exist and
* is sampled.
* @return this.
*/
public Builder withLocalParentSampled(Sampler localParentSampled) {
this.localParentSampled = localParentSampled;
return this;
}

/**
* Sets the localParentNotSampled. Optional.
*
* @param localParentNotSampled used to make the sampling decisions if the local parent exist
* and is not sampled.
* @return this.
*/
public Builder withLocalParentNotSampled(Sampler localParentNotSampled) {
this.localParentNotSampled = localParentNotSampled;
return this;
}

/**
* Builds the {@link ParentBased}.
*
* @return the ParentBased sampler.
*/
public ParentBased build() {
return new ParentBased(
this.root,
this.remoteParentSampled,
this.remoteParentNotSampled,
this.localParentSampled,
this.localParentNotSampled);
}

private Builder(Sampler root) {
this.root = root;
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@
public abstract class TraceConfig {
// These values are the default values for all the global parameters.
// TODO: decide which default sampler to use
private static final Sampler DEFAULT_SAMPLER = Samplers.parentOrElse(Samplers.alwaysOn());
private static final Sampler DEFAULT_SAMPLER = Samplers.parentBased(Samplers.alwaysOn());
private static final int DEFAULT_SPAN_MAX_NUM_ATTRIBUTES = 32;
private static final int DEFAULT_SPAN_MAX_NUM_EVENTS = 128;
private static final int DEFAULT_SPAN_MAX_NUM_LINKS = 32;
Expand Down
Loading