55using System . Threading . Tasks ;
66using Microsoft . Extensions . Logging ;
77using SharpHoundCommonLib . Exceptions ;
8+ using SharpHoundCommonLib . Interfaces ;
9+ using SharpHoundCommonLib . Models ;
10+ using SharpHoundCommonLib . Static ;
811using SharpHoundRPC . NetAPINative ;
912
1013namespace SharpHoundCommonLib ;
@@ -26,6 +29,7 @@ public sealed class AdaptiveTimeout : IDisposable {
2629 private const int ExcessiveTimeoutsThreshold = 7 ;
2730 private const int StdDevMultiplier = 7 ; // 7 standard deviations should be a very conservative upper bound
2831 private const int CountOfLatestSuccessToKeep = 3 ;
32+ private readonly IMetricRouter _metrics ;
2933
3034 public AdaptiveTimeout ( TimeSpan maxTimeout , ILogger log , int sampleCount = 100 , int logFrequency = 1000 , int minSamplesForAdaptiveTimeout = 30 , bool useAdaptiveTimeout = true , bool throwIfExcessiveTimeouts = false ) {
3135 if ( maxTimeout <= TimeSpan . Zero )
@@ -47,6 +51,7 @@ public AdaptiveTimeout(TimeSpan maxTimeout, ILogger log, int sampleCount = 100,
4751 _minSamplesForAdaptiveTimeout = minSamplesForAdaptiveTimeout ;
4852 _useAdaptiveTimeout = useAdaptiveTimeout ;
4953 _throwIfExcessiveTimeouts = throwIfExcessiveTimeouts ;
54+ _metrics = Metrics . Factory . CreateMetricRouter ( ) ;
5055 }
5156
5257 public AdaptiveTimeout ( TimeSpan maxTimeout , TimeSpan minTimeout , ILogger log , int sampleCount = 100 , int logFrequency = 1000 , int minSamplesForAdaptiveTimeout = 30 , bool useAdaptiveTimeout = true , bool throwIfExcessiveTimeouts = false )
@@ -75,15 +80,19 @@ public void ClearSamples() {
7580 /// <typeparam name="T"></typeparam>
7681 /// <param name="func"></param>
7782 /// <param name="parentToken"></param>
83+ /// <param name="latencyObservation">A method that is used to observe the latency of the request.</param>
7884 /// <returns>Returns a Fail result if a task runs longer than its budgeted time.</returns>
79- public async Task < Result < T > > ExecuteWithTimeout < T > ( Func < CancellationToken , T > func , CancellationToken parentToken = default ) {
85+ public async Task < Result < T > > ExecuteWithTimeout < T > ( Func < CancellationToken , T > func , CancellationToken parentToken = default , Action < double > latencyObservation = null ) {
8086 DateTime startTime = default ;
8187 var result = await Timeout . ExecuteWithTimeout ( GetAdaptiveTimeout ( ) , ( timeoutToken ) =>
8288 _sampler . SampleExecutionTime ( ( ) => {
8389 startTime = DateTime . Now ; // for ordinal tracking; see use in TimeSpikeSafetyValve
8490 return func ( timeoutToken ) ;
85- } ) , parentToken ) ;
91+ } , latencyObservation ) , parentToken ) ;
8692 TimeSpikeSafetyValve ( result . IsSuccess , startTime ) ;
93+ if ( ! result . IsSuccess ) {
94+ _metrics . Observe ( AdaptiveTimeoutDefinitions . TimeoutsTotal , 1 , new LabelValues ( ) ) ;
95+ }
8796 return result ;
8897 }
8998
@@ -97,15 +106,19 @@ public async Task<Result<T>> ExecuteWithTimeout<T>(Func<CancellationToken, T> fu
97106 /// </summary>
98107 /// <param name="func"></param>
99108 /// <param name="parentToken"></param>
109+ /// <param name="latencyObservation">A method that is used to observe the latency of the request.</param>
100110 /// <returns>Returns a Fail result if a task runs longer than its budgeted time.</returns>
101- public async Task < Result > ExecuteWithTimeout ( Action < CancellationToken > func , CancellationToken parentToken = default ) {
111+ public async Task < Result > ExecuteWithTimeout ( Action < CancellationToken > func , CancellationToken parentToken = default , Action < double > latencyObservation = null ) {
102112 DateTime startTime = default ;
103113 var result = await Timeout . ExecuteWithTimeout ( GetAdaptiveTimeout ( ) , ( timeoutToken ) =>
104114 _sampler . SampleExecutionTime ( ( ) => {
105115 startTime = DateTime . Now ; // for ordinal tracking; see use in TimeSpikeSafetyValve
106116 func ( timeoutToken ) ;
107- } ) , parentToken ) ;
117+ } , latencyObservation ) , parentToken ) ;
108118 TimeSpikeSafetyValve ( result . IsSuccess , startTime ) ;
119+ if ( ! result . IsSuccess ) {
120+ _metrics . Observe ( AdaptiveTimeoutDefinitions . TimeoutsTotal , 1 , new LabelValues ( ) ) ;
121+ }
109122 return result ;
110123 }
111124
@@ -120,15 +133,19 @@ public async Task<Result> ExecuteWithTimeout(Action<CancellationToken> func, Can
120133 /// <typeparam name="T"></typeparam>
121134 /// <param name="func"></param>
122135 /// <param name="parentToken"></param>
136+ /// <param name="latencyObservation">A method that is used to observe the latency of the request.</param>
123137 /// <returns>Returns a Fail result if a task runs longer than its budgeted time.</returns>
124- public async Task < Result < T > > ExecuteWithTimeout < T > ( Func < CancellationToken , Task < T > > func , CancellationToken parentToken = default ) {
138+ public async Task < Result < T > > ExecuteWithTimeout < T > ( Func < CancellationToken , Task < T > > func , CancellationToken parentToken = default , Action < double > latencyObservation = null ) {
125139 DateTime startTime = default ;
126140 var result = await Timeout . ExecuteWithTimeout ( GetAdaptiveTimeout ( ) , ( timeoutToken ) =>
127141 _sampler . SampleExecutionTime ( ( ) => {
128142 startTime = DateTime . Now ; // for ordinal tracking; see use in TimeSpikeSafetyValve
129143 return func ( timeoutToken ) ;
130- } ) , parentToken ) ;
144+ } , latencyObservation ) , parentToken ) ;
131145 TimeSpikeSafetyValve ( result . IsSuccess , startTime ) ;
146+ if ( ! result . IsSuccess ) {
147+ _metrics . Observe ( AdaptiveTimeoutDefinitions . TimeoutsTotal , 1 , new LabelValues ( ) ) ;
148+ }
132149 return result ;
133150 }
134151
@@ -142,15 +159,19 @@ public async Task<Result<T>> ExecuteWithTimeout<T>(Func<CancellationToken, Task<
142159 /// </summary>
143160 /// <param name="func"></param>
144161 /// <param name="parentToken"></param>
162+ /// <param name="latencyObservation">A method that is used to observe the latency of the request.</param>
145163 /// <returns>Returns a Fail result if a task runs longer than its budgeted time.</returns>
146- public async Task < Result > ExecuteWithTimeout ( Func < CancellationToken , Task > func , CancellationToken parentToken = default ) {
164+ public async Task < Result > ExecuteWithTimeout ( Func < CancellationToken , Task > func , CancellationToken parentToken = default , Action < double > latencyObservation = null ) {
147165 DateTime startTime = default ;
148166 var result = await Timeout . ExecuteWithTimeout ( GetAdaptiveTimeout ( ) , ( timeoutToken ) =>
149167 _sampler . SampleExecutionTime ( ( ) => {
150168 startTime = DateTime . Now ; // for ordinal tracking; see use in TimeSpikeSafetyValve
151169 return func ( timeoutToken ) ;
152- } ) , parentToken ) ;
170+ } , latencyObservation ) , parentToken ) ;
153171 TimeSpikeSafetyValve ( result . IsSuccess , startTime ) ;
172+ if ( ! result . IsSuccess ) {
173+ _metrics . Observe ( AdaptiveTimeoutDefinitions . TimeoutsTotal , 1 , new LabelValues ( ) ) ;
174+ }
154175 return result ;
155176 }
156177
@@ -174,6 +195,9 @@ public async Task<NetAPIResult<T>> ExecuteNetAPIWithTimeout<T>(Func<Cancellation
174195 return func ( timeoutToken ) ;
175196 } ) , parentToken ) ;
176197 TimeSpikeSafetyValve ( result . IsSuccess , startTime ) ;
198+ if ( ! result . IsSuccess ) {
199+ _metrics . Observe ( AdaptiveTimeoutDefinitions . TimeoutsTotal , 1 , new LabelValues ( ) ) ;
200+ }
177201 return result ;
178202 }
179203
@@ -197,6 +221,9 @@ public async Task<NetAPIResult<T>> ExecuteNetAPIWithTimeout<T>(Func<Cancellation
197221 return func ( timeoutToken ) ;
198222 } ) , parentToken ) ;
199223 TimeSpikeSafetyValve ( result . IsSuccess , startTime ) ;
224+ if ( ! result . IsSuccess ) {
225+ _metrics . Observe ( AdaptiveTimeoutDefinitions . TimeoutsTotal , 1 , new LabelValues ( ) ) ;
226+ }
200227 return result ;
201228 }
202229
@@ -220,6 +247,9 @@ public async Task<NetAPIResult<T>> ExecuteNetAPIWithTimeout<T>(Func<Cancellation
220247 return func ( timeoutToken ) ;
221248 } ) , parentToken ) ;
222249 TimeSpikeSafetyValve ( result . IsSuccess , startTime ) ;
250+ if ( ! result . IsSuccess ) {
251+ _metrics . Observe ( AdaptiveTimeoutDefinitions . TimeoutsTotal , 1 , new LabelValues ( ) ) ;
252+ }
223253 return result ;
224254 }
225255
0 commit comments