first draft of log explorer
This commit is contained in:
1 parent
191e69eb1d
commit
400837b41a
16 files changed
+1495
-79
No files matched your search
@@ -0,0 +1,47 @@
|
||||
const { test } = require('node:test');
|
||||
const assert = require('node:assert/strict');
|
||||
const fs = require('fs');
|
||||
const os = require('os');
|
||||
const path = require('path');
|
||||
const Module = require('module');
|
||||
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'ad-log-test-'));
|
||||
const originalLoad = Module._load;
|
||||
let messages = [];
|
||||
const vscode = {workspace:{workspaceFolders:[{uri:{fsPath:root}}], getConfiguration:()=>({get:(key, fallback)=>fallback})}};
|
||||
Module._load = function(id, ...args) { return id === 'vscode' ? vscode : originalLoad.call(this, id, ...args); };
|
||||
const {LogExplorer} = require('../out/logExplorer');
|
||||
Module._load = originalLoad;
|
||||
function explorer() { const e = new LogExplorer({}); const webview={postMessage:m=>messages.push(m)}; e.panel={webview}; e.activeWebview=webview; return e; }
|
||||
function latest() { return messages.at(-1)?.entries || []; }
|
||||
fs.mkdirSync(path.join(root,'logs'));
|
||||
const file=path.join(root,'logs/appdaemon.log');
|
||||
test('follows incomplete UTF-8 lines and multiline exceptions',()=>{
|
||||
const e=explorer(); messages=[];
|
||||
const first='27-09-26 10:12:13 ERROR app: Échec';
|
||||
const bytes=Buffer.from(first+'\n'); const split=bytes.indexOf(Buffer.from('É'))+1;
|
||||
fs.writeFileSync(file,bytes.subarray(0,split));e.poll();assert.equal(latest().length,0);
|
||||
fs.appendFileSync(file,Buffer.concat([bytes.subarray(split),Buffer.from(' File "app.py", line 42\nRuntimeError: failed\n')]));e.poll();
|
||||
assert.equal(latest().length,1);assert.match(latest()[0].message,/Échec\n File/);assert.match(latest()[0].message,/RuntimeError/);
|
||||
});
|
||||
test('detects same-sized inode replacement and truncation',()=>{
|
||||
const e=explorer();messages=[];
|
||||
fs.writeFileSync(file,'27-09-26 10:12:13 INFO app: before\n');e.poll();
|
||||
fs.renameSync(file,file+'.old');fs.writeFileSync(file,'27-09-26 10:12:14 INFO app: after!\n');e.poll();
|
||||
assert.ok(latest().some(x=>x.message==='after!'));
|
||||
fs.writeFileSync(file,'27-09-26 10:12:15 INFO a: x\n');e.poll();assert.ok(latest().some(x=>x.message==='x'));
|
||||
});
|
||||
test('reads base text logs and ignores structured events by default',()=>{
|
||||
const e=explorer();messages=[];
|
||||
fs.writeFileSync(file,'27-09-26 10:12:13 ERROR app: failed\n27-09-26 10:12:14 INFO AppDaemon: AppDaemon is ready\n');
|
||||
fs.writeFileSync(path.join(root,'logs/error.log'),'27-09-26 10:12:13 ERROR app: failed\n');
|
||||
fs.writeFileSync(path.join(root,'logs/events.jsonl'),JSON.stringify({version:1,event_id:'trace-only',timestamp:'2026-09-27T08:12:14Z',level:'INFO',kind:'evaluation',message:'not a raw log',app:'app',cause_ids:[]})+'\n');e.poll();
|
||||
assert.equal(latest().filter(e=>e.message==='failed').length,1);
|
||||
assert.ok(latest().some(e=>e.app==='AppDaemon' && e.message==='AppDaemon is ready'));
|
||||
assert.equal(latest().some(e=>e.event_id==='trace-only'),false);
|
||||
});
|
||||
test('bounds retained history',()=>{
|
||||
const e=explorer();messages=[];
|
||||
fs.writeFileSync(file,Array.from({length:10500},(_,i)=>`27-09-26 10:12:13 INFO app: message ${i}\n`).join(''));
|
||||
e.poll();e.poll();assert.ok(e.entries.size<=10000);
|
||||
});
|
||||
process.on('exit',()=>fs.rmSync(root,{recursive:true,force:true}));
|
||||
Reference in new issue
Block a user