lib/tracy/src/report.zig
daab053ee43316e1809a84551d573ddd1e5bf3d2
1 const std = @import("std");
2 const sys = @import("sys");
3
4 pub fn writeFromJsonlPath(
5 comptime Analyzer: type,
6 comptime write: anytype,
7 allocator: std.mem.Allocator,
8 path: []const u8,
9 writer: *std.Io.Writer,
10 options: anytype,
11 ) !void {
12 var analyzer = Analyzer.init(allocator);
13 defer analyzer.deinit();
14 try ingestJsonlPath(&analyzer, path);
15 try write(allocator, &analyzer, writer, options);
16 }
17
18 pub fn ingestJsonlPath(analyzer: anytype, path: []const u8) !void {
19 var file = try sys.fs.cwd().openFile(sys.fs.debugIo(), path, .{});
20 defer file.close(sys.fs.debugIo());
21
22 var buffer: [64 * 1024]u8 = undefined;
23 var reader = file.reader(sys.fs.debugIo(), &buffer);
24 while (true) {
25 const line = reader.interface.takeDelimiter('\n') catch |err| switch (err) {
26 error.ReadFailed => return reader.err.?,
27 else => return err,
28 };
29 const actual = line orelse break;
30 try analyzer.ingestJsonLine(actual);
31 }
32 }
33
34 test "report ingests JSONL path and writes through analyzer" {
35 const allocator = std.testing.allocator;
36 var tmp = std.testing.tmpDir(.{});
37 defer tmp.cleanup();
38
39 const root = try tmp.parent_dir.realPathFileAlloc(sys.fs.debugIo(), tmp.sub_path[0..], allocator);
40 defer allocator.free(root);
41 const path = try std.fs.path.join(allocator, &.{ root, "trace.jsonl" });
42 defer allocator.free(path);
43 try sys.fs.cwd().writeFile(sys.fs.debugIo(), .{ .sub_path = path, .data = "one\ntwo\n" });
44
45 var out = std.Io.Writer.Allocating.init(allocator);
46 defer out.deinit();
47 try writeFromJsonlPath(TestAnalyzer, writeTestAnalyzer, allocator, path, &out.writer, {});
48 try std.testing.expectEqualStrings("lines=2 first=one", out.written());
49 }
50
51 const TestAnalyzer = struct {
52 allocator: std.mem.Allocator,
53 lines: std.ArrayListUnmanaged([]u8) = .empty,
54
55 pub fn init(allocator: std.mem.Allocator) TestAnalyzer {
56 return .{ .allocator = allocator };
57 }
58
59 pub fn deinit(self: *TestAnalyzer) void {
60 for (self.lines.items) |line| self.allocator.free(line);
61 self.lines.deinit(self.allocator);
62 }
63
64 pub fn ingestJsonLine(self: *TestAnalyzer, line: []const u8) !void {
65 try self.lines.append(self.allocator, try self.allocator.dupe(u8, line));
66 }
67 };
68
69 fn writeTestAnalyzer(
70 allocator: std.mem.Allocator,
71 analyzer: *TestAnalyzer,
72 writer: *std.Io.Writer,
73 _: void,
74 ) !void {
75 _ = allocator;
76 try writer.print("lines={d} first={s}", .{ analyzer.lines.items.len, analyzer.lines.items[0] });
77 }