5

I am trying to create a msi package from golang program with error logging feature. So, that I will be able to retrieve golang app crash logs.

The following Golang code is saved to main.go, with a crash expected due to 1\0 division related error.

package main

import "fmt"

func main() {
    // intentionally cause a divide-by-zero error
    x := 0
    y := 1 / x
    fmt.Println(y)
}

Then I was trying to create msi package using following steps:

  • step 1: go get github.com/akavel/rsrc
  • step 2: rsrc -ico .\abc.ico
  • step 3: $Env:GOOS="windows"; go build -ldflags "-H windowsgui" -o ABC.exe
  • step 4: npm install electron-wix-msi@latest
  • step 5: npm install node-gyp@latest --save-dev
  • step 6: npm install child_process@latest --save-dev
  • step 7: npm install fs@0.0.1-security --save-dev
  • step 8: npm i exe-icon-extractor@latest --save-dev

Then I have created a javascript file name msi_creator.js to generate msi package. The javascript code is as below:

const { MSICreator } = require("electron-wix-msi");
const path = require("path");
const { execSync } = require("child_process");

async function start() {
  try {

    // Step 2: Instantiate the MSICreator
    const msiCreator = new MSICreator({
      appDirectory: path.resolve("."),
      description: "ABC",
      exe: "ABC.exe",
      name: "ABC",
      manufacturer: "FFFF",
      version: "0.1.0",
      upgradeCode: "{12343238-1111-2222-3333-123483275556}",
      removeExistingProduct: true,
      iconPath: "./abc.ico",
      outputDirectory: path.resolve("./output/"),
    });

    // Step 4: Create a .wxs template file
    console.log("Creating the .wxs template file...");
    await msiCreator.create();
    console.log("Created the .wxs template file.");

    // Step 5: Define the MSIErrorLog DLL function
    console.log("Defining the MSIErrorLog DLL function...");
    msiCreator.defineMsiErrorLogFunction(
      function MSIErrorLog(hInstall) {
        var exePath = session.property('CustomActionData');
        var errorLogFile = session.property('MsiErrorLogFile');
        try {
          var child_process = require('child_process');
          child_process.execFile(exePath, {stdio: 'ignore'}, function (error, stdout, stderr) {
            if (error) {
              var fs = require('fs');
              var logFile = fs.createWriteStream(path.join(process.env['TEMP'], 'msi_error.log'), {flags: 'a'});
              logFile.write('Error: ' + error.message + '\n');
              logFile.end();
            }
          });
        } catch (e) {
          var fs = require('fs');
          var logFile = fs.createWriteStream(path.join(process.env['TEMP'], 'msi_error.log'), {flags: 'a'});
          logFile.write('Error: ' + e.message + '\n');
          logFile.end();
        }
      }
    );
    console.log("Defined the MSIErrorLog DLL function.");

    // Step 6: Compile the template to a .msi file
    console.log("Compiling the .wxs template...");
    await msiCreator.compile();
    console.log("Compiled the .wxs template to an MSI installer.");
  } catch (error) {
    console.error(error);
  }
}

start();

Then I run the command

node .\msi_creator.js

But I am getting the following error:

Created the .wxs template file.
Defining the MSIErrorLog DLL function...
TypeError: msiCreator.defineMsiErrorLogFunction is not a function

How to fix this issue? How can I store error logs related app crash?

Thanks and Regards, manu

Bob Arnson
  • 21,377
  • 2
  • 40
  • 47
manoos
  • 1,675
  • 3
  • 21
  • 46

1 Answers1

0

Considering the electron-wix-msi module does not seem to include a defineMsiErrorLogFunction() function, it is not surprising to get "TypeError: msiCreator.defineMsiErrorLogFunction is not a function".

You could instead include in your .wsx file a directive to:

  • call ABC.exe and log any error
  • do so after the installation
<InstallExecuteSequence>
  <Custom Action="RunCollectLogs" After="InstallFinalize" />
  ...
</InstallExecuteSequence>
<Product>
  <Binary Id="CollectLogs" SourceFile="collect_logs.js" />
  <CustomAction Id="RunCollectLogs" BinaryKey="CollectLogs" ExeCommand="node collect_logs.js" Execute="deferred" />
  ...
</Product>

As mentioned here, a custom action needs to be a deferred custom action in order to run after InstallFiles.

With collect_logs.js:

const fs = require("fs");
const path = require("path");
const { exec } = require("child_process");

const logPath = path.join(process.env["TEMP"], "msi_error.log");

exec("ABC.exe", (error, stdout, stderr) => {
  if (error) {
    const logFile = fs.createWriteStream(logPath, { flags: "a" });
    logFile.write("Error: " + error.message + "\n");
    logFile.end();
  }
});
VonC
  • 1,262,500
  • 529
  • 4,410
  • 5,250
  • I have modified my code with custom actions sections as below to run custom actions to collect logs: ```javascript customActions: [ { id: "runABC", directory: "INSTALLDIR", executable: "cmd.exe", arguments: [ "/c", "start", "cmd.exe", "/c", "node", "collect_logs.js", ], execute: "immediate", logDescription: "Running custom_act.js after installation", }, ], ``` I am not seeing any crash logs. What is wrong with my set up? – manoos May 05 '23 at 00:05
  • @manoos Did you try the `collect_logs.js` I suggested? The issue with your approach is that it will run the command script during the installation, and not after the installation is completed. – VonC May 05 '23 at 12:14