web.ts 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. import { isDevBuild } from "@/utils/env";
  2. import { logError } from "@ente/shared/sentry";
  3. import {
  4. getData,
  5. LS_KEYS,
  6. removeData,
  7. setData,
  8. } from "@ente/shared/storage/localStorage";
  9. import { addLogLine } from ".";
  10. import { getSentryUserID } from "../sentry/utils";
  11. import { formatDateTimeShort } from "../time/format";
  12. import { ElectronFile } from "../upload/types";
  13. import type { User } from "../user/types";
  14. import { convertBytesToHumanReadable } from "../utils/size";
  15. export const MAX_LOG_SIZE = 5 * 1024 * 1024; // 5MB
  16. export const MAX_LOG_LINES = 1000;
  17. export interface Log {
  18. timestamp: number;
  19. logLine: string;
  20. }
  21. export function logWeb(logLine: string) {
  22. try {
  23. const log: Log = { logLine, timestamp: Date.now() };
  24. const logs = getLogs();
  25. if (logs.length > MAX_LOG_LINES) {
  26. logs.slice(logs.length - MAX_LOG_LINES);
  27. }
  28. logs.push(log);
  29. setLogs(logs);
  30. } catch (e) {
  31. if (e.name === "QuotaExceededError") {
  32. deleteLogs();
  33. logWeb("logs cleared");
  34. }
  35. }
  36. }
  37. export function getDebugLogs() {
  38. return combineLogLines(getLogs());
  39. }
  40. export function getFileNameSize(file: File | ElectronFile) {
  41. return `${file.name}_${convertBytesToHumanReadable(file.size)}`;
  42. }
  43. export const clearLogsIfLocalStorageLimitExceeded = () => {
  44. try {
  45. const logs = getDebugLogs();
  46. const logSize = getStringSize(logs);
  47. if (logSize > MAX_LOG_SIZE) {
  48. deleteLogs();
  49. logWeb("Logs cleared due to size limit exceeded");
  50. } else {
  51. try {
  52. logWeb(`app started`);
  53. } catch (e) {
  54. deleteLogs();
  55. }
  56. }
  57. logWeb(`logs size: ${convertBytesToHumanReadable(logSize)}`);
  58. } catch (e) {
  59. logError(
  60. e,
  61. "failed to clearLogsIfLocalStorageLimitExceeded",
  62. undefined,
  63. true,
  64. );
  65. }
  66. };
  67. export const logStartupMessage = async (appId: string) => {
  68. // TODO (MR): Remove the need to lowercase it, change the enum itself.
  69. const appIdL = appId.toLowerCase();
  70. const userID = (getData(LS_KEYS.USER) as User)?.id;
  71. const sentryID = await getSentryUserID();
  72. const buildId = isDevBuild ? "dev" : `git ${process.env.GIT_SHA}`;
  73. addLogLine(`ente-${appIdL}-web ${buildId} uid ${userID} sid ${sentryID}`);
  74. };
  75. function getLogs(): Log[] {
  76. return getData(LS_KEYS.LOGS)?.logs ?? [];
  77. }
  78. function setLogs(logs: Log[]) {
  79. setData(LS_KEYS.LOGS, { logs });
  80. }
  81. function deleteLogs() {
  82. removeData(LS_KEYS.LOGS);
  83. }
  84. function getStringSize(str: string) {
  85. return new Blob([str]).size;
  86. }
  87. export function formatLog(log: Log) {
  88. return `[${formatDateTimeShort(log.timestamp)}] ${log.logLine}`;
  89. }
  90. function combineLogLines(logs: Log[]) {
  91. return logs.map(formatLog).join("\n");
  92. }