Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enforce Zig styleguide #16

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
25 changes: 7 additions & 18 deletions src/handler.zig
Original file line number Diff line number Diff line change
Expand Up @@ -4,32 +4,21 @@ const KeyValue = @import("kv.zig").KeyValue;
const builtin = @import("builtin");

pub const LogHandler = struct {
pub fn levelToString(level: Level) []const u8 {
return switch (level) {
.Trace => "Trace",
.Debug => "Debug",
.Info => "Info",
.Warn => "Warn",
.Error => "Error",
.Fatal => "Fatal",
};
}

pub fn log(_: *LogHandler, level: Level, msg: []const u8, kv: ?[]const KeyValue) !void {
var buffer: [256]u8 = undefined;
const level_str = levelToString(level);
const level_str = level.toString();
if (!builtin.is_test) {
try std.io.getStdOut().writer().print("{s}: {s}\n", .{ level_str, msg });
}
//std.debug.print("{s}: {s}\n", .{ level_str, msg });
if (kv) |values| {
for (values) |entry| {
const valueString = switch (entry.value) {
const value_string = switch (entry.value) {
.String => entry.value.String,
.Int => try std.fmt.bufPrint(&buffer, "{}", .{entry.value.Int}),
.Float => try std.fmt.bufPrint(&buffer, "{}", .{entry.value.Float}),
};
std.debug.print("{s}={s}\n", .{ entry.key, valueString });
std.debug.print("{s}={s}\n", .{ entry.key, value_string });
}
}
}
Expand All @@ -39,19 +28,19 @@ pub const FileHandler = struct {
// ... file-specific fields ...

pub fn log(_: *FileHandler, _: Level, _: []const u8, _: ?[]const KeyValue) !void {
return error.NotImplemented;
@compileError("not implemented");
}

pub fn rotate(_: *FileHandler) !void {
return error.NotImplemented;
@compileError("not implemented");
}
};

pub const NetworkHandler = struct {
// ... network-specific fields ...

pub fn log(_: *NetworkHandler, _: Level, _: []const u8, _: ?[]const KeyValue) !void {
return error.NotImplemented;
@compileError("not implemented");
}
};

Expand All @@ -60,6 +49,6 @@ pub const AsyncLogHandler = struct {

pub fn log(_: *AsyncLogHandler, _: Level, _: []const u8, _: ?[]const KeyValue) !void {
// ... enqueue log message for processing by a separate worker thread ...
return error.NotImplemented;
@compileError("not implemented");
}
};
32 changes: 10 additions & 22 deletions src/json.zig
Original file line number Diff line number Diff line change
Expand Up @@ -4,41 +4,29 @@ const Level = @import("level.zig").Level;
const kv = @import("kv.zig");

fn appendFormattedInt(buffer: *std.ArrayList(u8), value: i64) !void {
var tmpBuf: [20]u8 = undefined; // Buffer for integer formatting
const formatted = try std.fmt.bufPrint(&tmpBuf, "{}", .{value});
var tmp_buf: [20]u8 = undefined; // Buffer for integer formatting
const formatted = try std.fmt.bufPrint(&tmp_buf, "{}", .{value});
try buffer.appendSlice(formatted);
}

fn appendFormattedFloat(buffer: *std.ArrayList(u8), value: f64) !void {
var tmpBuf: [32]u8 = undefined; // Buffer for float formatting
const formatted = try std.fmt.bufPrint(&tmpBuf, "{d:.2}", .{value});
var tmp_buf: [32]u8 = undefined; // Buffer for float formatting
const formatted = try std.fmt.bufPrint(&tmp_buf, "{d:.2}", .{value});
try buffer.appendSlice(formatted);
}

fn appendLevel(buffer: *std.ArrayList(u8), level: Level) !void {
const levelStr = switch (level) {
.Info => "Info",
.Warn => "Warn",
.Error => "Error",
.Debug => "Debug",
.Trace => "Trace",
.Fatal => "Fatal", // Handling the 'Fatal' case
};
try buffer.appendSlice(levelStr);
}

pub fn serializeLogMessage(log: LogMessage) ![]u8 {
var buffer = std.ArrayList(u8).init(std.heap.page_allocator);
defer buffer.deinit();

try buffer.appendSlice("{\"level\": \"");
try appendLevel(&buffer, log.level);
try buffer.appendSlice(log.level.toString());
try buffer.appendSlice("\", \"message\": \"");
try buffer.appendSlice(log.msg);
try buffer.appendSlice("\"");

if (log.kv) |kvPairs| {
for (kvPairs) |pair| {
if (log.kv) |kv_pairs| {
for (kv_pairs) |pair| {
try buffer.appendSlice(", \"");
try buffer.appendSlice(pair.key);
try buffer.appendSlice("\": ");
Expand All @@ -60,7 +48,7 @@ pub fn serializeLogMessage(log: LogMessage) ![]u8 {
}

test "JSON Serialization Test - Level and Message" {
const logMsg = LogMessage{
const log_msg = LogMessage{
.level = Level.Info,
.msg = "Test message",
.kv = &[_]kv.KeyValue{
Expand All @@ -71,7 +59,7 @@ test "JSON Serialization Test - Level and Message" {
},
};

const serializedMsg = try serializeLogMessage(logMsg);
const serialized_msg = try serializeLogMessage(log_msg);

try std.testing.expectEqualStrings("{\"level\": \"Info\", \"message\": \"Test message\", \"key1\": \"value1\", \"key2\": 42, \"key3\": 3.14}", serializedMsg);
try std.testing.expectEqualStrings("{\"level\": \"Info\", \"message\": \"Test message\", \"key1\": \"value1\", \"key2\": 42, \"key3\": 3.14}", serialized_msg);
}
4 changes: 4 additions & 0 deletions src/level.zig
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,8 @@ pub const Level = enum {
Warn,
Error,
Fatal,

pub fn toString(self: Level) []const u8 {
return @tagName(self);
}
};
59 changes: 29 additions & 30 deletions src/logger.zig
Original file line number Diff line number Diff line change
Expand Up @@ -15,73 +15,72 @@ pub const LogRecord = struct {
pub fn Logger(comptime HandlerType: type) type {
return struct {
level: Level,
outputFormat: OutputFormat,
output_format: OutputFormat,
handler: *HandlerType, // Ensure this is a pointer

pub fn init(_: *std.mem.Allocator, level: Level, outputFormat: OutputFormat, handler: *HandlerType) ZlogError!Logger(HandlerType) {
return Logger(HandlerType){
const Self = @This();

pub fn init(_: *std.mem.Allocator, level: Level, outputFormat: OutputFormat, handler: *HandlerType) ZlogError!Self {
return Self{
.level = level,
.outputFormat = outputFormat,
.output_format = outputFormat,
.handler = handler, // Store the pointer directly
};
}

pub fn setLevel(self: *Logger(HandlerType), newLevel: Level) ZlogError!void {
if (!std.meta.enumsHaveMember(Level, newLevel)) {
return error.InvalidLevel;
}
self.level = newLevel;
pub fn setLevel(self: *Self, new_level: Level) ZlogError!void {
self.level = new_level;
return self;
}

pub fn info(self: *Logger(HandlerType), msg: []const u8, kv: ?[]const KeyValue) void {
self.log(msg, kv) catch |logErr| {
std.debug.print("Log error: {}\n", .{logErr});
pub fn info(self: *Self, msg: []const u8, kv: ?[]const KeyValue) void {
self.log(msg, kv) catch |log_err| {
std.debug.print("Log error: {}\n", .{log_err});
return;
};
}

pub fn warn(self: *Logger(HandlerType), msg: []const u8, kv: ?[]const KeyValue) void {
self.log(msg, kv) catch |logErr| {
std.debug.print("Log error: {}\n", .{logErr});
pub fn warn(self: *Self, msg: []const u8, kv: ?[]const KeyValue) void {
self.log(msg, kv) catch |log_err| {
std.debug.print("Log error: {}\n", .{log_err});
return;
};
}

pub fn err(self: *Logger(HandlerType), msg: []const u8, kv: ?[]const KeyValue) void {
self.log(msg, kv) catch |logErr| {
std.debug.print("Log error: {}\n", .{logErr});
pub fn err(self: *Self, msg: []const u8, kv: ?[]const KeyValue) void {
self.log(msg, kv) catch |log_err| {
std.debug.print("Log error: {}\n", .{log_err});
return;
};
}

pub fn debug(self: *Logger(HandlerType), msg: []const u8, kv: ?[]const KeyValue) void {
self.log(msg, kv) catch |logErr| {
std.debug.print("Log error: {}\n", .{logErr});
pub fn debug(self: *Self, msg: []const u8, kv: ?[]const KeyValue) void {
self.log(msg, kv) catch |log_err| {
std.debug.print("Log error: {}\n", .{log_err});
return;
};
}

pub fn trace(self: *Logger(HandlerType), msg: []const u8, kv: ?[]const KeyValue) void {
self.log(msg, kv) catch |logErr| {
std.debug.print("Log error: {}\n", .{logErr});
pub fn trace(self: *Self, msg: []const u8, kv: ?[]const KeyValue) void {
self.log(msg, kv) catch |log_err| {
std.debug.print("Log error: {}\n", .{log_err});
return;
};
}

pub fn log(self: *Logger(HandlerType), msg: []const u8, kv: ?[]const KeyValue) anyerror!void {
pub fn log(self: *Self, msg: []const u8, kv: ?[]const KeyValue) anyerror!void {
// Debug print to show the handler's address
//std.debug.print("Logger: Logging with Logger instance at address {}\n", .{@intFromPtr(self)}); // Updated line

if (self.outputFormat == OutputFormat.JSON) {
const logMsg = LogRecord{ .level = self.level, .msg = msg, .kv = kv };
const serializedMsg = json.serializeLogMessage(logMsg) catch |JsonErr| {
std.debug.print("Error serializing log message: {}\n", .{JsonErr});
if (self.output_format == OutputFormat.JSON) {
const log_msg = LogRecord{ .level = self.level, .msg = msg, .kv = kv };
const serialized_msg = json.serializeLogMessage(log_msg) catch |json_err| {
std.debug.print("Error serializing log message: {}\n", .{json_err});
return error.HandlerFailure;
};

// Pass the serialized message slice directly
try self.handler.log(self.level, serializedMsg, null);
try self.handler.log(self.level, serialized_msg, null);
} else {
// Handle non-JSON formats as before
if (kv) |keyValues| {
Expand Down
37 changes: 19 additions & 18 deletions src/test.zig
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,14 @@ const LogHandler = @import("handler.zig").LogHandler;
const kv = @import("kv.zig");
const OutputFormat = @import("logger.zig").OutputFormat;

var globalAllocator = std.heap.page_allocator;
var global_allocator = std.heap.page_allocator;

fn setupLogger(comptime HandlerType: type, logLevel: Level, format: OutputFormat, handler: *HandlerType) !Logger(HandlerType) {
return Logger(HandlerType).init(&globalAllocator, logLevel, format, handler);
fn setupLogger(comptime HandlerType: type, log_level: Level, format: OutputFormat, handler: *HandlerType) !Logger(HandlerType) {
return Logger(HandlerType).init(&global_allocator, log_level, format, handler);
}

test "Benchmark different log levels" {
// do wyp p p
var handler = LogHandler{};
var logger = try setupLogger(LogHandler, Level.Info, OutputFormat.PlainText, &handler);

Expand All @@ -28,54 +29,54 @@ test "Benchmark Synchronous vs Asynchronous Logging" {
var logger = try setupLogger(LogHandler, Level.Error, OutputFormat.PlainText, &handler);

// Synchronous Logging
const startSync = std.time.milliTimestamp();
const start_sync = std.time.milliTimestamp();
logger.info("Synchronous log message", null);
const endSync = std.time.milliTimestamp();
const end_sync = std.time.milliTimestamp();

// Asynchronous Logging
const startAsync = std.time.milliTimestamp();
const start_async = std.time.milliTimestamp();
//logger.asyncLog("Asynchronous log message");
const endAsync = std.time.milliTimestamp();
const end_async = std.time.milliTimestamp();

std.debug.print("Synchronous Logging took {} ms\n", .{endSync - startSync});
std.debug.print("Not Implemented - Asynchronous Logging took {} ms\n", .{endAsync - startAsync});
std.debug.print("Synchronous Logging took {} ms\n", .{end_sync - start_sync});
std.debug.print("Not Implemented - Asynchronous Logging took {} ms\n", .{end_async - start_async});
}

const MockLogHandler = struct {
capturedOutput: std.ArrayList(u8),
captured_output: std.ArrayList(u8),

pub fn log(self: *MockLogHandler, _: Level, msg: []const u8, _: ?[]const kv.KeyValue) anyerror!void {
//std.debug.print("Before appending, capturedOutput length: {}\n", .{self.capturedOutput.items.len});
try self.capturedOutput.appendSlice(msg);
try self.captured_output.appendSlice(msg);
//std.debug.print("After appending, capturedOutput length: {}\n", .{self.capturedOutput.items.len});
//std.debug.print("Captured message: {s}\n", .{msg});
}
};

test "JSON Logging Test" {
var allocator = std.heap.page_allocator;
var mockHandler = MockLogHandler{ .capturedOutput = std.ArrayList(u8).init(allocator) };
defer mockHandler.capturedOutput.deinit();
var mock_handler = MockLogHandler{ .captured_output = std.ArrayList(u8).init(allocator) };
defer mock_handler.captured_output.deinit();

//std.debug.print("Test: Created MockLogHandler at address {}\n", .{@intFromPtr(&mockHandler)}); // Debug print

var logger = try Logger(MockLogHandler).init(&allocator, Level.Info, OutputFormat.JSON, &mockHandler);
var logger = try Logger(MockLogHandler).init(&allocator, Level.Info, OutputFormat.JSON, &mock_handler);
//std.debug.print("Test: Created Logger at address {}\n", .{@intFromPtr(&logger)}); // Debug print

const kvPairs = &[_]kv.KeyValue{
const kv_pairs = &.{
kv.KeyValue{ .key = "key1", .value = kv.Value{ .String = "value1" } },
kv.KeyValue{ .key = "key2", .value = kv.Value{ .Int = 42 } },
kv.KeyValue{ .key = "key3", .value = kv.Value{ .Float = 3.14 } },
};

logger.info("Test message", kvPairs);
logger.info("Test message", kv_pairs);

//std.debug.print("MockLogHandler: capturedOutput length = {}\n", .{mockHandler.capturedOutput.items.len}); // Debug print
const loggedJson = mockHandler.capturedOutput.items;
const logged_json = mock_handler.captured_output.items;

//std.debug.print("MockLogHandler: loggedJson = {s}\n", .{loggedJson}); // Debug line

try std.testing.expectEqualStrings("{\"level\": \"Info\", \"message\": \"Test message\", \"key1\": \"value1\", \"key2\": 42, \"key3\": 3.14}", loggedJson);
try std.testing.expectEqualStrings("{\"level\": \"Info\", \"message\": \"Test message\", \"key1\": \"value1\", \"key2\": 42, \"key3\": 3.14}", logged_json);
}

pub fn main() !void {}