1import { setFormatter, setLogLevel, getLogLevel } from "../../seed/log.js";
2import { sendOk, sendError, ERR } from "../../seed/protocol.js";
3import express from "express";
4import authenticate from "../../seed/middleware/authenticate.js";
5
6const DIM = "\x1b[2m";
7const RESET = "\x1b[0m";
8const BOLD = "\x1b[1m";
9const RED = "\x1b[31m";
10const YELLOW = "\x1b[33m";
11const CYAN = "\x1b[36m";
12const GREEN = "\x1b[32m";
13const WHITE = "\x1b[37m";
14
15function timestamp() {
16 const d = new Date();
17 return `${DIM}${d.toLocaleTimeString()}${RESET}`;
18}
19
20function formatTag(tag) {
21 return `${CYAN}${tag}${RESET}`;
22}
23
24function formatter(level, tag, message, ...args) {
25 const ts = timestamp();
26 const tagStr = formatTag(tag);
27
28 if (level === "error") {
29 console.error(`${ts} ${RED}ERR${RESET} ${tagStr} ${message}`, ...args);
30 return true;
31 }
32
33 if (level === "warn") {
34 console.warn(`${ts} ${YELLOW}WRN${RESET} ${tagStr} ${message}`, ...args);
35 return true;
36 }
37
38 if (level === 1) {
39 console.log(`${ts} ${GREEN}${BOLD}${tag}${RESET} ${WHITE}${message}${RESET}`, ...args);
40 return true;
41 }
42
43 if (level === 2) {
44 console.log(`${ts} ${tagStr} ${message}`, ...args);
45 return true;
46 }
47
48 if (level === 3) {
49 console.log(`${ts} ${DIM}${tag} ${message}${RESET}`, ...args);
50 return true;
51 }
52
53 return false;
54}
55
56const router = express.Router();
57
58router.post("/land/log-level", authenticate, async (req, res) => {
59 try {
60 const level = parseInt(req.body.level, 10);
61 if (isNaN(level) || level < 1 || level > 3) {
62 return sendError(res, 400, ERR.INVALID_INPUT, "Level must be 1, 2, or 3");
63 }
64 setLogLevel(level);
65 sendOk(res, { level: getLogLevel(), labels: { 1: "info", 2: "verbose", 3: "debug" } });
66 } catch (err) {
67 sendError(res, 500, ERR.INTERNAL, err.message);
68 }
69});
70
71router.get("/land/log-level", authenticate, async (req, res) => {
72 sendOk(res, { level: getLogLevel(), labels: { 1: "info", 2: "verbose", 3: "debug" } });
73});
74
75export async function init(core) {
76 setFormatter(formatter);
77
78 const level = parseInt(process.env.LOG_LEVEL, 10);
79 if (!isNaN(level)) setLogLevel(level);
80
81 return { router };
82}
83
1export default {
2 name: "console",
3 version: "1.0.1",
4 builtFor: "TreeOS",
5 description:
6 "Replaces the kernel's default log output with color-coded, timestamped, human-readable " +
7 "server logs. Without this extension, log calls go to bare console output. With it, " +
8 "every line gets a timestamp, a severity indicator, and a colored tag identifying the " +
9 "source system. " +
10 "\n\n" +
11 "Three severity levels. Level 1 (info): bold green tags, white messages. The important " +
12 "events. Extension loaded, server listening, migration complete. Level 2 (verbose): " +
13 "cyan tags, normal weight. The operational detail. Route registered, hook fired, session " +
14 "created. Level 3 (debug): dim text, everything. LLM call payloads, metadata writes, " +
15 "cache hits. Errors and warnings always print regardless of level, in red and yellow " +
16 "respectively. " +
17 "\n\n" +
18 "The log level is configurable at boot via the LOG_LEVEL environment variable and " +
19 "adjustable at runtime through the HTTP endpoint or CLI command. Set it to 1 in " +
20 "production for clean, quiet output. Set it to 3 when debugging a hook chain or " +
21 "tracing an orchestrator flow. The change takes effect immediately without restart. " +
22 "\n\n" +
23 "This extension replaces the kernel's log formatter function at init. It does not " +
24 "wrap or proxy. It provides the formatter that the kernel's log module calls on every " +
25 "output. Remove this extension and the land falls back to unformatted console output. " +
26 "Replace it with your own formatter for structured JSON logs, remote log shipping, or " +
27 "any output format your infrastructure requires.",
28
29 needs: {},
30
31 optional: {},
32
33 provides: {
34 models: {},
35 routes: false,
36 tools: false,
37 jobs: false,
38 env: [
39 { key: "LOG_LEVEL", required: false, default: "2", description: "Log severity: 1=info, 2=verbose, 3=debug" },
40 ],
41 cli: [
42 { command: "log-level <level>", scope: ["land"], description: "Set log level (1=info, 2=verbose, 3=debug)", method: "POST", endpoint: "/land/log-level", body: ["level"] },
43 ],
44 },
45};
46
Loading comments...