From 287abd241db6a49a7e7326a10e19cf8fcc012875 Mon Sep 17 00:00:00 2001 From: Fedor Indutny <79877362+indutny-signal@users.noreply.github.com> Date: Wed, 2 Jun 2021 13:13:33 -0700 Subject: [PATCH] Fix performance of debug logs view --- js/views/debug_log_view.js | 3 +-- ts/logging/shared.ts | 42 ++++++++++++++++++++++++++++++-------- 2 files changed, 34 insertions(+), 11 deletions(-) diff --git a/js/views/debug_log_view.js b/js/views/debug_log_view.js index 239ae7da365..b256db40911 100644 --- a/js/views/debug_log_view.js +++ b/js/views/debug_log_view.js @@ -111,8 +111,7 @@ // we need to scroll, but not so many that things get slow. const linesToShow = Math.ceil(Math.min(window.innerHeight, 2000) / 5); this.textarea.value = this.logText - .split(/\n/g) - .slice(0, linesToShow) + .split(/\n/g, linesToShow) .concat(['', i18n('loading')]) .join('\n'); diff --git a/ts/logging/shared.ts b/ts/logging/shared.ts index e890313dcbe..00da5af9dcf 100644 --- a/ts/logging/shared.ts +++ b/ts/logging/shared.ts @@ -1,7 +1,6 @@ // Copyright 2021 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -import { z } from 'zod'; import * as pino from 'pino'; import { redactAll } from '../util/privacy'; import { missingCaseError } from '../util/missingCaseError'; @@ -20,15 +19,40 @@ export enum LogLevel { // These match [Pino's core fields][1]. // [1]: https://getpino.io/#/?id=usage -const logEntrySchema = z.object({ - level: z.nativeEnum(LogLevel), - msg: z.string(), - time: z.string().refine(value => !Number.isNaN(new Date(value).getTime())), -}); -export type LogEntryType = z.infer; +export type LogEntryType = Readonly<{ + level: LogLevel; + msg: string; + time: string; +}>; -export const isLogEntry = (data: unknown): data is LogEntryType => - logEntrySchema.safeParse(data).success; +// The code below is performance sensitive since it runs for > 100k log entries +// whenever we want to send the debug log. We can't use `zod` because it clones +// the data on successful parse and ruins the performance. +export const isLogEntry = (data: unknown): data is LogEntryType => { + if (data === null || typeof data !== 'object') { + return false; + } + + const { level, msg, time } = data as Partial; + + if (typeof level !== 'number') { + return false; + } + + if (!LogLevel[level]) { + return false; + } + + if (typeof msg !== 'string') { + return false; + } + + if (typeof time !== 'string') { + return false; + } + + return !Number.isNaN(new Date(time).getTime()); +}; export function getLogLevelString(value: LogLevel): pino.Level { switch (value) {