diff --git a/.github/config.env b/.github/config.env new file mode 100644 index 0000000..a83af69 --- /dev/null +++ b/.github/config.env @@ -0,0 +1 @@ +ZIG_VERSION=0.14.1 \ No newline at end of file diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 39fc943..84fb7f0 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -1,60 +1,26 @@ name: build-and-test on: push: - branches: - - '**' pull_request: - schedule: - - cron: 0 4 * * * jobs: - test-with-zig-master: - runs-on: ubuntu-latest + build-and-test: + strategy: + fail-fast: true + matrix: + os: + - ubuntu-latest + - windows-latest + runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v4 + - name: Load configuration + shell: bash + run: | + source .github/config.env + echo "ZIG_VERSION=${ZIG_VERSION}" >> $GITHUB_ENV - uses: goto-bus-stop/setup-zig@v2 with: - version: master - - run: zig fmt --check *.zig src/*.zig + version: ${{ env.ZIG_VERSION }} - run: zig build - run: zig build test - - run: zig build docs - - name: Upload artifact - if: github.ref == 'refs/heads/main' && github.event_name != 'schedule' - uses: actions/upload-pages-artifact@v3 - with: - path: ./zig-out/docs/ - - test-with-zig-stable: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: goto-bus-stop/setup-zig@v2 - with: - version: 0.14.1 - - run: zig build - - run: zig build test - test-on-windows: - runs-on: windows-latest - steps: - - uses: actions/checkout@v4 - - uses: goto-bus-stop/setup-zig@v2 - with: - version: master - - run: zig build - - run: zig build test - - deploy-pages: - runs-on: ubuntu-latest - needs: test-with-zig-master - if: github.ref == 'refs/heads/main' && github.event_name != 'schedule' - permissions: - pages: write # to deploy to Pages - id-token: write # to verify the deployment originates from an appropriate source - environment: - name: github-pages - url: ${{ steps.deployment.outputs.page_url }} - steps: - - name: Deploy to GitHub Pages - id: deployment - uses: actions/deploy-pages@v4 diff --git a/.github/workflows/deploy-docs.yml b/.github/workflows/deploy-docs.yml new file mode 100644 index 0000000..9fda0c8 --- /dev/null +++ b/.github/workflows/deploy-docs.yml @@ -0,0 +1,41 @@ +name: deploy-docs +on: + workflow_run: + workflows: ["build-and-test"] + types: + - completed + branches: + - main + +jobs: + build-docs: + runs-on: ubuntu-latest + if: ${{ github.event.workflow_run.conclusion == 'success' }} + steps: + - uses: actions/checkout@v4 + - name: Load configuration + run: | + source .github/config.env + echo "ZIG_VERSION=${ZIG_VERSION}" >> $GITHUB_ENV + - uses: goto-bus-stop/setup-zig@v2 + with: + version: ${{ env.ZIG_VERSION }} + - run: zig build docs + - name: Upload artifact + uses: actions/upload-pages-artifact@v3 + with: + path: ./zig-out/docs/ + + deploy-pages: + runs-on: ubuntu-latest + needs: build-docs + permissions: + pages: write # to deploy to Pages + id-token: write # to verify the deployment originates from an appropriate source + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + steps: + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v4 diff --git a/src/Logger.zig b/src/Logger.zig index a62e019..6e7df77 100644 --- a/src/Logger.zig +++ b/src/Logger.zig @@ -1,6 +1,5 @@ const std = @import("std"); const Allocator = std.mem.Allocator; -const Value = std.json.Value; const testing = std.testing; const zeit = @import("zeit"); @@ -14,6 +13,7 @@ const util = @import("./util.zig"); const Level = util.Level; const LogEvent = util.LogEvent; const Field = util.Field; +const Value = util.Value; const Self = @This(); @@ -191,7 +191,7 @@ fn toFieldList(fields: anytype, alloc: Allocator) ![]Field { const field_val = @field(fields, field.name); const value: Value = switch (field_type) { .pointer, .int, .comptime_int, .float, .comptime_float, .bool, .null => toPlainValue(field_val), - .optional => if (field_val == null) Value.null else toPlainValue(@field(fields, field.name).?), + .optional => if (field_val) |val| toPlainValue(val) else Value.null, else => { @compileError(std.fmt.comptimePrint("unsupported type: {any}", .{field_type})); }, @@ -246,6 +246,6 @@ test "toField optional" { const result = try toFieldList(.{ .field1 = v1, .field2 = v2 }, al); try testing.expectEqual(2, result.len); - try testing.expectEqual(std.json.Value.null, result[0].value); + try testing.expectEqual(Value.null, result[0].value); try testing.expectEqual(34, result[1].value.integer); } diff --git a/src/formatter.zig b/src/formatter.zig index 22613eb..253ad52 100644 --- a/src/formatter.zig +++ b/src/formatter.zig @@ -7,11 +7,13 @@ const testing = std.testing; const zeit = @import("zeit"); const LogHandler = @import("./LogHandler.zig"); +const Writer = LogHandler.Writer; const Output = @import("./root.zig").Output; const util = @import("./util.zig"); const LogEvent = util.LogEvent; const Level = util.Level; const Field = util.Field; +const Value = util.Value; pub const ColorableItem = enum { timestamp, @@ -192,8 +194,6 @@ test "color format 1" { try testing.expectEqualSlices(u8, sc.field_types.get(.string).?, "32;1"); } -const Writer = LogHandler.Writer; - pub const Formatter = union(enum) { text: ?ColorSchema, json, @@ -247,9 +247,9 @@ const JsonPrinter = struct { try event.timestamp.time().gofmt(self.w, "2006-01-02T15:04:05.000"); try self.w.writeByte('"'); - try writeField(self.w, &Field{ .name = "level", .value = std.json.Value{ .string = levelName(event.level) } }); - try writeField(self.w, &Field{ .name = "logger", .value = std.json.Value{ .string = if (event.logger_name) |name| name else "root" } }); - try writeField(self.w, &Field{ .name = "message", .value = std.json.Value{ .string = event.message } }); + try writeField(self.w, &Field{ .name = "level", .value = Value{ .string = levelName(event.level) } }); + try writeField(self.w, &Field{ .name = "logger", .value = Value{ .string = if (event.logger_name) |name| name else "root" } }); + try writeField(self.w, &Field{ .name = "message", .value = Value{ .string = event.message } }); if (event.constant_fields) |cf| { for (cf) |field| { @@ -266,10 +266,10 @@ const JsonPrinter = struct { fn writeField(w: Writer, field: *const Field) !void { try w.writeByte(','); - // FIXME the field name can be one of already used: timestamp, level, message + // FIXME: the field name can be one of already used: timestamp, level, message try writeFieldName(w, field.name); try w.writeByte(':'); - try std.json.stringify(field.value, .{}, w); + try field.value.write(w.any()); } fn writeFieldName(w: Writer, str: []const u8) !void { @@ -320,7 +320,8 @@ const ColorPrinter = struct { else => .string, }; try self.writeFieldTypeColor(value_type); - try std.json.stringify(field.value, .{}, w); + + try field.value.write(w.any()); try self.reset(); } try w.writeByte('\n'); diff --git a/src/root.zig b/src/root.zig index 43b3c9a..484913b 100644 --- a/src/root.zig +++ b/src/root.zig @@ -140,11 +140,11 @@ test "text logger" { test "json logger" { var log = try initRootLogger(testing.allocator, .{ .formatter = .json }); - log.info("Hello slog!", .{ .field1 = "value1", .field2 = "value1", .rate = 30 }); + log.info("Hello\tslog!", .{ .field1 = "value1", .field2 = "value1", .rate = 30 }); defer log.deinit(); const si = StringInspector{ .str = log.dispatcher.handler.output.items }; - try si.hasPattern("message\":\"Hello"); + try si.hasPattern("message\":\"Hello\\t"); try si.hasPattern("field1\":\"value1\""); } diff --git a/src/util.zig b/src/util.zig index 26300a2..16edee5 100644 --- a/src/util.zig +++ b/src/util.zig @@ -23,7 +23,26 @@ pub const Level = enum(u3) { pub const Field = struct { name: []const u8, - value: std.json.Value, + value: Value, +}; + +pub const Value = union(enum) { + null, + bool: bool, + integer: i64, + float: f64, + string: []const u8, + + pub fn write(self: Value, w: std.io.AnyWriter) !void { + switch (self) { + .null => try w.writeAll("null"), + .bool => |x| try std.fmt.format(w, "{}", .{x}), + .integer => |x| try std.fmt.format(w, "{}", .{x}), + .float => |x| try std.fmt.format(w, "{}", .{x}), + // .string => |x| try std.fmt.format(w, "\"{s}\"", .{x}), + .string => |x| try std.json.encodeJsonString(x, .{}, w), + } + } }; pub const LogEvent = struct {