Skip to content

Commit 07bef74

Browse files
committed
chore: adds basic logger
Signed-off-by: Anthony D. Mays <[email protected]>
1 parent 2318a98 commit 07bef74

File tree

8 files changed

+372
-14
lines changed

8 files changed

+372
-14
lines changed

lib/javascript/fullstack_demo/package-lock.json

Lines changed: 264 additions & 12 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

lib/javascript/fullstack_demo/package.json

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,9 @@
1919
"@upstash/redis": "^1.34.3",
2020
"lowdb": "^7.0.1",
2121
"lucide-react": "^0.468.0",
22-
"next": "^14.2.22"
22+
"next": "^14.2.22",
23+
"uuid": "^11.0.5",
24+
"winston": "^3.17.0"
2325
},
2426
"devDependencies": {
2527
"@testing-library/dom": "^10.4.0",
@@ -46,4 +48,4 @@
4648
"vitest": "^2.1.8",
4749
"vitest-fetch-mock": "^0.4.3"
4850
}
49-
}
51+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import { logger } from '@/util/server-logger';
2+
3+
export async function POST(request: Request) {
4+
const { level, message, vars } = await request.json();
5+
logger.log(level, message, ...(vars || []));
6+
return new Response(null, { status: 204 });
7+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
import { Logger } from '@/util/logger';
2+
import { WinstonLogger } from '@/util/winston-logger';
3+
4+
export const logger: Logger = new WinstonLogger();

lib/javascript/fullstack_demo/src/middleware.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,19 @@
11
import { clerkMiddleware, createRouteMatcher } from '@clerk/nextjs/server';
2+
import { NextResponse } from 'next/server';
3+
import { v4 as uuidv4 } from 'uuid';
24

5+
const CORRELATION_ID_HEADER = 'x-correlation-id';
36
const isProtectedRoute = createRouteMatcher(['/(.*)']);
47

58
export default clerkMiddleware(async (auth, req) => {
9+
const correlationId = uuidv4();
10+
req.headers.set(CORRELATION_ID_HEADER, correlationId);
11+
612
if (isProtectedRoute(req)) await auth.protect();
13+
14+
const response = NextResponse.next();
15+
response.headers.set(CORRELATION_ID_HEADER, correlationId);
16+
return response;
717
});
818

919
export const config = {
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import { Logger, LogLevel } from './logger';
2+
3+
class ClientLogger implements Logger {
4+
log(level: LogLevel, message: string, ...vars: unknown[]): void {
5+
fetch('/api/log', {
6+
method: 'POST',
7+
headers: {
8+
'Content-Type': 'application/json',
9+
},
10+
body: JSON.stringify({ level, message, vars }),
11+
});
12+
}
13+
14+
debug(format: string, ...vars: unknown[]): void {
15+
this.log('DEBUG', format, ...vars);
16+
}
17+
info(format: string, ...vars: unknown[]): void {
18+
this.log('INFO', format, ...vars);
19+
}
20+
error(format: string, ...vars: unknown[]): void {
21+
this.log('ERROR', format, ...vars);
22+
}
23+
}
24+
25+
export const logger = new ClientLogger();
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
export interface Logger {
2+
log(level: LogLevel, message: string, ...vars: unknown[]): void;
3+
debug(format: string, ...vars: unknown[]): void;
4+
info(format: string, ...vars: unknown[]): void;
5+
error(format: string, ...vars: unknown[]): void;
6+
}
7+
8+
export type LogLevel = 'DEBUG' | 'INFO' | 'ERROR' | 'WARN';
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import { auth } from '@clerk/nextjs/server';
2+
import { headers } from 'next/headers';
3+
import winston, { format } from 'winston';
4+
import { Logger, LogLevel } from './logger';
5+
const { combine, timestamp, json } = format;
6+
7+
export class WinstonLogger implements Logger {
8+
private readonly winstonLogger: winston.Logger;
9+
10+
constructor() {
11+
this.winstonLogger = winston.createLogger({
12+
level: 'info',
13+
format: combine(
14+
format((info) => {
15+
const headerList = headers();
16+
info.correlationId = headerList.get('x-correlation-id');
17+
return info;
18+
})(),
19+
timestamp(),
20+
json(),
21+
),
22+
transports: [
23+
new winston.transports.Console(),
24+
new winston.transports.File({ filename: 'debug.log', level: 'debug' }),
25+
],
26+
});
27+
}
28+
29+
async log(level: LogLevel, message: string, ...vars: unknown[]) {
30+
const { userId } = await auth();
31+
this.winstonLogger.log(level.toLowerCase(), message, { ...vars, userId });
32+
}
33+
34+
async debug(format: string, ...vars: unknown[]) {
35+
const { userId } = await auth();
36+
this.winstonLogger.debug(format, { ...vars, userId });
37+
}
38+
39+
async info(format: string, ...vars: unknown[]) {
40+
const { userId } = await auth();
41+
this.winstonLogger.info(format, { ...vars, userId });
42+
}
43+
44+
async error(format: string, ...vars: unknown[]) {
45+
const { userId } = await auth();
46+
this.winstonLogger.error(format, { ...vars, userId });
47+
}
48+
}
49+
50+
export const logger = new WinstonLogger();

0 commit comments

Comments
 (0)