mirror of
https://github.com/heroblackink/ultimate-todoist-sync-for-obsidian.git
synced 2026-07-22 07:40:27 +00:00
fix: add logging to 22 silent early returns across sync pipeline
Previously, many guard conditions in the sync pipeline returned silently with zero feedback, making it impossible to diagnose why operations were dropped (root cause of issues #109, #111). Changes: - syncLock: log timeout failures in waitForRelease/waitForSaveRelease and acquire/acquireExclusive (console.warn + debugLog + logOperation) - toTodoist: log isTaskSyncEnabled skips on user actions (edit/close/reopen), isPrimaryDevice guard in lastLineNewTaskCheck, and parser failures - toObsidian: log missing mapping/file/taskLine in syncSingleTaskToObsidian - eventHandlers: log apiInitialized guards in all 5 event handlers - scheduler: log lock acquisition failures during file sync New logOperation event types: SYNC_LOCK_TIMEOUT, SYNC_DISABLED_SKIP, SYNC_TARGET_MISSING, TASK_PARSE_FAILED No logic changes, no Notice additions — logging only.
This commit is contained in:
parent
9f600b9e21
commit
07643d0450
5 changed files with 91 additions and 17 deletions
|
|
@ -18,7 +18,10 @@ export class EventHandlers {
|
|||
}
|
||||
|
||||
private async onKeyUp(evt: KeyboardEvent): Promise<void> {
|
||||
if (!this.plugin.settings.apiInitialized) return;
|
||||
if (!this.plugin.settings.apiInitialized) {
|
||||
this.plugin.debugLog('[onKeyUp] API not initialized, skipping');
|
||||
return;
|
||||
}
|
||||
if (!(this.plugin.app.workspace.activeEditor?.editor?.hasFocus())) {
|
||||
this.plugin.debugLog(`editor is not focused`);
|
||||
return;
|
||||
|
|
@ -46,7 +49,10 @@ export class EventHandlers {
|
|||
}
|
||||
|
||||
private async onClick(evt: MouseEvent): Promise<void> {
|
||||
if (!this.plugin.settings.apiInitialized) return;
|
||||
if (!this.plugin.settings.apiInitialized) {
|
||||
this.plugin.debugLog('[onClick] API not initialized, skipping');
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.plugin.app.workspace.activeEditor?.editor?.hasFocus()) {
|
||||
this.lineNumberCheck();
|
||||
|
|
@ -60,7 +66,10 @@ export class EventHandlers {
|
|||
}
|
||||
|
||||
private async onEditorChange(editor: Editor, view: MarkdownView): Promise<void> {
|
||||
if (!this.plugin.settings.apiInitialized) return;
|
||||
if (!this.plugin.settings.apiInitialized) {
|
||||
this.plugin.debugLog('[onEditorChange] API not initialized, skipping');
|
||||
return;
|
||||
}
|
||||
if (this.plugin.isSyncingFromTodoist) return;
|
||||
this.lineNumberCheck();
|
||||
if (!await this.plugin.checkModuleClass()) return;
|
||||
|
|
@ -75,7 +84,10 @@ export class EventHandlers {
|
|||
}
|
||||
|
||||
private async onFileRename(file: TFile, oldpath: string): Promise<void> {
|
||||
if (!this.plugin.settings.apiInitialized) return;
|
||||
if (!this.plugin.settings.apiInitialized) {
|
||||
this.plugin.debugLog('[onFileRename] API not initialized, skipping');
|
||||
return;
|
||||
}
|
||||
this.plugin.debugLog(`${oldpath} is renamed`);
|
||||
|
||||
const taskCount = this.plugin.cacheOperation!.getTaskCountInFile(oldpath);
|
||||
|
|
@ -99,7 +111,10 @@ export class EventHandlers {
|
|||
}
|
||||
|
||||
private async onFileModify(file: TFile): Promise<void> {
|
||||
if (!this.plugin.settings.apiInitialized) return;
|
||||
if (!this.plugin.settings.apiInitialized) {
|
||||
this.plugin.debugLog('[onFileModify] API not initialized, skipping');
|
||||
return;
|
||||
}
|
||||
if (this.plugin.isSyncingFromTodoist) return;
|
||||
if (this.plugin.isProcessingModify) return;
|
||||
if (!file.path.endsWith('.md')) return;
|
||||
|
|
|
|||
|
|
@ -53,7 +53,10 @@ export class SyncScheduler {
|
|||
const lockOk = await this.plugin.syncLockManager.run('obsidianToTodoist', async () => {
|
||||
await this.plugin.obsidianToTodoist!.fullTextNewTaskCheck(fileKey);
|
||||
});
|
||||
if (!lockOk) continue;
|
||||
if (!lockOk) {
|
||||
this.plugin.debugLog(`[Scheduler] Skipping file sync for ${fileKey}: lock not acquired`);
|
||||
continue;
|
||||
}
|
||||
|
||||
await this.plugin.syncLockManager.run('obsidianToTodoist', async () => {
|
||||
await this.plugin.obsidianToTodoist!.deletedTaskCheck(fileKey);
|
||||
|
|
|
|||
|
|
@ -25,7 +25,13 @@ export class SyncLockManager {
|
|||
await new Promise(resolve => setTimeout(resolve, 1000));
|
||||
attempts++;
|
||||
}
|
||||
return !this.locked;
|
||||
const released = !this.locked;
|
||||
if (!released) {
|
||||
console.warn('[SyncLock] Sync lock acquire FAILED after 10s timeout');
|
||||
this.plugin.debugLog('[SyncLock] Sync lock acquire FAILED after 10s timeout');
|
||||
this.plugin.logOperation?.log('SYNC_LOCK_TIMEOUT', 'Sync lock acquire failed after 10s timeout');
|
||||
}
|
||||
return released;
|
||||
}
|
||||
|
||||
async waitForSaveRelease(): Promise<boolean> {
|
||||
|
|
@ -34,7 +40,13 @@ export class SyncLockManager {
|
|||
await new Promise(resolve => setTimeout(resolve, 500));
|
||||
attempts++;
|
||||
}
|
||||
return !this.plugin.saveLock;
|
||||
const released = !this.plugin.saveLock;
|
||||
if (!released) {
|
||||
console.warn('[SyncLock] Save lock acquire FAILED after 5s timeout');
|
||||
this.plugin.debugLog('[SyncLock] Save lock acquire FAILED after 5s timeout');
|
||||
this.plugin.logOperation?.log('SYNC_LOCK_TIMEOUT', 'Save lock acquire failed after 5s timeout');
|
||||
}
|
||||
return released;
|
||||
}
|
||||
|
||||
async acquireExclusive(): Promise<boolean> {
|
||||
|
|
@ -50,7 +62,11 @@ export class SyncLockManager {
|
|||
if (this.locked) {
|
||||
this.plugin.debugLog('sync locked. waiting for exclusive acquire.');
|
||||
const released = await this.waitForRelease();
|
||||
if (!released) return false;
|
||||
if (!released) {
|
||||
console.warn('[SyncLock] Exclusive sync lock acquire FAILED after timeout');
|
||||
this.plugin.debugLog('[SyncLock] Exclusive sync lock acquire FAILED after timeout');
|
||||
return false;
|
||||
}
|
||||
this.plugin.debugLog('sync unlocked.');
|
||||
}
|
||||
|
||||
|
|
@ -87,7 +103,11 @@ export class SyncLockManager {
|
|||
if (this.locked) {
|
||||
this.plugin.debugLog('sync locked.');
|
||||
const released = await this.waitForRelease();
|
||||
if (!released) return false;
|
||||
if (!released) {
|
||||
console.warn(`[SyncLock] Sync lock acquire FAILED for direction=${direction || 'none'}`);
|
||||
this.plugin.debugLog(`[SyncLock] Sync lock acquire FAILED for direction=${direction || 'none'}`);
|
||||
return false;
|
||||
}
|
||||
this.plugin.debugLog('sync unlocked.');
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -93,10 +93,20 @@ export class TodoistToObsidianSync {
|
|||
|
||||
private async syncSingleTaskToObsidian(taskId: string, task: any): Promise<void> {
|
||||
const mapping = this.plugin.cacheOperation.getTaskFileMapping(taskId);
|
||||
if (!mapping) return;
|
||||
if (!mapping) {
|
||||
console.warn(`[syncSingleTaskToObsidian] No mapping found for task ${taskId}`);
|
||||
this.plugin.debugLog(`[syncSingleTaskToObsidian] No mapping found for task ${taskId}`);
|
||||
this.plugin.logOperation?.log('SYNC_TARGET_MISSING', `Todoist→Obsidian sync skipped: no mapping for task ${taskId}`, undefined, taskId);
|
||||
return;
|
||||
}
|
||||
|
||||
const file = this.app.vault.getAbstractFileByPath(mapping.filePath);
|
||||
if (!file) return;
|
||||
if (!file) {
|
||||
console.warn(`[syncSingleTaskToObsidian] File not found: ${mapping.filePath} (task ${taskId})`);
|
||||
this.plugin.debugLog(`[syncSingleTaskToObsidian] File not found: ${mapping.filePath} (task ${taskId})`);
|
||||
this.plugin.logOperation?.log('SYNC_TARGET_MISSING', `Todoist→Obsidian sync skipped: file not found ${mapping.filePath}`, mapping.filePath, taskId);
|
||||
return;
|
||||
}
|
||||
|
||||
const fileContent = await this.app.vault.read(file);
|
||||
const lines = fileContent.split('\n');
|
||||
|
|
@ -108,7 +118,12 @@ export class TodoistToObsidianSync {
|
|||
break;
|
||||
}
|
||||
}
|
||||
if (!taskLine) return;
|
||||
if (!taskLine) {
|
||||
console.warn(`[syncSingleTaskToObsidian] Task line not found in file for task ${taskId}`);
|
||||
this.plugin.debugLog(`[syncSingleTaskToObsidian] Task line not found in file for task ${taskId}`);
|
||||
this.plugin.logOperation?.log('SYNC_TARGET_MISSING', `Todoist→Obsidian sync skipped: task line not found in file`, mapping.filePath, taskId);
|
||||
return;
|
||||
}
|
||||
|
||||
const obsidianIsChecked = /\[(x|X)\]/.test(taskLine);
|
||||
const todoistIsChecked = task.checked || false;
|
||||
|
|
|
|||
|
|
@ -171,7 +171,10 @@ export class ObsidianToTodoistSync {
|
|||
* this fires once when the cursor moves away, so the user can finish typing.
|
||||
*/
|
||||
async lastLineNewTaskCheck(filepath: string, lineText: string, lineNumber: number, fileContent: string): Promise<void> {
|
||||
if (!this.plugin.isPrimaryDevice()) return;
|
||||
if (!this.plugin.isPrimaryDevice()) {
|
||||
this.plugin.debugLog('[lastLineNewTaskCheck] Push blocked: not primary device');
|
||||
return;
|
||||
}
|
||||
if (!this.plugin.settings.enableFullVaultSync) return;
|
||||
|
||||
const isTask = this.plugin.taskParser.isMarkdownTask(lineText);
|
||||
|
|
@ -191,7 +194,12 @@ export class ObsidianToTodoistSync {
|
|||
this.plugin.debugLog('[lastLineNewTaskCheck] New task detected on line leave:', processedLine);
|
||||
|
||||
const currentTask = await this.plugin.taskParser.convertTextToTodoistTaskObject(processedLine, filepath, lineNumber, fileContent);
|
||||
if (typeof currentTask === 'undefined') return;
|
||||
if (typeof currentTask === 'undefined') {
|
||||
console.warn(`[lastLineNewTaskCheck] Task parser returned undefined for line: ${processedLine}`);
|
||||
this.plugin.debugLog(`[lastLineNewTaskCheck] Task parser returned undefined for line ${lineNumber} in ${filepath}`);
|
||||
this.plugin.logOperation?.log('TASK_PARSE_FAILED', `Task parser failed for line ${lineNumber}`, filepath);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const newTask = await this.plugin.todoistSyncAPI.AddTask(currentTask);
|
||||
|
|
@ -284,6 +292,9 @@ export class ObsidianToTodoistSync {
|
|||
this.plugin.debugLog(filepath);
|
||||
const currentTask = await this.plugin.taskParser.convertTextToTodoistTaskObject(line, filepath, i, lines.join('\n'));
|
||||
if (typeof currentTask === 'undefined') {
|
||||
console.warn(`[fullTextNewTaskCheck] Task parser returned undefined for line ${i} in ${filepath}`);
|
||||
this.plugin.debugLog(`[fullTextNewTaskCheck] Task parser returned undefined for line ${i} in ${filepath}`);
|
||||
this.plugin.logOperation?.log('TASK_PARSE_FAILED', `Task parser failed for line ${i}`, filepath);
|
||||
continue;
|
||||
}
|
||||
this.plugin.debugLog(currentTask);
|
||||
|
|
@ -367,6 +378,8 @@ export class ObsidianToTodoistSync {
|
|||
}
|
||||
|
||||
if (!this.plugin.cacheOperation.isTaskSyncEnabled(lineTask_todoist_id)) {
|
||||
this.plugin.debugLog(`[lineModifiedTaskCheck] Sync disabled for task ${lineTask_todoist_id}, skipping modification`);
|
||||
this.plugin.logOperation?.log('SYNC_DISABLED_SKIP', `User edit ignored: sync disabled for task ${lineTask_todoist_id}`, filepath, lineTask_todoist_id);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -577,7 +590,11 @@ export class ObsidianToTodoistSync {
|
|||
this.plugin.debugLog('[toTodoist] Push blocked: not primary device');
|
||||
return;
|
||||
}
|
||||
if (!this.plugin.cacheOperation?.isTaskSyncEnabled(taskId)) return;
|
||||
if (!this.plugin.cacheOperation?.isTaskSyncEnabled(taskId)) {
|
||||
this.plugin.debugLog(`[closeTask] Sync disabled for task ${taskId}, skipping close`);
|
||||
this.plugin.logOperation?.log('SYNC_DISABLED_SKIP', `Checkbox close ignored: sync disabled for task ${taskId}`, undefined, taskId);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const taskMapping = this.plugin.cacheOperation.getTaskFileMapping(taskId);
|
||||
const savedTask = await this.plugin.todoistSyncAPI.GetTaskById(taskId);
|
||||
|
|
@ -638,7 +655,11 @@ export class ObsidianToTodoistSync {
|
|||
this.plugin.debugLog('[toTodoist] Push blocked: not primary device');
|
||||
return;
|
||||
}
|
||||
if (!this.plugin.cacheOperation?.isTaskSyncEnabled(taskId)) return;
|
||||
if (!this.plugin.cacheOperation?.isTaskSyncEnabled(taskId)) {
|
||||
this.plugin.debugLog(`[repoenTask] Sync disabled for task ${taskId}, skipping reopen`);
|
||||
this.plugin.logOperation?.log('SYNC_DISABLED_SKIP', `Checkbox reopen ignored: sync disabled for task ${taskId}`, undefined, taskId);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const taskMapping = this.plugin.cacheOperation.getTaskFileMapping(taskId);
|
||||
const savedTask = await this.plugin.todoistSyncAPI.GetTaskById(taskId);
|
||||
|
|
|
|||
Loading…
Reference in a new issue