diff --git a/src/TwitchAuthHandler.tsx b/src/TwitchAuthHandler.tsx
index 17a1562..a6daad6 100644
--- a/src/TwitchAuthHandler.tsx
+++ b/src/TwitchAuthHandler.tsx
@@ -19,7 +19,7 @@ export const TwitchAuthHandler = () => {
const { accessToken, state } = getTwitchAuthResponseData();
if (state !== authStateValue) {
- logger.error('Invalid state value. Possible CSRF attack. Expected:', authStateValue, 'Received:', state);
+ logger.error('Invalid state value. Possible CSRF attack.');
return Error: Invalid state value.;
}
diff --git a/src/TwitchBroadcasterIdLoader.tsx b/src/TwitchBroadcasterIdLoader.tsx
index af27a45..32615a0 100644
--- a/src/TwitchBroadcasterIdLoader.tsx
+++ b/src/TwitchBroadcasterIdLoader.tsx
@@ -45,7 +45,7 @@ export const TwitchBroadcasterIdLoader = () => {
// If a channel is specified, try to get the broadcaster ID from the channel name
if (channel) {
loadedBroadcasterId = await getBroadcasterIdFromChannel(channel);
- logger.info('Loaded broadcaster ID:', loadedBroadcasterId, 'from channel:', channel);
+ logger.info(`Loaded broadcaster ID: ${loadedBroadcasterId} from channel: ${channel}`);
}
// If we still don't have a broadcaster ID, try to get it from the access token,
@@ -57,9 +57,9 @@ export const TwitchBroadcasterIdLoader = () => {
return;
}
if (res.id && res.login) {
- logger.info('Loaded broadcaster ID:', res.id, 'from access token');
+ logger.info(`Loaded broadcaster ID: ${res.id} from access token`);
loadedBroadcasterId ??= res.id;
- logger.info('Loaded user ID:', res.id, 'from access token');
+ logger.info(`Loaded user ID: ${res.id} from access token`);
store.getState().setUserId(res.id);
store.getState().setUserLogin(res.login);
}
diff --git a/src/TwitchWebSocketClient.tsx b/src/TwitchWebSocketClient.tsx
index 96d8f17..37477e8 100644
--- a/src/TwitchWebSocketClient.tsx
+++ b/src/TwitchWebSocketClient.tsx
@@ -85,7 +85,7 @@ export const TwitchWebSocketClient = () => {
// Don't share so we can close the socket explicitly if needed
share: false,
onError: (event) => {
- logger.warn('WebSocket error', event);
+ logger.warn(`WebSocket error: ${JSON.stringify(event)}`);
},
onOpen: () => {
logger.info(`WebSocket opened to ${socketUrl}`);
@@ -147,7 +147,7 @@ export const TwitchWebSocketClient = () => {
}
}
} catch (e) {
- logger.warn('Error closing temporary reconnect socket', e);
+ logger.warn(`Error closing temporary reconnect socket: ${JSON.stringify(e)}`);
} finally {
temporarySocketRef.current = null;
}
@@ -187,7 +187,7 @@ export const TwitchWebSocketClient = () => {
try {
getWebSocket()?.close();
} catch (e) {
- logger.warn('Failed to close primary socket during handover', e);
+ logger.warn(`Failed to close primary socket during handover: ${JSON.stringify(e)}`);
}
// We can now close the temporary socket; the hook-managed connection will take over
closeTemporarySocket();
@@ -205,14 +205,14 @@ export const TwitchWebSocketClient = () => {
break;
}
case 'revocation': {
- logger.warn('EventSub subscription revoked (temporary socket)', jsonData.payload?.subscription);
+ logger.warn(`EventSub subscription revoked (temporary socket): ${JSON.stringify(jsonData.payload?.subscription)}`);
break;
}
default:
break;
}
} catch (e) {
- logger.warn('Failed to handle temporary reconnect message', e);
+ logger.warn(`Failed to handle temporary reconnect message: ${JSON.stringify(e)}`);
}
},
[closeTemporarySocket, getWebSocket, hasSeenMessageId, rememberMessageId, resetInactivityWatchdog],
@@ -289,33 +289,33 @@ export const TwitchWebSocketClient = () => {
temporarySocket.onopen = () => {
logger.info('Temporary reconnect WebSocket opened');
};
- temporarySocket.onmessage = (evt) => {
- const dataStr = typeof evt.data === 'string' ? evt.data : '';
+ temporarySocket.onmessage = (event) => {
+ const dataStr = typeof event.data === 'string' ? event.data : '';
if (dataStr) {
handleTempSocketMessage(dataStr);
}
};
- temporarySocket.onerror = (evt) => {
- logger.warn('Temporary reconnect WebSocket error', evt);
+ temporarySocket.onerror = (event) => {
+ logger.warn(`Temporary reconnect WebSocket error: ${JSON.stringify(event)}`);
};
- temporarySocket.onclose = (evt) => {
- logger.info(`Temporary reconnect WebSocket closed (code ${evt.code} reason: ${evt.reason || ''})`);
+ temporarySocket.onclose = (event) => {
+ logger.info(`Temporary reconnect WebSocket closed (code ${event.code} reason: ${event.reason || ''})`);
};
- } catch (e) {
- logger.warn('Failed to create temporary reconnect WebSocket', e);
+ } catch (error) {
+ logger.warn(`Failed to create temporary reconnect WebSocket: ${JSON.stringify(error)}`);
// Fall back: close primary to trigger hook reconnect on base
try {
getWebSocket()?.close();
- } catch (err) {
- logger.warn('Fallback close after temporary socket failure also failed', err);
+ } catch (error) {
+ logger.warn(`Fallback close after temporary socket failure also failed: ${JSON.stringify(error)}`);
}
}
} else {
logger.warn('session_reconnect without reconnect_url; closing socket to trigger base reconnect');
try {
getWebSocket()?.close();
- } catch (err) {
- logger.warn('Fallback close without reconnect_url failed', err);
+ } catch (error) {
+ logger.warn(`Fallback close without reconnect_url failed: ${JSON.stringify(error)}`);
}
}
}
@@ -323,7 +323,7 @@ export const TwitchWebSocketClient = () => {
}
case 'revocation':
- logger.warn('EventSub subscription revoked', jsonData.payload?.subscription);
+ logger.warn(`EventSub subscription revoked: ${JSON.stringify(jsonData.payload?.subscription)}`);
break;
default:
break;
diff --git a/src/handlers/bttv/fetchBetterTTVGlobalEmotes.ts b/src/handlers/bttv/fetchBetterTTVGlobalEmotes.ts
index 7cf8d60..3f0d32c 100644
--- a/src/handlers/bttv/fetchBetterTTVGlobalEmotes.ts
+++ b/src/handlers/bttv/fetchBetterTTVGlobalEmotes.ts
@@ -18,7 +18,7 @@ export const fetchBetterTTVGlobalEmotes = async (): Promise
return json as BttvEmote[];
}
} catch (error) {
- logger.error(error);
+ logger.error(`Failed to fetch BetterTTV global emotes: ${JSON.stringify(error)}`);
}
return null;
diff --git a/src/handlers/bttv/fetchBetterTTVUser.ts b/src/handlers/bttv/fetchBetterTTVUser.ts
index 14fbd39..0d294bd 100644
--- a/src/handlers/bttv/fetchBetterTTVUser.ts
+++ b/src/handlers/bttv/fetchBetterTTVUser.ts
@@ -17,7 +17,7 @@ export const fetchBetterTTVUser = async (broadcasterId: string): Promise =>
logger.warn('No badges found or data is not an array.');
}
} else {
- logger.error('Failed to parse badges response:', parsed.error);
+ logger.error(`Failed to parse badges response: ${parsed.error.message}`);
}
} catch (error) {
- logger.error(error);
+ logger.error(`Failed to fetch Twitch badges: ${JSON.stringify(error)}`);
}
};
diff --git a/src/handlers/twitch/helix/fetchCheers.ts b/src/handlers/twitch/helix/fetchCheers.ts
index 896722d..f48316f 100644
--- a/src/handlers/twitch/helix/fetchCheers.ts
+++ b/src/handlers/twitch/helix/fetchCheers.ts
@@ -33,10 +33,10 @@ export const fetchCheers = async (type: 'global' | 'channel'): Promise =>
logger.warn('No cheers found or data is not an array.');
}
} else {
- logger.error('Failed to parse cheers response:', parsed.error);
+ logger.error(`Failed to parse cheers response: ${parsed.error.message}`);
}
} catch (error) {
- logger.error(error);
+ logger.error(`Failed to fetch Twitch cheers: ${JSON.stringify(error)}`);
}
};
diff --git a/src/handlers/twitch/helix/fetchUserInformation.ts b/src/handlers/twitch/helix/fetchUserInformation.ts
index c6558a0..b12a156 100644
--- a/src/handlers/twitch/helix/fetchUserInformation.ts
+++ b/src/handlers/twitch/helix/fetchUserInformation.ts
@@ -31,7 +31,7 @@ export const fetchUserInformation = async (loginName: string): Promise =>
return data;
}
} catch (error) {
- logger.error(error);
+ logger.error(`Failed to validate access token: ${error}`);
}
return null;
diff --git a/src/main.tsx b/src/main.tsx
index 99e9dd9..d947efb 100644
--- a/src/main.tsx
+++ b/src/main.tsx
@@ -7,10 +7,6 @@ Sentry.init({
dsn: 'https://a688e1582950d78e4cb076f4fad4d95f@o939511.ingest.us.sentry.io/4510030479556608',
sendDefaultPii: false,
enableLogs: true,
- integrations: [
- // send console calls as logs to Sentry
- Sentry.consoleLoggingIntegration({ levels: ['log', 'info', 'warn', 'error'] }),
- ],
});
createRoot(document.getElementById('root')!).render(
diff --git a/src/utils/logger.ts b/src/utils/logger.ts
index 852f2d8..f5fc428 100644
--- a/src/utils/logger.ts
+++ b/src/utils/logger.ts
@@ -1,3 +1,4 @@
+import * as Sentry from '@sentry/react';
import pc from 'picocolors';
export const logLevels = ['error', 'warn', 'info', 'debug'];
@@ -26,23 +27,25 @@ export function setLogLevel(logLevelString: string) {
logLevel = logLevelsMap[logLevelString];
}
+const APP_VERSION = import.meta.env.APP_VERSION || 'unknown';
+
export const logger = {
- error: (...args: unknown[]) => {
- console.error(`${formattedDate()} ${pc.red('Error:')}`, ...args);
+ error: (message: string, extra?: Record) => {
+ Sentry.logger.error(`${formattedDate()} (v${APP_VERSION}) ${pc.red('Error:')} ${message}`, extra);
},
- warn: (...args: unknown[]) => {
+ warn: (message: string, extra?: Record) => {
if (logLevel >= logLevelsMap['warn']) {
- console.warn(`${formattedDate()} ${pc.yellow('Warn:')}`, ...args);
+ Sentry.logger.warn(`${formattedDate()} (v${APP_VERSION}) ${pc.yellow('Warn:')} ${message}`, extra);
}
},
- info: (...args: unknown[]) => {
+ info: (message: string, extra?: Record) => {
if (logLevel >= logLevelsMap['info']) {
- console.info(`${formattedDate()} ${pc.cyan('Info:')}`, ...args);
+ Sentry.logger.info(`${formattedDate()} (v${APP_VERSION}) ${pc.cyan('Info:')} ${message}`, extra);
}
},
debug: (...args: unknown[]) => {
if (logLevel >= logLevelsMap['debug']) {
- console.debug(`${formattedDate()} ${pc.magenta('Debug:')}`, ...args);
+ console.debug(`${formattedDate()} (v${APP_VERSION}) ${pc.magenta('Debug:')}`, ...args);
}
},
};