-
Notifications
You must be signed in to change notification settings - Fork 770
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
Make SuppressInstrumentation an IDisposable #988
Conversation
This is a bit different from what I was originally thinking - I was exploring something on the So instead of having: var foo = RuntimeContext.GetValue<int>("foo");
var bar = RuntimeContext.GetValue<string>("bar");
try
{
RuntimeContext.SetValue("foo", 1);
RuntimeContext.SetValue("bar", "hello");
// do something
}
finally
{
RuntimeContext.SetValue("foo", foo);
RuntimeContext.SetValue("bar", bar);
} One could use (not sure if people would like using (RuntimeContext.With("foo", 1).With("bar", "hello"))
{
// do something
} And for the flag (I don't know if it is possible in C# to have the following syntax - and meanwhile still have using (Sdk.SuppressInstrumentation(true))
{
// do something
} |
Hmm, I see. These are interesting ideas. Though both of them still raise the question of what the behavior should be if a Though, I could also be ok with just taking the simple approach, because in practice this may not likely arise. |
I kind of like what @alanwest has. I would probably add "Scope" (or "Context") into the name, a la: using (SuppressInstrumentationScope.Begin())
{
await ExportAsync(batch).ConfigureAwait(false);
} I think for the common case we don't need to pass Now if SuppressInstrumentationScope was just wrapping
What you are doing is (essentially): using (var scope = SuppressInstrumentation.Begin())
using (var innerScope = SuppressInstrumentation.Begin())
scope.Dispose();
innerScope.Dispose(); I would simply say, unsupported 😄 Have to dispose them in the correct order. using (var scope = SuppressInstrumentation.Begin())
using (var innerScope = SuppressInstrumentation.Begin())
innerScope.Dispose();
scope.Dispose(); That should work fine. |
I do like the
I was also imagining this to be true. Though also trying to stretch my brain 🧠 in search of use cases I may not be thinking of. @reyang, was there a use case you were thinking of? |
I'm being serious! hah I don't think the expectation on these scope/context type of things is that you can dispose them out of order. I'm thinking about Activity.Current. It has the same issue. If you dispose/stop a parent, it sets its parent as Activity.Current. If someone then does Activity.Current.Stop thinking it's the child, havoc ensues. Same idea for log scopes. |
I don't have a use case at all. It was mainly coming from natural language. For example |
It reads really naturally to me, but I'm working in a codebase that uses a lot of log scopes. Or its cousin, the change token. Basically a newer pattern in .NET where you return IDisposable as the mechanism for calling stop/end/cancel. I really like it 🤷 |
Then go for it 💯 😄 |
|
Yea me, too! Sorry if I sounded sarcastic 😅. I completely agree that it make sense not to support out-of-order disposal. I figured this was a case of over-thinking, so I always like to just stop and see what others think.
Sounds like a decent consensus here. I appreciate the thoughts around natural language, though I also agree that there is enough of a pattern and practice in .NET for the I'll get this PR cleaned up. |
/// Gets a value indicating whether automatic telemetry | ||
/// collection in the current context should be suppressed (disabled). | ||
/// </summary> | ||
public static bool IsSuppressed => SuppressInstrumentationRuntimeContextSlot.Get() != default; |
There was a problem hiding this comment.
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);
There was a problem hiding this comment.
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
}
There was a problem hiding this comment.
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!
There was a problem hiding this comment.
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.
{ | ||
public sealed class SuppressInstrumentationScope : IDisposable | ||
{ | ||
private static readonly RuntimeContextSlot<bool> SuppressInstrumentationRuntimeContextSlot = RuntimeContext.RegisterSlot<bool>("otel.suppress_instrumentation"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Given this is inside a class SuppressInstrumentationScope
, we can probably simplify the name to ContextSlot
or even Slot
.
SuppressInstrumentationRuntimeContextSlot.Set(value); | ||
} | ||
|
||
public static implicit operator bool(SuppressInstrumentationScope x) => SuppressInstrumentationRuntimeContextSlot.Get(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
public static implicit operator bool(SuppressInstrumentationScope x) => SuppressInstrumentationRuntimeContextSlot.Get(); | |
public static implicit operator bool(SuppressInstrumentationScope unused) => SuppressInstrumentationRuntimeContextSlot.Get(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Or other name that explains the intention.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
😄 agree unused
is better than x
. I changed it. Though this did leave me wondering if people would prefer to be able to use _
in this case. I think it's pretty common practice, though I imagine allowing it means allowing any variable to start with a _
which I'm guessing we don't want. No biggie unused
is great.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like _
and initially I was trying to use it, then caught by a style cop 😄
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM with some suggestions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
PLease address the small comments about naming which Reiley already left.
Can you also add this to changelog.md?
…alanwest/opentelemetry-dotnet into alanwest/using-suppress-instrumentation
Codecov Report
@@ Coverage Diff @@
## master #988 +/- ##
==========================================
+ Coverage 68.47% 68.55% +0.07%
==========================================
Files 220 221 +1
Lines 6002 6010 +8
Branches 983 984 +1
==========================================
+ Hits 4110 4120 +10
+ Misses 1619 1617 -2
Partials 273 273
|
@alanwest conflict here :-) |
You're a mergin' machine, @cijothomas! Thanks for shepherding so many PRs through! |
Implementing the suggestion from @reyang and 👍'ed by @CodeBlanch and myself in #960 to introduce
using
syntactic sugar 🍬 forSuppressInstrumentation
.Before I go too far, I wanted to have a quick discussion for what kind of behavior we'd like in the event of a nested situation like the following where Dispose is explicitly called:
The current logic is simplistic and would not pass this test. Though, if people agree this is the correct flow we'd like to expect, then I can implement it with a mechanism where the inner scope signals the parent that it is ok to dispose. However, I just want to make sure things aren't becoming more complicated than people would hope for.