Skip to content

Commit

Permalink
ref: Overhaul console integration
Browse files Browse the repository at this point in the history
Our console integration was designed to work on the same page with the Spotlight UI. It was using a naive filtering method to avoid infinite loops from Spotlight debug mode logger itself. Moreover, it was not taking the `sidecarURL` option, was defaulting to `localhost:8969` as the sidecar URL. This patch overhauls the two, leveraging the fact that they are on the same page. This means switching to the local event-based message passing between the UI and the console integration, removing the need for `fetch` calls and passing around the sidecarURL option. It also overhauls the Spotlight logger to always try to use an unmodified console implementation, removing the need for hacky filtering on the console integration side.
  • Loading branch information
BYK committed Sep 13, 2024
1 parent 42022e5 commit 34ae4ea
Show file tree
Hide file tree
Showing 6 changed files with 79 additions and 38 deletions.
5 changes: 5 additions & 0 deletions .changeset/proud-days-relate.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@spotlightjs/overlay': patch
---

Overhaul console integration for more performance and stability
6 changes: 5 additions & 1 deletion demos/sveltekit/vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,11 @@ import { defineConfig } from 'vitest/config';
import spotlight from '@spotlightjs/spotlight/vite-plugin';

export default defineConfig({
plugins: [sveltekit(), sentrySvelteKit({ autoUploadSourceMaps: false }), spotlight()],
plugins: [
sveltekit(),
sentrySvelteKit({ autoUploadSourceMaps: false }),
spotlight({ integrationNames: ['sentry', 'console'], debug: true })
],
test: {
include: ['src/**/*.{test,spec}.{js,ts}']
}
Expand Down
61 changes: 34 additions & 27 deletions packages/overlay/src/integrations/console/index.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,24 @@
import { trigger } from '../../lib/eventTarget';
import type { WindowWithSpotlight } from '../../types';
import type { Integration } from '../integration';
import ConsoleTab from './console-tab';
import { ConsoleMessage, Level } from './types';
import type { ConsoleMessage, Level } from './types';

const HEADER = 'application/x-spotlight-console';
const PORT = 8969;
const CONTENT_TYPE = 'application/x-spotlight-console';

/**
* This integration is meant to run on the same page where
* the Spotlight UI is running. For standalone UI cases such
* as the Electron app, we should publish a separate version
* that takes in the sidecar URL.
* @returns Integration Console integration for Spotlight
*/
export default function consoleIntegration() {
const pageloadId = window.crypto.randomUUID();

return {
name: 'console',
forwardedContentType: [HEADER],
forwardedContentType: [CONTENT_TYPE],
tabs: ({ processedEvents }) => [
{
id: 'console',
Expand All @@ -37,34 +45,33 @@ export default function consoleIntegration() {
}

function instrumentConsole(level: Level, pageloadId: string) {
const originalConsoleLog = window.console[level];
const windowWithSpotlight = window as WindowWithSpotlight;
if (!windowWithSpotlight.__spotlight) {
windowWithSpotlight.__spotlight = {};
}
if (!windowWithSpotlight.__spotlight.console) {
windowWithSpotlight.__spotlight.console = {};
}
const originalConsole = windowWithSpotlight.__spotlight.console;
if (!originalConsole[level]) {
originalConsole[level] = window.console[level];
}
const originalConsoleMethod = originalConsole[level];

window.console[level] = (...args: unknown[]) => {
const serializedArgs = argsToString(args);
// Super dumb way to avoid endless loops (we're gonna regret that)
if (serializedArgs.find(a => a.toLowerCase().includes('spotlight'))) {
return originalConsoleLog(...args);
}

try {
void fetch(`http://localhost:${PORT}/stream`, {
method: 'POST',
body: JSON.stringify({
type: level,
args: serializedArgs,
msg: serializedArgs.join(' '),
sessionId: pageloadId,
} satisfies ConsoleMessage),
headers: {
'Content-Type': HEADER,
},
mode: 'cors',
}).catch(() => {});
} catch {
// ignore failed fetch requests
}
trigger('event', {
contentType: CONTENT_TYPE,
data: JSON.stringify({
type: level,
args: serializedArgs,
msg: serializedArgs.join(' '),
sessionId: pageloadId,
} satisfies ConsoleMessage),
});

return originalConsoleLog(...args);
return originalConsoleMethod.call(window, ...args);
};
}

Expand Down
40 changes: 31 additions & 9 deletions packages/overlay/src/lib/logger.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,43 @@
let loggerActive = false;
import type { WindowWithSpotlight } from '../types';

export const SPOTLIGHT_PREFIX = '🔎 [Spotlight]';

const windowWithSpotlight = window as WindowWithSpotlight;
if (!windowWithSpotlight.__spotlight) {
windowWithSpotlight.__spotlight = {};
}
if (!windowWithSpotlight.__spotlight.console) {
windowWithSpotlight.__spotlight.console = {};
}

if (!windowWithSpotlight.__spotlight.console.log) {
windowWithSpotlight.__spotlight.console.log = window.console.log;
}

if (!windowWithSpotlight.__spotlight.console.warn) {
windowWithSpotlight.__spotlight.console.warn = window.console.warn;
}

const original = windowWithSpotlight.__spotlight.console;

const noop = (..._args: unknown[]) => {}; // eslint-disable-line @typescript-eslint/no-unused-vars
let _log = noop;
let _warn = noop;

export function activateLogger() {
loggerActive = true;
_log = (...args: unknown[]) => original.log.call(window, SPOTLIGHT_PREFIX, ...args);
_warn = (...args: unknown[]) => original.warn.call(window, SPOTLIGHT_PREFIX, ...args);
}

export function deactivateLogger() {
loggerActive = false;
_log = noop;
_warn = noop;
}

export function log(...args: unknown[]) {
if (loggerActive) {
console.log('🔎 [Spotlight]', ...args);
}
_log(...args);
}

export function warn(...args: unknown[]) {
if (loggerActive) {
console.warn('🔎 [Spotlight]', ...args);
}
_warn(...args);
}
1 change: 1 addition & 0 deletions packages/overlay/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -123,5 +123,6 @@ export type WindowWithSpotlight = Window & {
__spotlight?: {
eventTarget?: EventTarget;
initOptions?: SpotlightOverlayOptions;
console?: Record<string, (...args: unknown[]) => void>;
};
};
4 changes: 3 additions & 1 deletion packages/overlay/vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,9 @@ export default defineConfig({
},
rollupOptions: {
treeshake: 'smallest',
output: { footer: 'window.Spotlight && Spotlight.init()' },
output: {
footer: '(function(S){S && S.init({integrations: [S.sentry(), S.console()]})}(window.Spotlight))',
},
},
sourcemap: true,
},
Expand Down

0 comments on commit 34ae4ea

Please sign in to comment.