fix var log
This commit is contained in:
@@ -630,6 +630,7 @@ async function executeKernel(disk, store, swarm, initSource) {
|
||||
'BARE_OS_SHELL_NOUNSET',
|
||||
'BARE_OS_TELEMETRY_NDJSON',
|
||||
'BARE_OS_TELEMETRY_OTEL_JSONL',
|
||||
'BARE_OS_VAR_LOG_DEBUG',
|
||||
'BARE_OS_PROC_POLL_MS',
|
||||
'BARE_OS_TIMER_EVERY_MS_MONOTONIC',
|
||||
'BARE_OS_TRACE_ID',
|
||||
|
||||
@@ -1,11 +1,50 @@
|
||||
/**
|
||||
* Append-only UTF-8 logs under logical `/var/log/…` (VFS maps to the personal Hyperdrive).
|
||||
*
|
||||
* Until the first successful `mkdir`/`writeFile`, `readdir('/var/log')` may be empty even though
|
||||
* `lstat('/var/log')` looks like a directory — logs live under `/var/log/bare-os/` on the logical
|
||||
* tree and on the personal drive under `/.bare-os/…/var/log/<HOME-seg>/` (see `vfs.js` routing).
|
||||
*
|
||||
* Failures are best-effort silent unless **`BARE_OS_VAR_LOG_DEBUG=1`** (or `true`): then messages
|
||||
* go to **`process.stderr`** and **`ctx.console.error`**. Kernel metrics: `varlog.append.*`,
|
||||
* `varlog.ensure.*` (see `bareOsKernelMetricsSnapshot()`).
|
||||
*/
|
||||
|
||||
import {
|
||||
BARE_OS_LIFECYCLE_SCHEMA_VERSION,
|
||||
BARE_OS_TELEMETRY_SCHEMA_VERSION
|
||||
} from './bare-os-lifecycle-schema.js'
|
||||
import { bareOsKernelMetricInc } from './bare-os-kernel-metrics.js'
|
||||
|
||||
/**
|
||||
* @param {Record<string, unknown>} ctx
|
||||
* @param {string} msg
|
||||
*/
|
||||
function varLogDebug(ctx, msg) {
|
||||
try {
|
||||
const env =
|
||||
ctx && ctx.env && typeof ctx.env === 'object'
|
||||
? /** @type {Record<string, string | undefined>} */ (ctx.env)
|
||||
: /** @type {Record<string, string | undefined>} */ ({})
|
||||
const on =
|
||||
env.BARE_OS_VAR_LOG_DEBUG === '1' ||
|
||||
env.BARE_OS_VAR_LOG_DEBUG === 'true'
|
||||
if (!on) return
|
||||
const line = `[bare-os:var-log] ${msg}`
|
||||
try {
|
||||
globalThis.process?.stderr?.write?.(line + '\n')
|
||||
} catch {
|
||||
/* ignore */
|
||||
}
|
||||
try {
|
||||
ctx?.console?.error?.(line)
|
||||
} catch {
|
||||
/* ignore */
|
||||
}
|
||||
} catch {
|
||||
/* ignore */
|
||||
}
|
||||
}
|
||||
|
||||
export const BARE_OS_VAR_LOG_DIR = '/var/log/bare-os'
|
||||
|
||||
@@ -69,18 +108,29 @@ const LOG_KEEP_BYTES = 256 * 1024
|
||||
export async function ensureBareOsVarLogTree(ctx) {
|
||||
try {
|
||||
const vfs = ctx.vfs
|
||||
if (!vfs || typeof vfs.mkdir !== 'function') return
|
||||
if (!vfs || typeof vfs.mkdir !== 'function') {
|
||||
bareOsKernelMetricInc('varlog.ensure.skip_no_vfs_mkdir')
|
||||
varLogDebug(ctx, 'ensureBareOsVarLogTree: no ctx.vfs.mkdir')
|
||||
return
|
||||
}
|
||||
await vfs.mkdir(BARE_OS_VAR_LOG_DIR, { recursive: true })
|
||||
if (
|
||||
typeof vfs.readFile !== 'function' ||
|
||||
typeof vfs.writeFile !== 'function'
|
||||
)
|
||||
) {
|
||||
bareOsKernelMetricInc('varlog.ensure.skip_no_vfs_rw')
|
||||
varLogDebug(ctx, 'ensureBareOsVarLogTree: missing vfs.readFile/writeFile')
|
||||
return
|
||||
}
|
||||
const existing = await vfs.readFile(README_REL)
|
||||
if (existing && ctx.b4a.from(existing).length > 0) return
|
||||
await vfs.writeFile(README_REL, ctx.b4a.from(README_TEXT))
|
||||
} catch {
|
||||
/* ignore */
|
||||
} catch (e) {
|
||||
bareOsKernelMetricInc('varlog.ensure.error')
|
||||
varLogDebug(
|
||||
ctx,
|
||||
`ensureBareOsVarLogTree: ${e && e.message ? e.message : String(e)}`
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -94,7 +144,14 @@ export async function ensureBareOsVarLogTree(ctx) {
|
||||
export async function appendVarLog(ctx, logicalFilePath, kind, line) {
|
||||
try {
|
||||
const vfs = ctx.vfs
|
||||
if (!vfs || typeof vfs.readFile !== 'function') return
|
||||
if (!vfs || typeof vfs.readFile !== 'function') {
|
||||
bareOsKernelMetricInc('varlog.append.skip_no_vfs_readfile')
|
||||
varLogDebug(
|
||||
ctx,
|
||||
'appendVarLog: no vfs.readFile for ' + String(logicalFilePath)
|
||||
)
|
||||
return
|
||||
}
|
||||
const prev = await vfs.readFile(logicalFilePath)
|
||||
const ts = new Date().toISOString()
|
||||
const chunk = ctx.b4a.from(`[${ts}] [${kind}] ${line}\n`)
|
||||
@@ -119,8 +176,14 @@ export async function appendVarLog(ctx, logicalFilePath, kind, line) {
|
||||
kind,
|
||||
line: String(line).slice(0, 4000)
|
||||
})
|
||||
} catch {
|
||||
/* ignore */
|
||||
} catch (e) {
|
||||
bareOsKernelMetricInc('varlog.append.error')
|
||||
varLogDebug(
|
||||
ctx,
|
||||
`appendVarLog(${String(logicalFilePath)}): ${
|
||||
e && e.message ? e.message : String(e)
|
||||
}`
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -119,6 +119,15 @@ import {
|
||||
stopBareInitd,
|
||||
getLastBareInitdDagSnapshotJson
|
||||
} from './lib/bare-initd.js'
|
||||
import {
|
||||
appendVarLog,
|
||||
ensureBareOsVarLogTree,
|
||||
KERNEL_CONSOLE_LOG
|
||||
} from './lib/bare-os-var-log.js'
|
||||
import {
|
||||
bareOsKernelMetricsReset,
|
||||
bareOsKernelMetricsSnapshot
|
||||
} from './lib/bare-os-kernel-metrics.js'
|
||||
import { parseUnitDropInText } from './lib/bare-initd-user.js'
|
||||
import { bareOsProcessTableSnapshot } from './lib/bare-os-process-table.js'
|
||||
import { buildBareOsSyscallsProcJson } from './lib/bare-os-syscalls-proc-json.js'
|
||||
@@ -2835,6 +2844,40 @@ test('vfs chdir /var/log from home', async (t) => {
|
||||
rmSync(dir, { recursive: true, force: true })
|
||||
})
|
||||
|
||||
test('appendVarLog increments skip metric when vfs.readFile missing', async (t) => {
|
||||
bareOsKernelMetricsReset()
|
||||
await appendVarLog(
|
||||
{ b4a, env: {}, vfs: { async writeFile() {} } },
|
||||
KERNEL_CONSOLE_LOG,
|
||||
'x',
|
||||
'line'
|
||||
)
|
||||
const snap = bareOsKernelMetricsSnapshot()
|
||||
t.is(snap['varlog.append.skip_no_vfs_readfile'], 1)
|
||||
bareOsKernelMetricsReset()
|
||||
})
|
||||
|
||||
test('ensureBareOsVarLogTree + appendVarLog populate personal backing', async (t) => {
|
||||
const dir = testCorestoreDir('varlogpop')
|
||||
const store = new Corestore(dir)
|
||||
const sys = new Hyperdrive(store)
|
||||
const personal = new Hyperdrive(store.namespace('pvlog'))
|
||||
await sys.ready()
|
||||
await personal.ready()
|
||||
const ctx = testCtx(sys, personal)
|
||||
await ensureBareOsVarLogTree(ctx)
|
||||
await appendVarLog(ctx, KERNEL_CONSOLE_LOG, 't', 'hello-var-log')
|
||||
const backing = await personal.get(
|
||||
'/.bare-os/var/log/user/bare-os/kernel-console.log'
|
||||
)
|
||||
t.ok(backing)
|
||||
t.ok(b4a.toString(backing).includes('hello-var-log'))
|
||||
const readme = await personal.get('/.bare-os/var/log/user/bare-os/README')
|
||||
t.ok(readme && b4a.toString(readme).includes('kernel-console'))
|
||||
await store.close()
|
||||
rmSync(dir, { recursive: true, force: true })
|
||||
})
|
||||
|
||||
test('tokenize handles quotes and ops', async (t) => {
|
||||
const tok = tokenize('ls -la | cat > out')
|
||||
t.ok(tok.some((x) => x.type === 'op' && x.value === '|'))
|
||||
|
||||
Reference in New Issue
Block a user