logfire client for zig
1# logfire-zig
2
3zig 0.15+ SDK for pydantic logfire - OTLP HTTP/JSON export for traces, logs, metrics.
4
5## goal
6
7**full parity with logfire-rust client.** not simpler, not "good enough" - parity.
8
9## reference projects
10
11look at these for patterns, don't reinvent:
12
13- `~/tangled.sh/@zzstoatzz.io/prefect-server/` - zig 0.15 http server, json handling
14- `~/tangled.sh/@zzstoatzz.io/zat/` - zig 0.15 AT Protocol client
15- `~/tangled.sh/@zzstoatzz.io/leaflet-search/` - zig backend patterns
16- `~/tangled.sh/@zzstoatzz.io/notes/languages/ziglang/0.15/` - zig 0.15 syntax notes
17
18## zig 0.15 patterns
19
20### JSON serialization - use std.json.Stringify
21
22**DO NOT manually concatenate JSON strings.** use the stdlib:
23
24```zig
25const json = std.json;
26
27fn buildJson(alloc: std.mem.Allocator, data: MyData) ![]u8 {
28 var output: std.Io.Writer.Allocating = .init(alloc);
29 var jw: json.Stringify = .{ .writer = &output.writer };
30
31 try jw.beginObject();
32 try jw.objectField("name");
33 try jw.write(data.name);
34 try jw.objectField("count");
35 try jw.write(data.count);
36 try jw.endObject();
37
38 return output.toOwnedSlice();
39}
40```
41
42for raw JSON passthrough:
43```zig
44try jw.beginWriteRaw();
45try jw.writer.writeAll(raw_json_string);
46jw.endWriteRaw();
47```
48
49### ArrayList (unmanaged in 0.15)
50
51pass allocator to each method:
52
53```zig
54var buf: std.ArrayList(u8) = .empty;
55defer buf.deinit(alloc);
56
57try buf.appendSlice(alloc, data);
58try buf.print(alloc, "{d}", .{value});
59
60// borrow: buf.items (don't hold after deinit)
61// transfer ownership: buf.toOwnedSlice(alloc)
62```
63
64### HTTP client
65
66```zig
67var client = std.http.Client{ .allocator = allocator };
68defer client.deinit();
69
70var aw: std.Io.Writer.Allocating = .init(allocator);
71defer aw.deinit();
72
73const result = client.fetch(.{
74 .location = .{ .url = url },
75 .response_writer = &aw.writer,
76 .method = .POST,
77 .payload = body,
78 .headers = .{
79 .content_type = .{ .override = "application/json" },
80 .accept_encoding = .{ .override = "identity" }, // disable gzip (bug in 0.15)
81 },
82}) catch return error.RequestFailed;
83```
84
85### env vars
86
87```zig
88const token = std.posix.getenv("LOGFIRE_WRITE_TOKEN") orelse
89 std.posix.getenv("LOGFIRE_TOKEN");
90```
91
92## testing
93
94```bash
95zig build test # run tests
96zig build example # run examples/basic.zig
97```
98
99test with real export requires LOGFIRE_WRITE_TOKEN in .env
100
101## rust client reference
102
103`gh api repos/pydantic/logfire-rust/contents/src` - check metrics.rs for API parity