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

Make SuppressInstrumentation an IDisposable #988

Merged
46 changes: 0 additions & 46 deletions src/OpenTelemetry/Sdk.cs
Expand Up @@ -36,52 +36,6 @@ public static class Sdk
{
private static readonly TimeSpan DefaultPushInterval = TimeSpan.FromSeconds(60);

private static readonly RuntimeContextSlot<bool> SuppressInstrumentationRuntimeContextSlot = RuntimeContext.RegisterSlot<bool>("otel.suppress_instrumentation");

/// <summary>
/// Gets or sets a value indicating whether automatic telemetry
/// collection in the current context should be suppressed (disabled).
/// Default value: False.
/// </summary>
/// <remarks>
/// Set <see cref="SuppressInstrumentation"/> to <see langword="true"/>
/// when you want to turn off automatic telemetry collection.
/// This is typically used to prevent infinite loops created by
/// collection of internal operations, such as exporting traces over HTTP.
/// <code>
/// public override async Task&lt;ExportResult&gt; ExportAsync(
/// IEnumerable&lt;Activity&gt; batch,
/// CancellationToken cancellationToken)
/// {
/// var currentSuppressionPolicy = Sdk.SuppressInstrumentation;
/// Sdk.SuppressInstrumentation = true;
/// try
/// {
/// await this.SendBatchActivityAsync(batch, cancellationToken).ConfigureAwait(false);
/// return ExportResult.Success;
/// }
/// finally
/// {
/// Sdk.SuppressInstrumentation = currentSuppressionPolicy;
/// }
/// }
/// </code>
/// </remarks>
public static bool SuppressInstrumentation
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
return SuppressInstrumentationRuntimeContextSlot.Get();
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
set
{
SuppressInstrumentationRuntimeContextSlot.Set(value);
}
}

/// <summary>
/// Creates MeterProvider with the configuration provided.
/// Configuration involves MetricProcessor, Exporter and push internval.
Expand Down
77 changes: 77 additions & 0 deletions src/OpenTelemetry/SuppressInstrumentation.cs
@@ -0,0 +1,77 @@
// <copyright file="SuppressInstrumentation.cs" company="OpenTelemetry Authors">
// Copyright The 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>

using System;
using OpenTelemetry.Context;

namespace OpenTelemetry
{
public class SuppressInstrumentation : IDisposable
{
private static readonly RuntimeContextSlot<SuppressInstrumentation> SuppressInstrumentationRuntimeContextSlot = RuntimeContext.RegisterSlot<SuppressInstrumentation>("otel.suppress_instrumentation");

private readonly SuppressInstrumentation parent;
private bool disposed;

private SuppressInstrumentation()
{
this.parent = SuppressInstrumentationRuntimeContextSlot.Get();
SuppressInstrumentationRuntimeContextSlot.Set(this);
}

/// <summary>
/// Gets a value indicating whether automatic telemetry
/// collection in the current context should be suppressed (disabled).
/// </summary>
public static bool IsSuppressed => SuppressInstrumentationRuntimeContextSlot.Get() != default;
Copy link
Member

@reyang reyang Aug 4, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider implicit operator?

public sealed class SuppressInstrumentationScope : IDisposable
{
    private readonly bool value;
    public static implicit operator bool(SuppressInstrumentationScope _) => SuppressInstrumentationRuntimeContextSlot.Get();

    public SuppressInstrumentationScope(bool value = true)
    {
        this.value = value;
        SuppressInstrumentationRuntimeContextSlot.Set(value);
    }

    public void Dispose()
    {
        SuppressInstrumentationRuntimeContextSlot.Set(this.value);
    }

    public IDisposable Begin(bool value = true)
    {
        return new SuppressInstrumentationScope(value);
    }
}

public readonly static SuppressInstrumentationScope SuppressInstrumentation = new SuppressInstrumentationScope(false);

Copy link
Member

@reyang reyang Aug 4, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then from consumption side:

if (Sdk.SuppressInstrumentation)
{
    // do something
}

using (Sdk.SuppressInstrumentation.Begin())
{
    // do something
}

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interesting, I would not have thought of this approach!

Copy link
Member Author

@alanwest alanwest Aug 4, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok pushed up something that works.


/// <summary>
/// Begins a new scope in which automatic telemetry is suppressed (disabled).
/// </summary>
/// <returns>Object to dispose to end the scope.</returns>
/// <remarks>
/// This is typically used to prevent infinite loops created by
/// collection of internal operations, such as exporting traces over HTTP.
/// <code>
/// public override async Task&lt;ExportResult&gt; ExportAsync(
/// IEnumerable&lt;Activity&gt; batch,
/// CancellationToken cancellationToken)
/// {
/// using (var scope = SuppressInstrumentation.Begin())
alanwest marked this conversation as resolved.
Show resolved Hide resolved
/// {
/// // Instrumentation is suppressed (i.e., SuppressInstrumentation.IsSuppressed == true)
/// }
///
/// // Instrumentation is not suppressed (i.e., SuppressInstrumentation.IsSuppressed == false)
/// }
/// </code>
/// </remarks>
public static IDisposable Begin()
{
return new SuppressInstrumentation();
}

/// <inheritdoc/>
public void Dispose()
{
if (!this.disposed)
{
SuppressInstrumentationRuntimeContextSlot.Set(this.parent);
this.disposed = true;
}
}
}
}
34 changes: 34 additions & 0 deletions test/OpenTelemetry.Tests/SuppressInstrumentationTest.cs
@@ -0,0 +1,34 @@
// <copyright file="SuppressInstrumentationTest.cs" company="OpenTelemetry Authors">
// Copyright The 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>

using Xunit;

namespace OpenTelemetry.Tests
{
public class SuppressInstrumentationTest
{
[Fact]
public static void UsingSuppressInstrumentation()
{
using (var scope = SuppressInstrumentation.Begin())
{
Assert.True(SuppressInstrumentation.IsSuppressed);
}

Assert.False(SuppressInstrumentation.IsSuppressed);
}
}
}