summaryrefslogtreecommitdiff
path: root/tracer.ha
blob: 99f4189e238a3b6dbde169fb7a168eac727e6c05 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
use memio;
use time::date;
use fmt;
use io;
use strings;
use trace;

type Tracer = struct {
	trace::tracer,
	sink: io::handle,
};

fn newtracer(sink: io::handle) Tracer =
	Tracer {
		log = &tracer_log,
		sink = sink,
	};

fn tracer_log(
	tr: *trace::tracer,
	ctx: nullable *trace::context,
	lvl: trace::level,
	fmt: str,
	fields: fmt::field...
) void = {
	const tr = tr: *Tracer;

	// XXX: ideally there would be a statically allocated buffer for
	// reasonably short messages and allocation would only happen for
	// messages longer than that. ideally ideally there would be locking so
	// we wouldn't need to allocate at all.
	const buf = memio::dynamic_from(alloc([], 256));
	defer io::close(&buf)!;

	const now = date::now();
	io::write(&buf, [0x5b])!; // "["
	date::format(&buf, date::STAMP, &now)!;
	io::write(&buf, [0x5d, 0x20])!; // "] "

	const lvlstr = switch (lvl) {
	case trace::level::ERROR =>
		yield "error: ";
	case trace::level::WARN =>
		yield "warning: ";
	case trace::level::INFO =>
		yield "info: ";
	case trace::level::DEBUG =>
		yield "debug: ";
	case trace::level::TRACE =>
		yield "trace: ";
	};
	io::write(&buf, strings::toutf8(lvlstr))!;

	let ctx_ = ctx;
	for (true) match (ctx_) {
	case let ctx__: *trace::context =>
		fmt::fprintf(&buf, ctx__.fmt, ctx__.fields...)!;
		io::write(&buf, [0x3a, 0x20])!; // ": "
		ctx_ = ctx__.next;
	case null => break;
	};

	fmt::fprintfln(&buf, fmt, fields...)!;

	io::write(tr.sink, memio::buffer(&buf)): void;
};