mirror of
https://github.com/vrtmrz/obsidian-livesync.git
synced 2026-11-06 00:08:23 +00:00
Keep Commonlib CLI diagnostics behind debug mode
This commit is contained in:
1 parent
a0f1483891
commit
e7124eda98
4 files changed
+28
-24
No files matched your search
@@ -116,6 +116,11 @@ saved. After correcting the cause, run `sync` again with the same database and
|
|||||||
settings to retry it. Existing partial writes are retained. `fetch --force`
|
settings to retry it. Existing partial writes are retained. `fetch --force`
|
||||||
replaces the local database instead and follows the reconstruction rules below.
|
replaces the local database instead and follows the reconstruction rules below.
|
||||||
|
|
||||||
|
A failed `sync` prints `[Error] Command 'sync' failed` and exits with code `1`.
|
||||||
|
To inspect the Journal key, failure stage, and diagnostic details, retry with
|
||||||
|
`--debug`, for example `livesync-cli ./my-db --debug sync`, retaining the same
|
||||||
|
database and settings. Debug diagnostics are written to standard error.
|
||||||
|
|
||||||
If the Journal cannot be recovered and missing content or history is
|
If the Journal cannot be recovered and missing content or history is
|
||||||
acceptable, run `journal-skip <journal-key>`. The CLI first performs normal
|
acceptable, run `journal-skip <journal-key>`. The CLI first performs normal
|
||||||
replication with the retained local database. It skips only when that attempt
|
replication with the retained local database. It skips only when that attempt
|
||||||
|
|||||||
@@ -79,15 +79,6 @@ describe("CLI log handler", () => {
|
|||||||
it.each([
|
it.each([
|
||||||
["NOTICE", LOG_LEVEL_NOTICE],
|
["NOTICE", LOG_LEVEL_NOTICE],
|
||||||
["URGENT", LOG_LEVEL_URGENT],
|
["URGENT", LOG_LEVEL_URGENT],
|
||||||
] as const)("writes Commonlib %s diagnostics to stderr by default", async (name, level) => {
|
|
||||||
const message = `Commonlib ${name} diagnostic`;
|
|
||||||
const standardIo = await invokeGlobalLogger(databasePath, message, level);
|
|
||||||
|
|
||||||
expect(standardIo.writeStderr).toHaveBeenCalledWith(expect.stringContaining(`[${level}] ${message}\n`));
|
|
||||||
expect(standardIo.writeStdout).not.toHaveBeenCalledWith(expect.stringContaining(message));
|
|
||||||
});
|
|
||||||
|
|
||||||
it.each([
|
|
||||||
["DEBUG", LOG_LEVEL_DEBUG],
|
["DEBUG", LOG_LEVEL_DEBUG],
|
||||||
["INFO", LOG_LEVEL_INFO],
|
["INFO", LOG_LEVEL_INFO],
|
||||||
["VERBOSE", LOG_LEVEL_VERBOSE],
|
["VERBOSE", LOG_LEVEL_VERBOSE],
|
||||||
@@ -101,6 +92,8 @@ describe("CLI log handler", () => {
|
|||||||
|
|
||||||
it("writes detailed Commonlib diagnostics to stderr in debug mode", async () => {
|
it("writes detailed Commonlib diagnostics to stderr in debug mode", async () => {
|
||||||
const messages = [
|
const messages = [
|
||||||
|
["NOTICE", LOG_LEVEL_NOTICE],
|
||||||
|
["URGENT", LOG_LEVEL_URGENT],
|
||||||
["DEBUG", LOG_LEVEL_DEBUG],
|
["DEBUG", LOG_LEVEL_DEBUG],
|
||||||
["INFO", LOG_LEVEL_INFO],
|
["INFO", LOG_LEVEL_INFO],
|
||||||
["VERBOSE", LOG_LEVEL_VERBOSE],
|
["VERBOSE", LOG_LEVEL_VERBOSE],
|
||||||
|
|||||||
@@ -378,10 +378,15 @@ export async function main(
|
|||||||
const writeLine = avoidStdoutNoise ? writeStderrLine : writeStdoutLine;
|
const writeLine = avoidStdoutNoise ? writeStderrLine : writeStdoutLine;
|
||||||
writeLine(standardIo, ...values);
|
writeLine(standardIo, ...values);
|
||||||
};
|
};
|
||||||
setGlobalLogFunction((msg, level) => {
|
if (options.debug) {
|
||||||
if (!options.debug && level !== LOG_LEVEL_NOTICE && level !== LOG_LEVEL_URGENT) return;
|
setGlobalLogFunction((msg, level) => {
|
||||||
writeStderrLine(standardIo, `[${level}]`, msg);
|
writeStderrLine(standardIo, `[${level}]`, msg);
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
|
setGlobalLogFunction((msg, level) => {
|
||||||
|
// NO OP, leave it to logFunction
|
||||||
|
});
|
||||||
|
}
|
||||||
if (options.command === "init-settings") {
|
if (options.command === "init-settings") {
|
||||||
await createDefaultSettingsFile(options, standardIo);
|
await createDefaultSettingsFile(options, standardIo);
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -247,9 +247,12 @@ async function runScenario(encrypt: boolean): Promise<void> {
|
|||||||
assert.notEqual(finalRevision, firstRevision);
|
assert.notEqual(finalRevision, firstRevision);
|
||||||
|
|
||||||
await withCorruptedJournals(client, minioBucket, [brokenJournalKey, secondBrokenJournalKey], async () => {
|
await withCorruptedJournals(client, minioBucket, [brokenJournalKey, secondBrokenJournalKey], async () => {
|
||||||
const failedSync = await tryDefault("--debug", "sync");
|
const failedSync = await tryDefault("sync");
|
||||||
assert.notEqual(failedSync.code, 0, "Default receive must report failure for a corrupt Journal");
|
assert.equal(failedSync.code, 1, "Default receive must report failure for a corrupt Journal");
|
||||||
assert.match(failedSync.combined, /receive journal error|journal.*failed|replication.*failed/i);
|
assert.match(failedSync.stderr, /\[Error\] Command 'sync' failed/);
|
||||||
|
const debugRetry = await tryDefault("--debug", "sync");
|
||||||
|
assert.equal(debugRetry.code, 1, "Debug retry must still report the corrupt Journal");
|
||||||
|
assert.ok(debugRetry.stderr.includes(`Receive Journal ${brokenJournalKey} failed at `));
|
||||||
|
|
||||||
const checkpoint = await readReceivedJournalKeys(defaultDatabase);
|
const checkpoint = await readReceivedJournalKeys(defaultDatabase);
|
||||||
assert.ok(checkpoint.has(firstJournalKey), "Completed earlier Journal must remain checkpointed");
|
assert.ok(checkpoint.has(firstJournalKey), "Completed earlier Journal must remain checkpointed");
|
||||||
@@ -307,14 +310,12 @@ async function runScenario(encrypt: boolean): Promise<void> {
|
|||||||
`Skipping the first Journal should stop at the next broken Journal: ${firstSkip.combined}`
|
`Skipping the first Journal should stop at the next broken Journal: ${firstSkip.combined}`
|
||||||
);
|
);
|
||||||
assert.ok(firstSkip.combined.includes(brokenJournalKey), "The first skip must identify its Journal key");
|
assert.ok(firstSkip.combined.includes(brokenJournalKey), "The first skip must identify its Journal key");
|
||||||
|
assert.match(firstSkip.stderr, /\[Error\] Command 'journal-skip' failed/);
|
||||||
|
const nextFailure = await trySkip("--debug", "sync");
|
||||||
|
assert.equal(nextFailure.code, 1, "Debug retry must stop at the next broken Journal");
|
||||||
assert.ok(
|
assert.ok(
|
||||||
firstSkip.combined.includes(secondBrokenJournalKey),
|
nextFailure.stderr.includes(`Receive Journal ${secondBrokenJournalKey} failed at `),
|
||||||
"Resumed replication must stop and identify the next broken Journal"
|
"Debug retry must identify the next broken Journal and its failure stage"
|
||||||
);
|
|
||||||
assert.match(
|
|
||||||
firstSkip.combined,
|
|
||||||
/decrypt|inflate|decompress|decode|parse|persist|apply/i,
|
|
||||||
"The first skip attempt must report the failed Journal processing stage"
|
|
||||||
);
|
);
|
||||||
|
|
||||||
const firstSkipCheckpoint = await readReceivedJournalKeys(skipDatabase);
|
const firstSkipCheckpoint = await readReceivedJournalKeys(skipDatabase);
|
||||||
@@ -331,7 +332,7 @@ async function runScenario(encrypt: boolean): Promise<void> {
|
|||||||
assert.notEqual((await trySkip("cat", secondBrokenPath)).code, 0);
|
assert.notEqual((await trySkip("cat", secondBrokenPath)).code, 0);
|
||||||
assert.notEqual((await trySkip("cat", laterPath)).code, 0);
|
assert.notEqual((await trySkip("cat", laterPath)).code, 0);
|
||||||
|
|
||||||
const secondSkip = await trySkip("journal-skip", secondBrokenJournalKey);
|
const secondSkip = await trySkip("--debug", "journal-skip", secondBrokenJournalKey);
|
||||||
assert.equal(secondSkip.code, 0, `Explicit second skip should resume replication: ${secondSkip.combined}`);
|
assert.equal(secondSkip.code, 0, `Explicit second skip should resume replication: ${secondSkip.combined}`);
|
||||||
assert.ok(secondSkip.combined.includes(secondBrokenJournalKey), "The second skip must identify its key");
|
assert.ok(secondSkip.combined.includes(secondBrokenJournalKey), "The second skip must identify its key");
|
||||||
assert.match(
|
assert.match(
|
||||||
|
|||||||
Reference in new issue
Block a user