Skip to content

Commit fcecd43

Browse files
committed
Expose more builder details in the API
1 parent f67ea21 commit fcecd43

3 files changed

Lines changed: 91 additions & 48 deletions

File tree

src/Builder.zig

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
//! A builder to crate a list of scope filters.
2-
//! The input can be added programatically or a string is parsed.
2+
//! The input can be added programmatically or a string is parsed.
33
//! The string format is a comma-separated list of `scope=level` pairs:
44
//!
55
//! scope_a=info,scope_b=debug
@@ -115,6 +115,51 @@ pub fn tryParse(self: *Builder, spec: []const u8) (error{BuilderError} || mem.Al
115115
if (self.diags.items.len > 0) return error.BuilderError;
116116
}
117117

118+
pub fn parseLogErrors(self: *Builder, spec: []const u8) mem.Allocator.Error!void {
119+
self.tryParse(spec) catch |err| switch (err) {
120+
error.BuilderError => self.logDiagnostics(),
121+
else => |e| return e,
122+
};
123+
}
124+
125+
pub fn parseEnv(self: *Builder, env_var: []const u8) (mem.Allocator.Error)!bool {
126+
const spec = std.process.getEnvVarOwned(self.gpa, env_var) catch |err| switch (err) {
127+
error.EnvironmentVariableNotFound => return false,
128+
error.InvalidWtf8 => {
129+
try self.invalidFilter(env_var);
130+
return false;
131+
},
132+
else => |e| return e,
133+
};
134+
defer self.gpa.free(spec);
135+
try self.parse(spec);
136+
return true;
137+
}
138+
139+
pub fn tryParseEnv(self: *Builder, env_var: []const u8) (error{BuilderError} || mem.Allocator.Error)!bool {
140+
const ret = try self.parseEnv(env_var);
141+
if (self.diags.items.len > 0) return error.BuilderError;
142+
return ret;
143+
}
144+
145+
pub fn parseEnvLogErrors(self: *Builder, env_var: []const u8) mem.Allocator.Error!bool {
146+
return self.tryParseEnv(env_var) catch |err| switch (err) {
147+
error.BuilderError => {
148+
self.logDiagnostics();
149+
return false;
150+
},
151+
else => |e| return e,
152+
};
153+
}
154+
155+
pub fn logDiagnostics(self: *const Builder) void {
156+
for (self.diagnostics()) |diag| switch (diag) {
157+
.invalid_filter => |f| {
158+
std.debug.print("Warning: Invalid filter: `{s}`, ignoring it\n", .{f});
159+
},
160+
};
161+
}
162+
118163
pub fn addFilter(self: *Builder, scope: ?[]const u8, level: Level) mem.Allocator.Error!void {
119164
const search_scope = scope orelse "";
120165

@@ -132,6 +177,14 @@ pub fn addFilter(self: *Builder, scope: ?[]const u8, level: Level) mem.Allocator
132177
}
133178
}
134179

180+
pub fn addLevel(self: *Builder, level: Level) mem.Allocator.Error!void {
181+
try self.addFilter(null, level);
182+
}
183+
184+
pub fn addScopeLevel(self: *Builder, scope: ScopeLevel) mem.Allocator.Error!void {
185+
try self.addFilter(scope.scope, scope.level);
186+
}
187+
135188
pub fn diagnostics(self: *const Builder) []const Diagnostic {
136189
return self.diags.items;
137190
}

src/Filter.zig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ filters: []const ScopeLevel,
1212
/// The default filter only allows all error log messages.
1313
pub const default: Filter = .{ .filters = &[_]ScopeLevel{default_filter} };
1414

15-
const default_filter: ScopeLevel = .{ .scope = "", .level = .err };
15+
pub const default_filter: ScopeLevel = .{ .scope = "", .level = .err };
1616

1717
pub const ScopeLevel = struct {
1818
scope: []const u8,

src/Logger.zig

Lines changed: 36 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -115,64 +115,54 @@ pub const InitOptions = struct {
115115
fallback: ?Filter.Level = null,
116116
};
117117

118-
fn intoFilter(
119-
self: FilterOpts,
120-
parse_gpa: std.mem.Allocator,
118+
pub fn parseEnv(
119+
opts: EnvVarOpts,
120+
gpa: std.mem.Allocator,
121121
filter_arena: ?std.mem.Allocator,
122122
) TryInitError!Filter {
123-
// we can delay hitting the gpa for parsing the env var as it is likely smaller
124-
var fba = std.heap.stackFallback(4096, parse_gpa);
125-
const stack_gpa = fba.get();
126-
127-
// drop all at the end
128-
// maybe this is all overkill, dunno
129-
var arena_impl: std.heap.ArenaAllocator = .init(stack_gpa);
130-
defer arena_impl.deinit();
131-
132-
const arena = arena_impl.allocator();
133-
134-
sw: switch (self) {
135-
.env => |env| {
136-
const env_filters = std.process.getEnvVarOwned(arena, env.name) catch |err| switch (err) {
137-
error.EnvironmentVariableNotFound => {
138-
if (env.fallback) |fallback| {
139-
continue :sw .{ .level = fallback };
140-
} else {
141-
return .default;
142-
}
143-
},
144-
error.InvalidWtf8 => return TryInitError.InvalidEnvValue,
145-
else => |e| return e,
146-
};
147-
continue :sw .{ .parse = env_filters };
148-
},
149-
.parse => |filter_input| return try parseFilter(filter_input, arena, filter_arena),
150-
.level => |level| return try Builder.singleLevel(filter_arena orelse arena, level),
151-
.filter => |filter| return filter,
123+
var builder = Builder.init(gpa);
124+
defer builder.deinit();
125+
126+
if (!try builder.parseEnvLogErrors(opts.name)) {
127+
if (opts.fallback) |fallback| {
128+
try builder.addLevel(fallback);
129+
} else {
130+
try builder.addScopeLevel(Filter.default_filter);
131+
}
152132
}
133+
134+
return try if (filter_arena) |a| builder.buildWithAllocator(a) else builder.build();
153135
}
154136

155-
fn parseFilter(
156-
filter_input: []const u8,
157-
parse_gpa: std.mem.Allocator,
137+
pub fn parseConfig(
138+
config: []const u8,
139+
gpa: std.mem.Allocator,
158140
filter_arena: ?std.mem.Allocator,
159141
) TryInitError!Filter {
160-
var builder = Builder.init(parse_gpa);
142+
var builder = Builder.init(gpa);
161143
defer builder.deinit();
162144

163-
builder.tryParse(filter_input) catch |err| switch (err) {
164-
error.BuilderError => {
165-
for (builder.diagnostics()) |diag| switch (diag) {
166-
.invalid_filter => |f| {
167-
std.debug.print("Warning: Invalid filter: `{s}`, ignoring it\n", .{f});
168-
},
169-
};
170-
},
171-
else => |e| return e,
172-
};
145+
try builder.parseLogErrors(config);
173146

174147
return try if (filter_arena) |a| builder.buildWithAllocator(a) else builder.build();
175148
}
149+
150+
pub fn wrapLevel(level: Filter.Level, arena: std.mem.Allocator) TryInitError!Filter {
151+
return try Builder.singleLevel(arena, level);
152+
}
153+
154+
fn intoFilter(
155+
self: FilterOpts,
156+
parse_gpa: std.mem.Allocator,
157+
filter_arena: ?std.mem.Allocator,
158+
) TryInitError!Filter {
159+
switch (self) {
160+
.env => |env| return parseEnv(env, parse_gpa, filter_arena),
161+
.parse => |spec| return parseConfig(spec, parse_gpa, filter_arena),
162+
.level => |level| return try wrapLevel(level, filter_arena orelse parse_gpa),
163+
.filter => |filter| return filter,
164+
}
165+
}
176166
};
177167

178168
pub const Output = union(enum) {

0 commit comments

Comments
 (0)