Skip to content
Draft
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
5 changes: 5 additions & 0 deletions DevProxy.Abstractions/Plugins/BasePlugin.cs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,11 @@ public virtual Task AfterRequestLogAsync(RequestLogArgs e, CancellationToken can
return Task.CompletedTask;
}

public virtual Task AfterRecordingStartAsync(EventArgs e, CancellationToken cancellationToken)
{
return Task.CompletedTask;
}

public virtual Task AfterRecordingStopAsync(RecordingArgs e, CancellationToken cancellationToken)
{
return Task.CompletedTask;
Expand Down
1 change: 1 addition & 0 deletions DevProxy.Abstractions/Plugins/IPlugin.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ public interface IPlugin
Task BeforeResponseAsync(ProxyResponseArgs e, CancellationToken cancellationToken);
Task AfterResponseAsync(ProxyResponseArgs e, CancellationToken cancellationToken);
Task AfterRequestLogAsync(RequestLogArgs e, CancellationToken cancellationToken);
Task AfterRecordingStartAsync(EventArgs e, CancellationToken cancellationToken);
Task AfterRecordingStopAsync(RecordingArgs e, CancellationToken cancellationToken);
Task MockRequestAsync(EventArgs e, CancellationToken cancellationToken);
}
Expand Down
21 changes: 19 additions & 2 deletions DevProxy.Plugins/Inspection/OpenAITelemetryPlugin.cs
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,9 @@ public sealed class OpenAITelemetryPlugin(
private LanguageModelPricesLoader? _loader;
private MeterProvider? _meterProvider;
private TracerProvider? _tracerProvider;

private readonly ConcurrentDictionary<string, List<OpenAITelemetryPluginReportModelUsageInformation>> _modelUsage = [];
private bool _isRecording;

public override string Name => nameof(OpenAITelemetryPlugin);

Expand Down Expand Up @@ -192,6 +194,16 @@ public override Task AfterResponseAsync(ProxyResponseArgs e, CancellationToken c
return Task.CompletedTask;
}

public override Task AfterRecordingStartAsync(EventArgs e, CancellationToken cancellationToken)
{
Logger.LogTrace("{Method} called", nameof(AfterRecordingStartAsync));

_isRecording = true;

Logger.LogTrace("Left {Name}", nameof(AfterRecordingStartAsync));
return Task.CompletedTask;
}

public override Task AfterRecordingStopAsync(RecordingArgs e, CancellationToken cancellationToken)
{
Logger.LogTrace("{Method} called", nameof(AfterRecordingStopAsync));
Expand All @@ -206,6 +218,7 @@ public override Task AfterRecordingStopAsync(RecordingArgs e, CancellationToken
};

StoreReport(report, e);
_isRecording = false;
_modelUsage.Clear();

Logger.LogTrace("Left {Name}", nameof(AfterRecordingStopAsync));
Expand Down Expand Up @@ -856,8 +869,12 @@ private void RecordUsageMetrics(Activity activity, OpenAIRequest request, OpenAI
CompletionTokens = usage.CompletionTokens,
CachedTokens = usage.PromptTokensDetails?.CachedTokens ?? 0L
};
var usagePerModel = _modelUsage.GetOrAdd(response.Model, model => []);
usagePerModel.Add(reportModelUsageInformation);

if (_isRecording)
{
var usagePerModel = _modelUsage.GetOrAdd(response.Model, model => []);
usagePerModel.Add(reportModelUsageInformation);
}

if (!Configuration.IncludeCosts || Configuration.Prices is null)
{
Expand Down
2 changes: 1 addition & 1 deletion DevProxy/ApiControllers/ProxyController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ public async Task<IActionResult> SetAsync([FromBody] ProxyInfo proxyInfo, Cancel
{
if (proxyInfo.Recording.Value)
{
_proxyStateController.StartRecording();
await _proxyStateController.StartRecordingAsync(cancellationToken);
}
else
{
Expand Down
2 changes: 1 addition & 1 deletion DevProxy/Proxy/IProxyStateController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ public interface IProxyStateController
#pragma warning restore CA1515
{
IProxyState ProxyState { get; }
void StartRecording();
Task StartRecordingAsync(CancellationToken cancellationToken);
Task StopRecordingAsync(CancellationToken cancellationToken);
Task MockRequestAsync(CancellationToken cancellationToken);
void StopProxy();
Expand Down
8 changes: 4 additions & 4 deletions DevProxy/Proxy/ProxyEngine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ protected override async Task ExecuteAsync(CancellationToken stoppingToken)

if (_config.Record)
{
StartRecording();
await StartRecordingAsync(stoppingToken);
}

if (_config.TimeoutSeconds.HasValue)
Expand Down Expand Up @@ -210,7 +210,7 @@ private async Task ReadKeysAsync(CancellationToken cancellationToken)
#pragma warning restore IDE0010
{
case ConsoleKey.R:
StartRecording();
await StartRecordingAsync(cancellationToken);
break;
case ConsoleKey.S:
await StopRecordingAsync(cancellationToken);
Expand All @@ -225,14 +225,14 @@ private async Task ReadKeysAsync(CancellationToken cancellationToken)
}
}

private void StartRecording()
private async Task StartRecordingAsync(CancellationToken cancellationToken)
{
if (_proxyController.ProxyState.IsRecording)
{
return;
}

_proxyController.StartRecording();
await _proxyController.StartRecordingAsync(cancellationToken);
}

private async Task StopRecordingAsync(CancellationToken cancellationToken)
Expand Down
17 changes: 15 additions & 2 deletions DevProxy/Proxy/ProxyStateController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ sealed class ProxyStateController(
private readonly ILogger _logger = logger;
private ExceptionHandler ExceptionHandler => ex => _logger.LogError(ex, "An error occurred in a plugin");

public void StartRecording()
public async Task StartRecordingAsync(CancellationToken cancellationToken)
{
if (ProxyState.IsRecording)
{
Expand All @@ -32,6 +32,19 @@ public void StartRecording()

ProxyState.IsRecording = true;
PrintRecordingIndicator(ProxyState.IsRecording);

var eventArgs = EventArgs.Empty;
foreach (var plugin in _plugins.Where(p => p.Enabled))
{
try
{
await plugin.AfterRecordingStartAsync(eventArgs, cancellationToken);
}
catch (Exception ex)
{
ExceptionHandler(ex);
}
}
}

public async Task StopRecordingAsync(CancellationToken cancellationToken)
Expand Down Expand Up @@ -69,7 +82,7 @@ public async Task StopRecordingAsync(CancellationToken cancellationToken)

public async Task MockRequestAsync(CancellationToken cancellationToken)
{
var eventArgs = new EventArgs();
var eventArgs = EventArgs.Empty;

foreach (var plugin in _plugins.Where(p => p.Enabled))
{
Expand Down