Skip to content

Commit fbfc816

Browse files
committed
chore: configures batching for client logger
1 parent 07bef74 commit fbfc816

File tree

5 files changed

+97
-22
lines changed

5 files changed

+97
-22
lines changed
Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
import { logger } from '@/util/server-logger';
22

33
export async function POST(request: Request) {
4-
const { level, message, vars } = await request.json();
5-
logger.log(level, message, ...(vars || []));
4+
const batch = await request.json();
5+
for (const log of batch) {
6+
const { level, message, vars } = log;
7+
logger.log(level, message, { ...(vars || {}) });
8+
}
69
return new Response(null, { status: 204 });
710
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
1+
import { LogLevel } from './util/logger';
2+
13
export interface Todo {
24
id: number;
35
text: string;
46
completed: boolean;
57
}
8+
9+
export interface Log {
10+
level: LogLevel;
11+
message: string;
12+
vars: {};
13+
}

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

Lines changed: 73 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,88 @@
1+
import { Log } from '@/models';
12
import { Logger, LogLevel } from './logger';
23

4+
const FLUSH_AFTER_SIZE = 15;
5+
const MAX_BATCH_SIZE = 100;
6+
const FLUSH_INTERVAL_MS = 1000 * 5; // 5 seconds
7+
38
class ClientLogger implements Logger {
4-
log(level: LogLevel, message: string, ...vars: unknown[]): void {
5-
fetch('/api/log', {
9+
private readonly buffer: Log[] = [];
10+
private flushing = false;
11+
12+
constructor() {
13+
setInterval(() => this.flush(), FLUSH_INTERVAL_MS);
14+
}
15+
16+
log(level: LogLevel, message: string, vars?: {}): void {
17+
vars = { ...this.getDefaultVars(), ...(vars || {}) };
18+
this.buffer.push({ level, message, vars });
19+
if (this.buffer.length >= FLUSH_AFTER_SIZE && !this.flushing) {
20+
this.flush();
21+
}
22+
}
23+
24+
private getDefaultVars() {
25+
if (typeof window === 'undefined') {
26+
return [];
27+
}
28+
29+
return {
30+
client: {
31+
type: 'web',
32+
userAgent: navigator.userAgent,
33+
location: window.location.href,
34+
},
35+
};
36+
}
37+
38+
async flush(): Promise<void> {
39+
if (this.buffer.length === 0 || this.flushing) {
40+
return;
41+
}
42+
43+
this.flushing = true;
44+
45+
const batch = this.buffer.splice(0, MAX_BATCH_SIZE);
46+
let backoffInMs = FLUSH_INTERVAL_MS;
47+
48+
do {
49+
try {
50+
await this.sendLogs(batch);
51+
this.flushing = false;
52+
} catch (e) {
53+
console.error('Failed to send logs', e);
54+
backoffInMs *= 2;
55+
await this.delay(backoffInMs);
56+
}
57+
} while (this.flushing);
58+
}
59+
60+
async sendLogs(batch: Log[]): Promise<void> {
61+
let endpoint = '/api/log';
62+
if (typeof window === 'undefined') {
63+
endpoint = `${process.env?.NEXT_PUBLIC_API_URL || ''}/api/host`;
64+
}
65+
await fetch(endpoint, {
666
method: 'POST',
767
headers: {
868
'Content-Type': 'application/json',
969
},
10-
body: JSON.stringify({ level, message, vars }),
70+
body: JSON.stringify(batch),
1171
});
1272
}
1373

14-
debug(format: string, ...vars: unknown[]): void {
15-
this.log('DEBUG', format, ...vars);
74+
async delay(ms: number): Promise<void> {
75+
return new Promise((resolve) => setTimeout(resolve, ms));
76+
}
77+
78+
debug(format: string, vars?: {}): void {
79+
this.log('debug', format, vars);
1680
}
17-
info(format: string, ...vars: unknown[]): void {
18-
this.log('INFO', format, ...vars);
81+
info(format: string, vars?: {}): void {
82+
this.log('info', format, vars);
1983
}
20-
error(format: string, ...vars: unknown[]): void {
21-
this.log('ERROR', format, ...vars);
84+
error(format: string, vars?: {}): void {
85+
this.log('error', format, vars);
2286
}
2387
}
2488

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
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;
2+
log(level: LogLevel, message: string, vars?: {}): void;
3+
debug(format: string, vars?: {}): void;
4+
info(format: string, vars?: {}): void;
5+
error(format: string, vars?: {}): void;
66
}
77

8-
export type LogLevel = 'DEBUG' | 'INFO' | 'ERROR' | 'WARN';
8+
export type LogLevel = 'debug' | 'info' | 'error' | 'warn';

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

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ export class WinstonLogger implements Logger {
99

1010
constructor() {
1111
this.winstonLogger = winston.createLogger({
12-
level: 'info',
12+
level: 'debug',
1313
format: combine(
1414
format((info) => {
1515
const headerList = headers();
@@ -20,28 +20,28 @@ export class WinstonLogger implements Logger {
2020
json(),
2121
),
2222
transports: [
23-
new winston.transports.Console(),
23+
new winston.transports.Console({ level: 'info' }),
2424
new winston.transports.File({ filename: 'debug.log', level: 'debug' }),
2525
],
2626
});
2727
}
2828

29-
async log(level: LogLevel, message: string, ...vars: unknown[]) {
29+
async log(level: LogLevel, message: string, vars: {}) {
3030
const { userId } = await auth();
3131
this.winstonLogger.log(level.toLowerCase(), message, { ...vars, userId });
3232
}
3333

34-
async debug(format: string, ...vars: unknown[]) {
34+
async debug(format: string, vars: {}) {
3535
const { userId } = await auth();
3636
this.winstonLogger.debug(format, { ...vars, userId });
3737
}
3838

39-
async info(format: string, ...vars: unknown[]) {
39+
async info(format: string, vars: {}) {
4040
const { userId } = await auth();
4141
this.winstonLogger.info(format, { ...vars, userId });
4242
}
4343

44-
async error(format: string, ...vars: unknown[]) {
44+
async error(format: string, vars: {}) {
4545
const { userId } = await auth();
4646
this.winstonLogger.error(format, { ...vars, userId });
4747
}

0 commit comments

Comments
 (0)