Skip to content

Tracing Example ​

Distributed tracing support for tracking requests across services.

Distributed Configuration ​

To enable service identification and distributed features:

zig
var config = logly.Config.production();
config.distributed = .{
    .enabled = true,
    .service_name = "payment-service",
    .environment = "production",
    .region = "us-east-1",
};
const logger = try logly.Logger.initWithConfig(allocator, config);

In concurrent environments, use withTrace() to create lightweight logger handles with bound context.

zig
const std = @import("std");
const logly = @import("logly");
const Config = logly.Config;

pub fn main() !void {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    defer _ = gpa.deinit();
    const allocator = gpa.allocator();

    // Configure Service
    var config = Config.default();
    config.distributed = .{
        .enabled = true,
        .service_name = "tracing-example",
    };

    const logger = try logly.Logger.initWithConfig(allocator, config);
    defer logger.deinit();

    // Simulate Request Handling
    const trace_id = "trace-uuid-v4";
    const span_id = "span-001";
    
    // Create scoped logger for this request
    const req_logger = logger.withTrace(trace_id, span_id);
    
    // Logs automatically include service name, trace_id, and span_id
    try req_logger.info("Processing request", @src());
    try req_logger.warn("Simulated latency", @src());
}

Legacy Trace Context (Global) ​

For single-threaded scripts or tools:

zig
    // Set trace context for distributed tracing globally
    try logger.setTraceContext("trace-legacy-global", "span-global");
    
    // All logs will now include trace info
    try logger.info("Processing request", @src());
    try logger.debug("Validating input", @src());
    
    // Clear trace context
    logger.clearTraceContext();

Child Spans ​

zig
// Create child spans for nested operations
try logger.setTraceContext("trace-main", "span-root");

// External service call
{
    var span = try logger.startSpan("external-api");
    
    try logger.info("Calling external API", @src());
    try logger.debug("Sending request", @src());
    try logger.info("Response received", @src());
    
    try span.end(null); // End with optional message
}

// Database operation
{
    var db_span = try logger.startSpan("database");
    
    try logger.info("Executing query", @src());
    try logger.success("Query complete", @src());
    
    try db_span.end("database operation done");
}

Context Binding ​

zig
// Add service metadata as context
try logger.bind("service", .{ .string = "user-service" });
try logger.bind("version", .{ .string = "1.2.3" });
try logger.bind("environment", .{ .string = "production" });

// All logs will include this context
try logger.info("Service ready", @src());

// Remove context
logger.unbind("version");

Trace ID Propagation ​

When receiving requests from other services:

zig
pub fn handleRequest(req: Request, logger: *logly.Logger) !void {
    // Extract trace ID from incoming request headers
    const trace_id = req.getHeader("X-Trace-ID") orelse 
                     try generateTraceId();
    const parent_span = req.getHeader("X-Span-ID");
    
    // Set trace context
    try logger.setTraceContext(trace_id, null);
    
    // Create new span for this service
    var span = try logger.startSpan("handle-request");
    defer span.end(null) catch {};
    
    // Process request
    try logger.info("Request received", @src());
    // ...
}

When calling other services:

zig
// Note: trace_id and span_id are internal fields on the logger
// You can access them by extracting from the log record context
// or pass them explicitly through your application

pub fn callExternalService(trace_id: []const u8, span_id: []const u8) !void {
    // Include trace headers in outgoing request
    var headers = std.StringHashMap([]const u8).init(allocator);
    defer headers.deinit();
    
    try headers.put("X-Trace-ID", trace_id);
    try headers.put("X-Span-ID", span_id);
    
    // Make request with trace context
    // ...
}

JSON Output with Tracing ​

zig
var config = logly.Config.default();
config.json = true;
config.include_trace_id = true;

// Output:
// {
//   "timestamp": "2024-01-15T10:30:00Z",
//   "level": "info",
//   "message": "Request processed",
//   "trace_id": "trace-abc123",
//   "span_id": "span-001",
//   "correlation_id": "request-789"
// }

OpenTelemetry Compatibility ​

Logly's tracing is compatible with OpenTelemetry concepts:

LoglyOpenTelemetry
trace_idTrace ID
span_idSpan ID
correlation_idBaggage item
Context bindingAttributes

Use Cases ​

  • Microservices: Track requests across service boundaries
  • Debugging: Follow a single request through the system
  • Performance: Measure time spent in each component
  • Error tracking: Correlate errors with specific requests

Best Practices ​

  1. Generate trace IDs at entry - Create at the edge of your system
  2. Propagate always - Include trace IDs in all inter-service calls
  3. Use meaningful span names - Name spans by operation, not function
  4. Include correlation IDs - Link logs to business transactions
  5. Clean up context - Clear trace context between requests

Released under the MIT License.