-
Notifications
You must be signed in to change notification settings - Fork 4.9k
[WIP] Support IsEnabled with addtional arguments #15984 #15985
Changes from 2 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -59,24 +59,27 @@ public static IObservable<DiagnosticListener> AllListeners | |
| /// Add a subscriber (Observer). If 'IsEnabled' == null (or not present), then the Source's IsEnabled | ||
| /// will always return true. | ||
| /// </summary> | ||
| virtual public IDisposable Subscribe(IObserver<KeyValuePair<string, object>> observer, Predicate<string> isEnabled) | ||
| public virtual IDisposable Subscribe(IObserver<KeyValuePair<string, object>> observer, Predicate<string> isEnabled) | ||
| { | ||
| // If we have been disposed, we silently ignore any subscriptions. | ||
| if (_disposed) | ||
| { | ||
| return new DiagnosticSubscription() { Owner = this }; | ||
| } | ||
| DiagnosticSubscription newSubscription = new DiagnosticSubscription() { Observer = observer, IsEnabled = isEnabled, Owner = this, Next = _subscriptions }; | ||
| while (Interlocked.CompareExchange(ref _subscriptions, newSubscription, newSubscription.Next) != newSubscription.Next) | ||
| newSubscription.Next = _subscriptions; | ||
| return newSubscription; | ||
| return SubscribeInternal(observer, isEnabled, (name, arg1, arg2) => isEnabled(name)); | ||
| } | ||
|
|
||
| // Subscription implementation | ||
| /// <summary> | ||
| /// Add a subscriber (Observer). If 'IsEnabled' == null (or not present), then the Source's IsEnabled | ||
| /// will always return true. | ||
| /// </summary> | ||
| public virtual IDisposable Subscribe(IObserver<KeyValuePair<string, object>> observer, Func<string, object, object, bool> isEnabled) | ||
| { | ||
| return SubscribeInternal(observer, name => IsEnabled(name, null, null), isEnabled); | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Same as other Subscribe overload where the predicate is assumed to always return true. | ||
| /// </summary> | ||
| public IDisposable Subscribe(IObserver<KeyValuePair<string, object>> observer) | ||
| { | ||
| return Subscribe(observer, null); | ||
| return SubscribeInternal(observer, null, null); | ||
| } | ||
|
|
||
| /// <summary> | ||
|
|
@@ -183,6 +186,20 @@ public override bool IsEnabled(string name) | |
| return false; | ||
| } | ||
|
|
||
| // NotificationSource implementation | ||
| /// <summary> | ||
| /// Override abstract method | ||
| /// </summary> | ||
| public override bool IsEnabled(string name, object arg1, object arg2) | ||
| { | ||
| for (DiagnosticSubscription curSubscription = _subscriptions; curSubscription != null; curSubscription = curSubscription.Next) | ||
| { | ||
| if (curSubscription.IsEnabledExt == null || curSubscription.IsEnabledExt(name, arg1, arg2)) | ||
| return true; | ||
| } | ||
| return false; | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Override abstract method | ||
| /// </summary> | ||
|
|
@@ -196,7 +213,9 @@ public override void Write(string name, object value) | |
| private class DiagnosticSubscription : IDisposable | ||
| { | ||
| internal IObserver<KeyValuePair<string, object>> Observer; | ||
|
|
||
| internal Predicate<string> IsEnabled; | ||
| internal Func<string, object, object, bool> IsEnabledExt; | ||
|
||
| internal DiagnosticListener Owner; // The DiagnosticListener this is a subscription for. | ||
| internal DiagnosticSubscription Next; // Linked list of subscribers | ||
|
|
||
|
|
@@ -341,6 +360,27 @@ public void Dispose() | |
| } | ||
| #endregion | ||
|
|
||
| private IDisposable SubscribeInternal(IObserver<KeyValuePair<string, object>> observer, Predicate<string> isEnabled, Func<string, object, object, bool> isEnabledExt) | ||
| { | ||
| // If we have been disposed, we silently ignore any subscriptions. | ||
| if (_disposed) | ||
| { | ||
| return new DiagnosticSubscription() { Owner = this }; | ||
| } | ||
| DiagnosticSubscription newSubscription = new DiagnosticSubscription() | ||
| { | ||
| Observer = observer, | ||
| IsEnabled = isEnabled, | ||
| IsEnabledExt = isEnabledExt, | ||
| Owner = this, | ||
| Next = _subscriptions | ||
| }; | ||
|
|
||
| while (Interlocked.CompareExchange(ref _subscriptions, newSubscription, newSubscription.Next) != newSubscription.Next) | ||
| newSubscription.Next = _subscriptions; | ||
| return newSubscription; | ||
| } | ||
|
|
||
| private volatile DiagnosticSubscription _subscriptions; | ||
| private DiagnosticListener _next; // We keep a linked list of all NotificationListeners (s_allListeners) | ||
| private bool _disposed; // Has Dispose been called? | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -42,5 +42,19 @@ public abstract partial class DiagnosticSource | |
| /// </summary> | ||
| /// <param name="name">The name of the event being written.</param> | ||
| public abstract bool IsEnabled(string name); | ||
|
|
||
| /// <summary> | ||
| /// Optional: if there is expensive setup for the notification, you can call IsEnabled | ||
| /// before doing this setup with context | ||
| /// </summary> | ||
| /// <param name="name">The name of the event being written.</param> | ||
| /// <param name="arg1">An object that represents the additional context for IsEnabled</param> | ||
| /// <param name="arg2">An object that represents the additional context for IsEnabled</param> | ||
| /// <seealso cref="IsEnabled(string)"/> | ||
| public virtual bool IsEnabled(string name, object arg1, object arg2) | ||
|
||
| { | ||
| return IsEnabled(name); | ||
| } | ||
|
|
||
| } | ||
| } | ||
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.
Add more description of what the arguments of 'isEnabled' are (the first is the name of the event, the next are context object (which may be null) that are optionally passed to the isEnabled call from the DiagnosticSource.