Compare commits
15 Commits
ab0898f9c4
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| b3c8a3ab1c | |||
| 29c6e48d86 | |||
| 40ced30a57 | |||
| 57631f1905 | |||
|
b868bb1300
|
|||
|
4147c47f7e
|
|||
|
e813a3e195
|
|||
|
6f62c61897
|
|||
|
f065c08e91
|
|||
|
f43034cea9
|
|||
|
69da9265b8
|
|||
|
bd33f9c8f9
|
|||
|
a211aafed6
|
|||
|
411a6dc358
|
|||
|
cd99e5b4d3
|
@@ -17,7 +17,13 @@ jobs:
|
|||||||
- name: Setup zig installation
|
- name: Setup zig installation
|
||||||
uses: mlugg/setup-zig@v2
|
uses: mlugg/setup-zig@v2
|
||||||
with:
|
with:
|
||||||
version: master
|
version: latest
|
||||||
|
- name: Lint check
|
||||||
|
run: zig fmt --check .
|
||||||
|
- name: Spell checking
|
||||||
|
uses: crate-ci/typos@v1.39.0
|
||||||
|
with:
|
||||||
|
config: ./.typos-config
|
||||||
- name: Run tests
|
- name: Run tests
|
||||||
run: zig build --release=fast
|
run: zig build --release=fast
|
||||||
- name: Release build artifacts
|
- name: Release build artifacts
|
||||||
|
|||||||
@@ -16,11 +16,11 @@ jobs:
|
|||||||
- name: Setup zig installation
|
- name: Setup zig installation
|
||||||
uses: mlugg/setup-zig@v2
|
uses: mlugg/setup-zig@v2
|
||||||
with:
|
with:
|
||||||
version: master
|
version: latest
|
||||||
- name: Lint check
|
- name: Lint check
|
||||||
run: zig fmt --check .
|
run: zig fmt --check .
|
||||||
- name: Spell checking
|
- name: Spell checking
|
||||||
uses: crate-ci/typos@v1.25.0
|
uses: crate-ci/typos@v1.39.0
|
||||||
with:
|
with:
|
||||||
config: ./.typos-config
|
config: ./.typos-config
|
||||||
- name: Run tests
|
- name: Run tests
|
||||||
|
|||||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,2 +1,3 @@
|
|||||||
.zig-cache/
|
.zig-cache/
|
||||||
zig-out/
|
zig-out/
|
||||||
|
log
|
||||||
|
|||||||
@@ -1,2 +1,5 @@
|
|||||||
[files]
|
[files]
|
||||||
extend-exclude = []
|
extend-exclude = []
|
||||||
|
|
||||||
|
[default.extend-words]
|
||||||
|
WRONLY = "WRONLY"
|
||||||
|
|||||||
92
README.md
92
README.md
@@ -2,8 +2,25 @@
|
|||||||
|
|
||||||
Standard Library log wrapper. `zlog` provides adjusted `std.log` output and a pretty print function for easy overwriting of user defined types.
|
Standard Library log wrapper. `zlog` provides adjusted `std.log` output and a pretty print function for easy overwriting of user defined types.
|
||||||
|
|
||||||
> [!CAUTION]
|
## Install
|
||||||
> Only builds using the zig master version are tested to work.
|
|
||||||
|
Add or update this library as a dependency in your zig project run the following command:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
zig fetch --save git+https://gitea.yves-biener.de/yves-biener/zlog
|
||||||
|
```
|
||||||
|
|
||||||
|
Afterwards add the library as a dependency to any module in your *build.zig*:
|
||||||
|
|
||||||
|
```zig
|
||||||
|
const zlog_dependency = b.dependency("zlog", .{
|
||||||
|
.target = target,
|
||||||
|
.optimize = optimize,
|
||||||
|
.timestamp = true, // default (only required if non-default value shall be used)
|
||||||
|
.stderr = true, // default (only required if non-default value shall be used)
|
||||||
|
.file = "", // default (only required if non-default value shall be used)
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
@@ -58,6 +75,8 @@ const Struct = struct {
|
|||||||
};
|
};
|
||||||
|
|
||||||
pub fn main() void {
|
pub fn main() void {
|
||||||
|
// without explicit scope (i.e. `.default` scope)
|
||||||
|
std.log.info("Without explicit scope or `.default` scope", .{});
|
||||||
// initialize zlog with the scope of `main`
|
// initialize zlog with the scope of `main`
|
||||||
const log = std.log.scoped(.main);
|
const log = std.log.scoped(.main);
|
||||||
// NOTE the scope of `default` will result in no scoping being printed in
|
// NOTE the scope of `default` will result in no scoping being printed in
|
||||||
@@ -75,7 +94,7 @@ pub fn main() void {
|
|||||||
const void_tagged_union: TaggedUnion = .nothing;
|
const void_tagged_union: TaggedUnion = .nothing;
|
||||||
const uniun: Union = .{ .boolean = true };
|
const uniun: Union = .{ .boolean = true };
|
||||||
|
|
||||||
// NOTE: Depending on the optimization target some of these log messages
|
// NOTE Depending on the optimization target some of these log messages
|
||||||
// will not show, which is inline with the behavior of `std.log`.
|
// will not show, which is inline with the behavior of `std.log`.
|
||||||
log.debug("Debug message {any}", .{int_var});
|
log.debug("Debug message {any}", .{int_var});
|
||||||
log.info("Info message {any}", .{array_var});
|
log.info("Info message {any}", .{array_var});
|
||||||
@@ -87,6 +106,7 @@ pub fn main() void {
|
|||||||
log.err("Error message {any}", .{tagged_union});
|
log.err("Error message {any}", .{tagged_union});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// apply *zlog* logging options to `std` logger
|
||||||
pub const std_options = zlog.std_options;
|
pub const std_options = zlog.std_options;
|
||||||
|
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
@@ -96,62 +116,30 @@ const zlog = @import("zlog");
|
|||||||
This will result in the following output:
|
This will result in the following output:
|
||||||
|
|
||||||
```
|
```
|
||||||
[[1m2025-07-17 19:41:43[0m] [[38;5;12mdebug[0m]([2mmain[0m): Debug message 42
|
2025/11/02 11:57:29 [info] Without explicit scope or `.default` scope
|
||||||
[[1m2025-07-17 19:41:43[0m] [[38;5;10minfo[0m]([2mmain[0m): Info message { 1, 2, 3, 4 }
|
2025/11/02 11:57:29 [debug](main) Debug message 42
|
||||||
[[1m2025-07-17 19:41:43[0m] [[38;5;10minfo[0m]([2mmain[0m): Info message "This is a test"
|
2025/11/02 11:57:29 [info](main) Info message { 1, 2, 3, 4 }
|
||||||
[[1m2025-07-17 19:41:43[0m] [[38;5;11mwarning[0m]([2mmain[0m): Warning message main.Options = enum {
|
2025/11/02 11:57:29 [info](main) Info message "This is a test"
|
||||||
a,
|
2025/11/02 11:57:29 [warning](main) Warning message .a
|
||||||
b,
|
2025/11/02 11:57:29 [warning](main) Warning message .{ .nothing = void }
|
||||||
c,
|
2025/11/02 11:57:29 [warning](main) Warning message .{ ... }
|
||||||
} = .a
|
2025/11/02 11:57:29 [error](main) Error message .{ .a = 42, .b = true, .c = { 1, 2, 3, 4, 5 }, .d = { 115, 116, 114, 105, 110, 103 }, .e = .b, .f = .{ .one = -5 } }
|
||||||
[[1m2025-07-17 19:41:43[0m] [[38;5;11mwarning[0m]([2mmain[0m): Warning message main.TaggedUnion = union(enum) {
|
2025/11/02 11:57:29 [error](main) Error message .{ .three = { 84, 104, 114, 101, 101 } }
|
||||||
one: i16,
|
|
||||||
two: u32,
|
|
||||||
three: []const u8,
|
|
||||||
nothing,
|
|
||||||
} = .{ .nothing = void }
|
|
||||||
[[1m2025-07-17 19:41:43[0m] [[38;5;11mwarning[0m]([2mmain[0m): Warning message main.Union = union {
|
|
||||||
int: i32,
|
|
||||||
boolean: bool,
|
|
||||||
} = @7fffd1c71048
|
|
||||||
[[1m2025-07-17 19:41:43[0m] [[38;5;9merror[0m]([2mmain[0m): Error message main.Struct = struct {
|
|
||||||
.a = 42,
|
|
||||||
.b = true,
|
|
||||||
.c = []u16: { 1, 2, 3, 4, 5 },
|
|
||||||
.d = "string",
|
|
||||||
.e = main.Options = enum {
|
|
||||||
a,
|
|
||||||
b,
|
|
||||||
c,
|
|
||||||
} = .b,
|
|
||||||
.f = main.TaggedUnion = union(enum) {
|
|
||||||
one: i16,
|
|
||||||
two: u32,
|
|
||||||
three: []const u8,
|
|
||||||
nothing,
|
|
||||||
} = .{ .one = -5 },
|
|
||||||
}
|
|
||||||
[[1m2025-07-17 19:41:43[0m] [[38;5;9merror[0m]([2mmain[0m): Error message main.TaggedUnion = union(enum) {
|
|
||||||
one: i16,
|
|
||||||
two: u32,
|
|
||||||
three: []const u8,
|
|
||||||
nothing,
|
|
||||||
} = .{ .three = "Three" }
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Customization
|
## Customization
|
||||||
|
|
||||||
For more details about the output customization see the configuration options of the `zlog` module. Following options are available:
|
For more details about the output customization see the configuration options of the `zlog` module. Following options are available:
|
||||||
|
|
||||||
- _timestamp_ (default: `true`): Prepend the current timestamp before each log message.
|
- *timestamp* (default: `true`): Prepend the current timestamp before each log message. If disabled the date and time (i.e. `2025/11/02 11:57:29 `) are not prepended to each log message.
|
||||||
- _stderr_ (default: `true`): Print log messages to stderr.
|
- *stderr* (default: `true`): Print log messages to stderr.
|
||||||
> [!CAUTION]
|
- *file* (default: `""`): File path to log (appending; creates if does not exist) messages to. Without a path no log file will be created and logged to. Can be used in parallel with the *stderr* option.
|
||||||
> Currently not working as log output is not appended and only the last log message will be in the resulting log file! This is a not-yet-implemented feature of the standard library of zig! See this [issue](https://github.com/ziglang/zig/issues/14375) for more details.
|
|
||||||
> For now you should instead leave this option as it is and pipe the corresponding stderr outputs to a logfile instead.
|
|
||||||
|
|
||||||
## Tips
|
---
|
||||||
|
|
||||||
The following list shows some tips on how to use logging more effectively. These tips do not apply just to `zlog` (and not even only to zig code).
|
> [!tip]
|
||||||
|
> The following list shows some tips on how to use logging more effectively.
|
||||||
|
> These tips do not apply just to `zlog` (and not even only to zig code).
|
||||||
|
|
||||||
- Use `errdefer` to directly print messages on failures in the same function they occur:
|
- Use `errdefer` to directly print messages on failures in the same function they occur:
|
||||||
```zig
|
```zig
|
||||||
@@ -164,4 +152,4 @@ The following list shows some tips on how to use logging more effectively. These
|
|||||||
break :port try fmt.parseInt(u16, buf[0 .. len -| 1], 10);
|
break :port try fmt.parseInt(u16, buf[0 .. len -| 1], 10);
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
- When looking through the output of the log (i.e. written to disk by `program 2> log` when using the _stderr_ build option) the `log` file contains control code characters (*ansi*) for the colored outputs. You can still see them correctly with the following command `less -R log`.
|
- When looking through the output of the log (i.e. written to disk by `program 2> log` when using the *stderr* build option) the `log` file contains control code characters (*ansi*) for the colored outputs. You can still see them correctly with the following command `less -R log`. When using the *file* build option the *ansi* control characters are not omitted when logging to the file.
|
||||||
|
|||||||
@@ -27,11 +27,6 @@ pub fn build(b: *std.Build) void {
|
|||||||
// set a preferred release mode, allowing the user to decide how to optimize.
|
// set a preferred release mode, allowing the user to decide how to optimize.
|
||||||
const optimize = b.standardOptimizeOption(.{});
|
const optimize = b.standardOptimizeOption(.{});
|
||||||
|
|
||||||
const ztime_dependency = b.dependency("ztime", .{
|
|
||||||
.target = target,
|
|
||||||
.optimize = optimize,
|
|
||||||
});
|
|
||||||
|
|
||||||
const zlog_module = b.addModule("zlog", .{
|
const zlog_module = b.addModule("zlog", .{
|
||||||
// In this case the main source file is merely a path, however, in more
|
// In this case the main source file is merely a path, however, in more
|
||||||
// complicated build scripts, this could be a generated file.
|
// complicated build scripts, this could be a generated file.
|
||||||
@@ -39,7 +34,6 @@ pub fn build(b: *std.Build) void {
|
|||||||
.target = target,
|
.target = target,
|
||||||
.optimize = optimize,
|
.optimize = optimize,
|
||||||
.imports = &.{
|
.imports = &.{
|
||||||
.{ .name = "ztime", .module = ztime_dependency.module("ztime") },
|
|
||||||
.{ .name = "build_options", .module = options_module },
|
.{ .name = "build_options", .module = options_module },
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@@ -51,7 +45,6 @@ pub fn build(b: *std.Build) void {
|
|||||||
.target = target,
|
.target = target,
|
||||||
.optimize = optimize,
|
.optimize = optimize,
|
||||||
.imports = &.{
|
.imports = &.{
|
||||||
.{ .name = "ztime", .module = ztime_dependency.module("ztime") },
|
|
||||||
.{ .name = "zlog", .module = zlog_module },
|
.{ .name = "zlog", .module = zlog_module },
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
@@ -93,7 +86,6 @@ pub fn build(b: *std.Build) void {
|
|||||||
.target = target,
|
.target = target,
|
||||||
.optimize = optimize,
|
.optimize = optimize,
|
||||||
.imports = &.{
|
.imports = &.{
|
||||||
.{ .name = "ztime", .module = ztime_dependency.module("ztime") },
|
|
||||||
.{ .name = "build_options", .module = options_module },
|
.{ .name = "build_options", .module = options_module },
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
|
|||||||
@@ -1,16 +1,10 @@
|
|||||||
.{
|
.{
|
||||||
.name = .zlog,
|
.name = .zlog,
|
||||||
|
// This is a [Semantic Version](https://semver.org/).
|
||||||
|
.version = "0.16.0",
|
||||||
.fingerprint = 0x55b82e3347a594e8,
|
.fingerprint = 0x55b82e3347a594e8,
|
||||||
// version name should match the zig version except for the last number,
|
.minimum_zig_version = "0.16.0-dev.463+f624191f9",
|
||||||
// which stands for the version inside a given zig version
|
.dependencies = .{},
|
||||||
.version = "0.15.0",
|
|
||||||
.dependencies = .{
|
|
||||||
.ztime = .{
|
|
||||||
.url = "git+https://gitea.yves-biener.de/yves-biener/ztime#6a2f853f36aa55146e089d7c0c3f041012c0f8fe",
|
|
||||||
.hash = "ztime-0.0.0-e3nBJL5xAAC_guuqgVnOZncpvwH76NnKRC7JJ_zTF9rV",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
.minimum_zig_version = "0.15.0",
|
|
||||||
.paths = .{
|
.paths = .{
|
||||||
"build.zig",
|
"build.zig",
|
||||||
"build.zig.zon",
|
"build.zig.zon",
|
||||||
|
|||||||
@@ -46,6 +46,8 @@ const Struct = struct {
|
|||||||
};
|
};
|
||||||
|
|
||||||
pub fn main() void {
|
pub fn main() void {
|
||||||
|
// without explicit scope (i.e. `.default` scope)
|
||||||
|
std.log.info("Without explicit scope or `.default` scope", .{});
|
||||||
// initialize zlog with the scope of `main`
|
// initialize zlog with the scope of `main`
|
||||||
const log = std.log.scoped(.main);
|
const log = std.log.scoped(.main);
|
||||||
// NOTE the scope of `default` will result in no scoping being printed in
|
// NOTE the scope of `default` will result in no scoping being printed in
|
||||||
@@ -63,7 +65,7 @@ pub fn main() void {
|
|||||||
const void_tagged_union: TaggedUnion = .nothing;
|
const void_tagged_union: TaggedUnion = .nothing;
|
||||||
const uniun: Union = .{ .boolean = true };
|
const uniun: Union = .{ .boolean = true };
|
||||||
|
|
||||||
// NOTE: Depending on the optimization target some of these log messages
|
// NOTE Depending on the optimization target some of these log messages
|
||||||
// will not show, which is inline with the behavior of `std.log`.
|
// will not show, which is inline with the behavior of `std.log`.
|
||||||
log.debug("Debug message {any}", .{int_var});
|
log.debug("Debug message {any}", .{int_var});
|
||||||
log.info("Info message {any}", .{array_var});
|
log.info("Info message {any}", .{array_var});
|
||||||
@@ -75,6 +77,7 @@ pub fn main() void {
|
|||||||
log.err("Error message {any}", .{tagged_union});
|
log.err("Error message {any}", .{tagged_union});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// apply *zlog* logging options to `std` logger
|
||||||
pub const std_options = zlog.std_options;
|
pub const std_options = zlog.std_options;
|
||||||
|
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
|
|||||||
94
src/root.zig
94
src/root.zig
@@ -5,57 +5,86 @@ fn logFn(
|
|||||||
comptime format: []const u8,
|
comptime format: []const u8,
|
||||||
args: anytype,
|
args: anytype,
|
||||||
) void {
|
) void {
|
||||||
// TODO provide build time configuration to allow tweaking corresponding output
|
|
||||||
// - change output file for writing messages to (default `stderr`)
|
|
||||||
// - write into own file for each level?
|
|
||||||
|
|
||||||
const prefix = if (scope == .default) ": " else "(\x1b[2m" ++ @tagName(scope) ++ "\x1b[0m): ";
|
|
||||||
const level_txt = switch (comptime message_level) {
|
|
||||||
.err => "[\x1b[38;5;9merror\x1b[0m]",
|
|
||||||
.warn => "[\x1b[38;5;11mwarning\x1b[0m]",
|
|
||||||
.info => "[\x1b[38;5;10minfo\x1b[0m]",
|
|
||||||
.debug => "[\x1b[38;5;12mdebug\x1b[0m]",
|
|
||||||
};
|
|
||||||
const complete_format = level_txt ++ prefix ++ format ++ "\n";
|
|
||||||
var buf: [128]u8 = undefined;
|
var buf: [128]u8 = undefined;
|
||||||
if (comptime build_options.file.len != 0) {
|
if (comptime build_options.file.len > 0) {
|
||||||
// TODO handle errors accordingly (i.e. panic?)
|
const prefix = if (scope == .default) " " else "(" ++ @tagName(scope) ++ ") ";
|
||||||
// NOTE with zig 0.13.0 there is currently no way to open files to append (except to use libc or talk directly to posix, which this lib should not have to do)
|
const level_txt = switch (comptime message_level) {
|
||||||
const file = std.fs.openFileAbsolute(build_options.file, .{
|
.err => "[error]",
|
||||||
.mode = .read_write,
|
.warn => "[warning]",
|
||||||
}) catch std.fs.createFileAbsolute(build_options.file, .{
|
.info => "[info]",
|
||||||
.truncate = false,
|
.debug => "[debug]",
|
||||||
}) catch @panic("Failed to open and/or create configured log file");
|
};
|
||||||
defer file.close();
|
// TODO let user configure the format he wants to use for logging and use a pretty good default one?
|
||||||
|
const complete_format = level_txt ++ prefix ++ format ++ "\n";
|
||||||
|
// TODO use common logging format, such that in integrates well with other logging frameworks
|
||||||
|
// (i.e. golang's logger, log4j, etc.)
|
||||||
|
const fd = std.posix.open(build_options.file, .{
|
||||||
|
.CREAT = true,
|
||||||
|
.APPEND = true,
|
||||||
|
.ACCMODE = .WRONLY,
|
||||||
|
}, 0o600) catch @panic("Could not append to log file");
|
||||||
|
defer std.posix.close(fd);
|
||||||
|
|
||||||
|
var file: fs.File = .{ .handle = fd };
|
||||||
var buffer = file.writer(&buf);
|
var buffer = file.writer(&buf);
|
||||||
var writer = &buffer.interface;
|
var writer = &buffer.interface;
|
||||||
defer writer.flush() catch {};
|
defer writer.flush() catch unreachable;
|
||||||
|
|
||||||
log_writing(writer, complete_format, args);
|
log_writing(writer, complete_format, false, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (comptime build_options.stderr) {
|
if (comptime build_options.stderr) {
|
||||||
var buffer = stderr().writer(&buf);
|
const prefix = if (scope == .default) " " else "(\x1b[2m" ++ @tagName(scope) ++ "\x1b[0m) ";
|
||||||
var writer = &buffer.interface;
|
const level_txt = switch (comptime message_level) {
|
||||||
defer writer.flush() catch {};
|
.err => "[\x1b[38;5;9merror\x1b[0m]",
|
||||||
|
.warn => "[\x1b[38;5;11mwarning\x1b[0m]",
|
||||||
|
.info => "[\x1b[38;5;10minfo\x1b[0m]",
|
||||||
|
.debug => "[\x1b[38;5;12mdebug\x1b[0m]",
|
||||||
|
};
|
||||||
|
const complete_format = level_txt ++ prefix ++ format ++ "\n";
|
||||||
|
|
||||||
std.debug.lockStdErr();
|
std.debug.lockStdErr();
|
||||||
defer std.debug.unlockStdErr();
|
defer std.debug.unlockStdErr();
|
||||||
|
|
||||||
log_writing(writer, complete_format, args);
|
var buffer = fs.File.stderr().writer(&buf);
|
||||||
|
var writer = &buffer.interface;
|
||||||
|
defer writer.flush() catch unreachable;
|
||||||
|
|
||||||
|
log_writing(writer, complete_format, true, args);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inline fn log_writing(writer: *std.Io.Writer, comptime format: []const u8, args: anytype) void {
|
inline fn log_writing(writer: *std.Io.Writer, comptime format: []const u8, comptime ansi: bool, args: anytype) void {
|
||||||
nosuspend {
|
nosuspend {
|
||||||
if (build_options.timestamp) log_timestamp(writer);
|
if (build_options.timestamp) log_timestamp(writer, ansi);
|
||||||
writer.print(format, args) catch return;
|
writer.print(format, args) catch return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inline fn log_timestamp(writer: anytype) void {
|
/// Prepend the current timestamp in the following format:
|
||||||
writer.print("[\x1b[1m{any}\x1b[0m] ", .{ztime.DateTime.now()}) catch return;
|
/// `<year>/<month>/<day> <hour>:<minute>:<sec> `
|
||||||
|
///
|
||||||
|
/// NOTE all information are displayed using numbers
|
||||||
|
inline fn log_timestamp(writer: anytype, comptime ansi: bool) void {
|
||||||
|
const time = std.posix.clock_gettime(.REALTIME) catch @panic("Cannot request timestamp");
|
||||||
|
const epoch_secs: std.time.epoch.EpochSeconds = .{ .secs = @intCast(time.sec) };
|
||||||
|
const day_secs = epoch_secs.getDaySeconds();
|
||||||
|
const year_and_day = epoch_secs.getEpochDay().calculateYearDay();
|
||||||
|
const month_and_day = year_and_day.calculateMonthDay();
|
||||||
|
writer.print(
|
||||||
|
if (comptime ansi)
|
||||||
|
"\x1b[1m{d}/{d:0>2}/{d:0>2} {d:0>2}:{d:0>2}:{d:0>2}\x1b[0m "
|
||||||
|
else
|
||||||
|
"{d}/{d:0>2}/{d:0>2} {d:0>2}:{d:0>2}:{d:0>2} ",
|
||||||
|
.{
|
||||||
|
year_and_day.year,
|
||||||
|
month_and_day.month.numeric(),
|
||||||
|
month_and_day.day_index + 1,
|
||||||
|
day_secs.getHoursIntoDay(),
|
||||||
|
day_secs.getMinutesIntoHour(),
|
||||||
|
day_secs.getSecondsIntoMinute(),
|
||||||
|
},
|
||||||
|
) catch return;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn pretty_format(object: anytype, comptime format: []const u8, options: fmt.FormatOptions, writer: anytype) !void {
|
pub fn pretty_format(object: anytype, comptime format: []const u8, options: fmt.FormatOptions, writer: anytype) !void {
|
||||||
@@ -193,10 +222,7 @@ pub const std_options: std.Options = .{
|
|||||||
};
|
};
|
||||||
|
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const io = std.io;
|
|
||||||
const fs = std.fs;
|
const fs = std.fs;
|
||||||
const stderr = fs.File.stderr;
|
|
||||||
const log = std.log;
|
const log = std.log;
|
||||||
const fmt = std.fmt;
|
const fmt = std.fmt;
|
||||||
const build_options = @import("build_options");
|
const build_options = @import("build_options");
|
||||||
const ztime = if (build_options.timestamp) @import("ztime") else null;
|
|
||||||
|
|||||||
Reference in New Issue
Block a user