logfire client for zig
at main 168 lines 5.0 kB view raw view rendered
1# logfire-zig 2 3unofficial Zig SDK for [Pydantic Logfire](https://logfire.pydantic.dev/) - built on [otel-zig](https://github.com/open-telemetry/opentelemetry-zig) for OTLP/protobuf export. 4 5aiming for parity with [logfire-rust](https://github.com/pydantic/logfire-rust). 6 7see also: 8- [Logfire documentation](https://logfire.pydantic.dev/docs/) 9- [alternative clients guide](https://logfire.pydantic.dev/docs/how-to-guides/alternative-clients/) for OTLP protocol details 10 11## Using logfire-zig 12 13First [set up a Logfire project](https://logfire.pydantic.dev/docs/#logfire). Configure the SDK by [creating a write token](https://logfire.pydantic.dev/docs/how-to-guides/create-write-tokens/) and setting it as an environment variable (`LOGFIRE_WRITE_TOKEN` or `LOGFIRE_TOKEN`). 14 15Add to your `build.zig.zon`: 16 17```zig 18.dependencies = .{ 19 .logfire = .{ 20 .url = "https://tangled.sh/zzstoatzz.io/logfire-zig/archive/main", 21 .hash = "...", // zig build will tell you the hash 22 }, 23}, 24``` 25 26Add to your `build.zig`: 27 28```zig 29const logfire = b.dependency("logfire", .{ 30 .target = target, 31 .optimize = optimize, 32}); 33exe.root_module.addImport("logfire", logfire.module("logfire")); 34``` 35 36Then instrument your code: 37 38```zig 39const std = @import("std"); 40const logfire = @import("logfire"); 41 42pub fn main() !void { 43 const lf = try logfire.configure(.{ 44 .service_name = "my-service", 45 }); 46 defer lf.shutdown(); 47 48 // structured logging (console output) 49 logfire.info("application started", .{}); 50 51 // spans for timing operations (exported to Logfire) 52 { 53 const span = logfire.span("process.files", .{}); 54 defer span.end(); 55 56 // nested spans automatically link to parent 57 { 58 const child = logfire.span("process.single_file", .{ .filename = "data.csv" }); 59 defer child.end(); 60 std.time.sleep(10 * std.time.ns_per_ms); 61 } 62 } 63 64 // flush before exit 65 try lf.flush(); 66} 67``` 68 69Run with your token: 70 71```bash 72LOGFIRE_WRITE_TOKEN=pylf_v1_us_xxx zig build run 73``` 74 75Without a token, output goes to console for local development. 76 77## Features 78 79- **Spans** - timing and tracing with attributes, automatic parent-child linking 80- **Instrumentation helpers** - `httpSpan()` and `sqlSpan()` for common patterns 81- **Async batched export** - BatchSpanProcessor exports every 500ms (matches Python/Rust) 82- **Logging** - trace, debug, info, warn, err (console output) 83- **OTLP Export** - HTTP/protobuf via otel-zig to Logfire or any OTLP-compatible backend 84- **Zero Config** - reads token and endpoint from environment 85- **Cross-platform** - works on macOS and Linux 86 87## API 88 89```zig 90// configuration 91const lf = try logfire.configure(.{ 92 .service_name = "my-service", 93 .service_version = "1.0.0", 94}); 95defer lf.shutdown(); 96 97// spans (exported to Logfire via OTLP/protobuf) 98const span = logfire.span("operation.name", .{ 99 .user_id = @as(i64, 123), 100 .request_path = "/api/search", 101}); 102defer span.end(); 103 104// add attributes after creation 105span.setAttribute("result_count", @as(i64, 42)); 106 107// record errors (sets error status + adds exception event) 108span.recordError(error.ConnectionFailed); 109 110// instrumentation helpers for common patterns 111const http_span = logfire.httpSpan("GET", "/api/users", .{}); 112defer http_span.end(); 113// creates span named "HTTP GET /api/users" with http.request.method and url.path attrs 114 115const db_span = logfire.sqlSpan("SELECT * FROM users WHERE id = ?", "postgresql"); 116defer db_span.end(); 117// creates span with truncated SQL name and db.system attribute 118 119// logging (console output only for now) 120logfire.trace("detailed trace", .{}); 121logfire.debug("debug info", .{}); 122logfire.info("something happened", .{}); 123logfire.warn("warning message", .{}); 124logfire.err("error occurred", .{}); 125 126// manual flush 127try lf.flush(); 128``` 129 130## Environment Variables 131 132| Variable | Description | 133|----------|-------------| 134| `LOGFIRE_WRITE_TOKEN` | Write token (preferred) | 135| `LOGFIRE_TOKEN` | Write token (fallback) | 136| `LOGFIRE_SERVICE_NAME` | Service name override | 137| `OTEL_EXPORTER_OTLP_ENDPOINT` | Custom OTLP endpoint | 138 139## Requirements 140 141- Zig 0.15+ 142 143## Development 144 145```bash 146zig build test # run tests 147zig build example # run example 148``` 149 150## Status 151 152This is an unofficial community SDK aiming for parity with [logfire-rust](https://github.com/pydantic/logfire-rust). Built on [otel-zig](https://github.com/open-telemetry/opentelemetry-zig). 153 154- [x] Spans with attributes 155- [x] Parent-child span linking (thread-local context) 156- [x] Error recording (`span.recordError()`) 157- [x] OTLP HTTP/protobuf export 158- [x] Async batched export (500ms interval, matches Python/Rust) 159- [x] Environment-based configuration 160- [x] Instrumentation helpers (`httpSpan`, `sqlSpan`) 161- [x] Cross-platform (macOS + Linux) 162- [ ] Structured logging export (console only, OTLP TODO) 163- [ ] Metrics (API stubs, implementation TODO) 164- [ ] W3C trace context propagation (cross-service) 165 166## License 167 168MIT