@@ -16,20 +16,23 @@ public class ClientDiagnosticListener : IObserver<KeyValuePair<string, object>>,
1616 private readonly AsyncLocal < bool > _collectThisStack ;
1717
1818 private List < IDisposable > _subscriptions = new List < IDisposable > ( ) ;
19+ private readonly Action < ProducedDiagnosticScope > _scopeStartCallback ;
1920
2021 public List < ProducedDiagnosticScope > Scopes { get ; } = new List < ProducedDiagnosticScope > ( ) ;
2122
22- public ClientDiagnosticListener ( string name , bool asyncLocal = false ) : this ( n => n == name , asyncLocal )
23+ public ClientDiagnosticListener ( string name , bool asyncLocal = false , Action < ProducedDiagnosticScope > scopeStartCallback = default )
24+ : this ( n => n == name , asyncLocal , scopeStartCallback )
2325 {
2426 }
2527
26- public ClientDiagnosticListener ( Func < string , bool > filter , bool asyncLocal = false )
28+ public ClientDiagnosticListener ( Func < string , bool > filter , bool asyncLocal = false , Action < ProducedDiagnosticScope > scopeStartCallback = default )
2729 {
2830 if ( asyncLocal )
2931 {
3032 _collectThisStack = new AsyncLocal < bool > { Value = true } ;
3133 }
3234 _sourceNameFilter = filter ;
35+ _scopeStartCallback = scopeStartCallback ;
3336 DiagnosticListener . AllListeners . Subscribe ( this ) ;
3437 }
3538
@@ -69,6 +72,7 @@ public void OnNext(KeyValuePair<string, object> value)
6972 } ;
7073
7174 Scopes . Add ( scope ) ;
75+ _scopeStartCallback ? . Invoke ( scope ) ;
7276 }
7377 else if ( value . Key . EndsWith ( stopSuffix ) )
7478 {
@@ -144,7 +148,10 @@ public void Dispose()
144148 }
145149 }
146150
147- public ProducedDiagnosticScope AssertScopeStarted ( string name , params KeyValuePair < string , string > [ ] expectedAttributes )
151+ public ProducedDiagnosticScope AssertScopeStarted ( string name , params KeyValuePair < string , string > [ ] expectedAttributes ) =>
152+ AssertScopeStartedInternal ( name , false , expectedAttributes ) ;
153+
154+ private ProducedDiagnosticScope AssertScopeStartedInternal ( string name , bool remove , params KeyValuePair < string , string > [ ] expectedAttributes )
148155 {
149156 lock ( Scopes )
150157 {
@@ -160,16 +167,28 @@ public ProducedDiagnosticScope AssertScopeStarted(string name, params KeyValuePa
160167 }
161168 }
162169
170+ if ( remove )
171+ {
172+ Scopes . Remove ( producedDiagnosticScope ) ;
173+ }
174+
163175 return producedDiagnosticScope ;
164176 }
165177 }
166178 throw new InvalidOperationException ( $ "Event '{ name } ' was not started") ;
167179 }
168180 }
169181
170- public ProducedDiagnosticScope AssertScope ( string name , params KeyValuePair < string , string > [ ] expectedAttributes )
182+ public ProducedDiagnosticScope AssertScope ( string name , params KeyValuePair < string , string > [ ] expectedAttributes ) =>
183+ AssertScopeInternal ( name , false , expectedAttributes ) ;
184+
185+ public ProducedDiagnosticScope AssertAndRemoveScope ( string name , params KeyValuePair < string , string > [ ] expectedAttributes ) =>
186+ AssertScopeInternal ( name , true , expectedAttributes ) ;
187+
188+ private ProducedDiagnosticScope AssertScopeInternal ( string name , bool remove ,
189+ params KeyValuePair < string , string > [ ] expectedAttributes )
171190 {
172- ProducedDiagnosticScope scope = AssertScopeStarted ( name , expectedAttributes ) ;
191+ ProducedDiagnosticScope scope = AssertScopeStartedInternal ( name , remove , expectedAttributes ) ;
173192 if ( ! scope . IsCompleted )
174193 {
175194 throw new InvalidOperationException ( $ "'{ name } ' is not completed") ;
0 commit comments