Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 12 additions & 8 deletions src/CommonLib/AdaptiveTimeout.cs
Original file line number Diff line number Diff line change
Expand Up @@ -62,14 +62,15 @@ public void ClearSamples() {
/// <typeparam name="T"></typeparam>
/// <param name="func"></param>
/// <param name="parentToken"></param>
/// <param name="latencyObservation">A method that is used to observe the latency of the request.</param>
/// <returns>Returns a Fail result if a task runs longer than its budgeted time.</returns>
public async Task<Result<T>> ExecuteWithTimeout<T>(Func<CancellationToken, T> func, CancellationToken parentToken = default) {
public async Task<Result<T>> ExecuteWithTimeout<T>(Func<CancellationToken, T> func, CancellationToken parentToken = default, Action<double> latencyObservation = null) {
DateTime startTime = default;
var result = await Timeout.ExecuteWithTimeout(GetAdaptiveTimeout(), (timeoutToken) =>
_sampler.SampleExecutionTime(() => {
startTime = DateTime.Now; // for ordinal tracking; see use in TimeSpikeSafetyValve
return func(timeoutToken);
}), parentToken);
}, latencyObservation), parentToken);
TimeSpikeSafetyValve(result.IsSuccess, startTime);
return result;
}
Expand All @@ -84,14 +85,15 @@ public async Task<Result<T>> ExecuteWithTimeout<T>(Func<CancellationToken, T> fu
/// </summary>
/// <param name="func"></param>
/// <param name="parentToken"></param>
/// <param name="latencyObservation">A method that is used to observe the latency of the request.</param>
/// <returns>Returns a Fail result if a task runs longer than its budgeted time.</returns>
public async Task<Result> ExecuteWithTimeout(Action<CancellationToken> func, CancellationToken parentToken = default) {
public async Task<Result> ExecuteWithTimeout(Action<CancellationToken> func, CancellationToken parentToken = default, Action<double> latencyObservation = null) {
DateTime startTime = default;
var result = await Timeout.ExecuteWithTimeout(GetAdaptiveTimeout(), (timeoutToken) =>
_sampler.SampleExecutionTime(() => {
startTime = DateTime.Now; // for ordinal tracking; see use in TimeSpikeSafetyValve
func(timeoutToken);
}), parentToken);
}, latencyObservation), parentToken);
TimeSpikeSafetyValve(result.IsSuccess, startTime);
return result;
}
Expand All @@ -107,14 +109,15 @@ public async Task<Result> ExecuteWithTimeout(Action<CancellationToken> func, Can
/// <typeparam name="T"></typeparam>
/// <param name="func"></param>
/// <param name="parentToken"></param>
/// <param name="latencyObservation">A method that is used to observe the latency of the request.</param>
/// <returns>Returns a Fail result if a task runs longer than its budgeted time.</returns>
public async Task<Result<T>> ExecuteWithTimeout<T>(Func<CancellationToken, Task<T>> func, CancellationToken parentToken = default) {
public async Task<Result<T>> ExecuteWithTimeout<T>(Func<CancellationToken, Task<T>> func, CancellationToken parentToken = default, Action<double> latencyObservation = null) {
DateTime startTime = default;
var result = await Timeout.ExecuteWithTimeout(GetAdaptiveTimeout(), (timeoutToken) =>
_sampler.SampleExecutionTime(() => {
startTime = DateTime.Now; // for ordinal tracking; see use in TimeSpikeSafetyValve
return func(timeoutToken);
}), parentToken);
}, latencyObservation), parentToken);
TimeSpikeSafetyValve(result.IsSuccess, startTime);
return result;
}
Expand All @@ -129,14 +132,15 @@ public async Task<Result<T>> ExecuteWithTimeout<T>(Func<CancellationToken, Task<
/// </summary>
/// <param name="func"></param>
/// <param name="parentToken"></param>
/// <param name="latencyObservation">A method that is used to observe the latency of the request.</param>
/// <returns>Returns a Fail result if a task runs longer than its budgeted time.</returns>
public async Task<Result> ExecuteWithTimeout(Func<CancellationToken, Task> func, CancellationToken parentToken = default) {
public async Task<Result> ExecuteWithTimeout(Func<CancellationToken, Task> func, CancellationToken parentToken = default, Action<double> latencyObservation = null) {
DateTime startTime = default;
var result = await Timeout.ExecuteWithTimeout(GetAdaptiveTimeout(), (timeoutToken) =>
_sampler.SampleExecutionTime(() => {
startTime = DateTime.Now; // for ordinal tracking; see use in TimeSpikeSafetyValve
return func(timeoutToken);
}), parentToken);
}, latencyObservation), parentToken);
TimeSpikeSafetyValve(result.IsSuccess, startTime);
return result;
}
Expand Down
12 changes: 8 additions & 4 deletions src/CommonLib/ExecutionTimeSampler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,35 +43,39 @@ public double StandardDeviation() {

public double Average() => _samples.Average();

public async Task<T> SampleExecutionTime<T>(Func<Task<T>> func) {
public async Task<T> SampleExecutionTime<T>(Func<Task<T>> func, Action<double> latencyObservation = null) {
var stopwatch = Stopwatch.StartNew();
var result = await func.Invoke();
stopwatch.Stop();
latencyObservation?.Invoke(stopwatch.ElapsedMilliseconds);
AddTimeSample(stopwatch.Elapsed);

return result;
}

public async Task SampleExecutionTime(Func<Task> func) {
public async Task SampleExecutionTime(Func<Task> func, Action<double> latencyObservation = null) {
var stopwatch = Stopwatch.StartNew();
await func.Invoke();
stopwatch.Stop();
latencyObservation?.Invoke(stopwatch.ElapsedMilliseconds);
AddTimeSample(stopwatch.Elapsed);
}

public T SampleExecutionTime<T>(Func<T> func) {
public T SampleExecutionTime<T>(Func<T> func, Action<double> latencyObservation = null) {
var stopwatch = Stopwatch.StartNew();
var result = func.Invoke();
stopwatch.Stop();
latencyObservation?.Invoke(stopwatch.ElapsedMilliseconds);
AddTimeSample(stopwatch.Elapsed);

return result;
}

public void SampleExecutionTime(Action func) {
public void SampleExecutionTime(Action func, Action<double> latencyObservation = null) {
var stopwatch = Stopwatch.StartNew();
func.Invoke();
stopwatch.Stop();
latencyObservation?.Invoke(stopwatch.ElapsedMilliseconds);
AddTimeSample(stopwatch.Elapsed);
}

Expand Down
5 changes: 5 additions & 0 deletions src/CommonLib/Interfaces/ILabelValuesCache.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
namespace SharpHoundCommonLib.Interfaces;

public interface ILabelValuesCache {
string[] Intern(string[] values);
}
5 changes: 5 additions & 0 deletions src/CommonLib/Interfaces/IMetricFactory.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
namespace SharpHoundCommonLib.Interfaces;

public interface IMetricFactory {
IMetricRouter CreateMetricRouter();
}
9 changes: 9 additions & 0 deletions src/CommonLib/Interfaces/IMetricRegistry.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using System.Collections.Generic;
using SharpHoundCommonLib.Models;

namespace SharpHoundCommonLib.Interfaces;

public interface IMetricRegistry {
bool TryRegister(MetricDefinition definition, out int definitionId);
IReadOnlyList<MetricDefinition> Definitions { get; }
}
8 changes: 8 additions & 0 deletions src/CommonLib/Interfaces/IMetricRouter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
using SharpHoundCommonLib.Models;

namespace SharpHoundCommonLib.Interfaces;

public interface IMetricRouter {
void Observe(int definitionId, double value, LabelValues labelValues);
void Flush();
}
8 changes: 8 additions & 0 deletions src/CommonLib/Interfaces/IMetricSink.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
using SharpHoundCommonLib.Models;

namespace SharpHoundCommonLib.Interfaces;

public interface IMetricSink {
void Observe(in MetricObservation.DoubleMetricObservation observation);
void Flush();
}
17 changes: 17 additions & 0 deletions src/CommonLib/Interfaces/IMetricWriter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
using System;
using System.Text;
using SharpHoundCommonLib.Models;
using SharpHoundCommonLib.Services;

namespace SharpHoundCommonLib.Interfaces;

public interface IMetricWriter {
void StringBuilderAppendMetric(
StringBuilder builder,
MetricDefinition definition,
LabelValues labelValues,
MetricAggregator aggregator,
DateTimeOffset timestamp,
string timestampOutputString = "yyyy-MM-dd HH:mm:ss.fff"
);
}
Loading
Loading