Skip to content
Draft
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions src/Types.zig
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,18 @@ pub const Message = @import("types/Event.zig").Message;
pub const SDK = @import("types/Event.zig").SDK;
pub const SDKPackage = @import("types/Event.zig").SDKPackage;
pub const Contexts = @import("types/Contexts.zig").Contexts;

// Tracing types
pub const TraceId = @import("types/TraceId.zig").TraceId;
pub const SpanId = @import("types/SpanId.zig").SpanId;
pub const PropagationContext = @import("types/PropagationContext.zig").PropagationContext;

// Unified span types
pub const Span = @import("types/Span.zig").Span;
pub const Sampled = @import("types/Span.zig").Sampled;
pub const SpanStatus = @import("types/Span.zig").SpanStatus;
pub const SpanOrigin = @import("types/Span.zig").SpanOrigin;
pub const TransactionSource = @import("types/Span.zig").TransactionSource;

// Trace context for header parsing utility
pub const TraceContext = @import("types/TraceContext.zig").TraceContext;
2 changes: 1 addition & 1 deletion src/client.zig
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ pub const SentryClient = struct {
if (opts.environment) |env| {
std.log.debug("Environment: {s}", .{env});
}
std.log.debug("Sample rate: {d}", .{opts.sample_rate});
std.log.debug("Sample rate: {?}", .{opts.sample_rate});
}

return client;
Expand Down
18 changes: 16 additions & 2 deletions src/root.zig
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,25 @@ const std = @import("std");
const testing = std.testing;
const Allocator = std.mem.Allocator;
const types = @import("types");
const scopes = @import("scope.zig");
const tracing = @import("tracing.zig");
pub const Event = types.Event;
pub const EventId = types.EventId;
pub const SentryOptions = types.SentryOptions;
pub const Breadcrumb = types.Breadcrumb;
pub const Dsn = types.Dsn;
pub const Level = types.Level;
pub const StackTrace = types.StackTrace;
pub const Exception = types.Exception;
pub const TraceId = types.TraceId;
pub const SpanId = types.SpanId;
pub const PropagationContext = types.PropagationContext;
pub const TraceContext = types.TraceContext;
pub const Span = types.Span;
pub const StackTrace = types.StackTrace;
pub const Frame = types.Frame;

pub const SentryClient = @import("client.zig").SentryClient;

const scopes = @import("scope.zig");
pub const ScopeType = scopes.ScopeType;
pub const addBreadcrumb = scopes.addBreadcrumb;

Expand All @@ -33,6 +39,14 @@ pub fn captureEvent(event: Event) !?EventId {
return try scopes.captureEvent(event);
}

pub const startTransaction = tracing.startTransaction;
pub const continueFromHeaders = tracing.continueFromHeaders;
pub const finishTransaction = tracing.finishTransaction;
pub const startSpan = tracing.startSpan;
pub const getCurrentSpan = tracing.getCurrentSpan;
pub const getCurrentTransaction = tracing.getCurrentTransaction;
pub const getSentryTrace = tracing.getSentryTrace;

pub fn captureMessage(message: []const u8, level: Level) !?EventId {
const event = Event.fromMessage(message, level);
return captureEvent(event);
Expand Down
88 changes: 88 additions & 0 deletions src/scope.zig
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ const Level = types.Level;
const Event = types.Event;
const EventId = @import("types").EventId;
const Contexts = types.Contexts;
const TraceId = types.TraceId;
const SpanId = types.SpanId;
const PropagationContext = types.PropagationContext;
const ArrayList = std.ArrayList;
const HashMap = std.HashMap;
const Allocator = std.mem.Allocator;
Expand All @@ -34,6 +37,10 @@ pub const Scope = struct {
contexts: std.StringHashMap(std.StringHashMap([]const u8)),
client: ?*SentryClient,

// Tracing context
propagation_context: PropagationContext,
span: ?*anyopaque = null,

const MAX_BREADCRUMBS = 100;

pub fn init(allocator: Allocator) Scope {
Expand All @@ -46,6 +53,8 @@ pub const Scope = struct {
.breadcrumbs = ArrayList(Breadcrumb).init(allocator),
.contexts = std.StringHashMap(std.StringHashMap([]const u8)).init(allocator),
.client = null,
.propagation_context = PropagationContext.generate(),
.span = null,
};
}

Expand Down Expand Up @@ -151,6 +160,9 @@ pub const Scope = struct {
try new_scope.contexts.put(context_key, new_context);
}

// Copy propagation context
new_scope.propagation_context = self.propagation_context.clone();

return new_scope;
}

Expand Down Expand Up @@ -280,6 +292,7 @@ pub const Scope = struct {
try self.applyFingerprintToEvent(event);
try self.applyBreadcrumbsToEvent(event);
try self.applyContextsToEvent(event);
self.applyTracingToEvent(event);
}

fn applyLevelToEvent(self: *const Scope, event: *Event) void {
Expand Down Expand Up @@ -393,6 +406,29 @@ pub const Scope = struct {
}
}

fn applyTracingToEvent(self: *const Scope, event: *Event) void {
// Apply tracing context if event doesn't already have it
if (event.trace_id == null) {
event.trace_id = self.propagation_context.trace_id;
}
if (event.span_id == null) {
event.span_id = self.propagation_context.span_id;
}
if (event.parent_span_id == null) {
event.parent_span_id = self.propagation_context.parent_span_id;
}
}

/// Set trace context (equivalent to sentry_set_trace in Native SDK)
pub fn setTrace(self: *Scope, trace_id: TraceId, span_id: SpanId, parent_span_id: ?SpanId) void {
self.propagation_context.updateFromTrace(trace_id, span_id, parent_span_id);
}

/// Get the current propagation context
pub fn getPropagationContext(self: *const Scope) PropagationContext {
return self.propagation_context.clone();
}

/// Merge another scope into this one (other scope takes precedence)
pub fn merge(self: *Scope, other: *const Scope) !void {
// Merge level (other scope takes precedence)
Expand Down Expand Up @@ -433,11 +469,40 @@ pub const Scope = struct {

try self.addBreadcrumb(cloned_crumb);
}

// Merge propagation context (other scope takes precedence)
self.propagation_context = other.propagation_context.clone();
}

pub fn bindClient(self: *Scope, client: *SentryClient) void {
self.client = client;
}

/// Set the current span or transaction on this scope
pub fn setSpan(self: *Scope, span_or_transaction: ?*anyopaque) void {
self.span = span_or_transaction;
}

/// Get the current span or transaction from this scope
pub fn getSpan(self: *const Scope) ?*anyopaque {
return self.span;
}

/// Generate sentry-trace header from current span/transaction
pub fn traceHeaders(self: *const Scope, allocator: std.mem.Allocator) !?[]u8 {
if (self.span == null) {
// Generate from propagation context
const trace_hex = self.propagation_context.trace_id.toHexFixed();
const span_hex = self.propagation_context.span_id.toHexFixed();
return try std.fmt.allocPrint(allocator, "{s}-{s}", .{ trace_hex, span_hex });
}

// TODO: Determine if span is root span or child span and call appropriate method
// For now, generate from propagation context
const trace_hex = self.propagation_context.trace_id.toHexFixed();
const span_hex = self.propagation_context.span_id.toHexFixed();
return try std.fmt.allocPrint(allocator, "{s}-{s}", .{ trace_hex, span_hex });
}
};

var global_scope: ?*Scope = null;
Expand Down Expand Up @@ -617,6 +682,28 @@ pub fn addBreadcrumb(breadcrumb: Breadcrumb) !void {
try scope.addBreadcrumb(breadcrumb);
}

/// Set trace context (equivalent to sentry_set_trace in Native SDK)
pub fn setTrace(trace_id: TraceId, span_id: SpanId, parent_span_id: ?SpanId) !void {
const scope = try getIsolationScope();
scope.setTrace(trace_id, span_id, parent_span_id);
}

/// Get the current propagation context
pub fn getPropagationContext() !PropagationContext {
const scope = try getIsolationScope();
return scope.getPropagationContext();
}

// Convenience function to set the client on the global scope
pub fn setClient(client: *SentryClient) void {
if (getGlobalScope() catch null) |scope| {
scope.bindClient(client);
} else {
std.log.err("Failed to get global scope for setting client", .{});
}
}
Comment on lines +727 to +733
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: I think this should return !void instead of failing silently


// Convenience function to get the client
pub fn getClient() ?*SentryClient {
const scope_getters = .{ getCurrentScope, getIsolationScope, getGlobalScope };
inline for (scope_getters) |getter| {
Expand Down Expand Up @@ -652,6 +739,7 @@ pub fn captureEvent(event: Event) !?EventId {
return null;
}

// Used for tests
fn resetAllScopeState(allocator: std.mem.Allocator) void {
global_scope_mutex.lock();
defer global_scope_mutex.unlock();
Expand Down
Loading
Loading