Skip to content

Commit 64e4910

Browse files
committed
Implement logging using Roarr on server
1 parent 91c8375 commit 64e4910

File tree

6 files changed

+138
-4
lines changed

6 files changed

+138
-4
lines changed

scripts/stack/_lib/actions.js

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -152,10 +152,14 @@ export function runLocalApp() {
152152
console.log('app (local): running');
153153

154154
try {
155-
execSync('npx vite dev', {
156-
stdio: 'inherit',
157-
env: process.env,
158-
});
155+
execSync(
156+
'npx vite dev | npx roarr --include-date true --output-format pretty', // pretty | json
157+
{
158+
stdio: 'inherit',
159+
shell: '/bin/bash',
160+
env: process.env,
161+
},
162+
);
159163
} catch (e) {
160164
console.log('app (local): exited');
161165
}

src/hooks.server.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import {
1414
import { setSentryUserIdentity } from '$lib/server/sentry/hooks';
1515
import { posthog, setupNodePosthogClient } from '$lib/server/posthog';
1616
import { getServerSentryIntegrations } from '$lib/server/sentry/utils';
17+
import { roarr } from '$lib/shared/roarr';
1718

1819
setupNodePosthogClient(config.posthog.projectApiKey, config.posthog.apiHost);
1920
setupSentryClient({
@@ -23,6 +24,8 @@ setupSentryClient({
2324
integrations: [...getServerSentryIntegrations(config.sentry.organization)],
2425
});
2526

27+
roarr.info('Starting the app server...');
28+
2629
export const handle = (async (input) => {
2730
const maintenanceModeHandles: Handle[] = [maintenanceModeHandle];
2831
const nonMaintenanceModeHandles: Handle[] = [

src/lib/server/core/config/index.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import { env as privateEnv } from '$env/dynamic/private';
22
import { env as publicEnv } from '$env/dynamic/public';
3+
import path from 'path';
4+
import url from 'url';
35

46
export const config = {
57
get origin(): string {
@@ -8,6 +10,14 @@ export const config = {
810
get isMaintenanceMode(): boolean {
911
return privateEnv.MAINTENANCE_MODE === 'true';
1012
},
13+
folders: {
14+
get root(): string {
15+
return path.resolve(
16+
path.dirname(url.fileURLToPath(import.meta.url)),
17+
'../../../../../',
18+
);
19+
},
20+
},
1121
db: {
1222
get url(): string {
1323
return privateEnv.DATABASE_URL;
@@ -45,4 +55,15 @@ export const config = {
4555
return publicEnv.PUBLIC_SENTRY_ORGANIZATION;
4656
},
4757
},
58+
roarr: {
59+
get isEnabled(): boolean {
60+
return privateEnv.ROARR_LOG === 'true';
61+
},
62+
get minLogLevel(): string {
63+
return privateEnv.ROARR_MIN_LOG_LEVEL || 'info';
64+
},
65+
get isDebugContextShown(): boolean {
66+
return privateEnv.ROARR_SHOW_DEBUG_CONTEXT === 'true';
67+
},
68+
},
4869
};

src/lib/shared/roarr/client.ts

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
import { Roarr, logLevels, type LogLevelName } from 'roarr';
2+
import callsites from 'callsites';
3+
import { config } from '$lib/server/core/config';
4+
import type { JsonObject, LoggerLoggingMethodName } from './types';
5+
6+
export const roarr = (function () {
7+
const createLogger = (methodName: LoggerLoggingMethodName) => {
8+
return (message: string, context: JsonObject = {}) => {
9+
if (!shouldBeLogged(methodName)) {
10+
return;
11+
}
12+
13+
Roarr[methodName](
14+
config.roarr.isDebugContextShown
15+
? enrichContextWithDebugInfo(context)
16+
: context,
17+
message,
18+
);
19+
};
20+
};
21+
22+
const roarrLoggingMethodNamesNoOnce = Object.keys(Roarr).filter((property) =>
23+
Object.keys(logLevels).includes(property),
24+
) as LoggerLoggingMethodName[];
25+
const roarrLoggingMethodNamesOnce = roarrLoggingMethodNamesNoOnce.map(
26+
(methodName) => `${methodName}Once` as LoggerLoggingMethodName,
27+
);
28+
const roarrLoggingMethodNames = [
29+
...roarrLoggingMethodNamesNoOnce,
30+
...roarrLoggingMethodNamesOnce,
31+
];
32+
const roarrLogger = roarrLoggingMethodNames.reduce(
33+
(acc, methodName) => {
34+
acc[methodName] = createLogger(methodName);
35+
return acc;
36+
},
37+
{} as Record<
38+
LoggerLoggingMethodName,
39+
(message: string, context?: JsonObject) => void
40+
>,
41+
);
42+
43+
return roarrLogger;
44+
})();
45+
46+
function shouldBeLogged(methodName: LoggerLoggingMethodName): boolean {
47+
const requestedLogLevelName = methodName.replace('Once', '') as LogLevelName;
48+
const requestedLogLevel = logLevels[requestedLogLevelName];
49+
const minLogLevel = logLevels[config.roarr.minLogLevel as LogLevelName];
50+
51+
return requestedLogLevel >= minLogLevel;
52+
}
53+
54+
function enrichContextWithDebugInfo(override: JsonObject = {}): JsonObject {
55+
return {
56+
callName: getCallName(),
57+
fileName: getFileName(),
58+
...override,
59+
};
60+
}
61+
62+
function getCallName(): string {
63+
const typeName = callsites()[3]?.getTypeName() ?? '';
64+
const functionName =
65+
callsites()[3]?.getFunctionName() ?? callsites()[3]?.getMethodName() ?? '';
66+
67+
if (typeName) {
68+
return `${typeName}.${functionName}`;
69+
}
70+
71+
return functionName;
72+
}
73+
74+
function getFileName(): string {
75+
const fileName =
76+
callsites()[3]?.getFileName() ?? callsites()[3]?.getEvalOrigin() ?? '';
77+
78+
return fileName.replace(config.folders.root, '');
79+
}

src/lib/shared/roarr/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from './client';
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/**
2+
* Types partially copied from `node_modules/roarr/src/types.ts`.
3+
* Don't import from `node_modules/roarr/src/types.ts` directly to avoid type errors.
4+
*/
5+
6+
import type { LogLevelName } from 'roarr';
7+
8+
export type LoggerLoggingMethodName =
9+
| LoggerLoggingMethodNameNoOnce
10+
| LoggerLoggingMethodNameOnce;
11+
export type JsonObject = {
12+
[k: string]: JsonValue;
13+
};
14+
15+
type LoggerLoggingMethodNameNoOnce = LogLevelName;
16+
type LoggerLoggingMethodNameOnce = `${LoggerLoggingMethodNameNoOnce}Once`;
17+
18+
type JsonValue =
19+
| JsonObject
20+
| JsonValue[]
21+
| boolean
22+
| number
23+
| string
24+
| readonly JsonValue[]
25+
| null
26+
| undefined;

0 commit comments

Comments
 (0)