javascriptappletintrospectioncinnamon

Log to a file from Javascript code executed with no console window


Working on a Cinnamon applet (Example). These use Javascript interpreted by the cjs interpreter and run without a console window.

How can I log something to a file or to a console from within the code I am working on?

I can not put test code into a separate Javascript file and run it with cjs <the file>, because there I do not have access to modules provided to applets by Cinnamon.


Solution

  • Logging

    To log from the javascript:

    global.log('my message')
    

    To inspect things, including objects with possibly circular references, define this function:

    const inspect = (function() {
        function replace_circular_references(show_private_keys) {
            let fullpaths = new Map(), cleanpaths= new Map(), rootobject = null
            return function(key, value) {
                let decycled; {
                    if (!show_private_keys && key.startsWith('_')) return undefined
                    let path = fullpaths.get(this) + (
                        Array.isArray(this) ? `[${key}]` : `.${key}` )
                    let is_complex = value === Object(value)
                    if (is_complex) fullpaths.set(value, path)
                    let cleanpath = cleanpaths.get(value) || ''
                    if (!cleanpath && is_complex)
                        cleanpaths.set(value, path.replace(/undefined\.\.?/, ''))
                    decycled = cleanpath ?
                        `${cleanpath[0] == '[' ? '(this)' : '(this).'}${cleanpath}`
                        : value
                    if (rootobject === null) rootobject = value
                    else if (decycled === rootobject) { decycled = "(this)" }
                }
                return decycled
            }
        }
        return function (nameofthing, thing, show_private_keys=true, fold=null) {
            try {
                let thingrepr; {
                    thingrepr = JSON.stringify(
                        thing, replace_circular_references(show_private_keys), '\t'
                    ).replace(
                        /"([^\n"]+)"[:] /g, "$1: "  // prettify keys
                    ).replace(
                        /"(\(this\)[^\n"]*)"/g, "$1"  // prettify circular refs
                    )
                    if (fold !== null) {  // maybe fold away some things
                        for (const key of fold) {
                            thingrepr = thingrepr.replace(
                                new RegExp(`^([ ]*)${key}: [{][^]*?\\n\\1[}]`, 'gm'),
                                "$1" + key + ": {...}"
                            ).replace(
                                new RegExp(`^([ ]*)${key}: \\[[^]*?\\n\\1\\]`, 'gm'),
                                "$1" + key + ": [...]"
                            )
                        }
                    }
                }
                global.log(`\n${nameofthing} = ${thingrepr}`)
            } catch (error) {
                global.log(`${nameofthing} = (oops, can not do that)`)
                global.log(error)
                global.log(error.message)
            }
        }
    })()
    

    and use it like so:

    inspect('myobject', myobject)
    

    or like so, to hide keys starting with underscores:

    inspect('myobject', myobject, false)
    

    or like so, to fold specific keys you are not interested in:

    inspect('myobject', myobject, true, ['key1', 'key2', ...])
    

    Viewing the log

    To view the logged messages, either use the console or a GUI (or both).

    Using the console

    tail -f ~/.xsession-errors
    

    Or, prior to Cinnamon 3.8.8:

    tail -f ~/.cinnamon/glass.log 
    

    Press ctrl + c to abort the logging.

    To reload the applet:

    dbus-send --session --dest=org.Cinnamon.LookingGlass -- \
    type=method_call /org/Cinnamon/LookingGlass \
    org.Cinnamon.LookingGlass.ReloadExtension \
    string:'your-applet-uuid' \
    string:'APPLET'
    

    where your-applet-uuid is the value of the uuid key in metadata.json.

    It is simplest to run this command from another console, so you do not have to abort the logging.

    Using a GUI

    Cinnamon also has the Melange-Cinnamon debugger. To open it:

    The logging happens under the log tab.

    To reload the code of the applet, find it under the extensions tab, right click → reload code.

    To reload Cinnamon and do other things, use the Actions button.

    The debugger has a small bug, sometimes the scroll bar disappears when long stuff gets logged. To get it back, press ctrl + Home and ctrl + End.

    To be able to have the debugger window in the background, right click its title bar.

    Kudos