Electron Adventures: Episode 91: Application Logs
Tags: javascript, electron, svelte
Published: 2021-11-09 12:02:50

I wanted to add some more OS integrations, but a few of them only work with packaged app.

Developing an app and then packaging it is fine, but functionality that only works when packaged is a huge pain to test. First big issue is that there's no `console.log` from the backend process.

There are a few ways to get around this, let's try [`electron-log` package](https://www.npmjs.com/package/electron-log) to log things to a text file.

### Installing

```shell
$ npm install electron-log
```

### Using the logger

After that we can edit `index.js` and replace `console.log` with `log.info`. There are other log levels too, if you need this distinction. Only two lines here are new, but here's the whole file:

```javascript
let { app, BrowserWindow, dialog, Menu } = require("electron")
let settings = require("electron-settings")
let log = require("electron-log")

let isOSX = (process.platform === "darwin")

function createWindow(path) {
  log.info("Creating window for", path)
  let key = `windowState-${path}`
  let windowState = settings.getSync(key) || { width: 1024, height: 768 }

  let qs = new URLSearchParams({ path }).toString();
  let win = new BrowserWindow({
    ...windowState,
    webPreferences: {
      preload: `${__dirname}/preload.js`,
    },
  })

  function saveSettings() {
    windowState = win.getBounds()
    log.info("Saving window position", path, windowState)
    settings.setSync(key, windowState)
  }

  win.on("resize", saveSettings)
  win.on("move", saveSettings)
  win.on("close", saveSettings)

  win.loadURL(`http://localhost:5000/?${qs}`)
}

async function openFiles() {
  let { canceled, filePaths } = await dialog.showOpenDialog({
    properties: ["openFile", "multiSelections", "showHiddenFiles"],
    filters: [
      { name: "CSV files", extensions: ["csv"] },
      { name: "All Files", extensions: ["*"] }
    ],
    message: "Select a CSV file to open",
    defaultPath: `${__dirname}/samples`,
  })
  if (canceled && !isOSX) {
    app.quit()
  }
  for (let path of filePaths) {
    createWindow(path)
  }
}

let dockMenu = Menu.buildFromTemplate([
  {
    label: "Open files",
    click() { openFiles() }
  }
])

async function startApp() {
  if (isOSX) {
    app.dock.setMenu(dockMenu)
  }
  await openFiles()
  if (isOSX) {
    app.on("activate", function() {
      if (BrowserWindow.getAllWindows().length === 0) {
        openFiles()
      }
    })
  }
}

app.on("window-all-closed", () => {
  if (!isOSX) {
    app.quit()
  }
})

app.on("ready", startApp)
```

### Viewing the logs

The logs are saved in different location dependig on the operating system. For OSX, they will be at `~/Library/Logs/<application_name>/main.log` - `main` being the Electron word for backend.

If you use the logger from another process (frontend/renderer, or a worker process), it will go to a different file.

So let's take a look at `~/Library/Logs/episode-91-application-logs/main.log`:

```
[2021-11-09 11:55:16.344] [info]  Creating window for /Users/taw/electron-adventures/episode-91-application-logs/samples/06-reputation.csv
[2021-11-09 11:55:37.027] [info]  Saving window position /Users/taw/electron-adventures/episode-91-application-logs/samples/06-reputation.csv { x: 1116, y: 661, width: 1024, height: 768 }
[2021-11-09 11:55:37.129] [info]  Saving window position /Users/taw/electron-adventures/episode-91-application-logs/samples/06-reputation.csv { x: 812, y: 601, width: 1024, height: 768 }
[2021-11-09 11:55:37.235] [info]  Saving window position /Users/taw/electron-adventures/episode-91-application-logs/samples/06-reputation.csv { x: 768, y: 589, width: 1024, height: 768 }
[2021-11-09 11:55:37.348] [info]  Saving window position /Users/taw/electron-adventures/episode-91-application-logs/samples/06-reputation.csv { x: 767, y: 588, width: 1024, height: 768 }
```

### Results

Now that we have logging working even from a packaged app, let's see if we can integrate drag and dropping files onto Dock in the next episode.

As usual, [all the code for the episode is here](https://github.com/taw/electron-adventures/tree/master/episode-91-application-logs).