chore: Centralize clientside logging

This commit is contained in:
Tom Moor
2022-04-25 23:31:30 -07:00
parent 38409ff4ec
commit 11477a1185
10 changed files with 128 additions and 22 deletions

View File

@@ -5,6 +5,7 @@ import * as React from "react";
import Collection from "~/models/Collection";
import { icons } from "~/components/IconPicker";
import useStores from "~/hooks/useStores";
import Logger from "~/utils/logger";
type Props = {
collection: Collection;
@@ -36,7 +37,9 @@ function ResolvedCollectionIcon({
const Component = icons[collection.icon].component;
return <Component color={color} size={size} />;
} catch (error) {
console.warn("Failed to render custom icon " + collection.icon);
Logger.warn("Failed to render custom icon", {
icon: collection.icon,
});
}
}

View File

@@ -1,4 +1,3 @@
import * as Sentry from "@sentry/react";
import { observable } from "mobx";
import { observer } from "mobx-react";
import * as React from "react";
@@ -11,6 +10,7 @@ import PageTitle from "~/components/PageTitle";
import Text from "~/components/Text";
import env from "~/env";
import isHosted from "~/utils/isHosted";
import Logger from "~/utils/logger";
type Props = WithTranslation & {
reloadOnChunkMissing?: boolean;
@@ -26,7 +26,6 @@ class ErrorBoundary extends React.Component<Props> {
componentDidCatch(error: Error) {
this.error = error;
console.error(error);
if (
this.props.reloadOnChunkMissing &&
@@ -40,9 +39,7 @@ class ErrorBoundary extends React.Component<Props> {
return;
}
if (env.SENTRY_DSN) {
Sentry.captureException(error);
}
Logger.error("ErrorBoundary", error);
}
handleReload = () => {

View File

@@ -28,6 +28,7 @@ import { EmbedDescriptor, EventType } from "@shared/editor/types";
import EventEmitter from "@shared/utils/events";
import Flex from "~/components/Flex";
import { Dictionary } from "~/hooks/useDictionary";
import Logger from "~/utils/logger";
import BlockMenu from "./components/BlockMenu";
import ComponentView from "./components/ComponentView";
import EditorContext from "./components/EditorContext";
@@ -476,7 +477,7 @@ export class Editor extends React.PureComponent<
// querySelector will throw an error if the hash begins with a number
// or contains a period. This is protected against now by safeSlugify
// however previous links may be in the wild.
console.warn(`Attempted to scroll to invalid hash: ${hash}`, err);
Logger.debug("editor", `Attempted to scroll to invalid hash: ${hash}`);
}
}

View File

@@ -1,6 +1,7 @@
import * as React from "react";
import { Primitive } from "utility-types";
import Storage from "~/utils/Storage";
import Logger from "~/utils/logger";
import useEventListener from "./useEventListener";
/**
@@ -32,7 +33,7 @@ export default function usePersistedState(
Storage.set(key, valueToStore);
} catch (error) {
// A more advanced implementation would handle the error case
console.log(error);
Logger.debug("misc", "Failed to persist state", { error });
}
};

View File

@@ -17,6 +17,7 @@ import Toasts from "~/components/Toasts";
import env from "~/env";
import Routes from "./routes";
import history from "./utils/history";
import Logger from "./utils/logger";
import { initSentry } from "./utils/sentry";
initI18n();
@@ -40,10 +41,14 @@ if ("serviceWorker" in window.navigator) {
if (maybePromise?.then) {
maybePromise
.then((registration) => {
console.log("SW registered: ", registration);
Logger.debug("lifecycle", "SW registered: ", registration);
})
.catch((registrationError) => {
console.log("SW registration failed: ", registrationError);
Logger.debug(
"lifecycle",
"SW registration failed: ",
registrationError
);
});
}
});

View File

@@ -16,6 +16,7 @@ import useStores from "~/hooks/useStores";
import useToasts from "~/hooks/useToasts";
import MultiplayerExtension from "~/multiplayer/MultiplayerExtension";
import { supportsPassiveListener } from "~/utils/browser";
import Logger from "~/utils/logger";
import { homePath } from "~/utils/routeHelpers";
type Props = EditorProps & {
@@ -139,15 +140,21 @@ function MultiplayerEditor({ onSynced, ...props }: Props, ref: any) {
if (debug) {
provider.on("status", (ev: ConnectionStatusEvent) =>
console.log("status", ev.status)
Logger.debug("collaboration", "status", ev)
);
provider.on("message", (ev: MessageEvent) =>
console.log("incoming", ev.message)
Logger.debug("collaboration", "incoming", {
message: ev.message,
})
);
provider.on("outgoingMessage", (ev: MessageEvent) =>
console.log("outgoing", ev.message)
Logger.debug("collaboration", "outgoing", {
message: ev.message,
})
);
localProvider.on("synced", () =>
Logger.debug("collaboration", "local synced")
);
localProvider.on("synced", () => console.log("local synced"));
}
provider.on("status", (ev: ConnectionStatusEvent) =>

View File

@@ -23,6 +23,7 @@ import RegisterKeyDown from "~/components/RegisterKeyDown";
import Scene from "~/components/Scene";
import Text from "~/components/Text";
import withStores from "~/components/withStores";
import Logger from "~/utils/logger";
import { searchPath } from "~/utils/routeHelpers";
import { decodeURIComponentSafe } from "~/utils/urls";
import CollectionFilter from "./components/CollectionFilter";
@@ -257,9 +258,9 @@ class Search extends React.Component<Props> {
} else {
this.offset += DEFAULT_PAGINATION_LIMIT;
}
} catch (err) {
} catch (error) {
Logger.error("Search query failed", error);
this.lastQuery = "";
throw err;
} finally {
this.isLoading = false;
}

View File

@@ -1,6 +1,6 @@
import * as Sentry from "@sentry/react";
import invariant from "invariant";
import { client } from "./ApiClient";
import Logger from "./logger";
type UploadOptions = {
/** The user facing name of the file */
@@ -45,7 +45,6 @@ export const uploadFile = async (
}
// Using XMLHttpRequest instead of fetch because fetch doesn't support progress
let error;
const xhr = new XMLHttpRequest();
const success = await new Promise((resolve) => {
xhr.upload.addEventListener("progress", (event) => {
@@ -53,7 +52,12 @@ export const uploadFile = async (
options.onProgress(event.loaded / event.total);
}
});
xhr.addEventListener("error", (err) => (error = err));
xhr.addEventListener("error", () => {
Logger.error(
"File upload failed",
new Error(`${xhr.status} ${xhr.statusText}`)
);
});
xhr.addEventListener("loadend", () => {
resolve(xhr.readyState === 4 && xhr.status >= 200 && xhr.status < 400);
});
@@ -62,7 +66,6 @@ export const uploadFile = async (
});
if (!success) {
Sentry.captureException(error);
throw new Error("Upload failed");
}

86
app/utils/logger.ts Normal file
View File

@@ -0,0 +1,86 @@
import * as Sentry from "@sentry/react";
import env from "~/env";
type LogCategory =
| "lifecycle"
| "http"
| "editor"
| "router"
| "collaboration"
| "misc";
type Extra = Record<string, any>;
class Logger {
/**
* Log information
*
* @param category A log message category that will be prepended
* @param extra Arbitrary data to be logged that will appear in prod logs
*/
info(label: LogCategory, message: string, extra?: Extra) {
console.info(`[${label}] ${message}`, extra);
}
/**
* Debug information
*
* @param category A log message category that will be prepended
* @param extra Arbitrary data to be logged
*/
debug(label: LogCategory, message: string, extra?: Extra) {
if (env.ENVIRONMENT === "development") {
console.debug(`[${label}] ${message}`, extra);
}
}
/**
* Log a warning
*
* @param message A warning message
* @param extra Arbitrary data to be logged that will appear in prod logs
*/
warn(message: string, extra?: Extra) {
if (env.SENTRY_DSN) {
Sentry.withScope(function (scope) {
scope.setLevel(Sentry.Severity.Warning);
for (const key in extra) {
scope.setExtra(key, extra[key]);
}
Sentry.captureMessage(message);
});
}
console.warn(message, extra);
}
/**
* Report a runtime error
*
* @param message A description of the error
* @param error The error that occurred
* @param extra Arbitrary data to be logged that will appear in prod logs
*/
error(message: string, error: Error, extra?: Extra) {
if (env.SENTRY_DSN) {
Sentry.withScope(function (scope) {
scope.setLevel(Sentry.Severity.Error);
for (const key in extra) {
scope.setExtra(key, extra[key]);
}
Sentry.captureException(error);
});
}
console.error(message, {
error,
extra,
});
}
}
export default new Logger();

View File

@@ -74,9 +74,10 @@ class Logger {
if (process.env.SENTRY_DSN) {
Sentry.withScope(function (scope) {
scope.setLevel(Sentry.Severity.Warning);
for (const key in extra) {
scope.setExtra(key, extra[key]);
scope.setLevel(Sentry.Severity.Warning);
}
Sentry.captureMessage(message);
@@ -105,9 +106,10 @@ class Logger {
if (process.env.SENTRY_DSN) {
Sentry.withScope(function (scope) {
scope.setLevel(Sentry.Severity.Error);
for (const key in extra) {
scope.setExtra(key, extra[key]);
scope.setLevel(Sentry.Severity.Error);
}
Sentry.captureException(error);