diff --git a/src/st/http.zig b/src/st/http.zig --- a/src/st/http.zig +++ b/src/st/http.zig @@ -198,6 +198,12 @@ http: HTTPClient, + // Stats + total_requests: std.atomic.Value(u64) = .init(0), + successful_requests: std.atomic.Value(u64) = .init(0), + total_latency: std.atomic.Value(u64) = .init(0), + average_latency: std.atomic.Value(u64) = .init(0), + pub fn init( allocator: std.mem.Allocator, io: std.Io, @@ -274,6 +280,8 @@ log.debug("requesting: {s}", .{uri.path.percent_encoded}); + const start: ?Io.Timestamp = Io.Clock.now(.real, client.io) catch null; + switch (opts.body) { .empty => try req.sendBodiless(), .buffer => |body| try req.sendBodyComplete(body), @@ -289,6 +297,27 @@ break :blk "\x1b[1m\x1b[91m"; } }; + + _ = client.total_requests.fetchAdd(1, .seq_cst); + + if (start) |s| blk: { + const latency: u64 = @intCast(s.durationTo(Io.Clock.now(.real, client.io) catch break :blk).toMilliseconds()); + const old_average = client.average_latency.load(.seq_cst); + var new_average: u64 = 0; + + if (old_average == 0) { + new_average = latency; + } else { + const total_reqs = client.total_requests.load(.seq_cst); + new_average = old_average * (total_reqs - 1) / total_reqs + latency / total_reqs; + } + + client.average_latency.store(new_average, .seq_cst); + _ = client.total_latency.fetchAdd(latency, .seq_cst); + + log.debug("latency: {} ms - average: {}ms", .{ latency, new_average }); + } + log.debug( "\x1b[2m[path = {s}]\x1b[0m received {s}{d} {s}\x1b[0m", .{ url[client.base_url.len..], colour, response.head.status, response.head.reason }, @@ -308,11 +337,20 @@ var json_reader: json.Reader = .init(client.allocator, decompressed_body_reader); defer json_reader.deinit(); - return json.parseFromTokenSource(T, client.allocator, &json_reader, .{ + const result = json.parseFromTokenSource(T, client.allocator, &json_reader, .{ .ignore_unknown_fields = true, }) catch |err| { - log.err("Error parsing response: {}", .{err}); + const body_reader = response.readerDecompressing(&transfer_buffer, &decompress, &decompress_buffer); + const body = body_reader.allocRemaining(client.allocator, .unlimited) catch return error.InvalidResponse; + defer client.allocator.free(body); + + log.err("Error parsing response: {} - Body:\n{s}", .{ err, body }); + return RequestError.InvalidResponse; }; + + _ = client.successful_requests.fetchAdd(1, .seq_cst); + + return result; } };