Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Save console messages to logfile for mobile debugging
declare module "obsidian" {
interface App {
isMobile: boolean;
}
}
// Call this method inside your plugin's `onLoad` function
function monkeyPatchConsole(plugin: Plugin) {
if (!plugin.app.isMobile) {
return;
}
const logFile = `${plugin.manifest.dir}/logs.txt`;
const logs: string[] = [];
const logMessages = (prefix: string) => (...messages: unknown[]) => {
logs.push(`\n[${prefix}]`);
for (const message of messages) {
logs.push(String(message));
}
plugin.app.vault.adapter.write(logFile, logs.join(" "));
};
console.debug = logMessages("debug");
console.error = logMessages("error");
console.info = logMessages("info");
console.log = logMessages("log");
console.warn = logMessages("warn");
}
@shabegom
Copy link

shabegom commented Mar 30, 2021

I added the following to make Typescript happier:

declare module "obsidian" {
    interface App {
        isMobile: boolean;
    }
}

and gave const logs a type:

const logs: string[] = []

optional unless you have strict typescript rules

@ryanpcmcquen
Copy link

ryanpcmcquen commented Jun 5, 2021

This is beautiful!

@ryanpcmcquen
Copy link

ryanpcmcquen commented Jun 6, 2021

Here's my slightly modified version. If you import Platform from obsidian, you get the isMobile type declaration:

// Call this method inside your plugin's
// `onload` function like so:
// monkeyPatchConsole(this);
const monkeyPatchConsole = (plugin: Plugin) => {
    if (!Platform.isMobile) {
        return;
    }

    const logFile = `${plugin.manifest.dir}/logs.txt`;
    const logs: string[] = [];
    const logMessages = (prefix: string) => (...messages: unknown[]) => {
        logs.push(`\n[${prefix}]`);
        for (const message of messages) {
            logs.push(String(message));
        }
        plugin.app.vault.adapter.write(logFile, logs.join(" "));
    };

    console.debug = logMessages("debug");
    console.error = logMessages("error");
    console.info = logMessages("info");
    console.log = logMessages("log");
    console.warn = logMessages("warn");
};

@AndrewNatoli
Copy link

AndrewNatoli commented Jan 22, 2022

Hiya @liamcain - I was wondering if you're still having luck if and when you ever need this script. I tried adding it to the obsidian-checklist-plugin to try and find why it fails to enable on iOS. If I knock out the platform restriction line and run it on desktop, I generate a log file just fine. Using it with the mobile app (Obsidian 1.1), I don't get a log file.

I've tried using an iCloud vault as well as an Obsidian Sync vault, having the log file saved to the plugin directory as well as a markdown file in the vault. Was hoping I would see a file appear in the Sync console that maybe Sync rejects (the way Sync seems to delete irrelevant files in plugin directories) but there was no trace of a log file being created.

@liamcain
Copy link
Author

liamcain commented Jan 22, 2022

@AndrewNatoli Since this script doesn't run until after the plugin is loaded, it won't help you track down initialization issues. For those, I recommend taking a look at your package dependencies and make sure that all the packages can run in a browser environment (as opposed to a node environment).


If you're still having trouble, another option would be loading this script from a separate plugin. You can do this either by creating an entirely barebones plugin that just calls this script, or making this a startup script with any of the existing plugins that allow for running arbitrary javascript (Templater, Dataview, CustomJS all come to mind).

That way, you can have this script run before trying to enable the plugin you're trying to debug.

@AndrewNatoli
Copy link

AndrewNatoli commented Jan 23, 2022

@liamcain That suggestion was a huge help, thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment