Skip to content

Commit

Permalink
fix(logger): Update log messages for better readability
Browse files Browse the repository at this point in the history
- Update log messages in different parts of the code for better understanding
- Add context to log messages and improve consistency in logging conventions, ensuring better readability.
  • Loading branch information
thostetler committed Mar 24, 2024
1 parent 50e465e commit 2d677b8
Show file tree
Hide file tree
Showing 7 changed files with 58 additions and 35 deletions.
24 changes: 24 additions & 0 deletions logger/logger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,27 @@ export const logger: Logger = pino({
env: process.env.NODE_ENV || 'development',
},
});

// for use in edge functions (i.e. middleware)
export const edgeLogger: Logger = pino({
browser: {
// this is a workaround for the edge function environment, which does not support
// some formatter pino uses under the hood
write: (obj) => {
try {
console.log(JSON.stringify(obj));
} catch (err) {
if (err instanceof Error) {
// without a `replacer` argument, stringify on Error results in `{}`
console.log(JSON.stringify(err, ['name', 'message', 'stack']));
} else {
console.log(JSON.stringify({ message: 'Unknown error type' }));
}
}
},
},
level: process.env.NODE_ENV === 'development' ? 'debug' : 'info',
base: {
env: process.env.NODE_ENV || 'development',
},
});
12 changes: 6 additions & 6 deletions src/api/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ enum API_STATUS {
UNAUTHORIZED = 401,
}

const log = logger.child({ module: 'api' });
const log = logger.child({}, { msgPrefix: '[api] ' });

/**
* Api structure that wraps the axios instance
Expand Down Expand Up @@ -99,7 +99,7 @@ class Api {
) {
// clear the recent error
this.recentError = null;
log.debug({ msg: 'rejecting request due to recent error', err: error });
log.debug({ msg: 'Rejecting request due to recent error', err: error });
return Promise.reject(error);
}

Expand All @@ -111,7 +111,7 @@ class Api {
if (error.response.status === API_STATUS.UNAUTHORIZED) {
this.invalidateUserData();

log.debug({ msg: 'unauthorized request, refreshing token and retrying', err: error });
log.debug({ msg: 'Unauthorized request, refreshing token and retrying', err: error });

// retry the request
return this.request(error.config as ApiRequestConfig);
Expand Down Expand Up @@ -146,7 +146,7 @@ class Api {
async request<T>(config: ApiRequestConfig): Promise<AxiosResponse<T>> {
if (process.env.NODE_ENV === 'development') {
log.info({
msg: 'request',
msg: 'API Request',
config,
userData: this.userData,
});
Expand Down Expand Up @@ -201,10 +201,10 @@ class Api {
async fetchUserData() {
const { data } = await axios.get<IApiUserResponse>('/api/user', {
headers: {
'x-RefreshToken': 1,
'x-Refresh-Token': 1,
},
});
log.debug({ msg: 'fetching user data', data });
log.debug({ msg: 'Fetching user data', data });
return data.user;
}

Expand Down
4 changes: 2 additions & 2 deletions src/lib/useCreateQueryClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,15 @@ export const useCreateQueryClient = () => {
}

if (axios.isAxiosError(error) || error instanceof Error) {
logger.error({ msg: 'Query error', error, query });
logger.error('Query Error', { error, query });
}
},
});

const mutationCache = new MutationCache({
onError: (error, mutation) => {
if (axios.isAxiosError(error) || error instanceof Error) {
logger.error({ msg: 'Mutation error', error, mutation });
logger.error('Mutation Error', { error, mutation });
}
},
});
Expand Down
4 changes: 2 additions & 2 deletions src/pages/_app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ const TopProgressBar = dynamic<Record<string, never>>(
export type AppPageProps = { dehydratedState: DehydratedState; dehydratedAppState: AppState; [key: string]: unknown };

const NectarApp = memo(({ Component, pageProps }: AppProps): ReactElement => {
logger.debug({ msg: 'app page props', ...pageProps });
logger.debug('App', { props: pageProps as unknown });

return (
<Providers pageProps={pageProps as AppPageProps}>
Expand Down Expand Up @@ -165,7 +165,7 @@ const UserSync = (): ReactElement => {
};

export const reportWebVitals = (metric: NextWebVitalsMetric) => {
logger.debug({ msg: 'web vitals', ...metric });
logger.debug('Web Vitals', { metric });

sendGTMEvent({
event: 'web_vitals',
Expand Down
16 changes: 8 additions & 8 deletions src/pages/api/auth/login.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import axios, { AxiosResponse } from 'axios';
import setCookie from 'set-cookie-parser';
import { logger } from '../../../../logger/logger';

const log = logger.child({ module: 'api/login' });
const log = logger.child({}, { msgPrefix: '[api/login] ' });

export interface ILoginResponse {
success?: boolean;
Expand Down Expand Up @@ -84,24 +84,24 @@ export const handleAuthentication = async (
session.isAuthenticated = true;
session.apiCookieHash = await hash(apiSessionCookie?.value);
await session.save();
log.info({}, 'session updated, success');
log.info('session updated, success');
return res.status(200).json({ success: true });
} else {
// in the case the token is invalid, redirect to root
log.debug({ userData, session }, 'invalid user-data, not updating session');
log.debug('Invalid user-data, not updating session', { userData, session });
return res.status(200).json({ success: false, error: 'invalid-token' });
}
} catch (e) {
log.trace({ error: e }, 'login failed during bootstrapping step');
} catch (error) {
log.trace('Login failed during bootstrapping step', { error });

// if there is an error fetching the user data, we can recover later in a subsequent request
return res.status(200).json({ success: false, error: 'failed-userdata-request' });
}
}
log.debug({ data }, 'login failed');
log.debug('Login failed', { data });
return res.status(401).json({ success: false, error: 'login-failed' });
} catch (e) {
log.trace({ error: e }, 'login failed');
} catch (error) {
log.trace('Login failed', { error });
return res.status(401).json({ success: false, error: 'login-failed' });
}
};
12 changes: 6 additions & 6 deletions src/pages/api/auth/logout.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export interface ILogoutResponse {
error?: 'logout-failed' | 'failed-userdata-request' | 'invalid-token' | 'method-not-allowed';
}

const log = logger.child({ module: 'api/logout' });
const log = logger.child({}, { msgPrefix: '[api/logout] ' });

export default withIronSessionApiRoute(logout, sessionConfig);

Expand Down Expand Up @@ -60,24 +60,24 @@ async function logout(req: NextApiRequest, res: NextApiResponse<ILogoutResponse>
session.isAuthenticated = false;
session.apiCookieHash = await hash(apiSessionCookie?.value);
await session.save();
log.info({}, 'logout successful');
log.info('Logout successful');
return res.status(200).json({ success: true });
} else {
// in the case the token is invalid, redirect to root
log.debug({ userData, session }, 'invalid user-data, not updating session');
log.debug('Invalid user-data, not updating session', { userData, session });
return res.status(200).json({ success: false, error: 'invalid-token' });
}
} catch (e) {
log.trace({ error: e }, 'logout failed during bootstrapping step');
log.trace('Logout failed during bootstrapping step', { error: e });

// if there is an error fetching the user data, we can recover later in a subsequent request
return res.status(200).json({ success: false, error: 'failed-userdata-request' });
}
}
log.debug({ data }, 'logout failed');
log.debug('Logout failed', { data });
return res.status(401).json({ success: false, error: 'logout-failed' });
} catch (e) {
log.trace({ error: e }, 'logout failed');
log.trace('Logout failed', { error: e });
return res.status(401).json({ success: false, error: 'logout-failed' });
}
}
21 changes: 10 additions & 11 deletions src/pages/api/isBot.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { NextApiHandler } from 'next';
// eslint-disable-next-line @next/next/no-server-import-in-page
import { logger } from '../../../logger/logger';
import { logger } from 'logger/logger';
import { resolve as dnsResolve, resolve4 as dnsResolve4 } from 'dns';
import { promisify } from 'util';

Expand All @@ -11,12 +10,12 @@ enum RESULT {
UNVERIFIABLE,
}

const log = logger.child({ module: 'isBot' });
const log = logger.child({}, { msgPrefix: '[isBot] ' });

export const isBot: NextApiHandler = async (req, res) => {
const body = JSON.parse(req.body as string) as { ua: string; ip: string };

log.info(body, 'Checking if request is from a bot');
log.info('Checking if request is from a bot', { body });

const result = await evaluate(body.ua, body.ip);
return res.json(result);
Expand All @@ -35,19 +34,19 @@ const classify = async (ua: string, remoteIP: string) => {

if (bot) {
if (bot.type === 'UNVERIFIABLE') {
log.debug({ msg: 'bot is known, but unverifiable', bot });
log.debug('Request is from a known, but unverifiable bot', { bot });
return RESULT.UNVERIFIABLE;
}

if (await verifyBot(bot, remoteIP)) {
log.debug({ msg: 'bot is known and verified', bot });
log.debug('Request is from a known, and verified bot', { bot });
return RESULT.BOT;
}

log.debug({ msg: 'bot is unknown and unverifiable, potentially malicious', bot });
log.debug('Request is from an unknown and unverifiable bot', { bot });
return RESULT.POTENTIAL_MALICIOUS_BOT;
}
log.debug('not a bot');
log.debug('Request is likely from a human');
return RESULT.HUMAN;
};

Expand Down Expand Up @@ -84,7 +83,7 @@ const resolve4 = promisify(dnsResolve4);
const resolve = async (remoteIp: string, searchEngineBotDomains: string[]) => {
try {
const ptrRecords = await reverseDns(remoteIp);
log.debug({ msg: 'PTR records', ptrRecords });
log.debug('PTR records', { ptrRecords });
const resolvedDomains = new Set();

for (const ptrRecord of ptrRecords) {
Expand All @@ -101,7 +100,7 @@ const resolve = async (remoteIp: string, searchEngineBotDomains: string[]) => {
resolvedDomains.add(ptrDomain);

const ipAddresses = await resolve4(ptrDomain);
log.debug({ msg: 'IP addresses', ipAddresses });
log.debug('IP addresses', { ipAddresses });
if (ipAddresses.includes(remoteIp)) {
return true;
} else if (resolvedDomains.size === ptrRecords.length) {
Expand All @@ -114,7 +113,7 @@ const resolve = async (remoteIp: string, searchEngineBotDomains: string[]) => {

return ptrRecords.length !== 0;
} catch (error) {
log.error({ msg: 'error resolving PTR record', error });
log.error('Error resolving PTR record, could not verify', { error });
return false;
}
};
Expand Down

0 comments on commit 2d677b8

Please sign in to comment.