implement sentry transport to write crash reports to XDG_STATE_HOME

This commit is contained in:
Mitchell Hashimoto
2024-08-27 19:29:34 -07:00
parent e029490535
commit 2abdf291f4
5 changed files with 58 additions and 3 deletions

View File

@ -1004,6 +1004,7 @@ fn addDeps(
const sentry_dep = b.dependency("sentry", .{
.target = target,
.optimize = optimize,
.backend = .inproc,
});
const zlib_dep = b.dependency("zlib", .{
.target = target,

View File

@ -7,4 +7,12 @@ pub const Envelope = opaque {
pub fn deinit(self: *Envelope) void {
c.sentry_envelope_free(@ptrCast(self));
}
pub fn writeToFile(self: *Envelope, path: []const u8) !void {
if (c.sentry_envelope_write_to_file_n(
@ptrCast(self),
path.ptr,
path.len,
) != 0) return error.WriteFailed;
}
};

View File

@ -6,6 +6,10 @@ const c = @import("c.zig").c;
pub const UUID = struct {
value: c.sentry_uuid_t,
pub fn init() UUID {
return .{ .value = c.sentry_uuid_new_v4() };
}
pub fn isNil(self: UUID) bool {
return c.sentry_uuid_is_nil(&self.value) != 0;
}

View File

@ -37,6 +37,15 @@ pub fn cache(alloc: Allocator, opts: Options) ![]u8 {
});
}
/// Get the XDG state directory. The returned value is allocated.
pub fn state(alloc: Allocator, opts: Options) ![]u8 {
return try dir(alloc, opts, .{
.env = "XDG_STATE_HOME",
.windows_env = "LOCALAPPDATA",
.default_subdir = ".local/state",
});
}
const InternalOptions = struct {
env: []const u8,
windows_env: []const u8,

View File

@ -4,6 +4,7 @@ const Allocator = std.mem.Allocator;
const build_config = @import("build_config.zig");
const sentry = @import("sentry");
const internal_os = @import("os/main.zig");
const state = &@import("global.zig").state;
const log = std.log.scoped(.sentry);
@ -61,10 +62,42 @@ pub fn deinit() void {
}
pub const Transport = struct {
pub fn send(envelope: *sentry.Envelope, state: ?*anyopaque) callconv(.C) void {
_ = state;
pub fn send(envelope: *sentry.Envelope, ud: ?*anyopaque) callconv(.C) void {
_ = ud;
defer envelope.deinit();
log.warn("sending envelope", .{});
// Call our internal impl. If it fails there is nothing we can do
// but log to the user.
sendInternal(envelope) catch |err| {
log.warn("failed to persist crash report err={}", .{err});
};
}
/// Implementation of send but we can use Zig errors.
fn sendInternal(envelope: *sentry.Envelope) !void {
var arena = std.heap.ArenaAllocator.init(state.alloc);
defer arena.deinit();
const alloc = arena.allocator();
// Generate a UUID for this envelope. The envelope DOES have an event_id
// header but I don't think there is any public API way to get it
// afaict so we generate a new UUID for the filename just so we don't
// conflict.
const uuid = sentry.UUID.init();
// Get our XDG state directory where we'll store the crash reports.
// This directory must exist for writing to work.
const crash_dir = try internal_os.xdg.state(alloc, .{ .subdir = "ghostty/crash" });
try std.fs.cwd().makePath(crash_dir);
// Build our final path and write to it.
const path = try std.fs.path.join(alloc, &.{
crash_dir,
try std.fmt.allocPrint(alloc, "{s}.ghosttycrash", .{uuid.string()}),
});
log.debug("writing crash report to disk path={s}", .{path});
try envelope.writeToFile(path);
log.warn("crash report written to disk path={s}", .{path});
}
};