Skip to content

Commit c04725d

Browse files
committed
wip: attempts to add a prisma transport for logger
1 parent fbfc816 commit c04725d

File tree

8 files changed

+68
-12
lines changed

8 files changed

+68
-12
lines changed

lib/javascript/fullstack_demo/prisma/schema.prisma

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,12 @@ model Todos {
1818
created_at DateTime @default(now()) @db.Timestamptz(6)
1919
updated_at DateTime @default(now()) @db.Timestamp(6)
2020
}
21+
22+
/// This model contains row level security and requires additional setup for migrations. Visit https://pris.ly/d/row-level-security for more info.
23+
model Logs {
24+
id String @id @default(dbgenerated("gen_random_uuid()")) @db.Uuid
25+
level String @db.VarChar
26+
message String @default("") @db.VarChar
27+
timestamp DateTime @db.Timestamp(6)
28+
meta Json? @db.Json
29+
}

lib/javascript/fullstack_demo/src/components/todo-list/todo-list.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
import { Todo } from '@/models';
2+
import { logger } from '@/util/client-logger';
3+
import { LogEvent } from '@/util/events';
24
import { TodoComponent } from './todo';
35

46
export type TodoProps = {
@@ -8,6 +10,7 @@ export type TodoProps = {
810

911
export const TodoList: React.FC<TodoProps> = ({ todos, onChange }) => {
1012
const toggleTodo = async (id: number) => {
13+
logger.event(LogEvent.TODO_TOGGLE, { id });
1114
const todo = todos.find((todo) => todo.id === id);
1215
if (!todo) return;
1316
todo.completed = !todo.completed;
@@ -21,6 +24,7 @@ export const TodoList: React.FC<TodoProps> = ({ todos, onChange }) => {
2124
};
2225

2326
const deleteTodo = async (id: number) => {
27+
logger.event(LogEvent.TODO_DELETE, { id });
2428
await fetch(`/api/todos/${id}`, {
2529
method: 'DELETE',
2630
});

lib/javascript/fullstack_demo/src/logger.ts

Lines changed: 0 additions & 4 deletions
This file was deleted.

lib/javascript/fullstack_demo/src/util/client-logger.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { Log } from '@/models';
2+
import { LogEvent } from './events';
23
import { Logger, LogLevel } from './logger';
34

45
const FLUSH_AFTER_SIZE = 15;
@@ -13,7 +14,7 @@ class ClientLogger implements Logger {
1314
setInterval(() => this.flush(), FLUSH_INTERVAL_MS);
1415
}
1516

16-
log(level: LogLevel, message: string, vars?: {}): void {
17+
log(level: LogLevel, message: string, vars = {}): void {
1718
vars = { ...this.getDefaultVars(), ...(vars || {}) };
1819
this.buffer.push({ level, message, vars });
1920
if (this.buffer.length >= FLUSH_AFTER_SIZE && !this.flushing) {
@@ -75,15 +76,18 @@ class ClientLogger implements Logger {
7576
return new Promise((resolve) => setTimeout(resolve, ms));
7677
}
7778

78-
debug(format: string, vars?: {}): void {
79+
debug(format: string, vars = {}): void {
7980
this.log('debug', format, vars);
8081
}
81-
info(format: string, vars?: {}): void {
82+
info(format: string, vars = {}): void {
8283
this.log('info', format, vars);
8384
}
84-
error(format: string, vars?: {}): void {
85+
error(format: string, vars = {}): void {
8586
this.log('error', format, vars);
8687
}
88+
event(eventId: LogEvent, vars = {}): void {
89+
this.log('info', '', { ...vars, eventId });
90+
}
8791
}
8892

8993
export const logger = new ClientLogger();
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
export enum LogEvent {
2+
TODO_TOGGLE = 'todo_toggle',
3+
TODO_DELETE = 'todo_delete',
4+
TODO_ADD = 'todo_add',
5+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
1+
import { LogEvent } from './events';
2+
13
export interface Logger {
24
log(level: LogLevel, message: string, vars?: {}): void;
35
debug(format: string, vars?: {}): void;
46
info(format: string, vars?: {}): void;
57
error(format: string, vars?: {}): void;
8+
event(id: LogEvent, vars?: {}): void;
69
}
710

811
export type LogLevel = 'debug' | 'info' | 'error' | 'warn';
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import { PrismaClient } from '@prisma/client';
2+
import Transport from 'winston-transport';
3+
4+
export class PrismaTransport extends Transport {
5+
private readonly client = new PrismaClient();
6+
7+
constructor(opts: any) {
8+
super(opts);
9+
}
10+
11+
log(info: any, callback: () => void): void {
12+
setImmediate(() => {
13+
this.emit('logged', info);
14+
});
15+
16+
this.client.logs.create({
17+
data: {
18+
level: info.level,
19+
message: info.message,
20+
meta: info.vars,
21+
timestamp: info.timestamp,
22+
},
23+
});
24+
25+
callback();
26+
}
27+
}

lib/javascript/fullstack_demo/src/util/server-logger.ts

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
import { auth } from '@clerk/nextjs/server';
22
import { headers } from 'next/headers';
33
import winston, { format } from 'winston';
4+
import { LogEvent } from './events';
45
import { Logger, LogLevel } from './logger';
6+
import { PrismaTransport } from './prisma-transport';
57
const { combine, timestamp, json } = format;
68

79
export class WinstonLogger implements Logger {
@@ -22,29 +24,35 @@ export class WinstonLogger implements Logger {
2224
transports: [
2325
new winston.transports.Console({ level: 'info' }),
2426
new winston.transports.File({ filename: 'debug.log', level: 'debug' }),
27+
new PrismaTransport({ level: 'debug' }),
2528
],
2629
});
2730
}
2831

29-
async log(level: LogLevel, message: string, vars: {}) {
32+
async log(level: LogLevel, message: string, vars = {}) {
3033
const { userId } = await auth();
3134
this.winstonLogger.log(level.toLowerCase(), message, { ...vars, userId });
3235
}
3336

34-
async debug(format: string, vars: {}) {
37+
async debug(format: string, vars = {}) {
3538
const { userId } = await auth();
3639
this.winstonLogger.debug(format, { ...vars, userId });
3740
}
3841

39-
async info(format: string, vars: {}) {
42+
async info(format: string, vars = {}) {
4043
const { userId } = await auth();
4144
this.winstonLogger.info(format, { ...vars, userId });
4245
}
4346

44-
async error(format: string, vars: {}) {
47+
async error(format: string, vars = {}) {
4548
const { userId } = await auth();
4649
this.winstonLogger.error(format, { ...vars, userId });
4750
}
51+
52+
async event(eventId: LogEvent, vars = {}) {
53+
const { userId } = await auth();
54+
this.winstonLogger.debug('', { ...vars, userId, eventId });
55+
}
4856
}
4957

5058
export const logger = new WinstonLogger();

0 commit comments

Comments
 (0)