Logger Reference
January 20, 2026 ยท View on GitHub
The Logger module provides access to Fastly logging endpoints.
Logger
Opening a Logger
pub fn open(name: []const u8) !Logger
Open a logging endpoint by name.
const Logger = zigly.Logger;
var log = try Logger.open("my_log_endpoint");
Methods
write
pub fn write(self: *Logger, msg: []const u8) !void
Send a message to the logging endpoint.
try log.write("Request processed successfully");
Example Usage
Basic Logging
const std = @import("std");
const zigly = @import("zigly");
const Logger = zigly.Logger;
fn start() !void {
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
defer arena.deinit();
const allocator = arena.allocator();
var downstream = try zigly.downstream();
// Open log endpoint
var log = try Logger.open("access_log");
// Get request info
var method_buf: [16]u8 = undefined;
const method = try downstream.request.getMethod(&method_buf);
var uri_buf: [4096]u8 = undefined;
const uri = try downstream.request.getUriString(&uri_buf);
// Log request
var log_buf: [512]u8 = undefined;
const log_msg = try std.fmt.bufPrint(&log_buf, "{s} {s}", .{ method, uri });
try log.write(log_msg);
try downstream.proxy("origin", null);
}
Structured Logging
fn logRequest(
allocator: Allocator,
log: *Logger,
request: anytype,
status: u16,
duration_ms: u64,
) !void {
var method_buf: [16]u8 = undefined;
const method = try request.getMethod(&method_buf);
var uri_buf: [4096]u8 = undefined;
const uri = try request.getUriString(&uri_buf);
const client_ip = zigly.http.Downstream.getClientIpAddr() catch unreachable;
const ip_str = try client_ip.print(allocator);
defer allocator.free(ip_str);
// JSON structured log
const log_msg = try std.fmt.allocPrint(allocator,
\\{{"method":"{s}","uri":"{s}","status":{d},"client_ip":"{s}","duration_ms":{d}}}
, .{ method, uri, status, ip_str, duration_ms });
defer allocator.free(log_msg);
try log.write(log_msg);
}
Error Logging
fn logError(err: anyerror, context: []const u8) void {
var log = Logger.open("error_log") catch return;
var buf: [256]u8 = undefined;
const msg = std.fmt.bufPrint(&buf, "ERROR: {} - {s}", .{ err, context }) catch return;
log.write(msg) catch {};
}
fn start() !void {
var downstream = try zigly.downstream();
downstream.proxy("origin", null) catch |err| {
logError(err, "proxy to origin failed");
try downstream.response.setStatus(503);
try downstream.response.finish();
return;
};
}
Apache Combined Log Format
Use the built-in Apache log function:
fn start() !void {
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
defer arena.deinit();
const allocator = arena.allocator();
var downstream = try zigly.downstream();
// Process request and track response details
try downstream.proxy("origin", null);
// Log in Apache combined format
try downstream.request.logApacheCombined(
allocator,
"access_log", // Log endpoint name
200, // Status code
1234, // Response size in bytes
);
}
Local Testing Configuration
Configure logging endpoints in fastly.toml:
[local_server.log_endpoints]
[local_server.log_endpoints.access_log]
file = "logs/access.log"
[local_server.log_endpoints.error_log]
file = "logs/error.log"
Logs will be written to the specified files.
Production Configuration
In production, configure logging endpoints through the Fastly UI or CLI:
# S3 logging
fastly logging s3 create \
--name access_log \
--bucket my-logs-bucket \
--access-key $AWS_ACCESS_KEY \
--secret-key $AWS_SECRET_KEY \
--version latest
# Datadog logging
fastly logging datadog create \
--name datadog_log \
--token $DATADOG_API_KEY \
--region US \
--version latest
# BigQuery logging
fastly logging bigquery create \
--name bigquery_log \
--project my-project \
--dataset my_dataset \
--table request_logs \
--user $SERVICE_ACCOUNT \
--secret-key $PRIVATE_KEY \
--version latest