Native Sentry SDK in Zig (0.15.2+) for capturing errors, transactions, sessions,
and monitor check-ins via the Sentry Envelope protocol.
This repository focuses on a clean public API, production-safe defaults, and predictable shutdown behavior.
Detailed guide: docs/USER_GUIDE.md
- README.md: install, architecture map, production bootstrap.
- docs/USER_GUIDE.md: full usage reference with advanced flows.
const std = @import("std");
const sentry = @import("sentry-zig");
pub fn main() !void {
const allocator = std.heap.page_allocator;
const client = try sentry.init(allocator, .{
.dsn = "https://PUBLIC_KEY@o0.ingest.sentry.io/PROJECT_ID",
.release = "my-app@1.0.0",
.environment = "production",
.traces_sample_rate = 1.0,
});
defer client.deinit();
client.captureMessage("Hello from Zig", .info);
_ = client.flush(5000);
}- Zig
>= 0.15.2
Version enforcement is explicit in three places:
build.zig.zon:.minimum_zig_version = "0.15.2"build.zig: compile-time guard (@compileError) for< 0.15.2src/sentry.zig: module-level compile-time guard (@compileError) for< 0.15.2
Add dependency:
zig fetch --save git+https://github.com/nullclaw/sentry-zig.gitFor reproducible production builds, pin to a release tag:
zig fetch --save https://github.com/nullclaw/sentry-zig/archive/refs/tags/v0.2.0.tar.gzImport module in build.zig:
const sentry_dep = b.dependency("sentry-zig", .{
.target = target,
.optimize = optimize,
});
exe.root_module.addImport("sentry-zig", sentry_dep.module("sentry-zig"));Sentry-Zig is consumed as a Zig dependency source package.
- You do not need to publish or preload SDK-specific binary artifacts.
- Your application CI/CD resolves the dependency (
zig fetch), compiles your app, and runs tests. - Release tags are used for deterministic builds.
Minimal CI checks:
zig build teston every pull request.zig build test-integrationin integration/staging pipelines.zig fmt --check .for formatting gate.
Example GitHub Actions workflow:
name: ci
on:
pull_request:
push:
branches: [main]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: mlugg/setup-zig@v2
with:
version: 0.15.2
- run: test "$(zig version)" = "0.15.2"
- run: zig build test
- run: zig build test-integration- Current stable release:
v0.2.0 - Versioning policy: Semantic Versioning (SemVer)
- Zig compatibility target:
>= 0.15.2(older Zig versions are out of scope) - Use release tags for pinned dependencies and deterministic builds.
Client: owns transport, worker queue, and runtime configuration.InitGuard: helper returned byinitGlobalthat binds/restores TLS Hub automatically.Scope: mutable event context (user, tags, extras, breadcrumbs, attachments).Hub: scope stack + thread-local current hub API for scoped captures.- Global helpers via current Hub:
captureMessage,captureException,captureError,captureCheckIn,startSession,endSession,flush,close,addBreadcrumb,pushScope,configureScope,withIntegration. Event: error/message payload (captureMessage,captureException,captureEvent).Transaction+Span: tracing payloads (startTransaction,finishTransaction).Session: release health lifecycle (startSession,endSession).MonitorCheckIn: cron monitor status payload (captureCheckIn).LogEntry: structured log payload (captureLogMessage,captureLog).
- Most mutating API calls have both forms:
- ergonomic (
setTag,addBreadcrumb,addAttachment) that never fail outwardly. - explicit fallible (
trySetTag,tryAddBreadcrumb,tryAddAttachment) for strict error handling.
- ergonomic (
- Use
try*methods when you want full control overOutOfMemoryand other allocation failures.
| Capability | Status | Notes |
|---|---|---|
| Event capture | Implemented | Message/exception/custom event capture, before-send filtering |
| Scope enrichment | Implemented | User/tags/extras/contexts/breadcrumbs/fingerprint/transaction |
| Attachments | Implemented | In-memory and file-backed attachments |
| Transactions & spans | Implemented | Sampling + trace context serialization |
| Event context bootstrap | Implemented | Captured events receive missing contexts.trace + runtime/os/device entries while preserving custom contexts |
| Transaction DSC envelope header | Implemented | Envelope header includes trace_id/public_key/sample_rate/sampled |
| Trace propagation headers | Implemented | sentry-trace/baggage generation + continuation from trace value, header pairs, or explicit propagation headers |
| Traces sampler callback | Implemented | traces_sampler has priority over traces_sample_rate |
| Sessions (application/request mode) | Implemented | Request mode disables duration tracking and emits aggregated sessions envelopes |
Session distinct id (did) |
Implemented | Derived from Scope.user (id/email/username) when available |
| Monitor check-ins | Implemented | check_in envelopes with env inheritance |
| Worker + queue draining | Implemented | Bounded queue + flush/close semantics |
| Transport rate limits | Implemented | Retry-After + X-Sentry-Rate-Limits parsing |
| Transport customization | Implemented | Custom transport callback + explicit HTTP/HTTPS proxy options + built-in transport_backends.file / transport_backends.fanout |
| Signal crash marker flow | Implemented | POSIX marker write/read cycle |
| Hub/TLS scope stack | Implemented | Push/pop scopes + TLS current hub helpers |
| Structured logs pipeline | Implemented | log envelope items + captureLogMessage API |
| Auto integration helpers | Implemented | Global init guard + std.log/panic/http inbound+outbound/error/runtime helper integrations + OTel traceparent helper API + std.http adapter |
| Extended integrations | Roadmap | Additional framework/runtime integrations will be added incrementally |
// Capture message
client.captureMessage("checkout failed", .err);
// Capture exception
client.captureException("PaymentError", "gateway timeout");
// Capture Zig error value
client.captureError(error.PaymentGatewayTimeout);
// Get event id when accepted
if (client.captureMessageId("degraded mode", .warning)) |event_id| {
std.log.warn("event_id={s}", .{event_id});
}
// Scope data
client.setUser(.{ .id = "user-42", .email = "user@example.com" });
client.setTag("feature", "checkout");
client.addBreadcrumb(.{ .category = "http", .message = "POST /checkout", .level = .info });
// Structured log
client.captureLogMessage("checkout started", .info);// Continue trace from incoming sentry-trace header
var txn = try client.startTransactionFromSentryTrace(
.{ .name = "GET /orders", .op = "http.server" },
"0123456789abcdef0123456789abcdef-89abcdef01234567-1",
);
defer txn.deinit();
// Propagate trace downstream
const sentry_trace = try client.sentryTraceHeader(&txn, allocator);
defer allocator.free(sentry_trace);
const baggage = try client.baggageHeader(&txn, allocator);
defer allocator.free(baggage);
// Variant that accepts both incoming headers
var txn2 = try client.startTransactionFromPropagationHeaders(
.{ .name = "GET /orders", .op = "http.server" },
incoming_sentry_trace,
incoming_baggage,
);
defer txn2.deinit();
const headers = [_]sentry.PropagationHeader{
.{ .name = "sentry-trace", .value = incoming_sentry_trace.? },
.{ .name = "baggage", .value = incoming_baggage.? },
};
var txn3 = client.startTransactionFromHeaders(
.{ .name = "GET /orders", .op = "http.server" },
&headers,
);
defer txn3.deinit();
// If sentry-trace is missing, traceparent is used as fallback automatically.
var txn4 = client.startTransactionFromSpan(
.{ .name = "GET /orders-fanout", .op = "worker" },
.{ .transaction = &txn2 },
);
defer txn4.deinit();
// Optional explicit start timestamp (seconds, unix epoch)
var timed_txn = client.startTransactionWithTimestamp(
.{ .name = "GET /orders-backdated", .op = "http.server" },
1704067200.125,
);
defer timed_txn.deinit();
var fixed_ids_txn = client.startTransaction(.{
.name = "GET /orders-fixed",
.op = "http.server",
.trace_id = "0123456789abcdef0123456789abcdef".*,
.span_id = "89abcdef01234567".*,
});
defer fixed_ids_txn.deinit();
// Optional explicit child-span details
const fixed_span = try timed_txn.startChildWithDetails(
.{ .op = "db.query", .description = "SELECT 1" },
"0123456789abcdef".*,
1704067200.250,
);
fixed_span.finishWithTimestamp(1704067200.500);
const nested_span = try fixed_span.startChild(.{
.op = "db.lock",
.description = "Acquire order lock",
});
nested_span.finish();
try timed_txn.setTag("flow", "checkout");
try timed_txn.setExtra("attempt", .{ .integer = 2 });
try timed_txn.setData("cache_hit", .{ .bool = true });
try timed_txn.setOrigin("auto.http");
try fixed_span.setTag("db.system", "postgresql");
try fixed_span.setData("rows", .{ .integer = 1 });
try timed_txn.setRequest(.{
.method = "POST",
.url = "https://api.example.com/orders",
});
try fixed_span.setRequest(.{
.method = "POST",
.url = "https://api.example.com/orders",
});
const trace_ctx = timed_txn.getTraceContext();
const span_trace_header = try fixed_span.sentryTraceHeaderAlloc(allocator);
defer allocator.free(span_trace_header);
// `sentry-sample_rate` from baggage is honored when transaction opts use default sample_rate.
// Third-party baggage members are preserved when generating downstream baggage headers.
// Parse incoming baggage directly (borrowed or decoded/owned variants)
const parsed_baggage = sentry.parseBaggage(incoming_baggage);
var parsed_baggage_owned = try sentry.parseBaggageAlloc(allocator, incoming_baggage);
defer parsed_baggage_owned.deinit();
const parsed_trace = sentry.parseHeaders(&headers);// Hub scope stack
var hub = try sentry.Hub.init(allocator, client);
defer hub.deinit();
try hub.pushScope();
defer _ = hub.popScope();
hub.setTag("flow", "checkout");
hub.captureMessage("scoped event", .info);
// Optional global API through TLS current hub
_ = sentry.setCurrentHub(&hub);
defer _ = sentry.clearCurrentHub();
_ = sentry.captureMessage("global scoped capture", .warning);// Global bootstrap that binds a Hub automatically (guard restores previous hub)
var guard = try sentry.initGlobal(allocator, .{
.dsn = "https://PUBLIC_KEY@o0.ingest.sentry.io/PROJECT_ID",
.install_signal_handlers = false,
});
defer guard.deinit();
// std.log integration helper (set this as std_options.logFn in your app root)
sentry.integrations.log.install(.{
.min_level = .info,
.forward_to_default_logger = true,
});// Env-default bootstrap: populate missing fields from SENTRY_* and proxy env vars.
// Use .dsn = "" to allow SENTRY_DSN to provide DSN.
const client = try sentry.initWithEnvDefaults(allocator, .{
.dsn = "",
.install_signal_handlers = false,
});
defer client.deinit();// One-call defaults bootstrap: built-in integrations + env defaults.
const client = try sentry.initWithDefaults(allocator, .{
.dsn = "https://PUBLIC_KEY@o0.ingest.sentry.io/PROJECT_ID",
.install_signal_handlers = false,
});
defer client.deinit();// Global one-call defaults bootstrap: binds current hub + built-in integrations + env defaults.
var guard = try sentry.initGlobalWithDefaults(allocator, .{
.dsn = "https://PUBLIC_KEY@o0.ingest.sentry.io/PROJECT_ID",
.install_signal_handlers = false,
});
defer guard.deinit();initWithDefaults and initGlobalWithDefaults honor default_integrations=false
and keep user integration order after the optional built-ins.
// One-line built-in setup preset for Options.integrations
const client = try sentry.init(allocator, .{
.dsn = "https://PUBLIC_KEY@o0.ingest.sentry.io/PROJECT_ID",
.integrations = sentry.integrations.auto.defaults(),
});
defer client.deinit();// Full bootstrap helper that prepends built-ins and initializes client directly
const client = try sentry.integrations.auto.initWithDefaults(allocator, .{
.dsn = "https://PUBLIC_KEY@o0.ingest.sentry.io/PROJECT_ID",
});
defer client.deinit();// Minimal runtime wiring helpers
pub const std_options: std.Options = sentry.integrations.auto.stdOptions();
pub const panic = sentry.integrations.auto.panicHandler;
sentry.integrations.auto.installRuntime(.{
.log = .{ .min_level = .info },
.panic = .{ .exception_type = "AppPanic" },
});// One-call bootstrap: apply runtime config + prepend built-ins + initialize client
const client = try sentry.integrations.auto.initWithDefaultsAndRuntime(allocator, .{
.dsn = "https://PUBLIC_KEY@o0.ingest.sentry.io/PROJECT_ID",
}, .{
.log = .{
.min_level = .info,
.forward_to_default_logger = false,
},
.panic = .{
.exception_type = "AppPanic",
},
});
defer client.deinit();// Global one-call variant: runtime config + default integrations + current TLS hub binding
var guard = try sentry.integrations.auto.initGlobalWithDefaultsAndRuntime(allocator, .{
.dsn = "https://PUBLIC_KEY@o0.ingest.sentry.io/PROJECT_ID",
}, .{
.log = .{ .min_level = .info },
.panic = .{ .exception_type = "AppPanic" },
});
defer guard.deinit();// HTTP request helper: starts/continues trace, binds per-request hub, maps status
var req_ctx = try sentry.integrations.http.RequestContext.begin(allocator, client, .{
.name = "GET /orders/:id",
.method = "GET",
.url = "https://api.example.com/orders/42",
.sentry_trace_header = incoming_sentry_trace,
.baggage_header = incoming_baggage,
.add_breadcrumb_on_finish = true,
});
defer req_ctx.deinit();
req_ctx.setTag("route", "orders.show");
req_ctx.setStatusCode(200);
req_ctx.finish(null);// Middleware-style helper for inbound handlers (auto begin/finish/error capture)
const status = try sentry.integrations.http.runIncomingRequest(
allocator,
client,
.{
.name = "GET /orders/:id",
.method = "GET",
.url = "https://api.example.com/orders/42",
.sentry_trace_header = incoming_sentry_trace,
.baggage_header = incoming_baggage,
},
incomingHandler,
handler_ctx,
.{},
);
_ = status;// Same flow but resolved from current TLS Hub (no explicit client argument)
const status = try sentry.integrations.auto.runIncomingRequestWithCurrentHub(
allocator,
.{
.name = "GET /orders/:id",
.method = "GET",
.url = "https://api.example.com/orders/42",
},
incomingHandler,
handler_ctx,
.{},
);
_ = status;// Typed variant: no anyopaque in your handler, signature validated at compile time
const IncomingState = struct { handled: bool = false };
fn incomingTyped(ctx: *sentry.integrations.http.RequestContext, state: *IncomingState) !u16 {
state.handled = true;
return 204;
}
var state = IncomingState{};
const status = try sentry.integrations.auto.runIncomingRequestWithCurrentHubTyped(
allocator,
.{ .name = "GET /orders/:id", .method = "GET" },
incomingTyped,
&state,
.{},
);
_ = status;// Variant that extracts sentry-trace/baggage from raw headers automatically
const incoming_headers = [_]sentry.PropagationHeader{
.{ .name = "sentry-trace", .value = incoming_sentry_trace },
.{ .name = "baggage", .value = incoming_baggage },
};
const status = try sentry.integrations.http.runIncomingRequestFromHeaders(
allocator,
client,
.{
.name = "GET /orders/:id",
.method = "GET",
.url = "https://api.example.com/orders/42",
},
&incoming_headers,
incomingHandler,
handler_ctx,
.{},
);
_ = status;
// If sentry-trace is missing, traceparent is also supported automatically.// Current TLS Hub variant for header-driven inbound flow
const status = try sentry.integrations.auto.runIncomingRequestFromHeadersWithCurrentHub(
allocator,
.{
.name = "GET /orders/:id",
.method = "GET",
.url = "https://api.example.com/orders/42",
},
&incoming_headers,
incomingHandler,
handler_ctx,
.{},
);
_ = status;// std.http adapter: map std.http method/target/headers to Sentry request instrumentation
const std_headers = [_]std.http.Header{
.{ .name = "traceparent", .value = incoming_traceparent_header },
.{ .name = "baggage", .value = incoming_baggage_header },
};
const status = try sentry.integrations.std_http.runIncomingRequest(
allocator,
client,
.GET,
"/orders/42?expand=items",
&std_headers,
.{ .transaction_name = "GET /orders/:id" },
incomingHandler,
handler_ctx,
.{},
);
_ = status;// std.http HeaderIterator variant (no intermediate header array)
var it = request.iterateHeaders();
const status = try sentry.integrations.std_http.runIncomingRequestFromHeaderIteratorTyped(
allocator,
client,
request.head.method,
request.head.target,
&it,
.{}, // transaction_name defaults to request path when omitted
incomingTypedHandler,
handler_state,
.{},
);
_ = status;// std.http Server.Request direct variant (method/target/headers extracted automatically)
const status = try sentry.integrations.std_http.runIncomingServerRequestWithCurrentHubTyped(
allocator,
request,
.{ .transaction_name = "GET /orders/:id" },
incomingTypedHandler,
handler_state,
.{},
);
_ = status;// Downstream HTTP helper: child span + propagation headers + status mapping
var out = try sentry.integrations.http.OutgoingRequestContext.begin(.{
.method = "POST",
.url = "https://payments.example.com/charge",
.description = "POST payments charge",
});
defer out.deinit();
var headers = try out.propagationHeadersAlloc(allocator);
defer headers.deinit(allocator);
// Attach headers.sentry_trace and headers.baggage to your outgoing HTTP request.
var header_list = try out.propagationHeaderListAlloc(allocator);
defer header_list.deinit(allocator);
// Or use header_list.slice() where []sentry.PropagationHeader is accepted.
var header_list_w3c = try out.propagationHeaderListWithTraceParentAlloc(allocator);
defer header_list_w3c.deinit(allocator);
// Includes sentry-trace + baggage + traceparent.
out.setStatusCode(200);
out.finish(null);
// HTTP breadcrumb is added automatically on finish by default.// Typed outgoing helper variant
const OutState = struct { propagated: bool = false };
fn outgoingTyped(ctx: *sentry.integrations.http.OutgoingRequestContext, state: *OutState) !u16 {
var h = try ctx.propagationHeadersAlloc(allocator);
defer h.deinit(allocator);
state.propagated = true;
return 200;
}
var out_state = OutState{};
const code = try sentry.integrations.auto.runOutgoingRequestWithCurrentHubTyped(
.{ .method = "POST", .url = "https://payments.example.com/charge" },
outgoingTyped,
&out_state,
.{},
);
_ = code;// std.http outgoing wrapper + direct std.http.Header propagation
var status = try sentry.integrations.std_http.runOutgoingRequestTyped(
.{
.method = .POST,
.url = "https://payments.example.com/charge",
.description = "POST charge",
},
outgoingTyped,
&out_state,
.{},
);
_ = status;// OTel/W3C traceparent continuation helper
var txn_from_traceparent = try sentry.integrations.otel.startTransactionFromTraceParent(
client,
.{ .name = "GET /inventory", .op = "http.server" },
incoming_traceparent_header,
);
defer txn_from_traceparent.deinit();// Built-in transport backend composition
var file_backend = try sentry.transport_backends.file.Backend.init(allocator, .{
.directory = "/var/tmp/sentry-outbox",
.failure_backoff_seconds = 1,
});
defer file_backend.deinit();
const file_transport = file_backend.transportConfig();
var fanout_backend = try sentry.transport_backends.fanout.Backend.init(allocator, &.{
.{ .send_fn = file_transport.send_fn, .ctx = file_transport.ctx },
// Add more targets here (for example, another file sink or custom sender).
});
defer fanout_backend.deinit();
const client = try sentry.init(allocator, .{
.dsn = "https://PUBLIC_KEY@o0.ingest.sentry.io/PROJECT_ID",
.transport = fanout_backend.transportConfig(),
});
defer client.deinit();
const backend_stats = file_backend.stats();
_ = backend_stats;// Middleware-style helper for outbound handlers (auto span finish/error capture)
const upstream_status = try sentry.integrations.http.runOutgoingRequest(
.{
.method = "POST",
.url = "https://payments.example.com/charge",
},
outgoingHandler,
handler_ctx,
.{},
);
_ = upstream_status;// Error-return helper: captures returned errors automatically
const value = try sentry.integrations.errors.runAndCapture(doWork, .{input});// Worker/task helper: clone current top scope into detached Hub and run code with TLS swap
var detached = try sentry.integrations.runtime.DetachedHub.fromCurrent(allocator, client);
defer detached.deinit();
try detached.run(workerEntry, .{&detached});// Thread helper: spawn worker with inherited Hub context automatically
const worker = try sentry.integrations.runtime.spawnWithCurrentHub(
allocator,
.{},
workerEntry,
.{arg1, arg2},
);
worker.join();All options are provided via sentry.Options in sentry.init.
| Option | Type | Default | Description |
|---|---|---|---|
dsn |
[]const u8 |
required | Sentry DSN |
debug |
bool |
false |
Debug flag |
release |
?[]const u8 |
null |
Release identifier |
dist |
?[]const u8 |
null |
Distribution/build identifier applied to events and transactions |
environment |
?[]const u8 |
null |
Environment name |
server_name |
?[]const u8 |
null |
Host/server name |
sample_rate |
f64 |
1.0 |
Event sampling (0.0..1.0) |
traces_sample_rate |
f64 |
0.0 |
Trace sampling (0.0..1.0) |
traces_sampler |
?TracesSampler |
null |
Per-transaction sampling callback |
max_breadcrumbs |
u32 |
100 |
Scope breadcrumb cap |
attach_stacktrace |
bool |
false |
Attach current-thread stacktrace payload (with safe fallback) only when event has no stacktrace payload (event/exception/threads) |
attach_debug_images |
bool |
true |
Attach default debug_meta.images payload when event has no debug image metadata |
send_default_pii |
bool |
false |
Reserved option for explicit PII policy toggles |
in_app_include |
?[]const []const u8 |
null |
Optional in-app include patterns for stack frame classification |
in_app_exclude |
?[]const []const u8 |
null |
Optional in-app exclude patterns for stack frame classification |
default_integrations |
bool |
true |
Controls default integration behavior for future integrations |
integrations |
?[]const Integration |
null |
Setup callbacks executed during client initialization |
before_send |
?*const fn (*Event) ?*Event |
null |
Drop/mutate event before queueing |
before_breadcrumb |
?*const fn (Breadcrumb) ?Breadcrumb |
null |
Drop/mutate breadcrumb |
before_send_transaction |
?*const fn (*Transaction) ?*Transaction |
null |
Drop/mutate transaction before queueing |
before_send_log |
?*const fn (*LogEntry) ?*LogEntry |
null |
Drop/mutate log entry before queueing |
transport |
?TransportConfig |
null |
Custom transport callback override |
http_proxy |
?[]const u8 |
null |
Explicit HTTP proxy URL (fallback to env vars when unset) |
https_proxy |
?[]const u8 |
null |
Explicit HTTPS proxy URL (fallback to env vars when unset) |
accept_invalid_certs |
bool |
false |
Disable TLS certificate verification for direct HTTPS transport (development/testing only) |
max_request_body_size |
?usize |
null |
Drop envelopes larger than this byte size |
enable_logs |
bool |
true |
Enable/disable structured log submissions |
cache_dir |
[]const u8 |
"/tmp/sentry-zig" |
Crash marker directory |
user_agent |
[]const u8 |
"sentry-zig/0.2.0" |
Transport User-Agent |
install_signal_handlers |
bool |
true |
POSIX signal handler install |
auto_session_tracking |
bool |
false |
Auto-start session on init |
session_mode |
SessionMode |
.application |
.application / .request |
session_aggregate_flush_interval_ms |
u64 |
60000 |
Request-mode aggregate auto-flush interval (0 disables timer flush) |
shutdown_timeout_ms |
u64 |
2000 |
Timeout for shutdown flush |
When default_integrations = false, automatic runtime/os/device context enrichment is disabled
(trace context bootstrap remains enabled).
traces_sampler receives transaction_name, transaction_op, trace_id, span_id,
parent_sampled, and optional custom_sampling_context from TransactionOpts.
Without traces_sampler, TransactionOpts.sampled_override forces per-transaction
sampling (true => 1.0, false => 0.0) and overrides
TransactionOpts.sample_rate.
Structured log records automatically include default sentry.environment,
sentry.release, and server.address attributes when configured.
When server_name is unset and default_integrations = true, the SDK attempts to use the local hostname.
in_app_include/in_app_exclude are applied to event, exception, and thread stack frames.
With default_integrations=true, stacktrace frames are also classified even without explicit in-app patterns.
Include/exclude patterns are matched against Rust-style frame.function prefixes.
Well-known runtime/library function prefixes (for example std::, core::, tokio::) are classified as in_app=false.
When a frame has function but no package, package is derived from Rust-style symbol prefixes (crate::, crate.., crate[hash]::, impl-style symbols).
When no frame is marked in_app=true, frames with missing in_app are treated as true.
attach_debug_images=true injects default debug_meta.images metadata for events that do not already include debug image info.
accept_invalid_certs=true is intended for local/dev environments and is not supported together with explicit proxy transport.
initWithEnvDefaults / initGlobalWithEnvDefaults resolve missing values from environment:
SENTRY_DSN(used only whenoptions.dsnis blank)SENTRY_RELEASESENTRY_DISTSENTRY_ENVIRONMENTSENTRY_NAMESENTRY_DEBUGSENTRY_SAMPLE_RATESENTRY_TRACES_SAMPLE_RATEHTTP_PROXY/http_proxyHTTPS_PROXY/https_proxySSL_VERIFY(falseenablesaccept_invalid_certs)
SSL_VERIFY always overrides explicit accept_invalid_certs in env-default init.
Unknown SSL_VERIFY values are treated as true (certificate verification enabled).
When no explicit environment and no SENTRY_ENVIRONMENT are provided,
env-default initialization sets:
"development"for debug builds"production"for non-debug builds
When HTTPS_PROXY is missing but HTTP_PROXY is available, HTTPS proxy defaults to HTTP proxy.
Example integration setup callback:
fn setupCheckoutIntegration(client: *sentry.Client, _: ?*anyopaque) void {
client.setTag("integration", "checkout");
}See docs/USER_GUIDE.md for full examples and edge cases.
flush(timeout_ms)waits for queue drain without stopping client.close(null)flushes (with default timeout) and shuts down worker.deinit()is the standard safe shutdown path and should always run.
- Set
release,environment, andserver_nameexplicitly. - Validate event delivery on a staging environment before production rollout.
- Keep queue drain guarantees in shutdown hooks (
flush+deinit). - Add
before_send/ processors for redaction and noise filtering. - Tune sampling and queue/body limits to your traffic profile.
Run all tests:
zig build testRun integration tests only:
zig build test-integrationTest capture helpers:
const std = @import("std");
const sentry = @import("sentry-zig");
fn capture(client: *sentry.Client, _: ?*anyopaque) !void {
_ = client.captureMessageId("hello testkit", .info);
}
var events = try sentry.testkit.withCapturedEvents(
std.testing.allocator,
capture,
null,
);
defer events.deinit();Tracing note: each transaction stores up to 1000 child spans (MAX_SPANS).
- Full guide: docs/USER_GUIDE.md
- Project repository: github.com/nullclaw/sentry-zig
MIT