authorgravatar for hello@nektro.netMeghan Denny <hello@nektro.net> 2026-05-01 23:55:37 -07:00
committergravatar for hello@nektro.netMeghan Denny <hello@nektro.net> 2026-05-01 23:55:37 -07:00
loga420cb6394c1a660501375a6f0111920a0bbd9b1
treef9d11b37b57ac5937c4111781d6ad131aec9dfcc
parent6f1f461e2941d0e1114fdcbdeac5fa06d681dafa
signaturebadge-check Signed by SSH key SHA256:4hHJbtBRU58AYXwjL7fkz2fnQHdiye8x1QpTCQ0sHNw

otel: add more attributes and docs


1 files changed, 71 insertions(+), 3 deletions(-)

src/otel.zig+71-3
......@@ -16,14 +16,38 @@ const sys = switch (builtin.target.os.tag) {
1616// export OTEL_EXPORTER_OTLP_ENDPOINT=http://127.0.0.1:4318
1717// export OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=http://localhost:4318/v1/traces
1818
19// https://opentelemetry.io/docs/specs/otlp/
20// https://protobuf.dev/programming-guides/encoding/
1921// https://github.com/open-telemetry/opentelemetry-proto/tree/v1.10.0/opentelemetry/proto
2022
23var etc_os_release: []const u8 = "";
24var @"os.version": ?[]const u8 = null;
25var @"os.name": ?[]const u8 = null;
26
2127pub fn init(args: struct {}) !void {
2228 _ = args;
29 const file = try nfs.cwd().openFile("/etc/os-release", .{});
30 defer file.close();
31 etc_os_release = try file.mmap();
32 var iter = std.mem.splitScalar(u8, etc_os_release, '\n');
33 iter.index = 0;
34 while (iter.next()) |line| {
35 if (extras.trimPrefixEnsure(line, "VERSION_ID=")) |val| {
36 @"os.version" = std.mem.trim(u8, val, &.{'"'});
37 break;
38 }
39 }
40 iter.index = 0;
41 while (iter.next()) |line| {
42 if (extras.trimPrefixEnsure(line, "NAME=")) |val| {
43 @"os.name" = std.mem.trim(u8, val, &.{'"'});
44 break;
45 }
46 }
2347}
2448
2549pub fn deinit() void {
26 _ = {};
50 nfs.munmap(etc_os_release);
2751}
2852
2953threadlocal var allocator: std.mem.Allocator = undefined;
......@@ -32,6 +56,16 @@ threadlocal var trace_id: [16]u8 = undefined;
3256threadlocal var prev_span_id: ?[8]u8 = undefined;
3357threadlocal var spans: std.ArrayListUnmanaged([]const u8) = .empty;
3458
59pub var @"service.version": ?[]const u8 = null;
60pub var @"server.address": ?[]const u8 = null;
61pub var @"server.port": ?u16 = null;
62pub threadlocal var @"http.request.method": ?[]const u8 = null;
63pub threadlocal var @"http.response.status_code": ?u16 = null;
64pub threadlocal var @"http.route": ?[]const u8 = null;
65
66pub threadlocal var @"url.path": ?[]const u8 = null;
67pub threadlocal var @"url.query": ?[]const u8 = null;
68
3569pub fn init_thread(args: struct { std.mem.Allocator, std.Uri }) !void {
3670 allocator, traces_endpoint = args;
3771 trace_id = extras.randomBytes(16);
......@@ -73,7 +107,15 @@ fn deinit_thread_inner() !void {
73107 .@"telemetry.sdk.version" = "(hash)",
74108 .@"telemetry.sdk.language" = "zig",
75109 .@"service.name" = root.otel_service_name,
110 .@"service.version" = @"service.version",
76111 .@"os.type" = "linux",
112 .@"os.version" = @"os.version",
113 .@"os.name" = @"os.name",
114 .@"server.address" = @"server.address",
115 .@"server.port" = @"server.port",
116 .@"http.request.method" = @"http.request.method",
117 .@"http.response.status_code" = @"http.response.status_code",
118 .@"http.route" = @"http.route",
77119 });
78120 try writef_varint(w, 2, 0);
79121 }
......@@ -149,6 +191,7 @@ fn trace_end_inner(ctx: tracer.Ctx) !void {
149191 try writef_varint(w, 6, 2);
150192 try writef_i64(w, 7, (ctx.data.time_start_ns));
151193 try writef_i64(w, 8, @intCast(time.nanoTimestamp()));
194 if (ctx.data.parent_id == null) try writef_kv(w, 9, .{ .@"url.path" = @"url.path", .@"url.query" = @"url.query" });
152195 try spans.append(allocator, temp.items);
153196}
154197
......@@ -227,10 +270,13 @@ fn writef_kv(w: anytype, nr: u64, kvs: anytype) !void {
227270 defer temp2.deinit(allocator);
228271 const y = temp2.writer(allocator);
229272
230 inline for (comptime std.meta.fields(@TypeOf(kvs))) |field| {
273 inline for (comptime std.meta.fields(@TypeOf(kvs))) |field| blk: {
274 const value = @field(kvs, field.name);
275 if (@typeInfo(@TypeOf(value)) == .optional and value == null) break :blk;
276
231277 try writef_string(x, 1, field.name);
232278
233 try writef_string(y, 1, @field(kvs, field.name));
279 try writef_kv_v(y, value);
234280 try writef_len(x, 2, temp2.items.len);
235281 try x.writeAll(temp2.items);
236282 temp2.clearRetainingCapacity();
......@@ -240,6 +286,28 @@ fn writef_kv(w: anytype, nr: u64, kvs: anytype) !void {
240286 temp.clearRetainingCapacity();
241287 }
242288}
289fn writef_kv_v(w: anytype, v: anytype) !void {
290 const V = @TypeOf(v);
291 const info = @typeInfo(V);
292 if (info == .optional) {
293 if (v == null) return;
294 return writef_kv_v(w, v.?);
295 }
296 if (comptime extras.isZigString(V)) {
297 return writef_string(w, 1, v);
298 }
299 if (info == .bool) {
300 return write_varint(w, 2, @intFromBool(v));
301 }
302 if (info == .int) {
303 return writef_varint(w, 3, v);
304 }
305 if (info == .float) {
306 return writef_i64(w, 4, @bitCast(v));
307 }
308 @compileLog(v);
309 comptime unreachable;
310}
243311
244312fn writef_i64(w: anytype, nr: u64, i: u64) !void {
245313 try write_tag(w, nr, .i64);