Skip to content

Commit 947eb40

Browse files
Make OpenAI usage logging more robust by safely parsing headers
- Use DateTime.TryParse for the response Date header and fall back to DateTime.Now when missing/invalid. - Extract TryParseHeaderAsLong helper to centralize/parsing of numeric headers. - Replace inline parsing for x-ratelimit-remaining-tokens and x-ratelimit-remaining-requests with the new helper. - Add missing using for Titanium.Web.Proxy.Http.
1 parent 2c917b2 commit 947eb40

File tree

1 file changed

+24
-3
lines changed

1 file changed

+24
-3
lines changed

DevProxy.Plugins/Inspection/OpenAIUsageDebuggingPlugin.cs

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
using Microsoft.Extensions.Logging;
1111
using System.Globalization;
1212
using System.Text.Json;
13+
using Titanium.Web.Proxy.Http;
1314

1415
namespace DevProxy.Plugins.Inspection;
1516

@@ -98,7 +99,13 @@ public override async Task AfterResponseAsync(ProxyResponseArgs e, CancellationT
9899

99100
var usage = new UsageRecord
100101
{
101-
Time = DateTime.Parse(e.Session.HttpClient.Response.Headers.FirstOrDefault(h => h.Name.Equals("date", StringComparison.OrdinalIgnoreCase))?.Value ?? DateTime.Now.ToString(CultureInfo.InvariantCulture), CultureInfo.InvariantCulture),
102+
Time = DateTime.TryParse(
103+
e.Session.HttpClient.Response.Headers.FirstOrDefault(h => h.Name.Equals("date", StringComparison.OrdinalIgnoreCase))?.Value,
104+
CultureInfo.InvariantCulture,
105+
DateTimeStyles.None,
106+
out var parsedDate)
107+
? parsedDate
108+
: DateTime.Now,
102109
Status = e.Session.HttpClient.Response.StatusCode
103110
};
104111

@@ -136,8 +143,8 @@ private void ProcessSuccessResponse(string responseBody, UsageRecord usage, Prox
136143
usage.CompletionTokens = oaiResponse.Usage?.CompletionTokens;
137144
usage.CachedTokens = oaiResponse.Usage?.PromptTokensDetails?.CachedTokens;
138145
usage.TotalTokens = oaiResponse.Usage?.TotalTokens;
139-
usage.RemainingTokens = response.Headers.FirstOrDefault(h => h.Name.Equals("x-ratelimit-remaining-tokens", StringComparison.OrdinalIgnoreCase))?.Value is string remainingTokensStr && long.TryParse(remainingTokensStr, out var remainingTokens) ? remainingTokens : null;
140-
usage.RemainingRequests = response.Headers.FirstOrDefault(h => h.Name.Equals("x-ratelimit-remaining-requests", StringComparison.OrdinalIgnoreCase))?.Value is string remainingRequestsStr && long.TryParse(remainingRequestsStr, out var remainingRequests) ? remainingRequests : null;
146+
usage.RemainingTokens = TryParseHeaderAsLong(response, "x-ratelimit-remaining-tokens", out var remainingTokens) ? remainingTokens : null;
147+
usage.RemainingRequests = TryParseHeaderAsLong(response, "x-ratelimit-remaining-requests", out var remainingRequests) ? remainingRequests : null;
141148

142149
Logger.LogTrace("Left {Name}", nameof(ProcessSuccessResponse));
143150
}
@@ -152,4 +159,18 @@ private void ProcessErrorResponse(UsageRecord usage, ProxyResponseArgs e)
152159

153160
Logger.LogTrace("Left {Name}", nameof(ProcessErrorResponse));
154161
}
162+
163+
private static bool TryParseHeaderAsLong(Response response, string headerName, out long? value)
164+
{
165+
value = null;
166+
var header = response.Headers.FirstOrDefault(h => h.Name.Equals(headerName, StringComparison.OrdinalIgnoreCase))?.Value;
167+
168+
if (header is not null && long.TryParse(header, out var parsedValue))
169+
{
170+
value = parsedValue;
171+
return true;
172+
}
173+
174+
return false;
175+
}
155176
}

0 commit comments

Comments
 (0)