132 lines
3.7 KiB
JavaScript
132 lines
3.7 KiB
JavaScript
/**
|
|
* Host-side booter diagnostics (runs before guest VFS exists).
|
|
* Avoids raw console.warn as the only sink; supports suppression and NDJSON file append.
|
|
*
|
|
* Env:
|
|
* - BARE_OS_HOST_BOOTER_LOG — `stderr` (default), `0`/`false`/`off` (silent), `ndjson` (append file)
|
|
* - BARE_OS_HOST_BOOTER_LOG_PATH — override path when mode is `ndjson` (default: ~/.bare-os/var/log/booter-host.ndjson)
|
|
*/
|
|
import fs from '#host-fs'
|
|
import path from '#host-path'
|
|
|
|
function hostDataRoot() {
|
|
const override =
|
|
globalThis.process?.env && globalThis.process.env.BARE_OS_HOST_DATA
|
|
if (override) return path.resolve(String(override))
|
|
const home =
|
|
(globalThis.process?.env && globalThis.process.env.HOME) || '/tmp'
|
|
return path.join(String(home), '.bare-os')
|
|
}
|
|
|
|
function defaultNdjsonPath() {
|
|
return path.join(hostDataRoot(), 'var', 'log', 'booter-host.ndjson')
|
|
}
|
|
|
|
/**
|
|
* @param {string} code Stable machine-readable code (e.g. ctx_bare_load_failed).
|
|
* @param {string} human Human-readable message (no secrets).
|
|
* @param {string} [detail] Optional short detail (error.message, etc.).
|
|
*/
|
|
/**
|
|
* Host-side informational line (boot trace off): stderr when mode is stderr; optional NDJSON append.
|
|
* @param {string} code
|
|
* @param {string} human
|
|
* @param {string} [detail]
|
|
*/
|
|
export function bareOsHostBooterInfo(code, human, detail) {
|
|
const env = globalThis.process?.env || {}
|
|
const mode = String(env.BARE_OS_HOST_BOOTER_LOG || 'stderr')
|
|
.trim()
|
|
.toLowerCase()
|
|
if (
|
|
mode === '0' ||
|
|
mode === 'false' ||
|
|
mode === 'off' ||
|
|
mode === 'no' ||
|
|
mode === 'silent'
|
|
) {
|
|
return
|
|
}
|
|
|
|
const d = detail != null ? String(detail).slice(0, 4000) : ''
|
|
const line = `[bare-os-booter][${code}] ${human}${d ? `: ${d}` : ''}`
|
|
|
|
if (mode === 'ndjson') {
|
|
const logPath = String(env.BARE_OS_HOST_BOOTER_LOG_PATH || '').trim() || defaultNdjsonPath()
|
|
try {
|
|
fs.mkdirSync(path.dirname(logPath), { recursive: true })
|
|
fs.appendFileSync(
|
|
logPath,
|
|
`${JSON.stringify({
|
|
type: 'booterHostInfo',
|
|
code: String(code).slice(0, 128),
|
|
message: String(human).slice(0, 2000),
|
|
detail: d || undefined,
|
|
ts: Date.now()
|
|
})}\n`,
|
|
'utf8'
|
|
)
|
|
} catch {
|
|
/* fall through */
|
|
}
|
|
}
|
|
|
|
if (mode === 'ndjson' && env.BARE_OS_HOST_BOOTER_LOG_STDERR !== '1') {
|
|
return
|
|
}
|
|
|
|
const err = globalThis.process?.stderr
|
|
if (err && typeof err.write === 'function') {
|
|
err.write(`${line}\n`)
|
|
} else if (typeof console.info === 'function') {
|
|
console.info(line)
|
|
}
|
|
}
|
|
|
|
export function bareOsHostBooterWarn(code, human, detail) {
|
|
const env = globalThis.process?.env || {}
|
|
const mode = String(env.BARE_OS_HOST_BOOTER_LOG || 'stderr')
|
|
.trim()
|
|
.toLowerCase()
|
|
if (
|
|
mode === '0' ||
|
|
mode === 'false' ||
|
|
mode === 'off' ||
|
|
mode === 'no' ||
|
|
mode === 'silent'
|
|
) {
|
|
return
|
|
}
|
|
|
|
const d = detail != null ? String(detail).slice(0, 4000) : ''
|
|
const line = `[bare-os-booter][${code}] ${human}${d ? `: ${d}` : ''}`
|
|
|
|
if (mode === 'ndjson') {
|
|
const logPath = String(env.BARE_OS_HOST_BOOTER_LOG_PATH || '').trim() || defaultNdjsonPath()
|
|
try {
|
|
fs.mkdirSync(path.dirname(logPath), { recursive: true })
|
|
fs.appendFileSync(
|
|
logPath,
|
|
`${JSON.stringify({
|
|
type: 'booterHostWarn',
|
|
code: String(code).slice(0, 128),
|
|
message: String(human).slice(0, 2000),
|
|
detail: d || undefined,
|
|
ts: Date.now()
|
|
})}\n`,
|
|
'utf8'
|
|
)
|
|
} catch {
|
|
/* fall through to stderr */
|
|
}
|
|
}
|
|
|
|
if (mode === 'ndjson' && env.BARE_OS_HOST_BOOTER_LOG_STDERR !== '1') {
|
|
return
|
|
}
|
|
|
|
if (typeof console !== 'undefined' && typeof console.warn === 'function') {
|
|
console.warn(line)
|
|
}
|
|
}
|