logfire client for zig
at main 103 lines 3.5 kB view raw
1//! otel-zig OTLP export test 2//! 3//! tests that otel-zig's OTLP exporter works with logfire endpoint. 4//! 5//! run with: 6//! LOGFIRE_TOKEN=your_token zig build otel-test 7//! 8//! this validates phase 1 of the otel-zig adoption plan. 9 10const std = @import("std"); 11const otel = @import("otel"); 12const otel_api = otel.api; 13const otel_sdk = otel.sdk; 14const otel_exporters = otel.exporters; 15 16pub fn main() !void { 17 var gpa = std.heap.GeneralPurposeAllocator(.{}){}; 18 defer _ = gpa.deinit(); 19 const allocator = gpa.allocator(); 20 21 // get logfire token and endpoint from env 22 const token = std.posix.getenv("LOGFIRE_WRITE_TOKEN") orelse 23 std.posix.getenv("LOGFIRE_TOKEN") orelse { 24 std.debug.print("LOGFIRE_TOKEN not set, skipping OTLP test\n", .{}); 25 return; 26 }; 27 28 // determine endpoint from token region 29 const endpoint = getEndpointFromToken(token); 30 std.debug.print("using endpoint: {s}\n", .{endpoint}); 31 32 // build authorization header 33 var auth_header_buf: [256]u8 = undefined; 34 const auth_value = std.fmt.bufPrint(&auth_header_buf, "Bearer {s}", .{token}) catch { 35 std.debug.print("token too long\n", .{}); 36 return; 37 }; 38 39 // configure OTLP exporter for logfire 40 const otlp_config = otel_exporters.otlp.OtlpExporterConfig{ 41 .endpoint = endpoint, 42 .transport = .http_protobuf, 43 .headers = &[_]std.http.Header{ 44 .{ .name = "Authorization", .value = auth_value }, 45 }, 46 }; 47 48 // set up trace provider with OTLP exporter 49 const provider = try otel_sdk.trace.setupGlobalProvider( 50 allocator, 51 .{otel_sdk.trace.BasicSpanProcessor.PipelineStep.init({}) 52 .flowTo(otel_exporters.otlp.OtlpTraceExporter.PipelineStep.init(otlp_config))}, 53 ); 54 defer { 55 provider.deinit(); 56 provider.destroy(); 57 } 58 defer otel_api.provider_registry.unsetAllProviders(); 59 60 // get tracer 61 const scope = otel_api.InstrumentationScope{ 62 .name = "logfire-zig-otel-test", 63 .version = "0.1.0", 64 }; 65 var tracer = try otel_api.getGlobalTracerProvider().getTracerWithScope(scope); 66 67 // create a test span 68 const ctx = &[_]otel_api.ContextKeyValue{}; 69 var span_result = try tracer.startSpan("otel-zig-test-span", .{ 70 .kind = .internal, 71 .attributes = &[_]otel_api.common.AttributeKeyValue{ 72 .{ .key = "test.source", .value = .{ .string = "logfire-zig" } }, 73 .{ .key = "test.type", .value = .{ .string = "otel-adoption-validation" } }, 74 }, 75 }, ctx); 76 77 // simulate some work 78 std.posix.nanosleep(0, 50 * std.time.ns_per_ms); 79 80 // end span (triggers export) 81 span_result.end(null); 82 span_result.deinit(); 83 84 std.debug.print("span exported successfully!\n", .{}); 85 std.debug.print("check logfire dashboard for 'otel-zig-test-span'\n", .{}); 86} 87 88/// extract region from logfire token and return base OTLP endpoint 89/// note: otel-zig appends /v1/traces path automatically 90fn getEndpointFromToken(token: []const u8) []const u8 { 91 // token format: pylf_v{version}_{region}_{token} 92 if (std.mem.startsWith(u8, token, "pylf_v")) { 93 var it = std.mem.splitScalar(u8, token, '_'); 94 _ = it.next(); // pylf 95 _ = it.next(); // v1 96 if (it.next()) |region| { 97 if (std.mem.eql(u8, region, "eu")) { 98 return "https://logfire-eu.pydantic.dev:443"; 99 } 100 } 101 } 102 return "https://logfire-us.pydantic.dev:443"; 103}