mirror of
				https://github.com/zulip/zulip-desktop.git
				synced 2025-11-04 05:53:21 +00:00 
			
		
		
		
	Untangle Sentry initialization.
Thanks to upstream for the helpful advice at https://github.com/getsentry/sentry-electron/issues/427. Signed-off-by: Anders Kaseorg <anders@zulip.com>
This commit is contained in:
		@@ -1,6 +1,7 @@
 | 
				
			|||||||
import fs from "fs";
 | 
					import fs from "fs";
 | 
				
			||||||
import path from "path";
 | 
					import path from "path";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import * as Sentry from "@sentry/electron";
 | 
				
			||||||
import {JsonDB} from "node-json-db";
 | 
					import {JsonDB} from "node-json-db";
 | 
				
			||||||
import {DataError} from "node-json-db/dist/lib/Errors";
 | 
					import {DataError} from "node-json-db/dist/lib/Errors";
 | 
				
			||||||
import type * as z from "zod";
 | 
					import type * as z from "zod";
 | 
				
			||||||
@@ -91,7 +92,7 @@ function reloadDB(): void {
 | 
				
			|||||||
      );
 | 
					      );
 | 
				
			||||||
      logger.error("Error while JSON parsing settings.json: ");
 | 
					      logger.error("Error while JSON parsing settings.json: ");
 | 
				
			||||||
      logger.error(error);
 | 
					      logger.error(error);
 | 
				
			||||||
      logger.reportSentry(error);
 | 
					      Sentry.captureException(error);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,11 +1,9 @@
 | 
				
			|||||||
import {Console} from "console"; // eslint-disable-line node/prefer-global/console
 | 
					import {Console} from "console"; // eslint-disable-line node/prefer-global/console
 | 
				
			||||||
import electron from "electron";
 | 
					 | 
				
			||||||
import fs from "fs";
 | 
					import fs from "fs";
 | 
				
			||||||
import os from "os";
 | 
					import os from "os";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import {initSetUp} from "./default-util";
 | 
					import {initSetUp} from "./default-util";
 | 
				
			||||||
import {app} from "./remote";
 | 
					import {app} from "./remote";
 | 
				
			||||||
import {captureException, sentryInit} from "./sentry-util";
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
interface LoggerOptions {
 | 
					interface LoggerOptions {
 | 
				
			||||||
  file?: string;
 | 
					  file?: string;
 | 
				
			||||||
@@ -13,24 +11,6 @@ interface LoggerOptions {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
initSetUp();
 | 
					initSetUp();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
let reportErrors = true;
 | 
					 | 
				
			||||||
if (process.type === "renderer") {
 | 
					 | 
				
			||||||
  // Report Errors to Sentry only if it is enabled in settings
 | 
					 | 
				
			||||||
  // Gets the value of reportErrors from config-util for renderer process
 | 
					 | 
				
			||||||
  // For main process, sentryInit() is handled in index.js
 | 
					 | 
				
			||||||
  const {ipcRenderer} = electron;
 | 
					 | 
				
			||||||
  ipcRenderer.send("error-reporting");
 | 
					 | 
				
			||||||
  ipcRenderer.on(
 | 
					 | 
				
			||||||
    "error-reporting-val",
 | 
					 | 
				
			||||||
    (_event: Event, errorReporting: boolean) => {
 | 
					 | 
				
			||||||
      reportErrors = errorReporting;
 | 
					 | 
				
			||||||
      if (reportErrors) {
 | 
					 | 
				
			||||||
        sentryInit();
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
  );
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const logDir = `${app.getPath("userData")}/Logs`;
 | 
					const logDir = `${app.getPath("userData")}/Logs`;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type Level = "log" | "debug" | "info" | "warn" | "error";
 | 
					type Level = "log" | "debug" | "info" | "warn" | "error";
 | 
				
			||||||
@@ -91,12 +71,6 @@ export default class Logger {
 | 
				
			|||||||
    return timestamp;
 | 
					    return timestamp;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  reportSentry(error: unknown): void {
 | 
					 | 
				
			||||||
    if (reportErrors) {
 | 
					 | 
				
			||||||
      captureException(error);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  async trimLog(file: string): Promise<void> {
 | 
					  async trimLog(file: string): Promise<void> {
 | 
				
			||||||
    const data = await fs.promises.readFile(file, "utf8");
 | 
					    const data = await fs.promises.readFile(file, "utf8");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,18 +0,0 @@
 | 
				
			|||||||
import {init} from "@sentry/electron";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import {app} from "./remote";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export const sentryInit = (): void => {
 | 
					 | 
				
			||||||
  if (app.isPackaged) {
 | 
					 | 
				
			||||||
    init({
 | 
					 | 
				
			||||||
      dsn: "https://628dc2f2864243a08ead72e63f94c7b1@sentry.io/204668",
 | 
					 | 
				
			||||||
      // We should ignore this error since it's harmless and we know the reason behind this
 | 
					 | 
				
			||||||
      // This error mainly comes from the console logs.
 | 
					 | 
				
			||||||
      // This is a temp solution until Sentry supports disabling the console logs
 | 
					 | 
				
			||||||
      ignoreErrors: ["does not appear to be a valid Zulip server"],
 | 
					 | 
				
			||||||
      /// sendTimeout: 30 // wait 30 seconds before considering the sending capture to have failed, default is 1 second
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export {captureException} from "@sentry/electron";
 | 
					 | 
				
			||||||
@@ -5,7 +5,6 @@ export interface MainMessage {
 | 
				
			|||||||
  "clear-app-settings": () => void;
 | 
					  "clear-app-settings": () => void;
 | 
				
			||||||
  "configure-spell-checker": () => void;
 | 
					  "configure-spell-checker": () => void;
 | 
				
			||||||
  downloadFile: (url: string, downloadPath: string) => void;
 | 
					  downloadFile: (url: string, downloadPath: string) => void;
 | 
				
			||||||
  "error-reporting": () => void;
 | 
					 | 
				
			||||||
  "fetch-user-agent": () => string;
 | 
					  "fetch-user-agent": () => string;
 | 
				
			||||||
  "focus-app": () => void;
 | 
					  "focus-app": () => void;
 | 
				
			||||||
  "focus-this-webview": () => void;
 | 
					  "focus-this-webview": () => void;
 | 
				
			||||||
@@ -39,7 +38,6 @@ export interface RendererMessage {
 | 
				
			|||||||
  downloadFileCompleted: (filePath: string, fileName: string) => void;
 | 
					  downloadFileCompleted: (filePath: string, fileName: string) => void;
 | 
				
			||||||
  downloadFileFailed: (state: string) => void;
 | 
					  downloadFileFailed: (state: string) => void;
 | 
				
			||||||
  "enter-fullscreen": () => void;
 | 
					  "enter-fullscreen": () => void;
 | 
				
			||||||
  "error-reporting-val": (errorReporting: boolean) => void;
 | 
					 | 
				
			||||||
  focus: () => void;
 | 
					  focus: () => void;
 | 
				
			||||||
  "focus-webview-with-id": (webviewId: number) => void;
 | 
					  "focus-webview-with-id": (webviewId: number) => void;
 | 
				
			||||||
  forward: () => void;
 | 
					  forward: () => void;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,7 +6,6 @@ import * as remoteMain from "@electron/remote/main";
 | 
				
			|||||||
import windowStateKeeper from "electron-window-state";
 | 
					import windowStateKeeper from "electron-window-state";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import * as ConfigUtil from "../common/config-util";
 | 
					import * as ConfigUtil from "../common/config-util";
 | 
				
			||||||
import {sentryInit} from "../common/sentry-util";
 | 
					 | 
				
			||||||
import type {RendererMessage} from "../common/typed-ipc";
 | 
					import type {RendererMessage} from "../common/typed-ipc";
 | 
				
			||||||
import type {MenuProps} from "../common/types";
 | 
					import type {MenuProps} from "../common/types";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -14,11 +13,15 @@ import {appUpdater} from "./autoupdater";
 | 
				
			|||||||
import * as BadgeSettings from "./badge-settings";
 | 
					import * as BadgeSettings from "./badge-settings";
 | 
				
			||||||
import * as AppMenu from "./menu";
 | 
					import * as AppMenu from "./menu";
 | 
				
			||||||
import {_getServerSettings, _isOnline, _saveServerIcon} from "./request";
 | 
					import {_getServerSettings, _isOnline, _saveServerIcon} from "./request";
 | 
				
			||||||
 | 
					import {sentryInit} from "./sentry";
 | 
				
			||||||
import {setAutoLaunch} from "./startup";
 | 
					import {setAutoLaunch} from "./startup";
 | 
				
			||||||
import {ipcMain, send} from "./typed-ipc-main";
 | 
					import {ipcMain, send} from "./typed-ipc-main";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const {GDK_BACKEND} = process.env;
 | 
					const {GDK_BACKEND} = process.env;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Initialize sentry for main process
 | 
				
			||||||
 | 
					sentryInit();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
let mainWindowState: windowStateKeeper.State;
 | 
					let mainWindowState: windowStateKeeper.State;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Prevent window being garbage collected
 | 
					// Prevent window being garbage collected
 | 
				
			||||||
@@ -199,12 +202,6 @@ function createMainWindow(): Electron.BrowserWindow {
 | 
				
			|||||||
    mainWindow.setMenuBarVisibility(!shouldHideMenu);
 | 
					    mainWindow.setMenuBarVisibility(!shouldHideMenu);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Initialize sentry for main process
 | 
					 | 
				
			||||||
  const errorReporting = ConfigUtil.getConfigItem("errorReporting", true);
 | 
					 | 
				
			||||||
  if (errorReporting) {
 | 
					 | 
				
			||||||
    sentryInit();
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const page = mainWindow.webContents;
 | 
					  const page = mainWindow.webContents;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  page.on("dom-ready", () => {
 | 
					  page.on("dom-ready", () => {
 | 
				
			||||||
@@ -460,12 +457,6 @@ ${error}`,
 | 
				
			|||||||
    },
 | 
					    },
 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Using event.sender.send instead of page.send here to
 | 
					 | 
				
			||||||
  // make sure the value of errorReporting is sent only once on load.
 | 
					 | 
				
			||||||
  ipcMain.on("error-reporting", (event: Electron.IpcMainEvent) => {
 | 
					 | 
				
			||||||
    send(event.sender, "error-reporting-val", errorReporting);
 | 
					 | 
				
			||||||
  });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  ipcMain.on(
 | 
					  ipcMain.on(
 | 
				
			||||||
    "save-last-tab",
 | 
					    "save-last-tab",
 | 
				
			||||||
    (_event: Electron.IpcMainEvent, index: number) => {
 | 
					    (_event: Electron.IpcMainEvent, index: number) => {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,6 +5,7 @@ import path from "path";
 | 
				
			|||||||
import stream from "stream";
 | 
					import stream from "stream";
 | 
				
			||||||
import util from "util";
 | 
					import util from "util";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import * as Sentry from "@sentry/electron";
 | 
				
			||||||
import getStream from "get-stream";
 | 
					import getStream from "get-stream";
 | 
				
			||||||
import * as z from "zod";
 | 
					import * as z from "zod";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -103,7 +104,7 @@ export const _saveServerIcon = async (
 | 
				
			|||||||
  } catch (error: unknown) {
 | 
					  } catch (error: unknown) {
 | 
				
			||||||
    logger.log("Could not get server icon.");
 | 
					    logger.log("Could not get server icon.");
 | 
				
			||||||
    logger.log(error);
 | 
					    logger.log(error);
 | 
				
			||||||
    logger.reportSentry(error);
 | 
					    Sentry.captureException(error);
 | 
				
			||||||
    return defaultIconUrl;
 | 
					    return defaultIconUrl;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										22
									
								
								app/main/sentry.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								app/main/sentry.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,22 @@
 | 
				
			|||||||
 | 
					import {app} from "electron";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import * as Sentry from "@sentry/electron";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import {getConfigItem} from "../common/config-util";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const sentryInit = (): void => {
 | 
				
			||||||
 | 
					  Sentry.init({
 | 
				
			||||||
 | 
					    dsn: "https://628dc2f2864243a08ead72e63f94c7b1@sentry.io/204668",
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Don't report errors in development or if disabled by the user.
 | 
				
			||||||
 | 
					    beforeSend: (event) =>
 | 
				
			||||||
 | 
					      app.isPackaged && getConfigItem("errorReporting", true) ? event : null,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // We should ignore this error since it's harmless and we know the reason behind this
 | 
				
			||||||
 | 
					    // This error mainly comes from the console logs.
 | 
				
			||||||
 | 
					    // This is a temp solution until Sentry supports disabling the console logs
 | 
				
			||||||
 | 
					    ignoreErrors: ["does not appear to be a valid Zulip server"],
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// sendTimeout: 30 // wait 30 seconds before considering the sending capture to have failed, default is 1 second
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
@@ -3,6 +3,7 @@ import path from "path";
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import {Menu, app, dialog, session} from "@electron/remote";
 | 
					import {Menu, app, dialog, session} from "@electron/remote";
 | 
				
			||||||
import * as remote from "@electron/remote";
 | 
					import * as remote from "@electron/remote";
 | 
				
			||||||
 | 
					import * as Sentry from "@sentry/electron";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import type {Config} from "../../common/config-util";
 | 
					import type {Config} from "../../common/config-util";
 | 
				
			||||||
import * as ConfigUtil from "../../common/config-util";
 | 
					import * as ConfigUtil from "../../common/config-util";
 | 
				
			||||||
@@ -24,6 +25,8 @@ import * as DomainUtil from "./utils/domain-util";
 | 
				
			|||||||
import * as LinkUtil from "./utils/link-util";
 | 
					import * as LinkUtil from "./utils/link-util";
 | 
				
			||||||
import ReconnectUtil from "./utils/reconnect-util";
 | 
					import ReconnectUtil from "./utils/reconnect-util";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Sentry.init({});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type WebviewListener =
 | 
					type WebviewListener =
 | 
				
			||||||
  | "webview-reload"
 | 
					  | "webview-reload"
 | 
				
			||||||
  | "back"
 | 
					  | "back"
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,6 +2,7 @@ import fs from "fs";
 | 
				
			|||||||
import path from "path";
 | 
					import path from "path";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import {app, dialog} from "@electron/remote";
 | 
					import {app, dialog} from "@electron/remote";
 | 
				
			||||||
 | 
					import * as Sentry from "@sentry/electron";
 | 
				
			||||||
import {JsonDB} from "node-json-db";
 | 
					import {JsonDB} from "node-json-db";
 | 
				
			||||||
import {DataError} from "node-json-db/dist/lib/Errors";
 | 
					import {DataError} from "node-json-db/dist/lib/Errors";
 | 
				
			||||||
import * as z from "zod";
 | 
					import * as z from "zod";
 | 
				
			||||||
@@ -148,7 +149,7 @@ export async function updateSavedServer(
 | 
				
			|||||||
  } catch (error: unknown) {
 | 
					  } catch (error: unknown) {
 | 
				
			||||||
    logger.log("Could not update server icon.");
 | 
					    logger.log("Could not update server icon.");
 | 
				
			||||||
    logger.log(error);
 | 
					    logger.log(error);
 | 
				
			||||||
    logger.reportSentry(error);
 | 
					    Sentry.captureException(error);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -170,7 +171,7 @@ function reloadDB(): void {
 | 
				
			|||||||
      );
 | 
					      );
 | 
				
			||||||
      logger.error("Error while JSON parsing domain.json: ");
 | 
					      logger.error("Error while JSON parsing domain.json: ");
 | 
				
			||||||
      logger.error(error);
 | 
					      logger.error(error);
 | 
				
			||||||
      logger.reportSentry(error);
 | 
					      Sentry.captureException(error);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user