From 87fe88aafd6df548cdb67200676611bb1d83b023 Mon Sep 17 00:00:00 2001 From: joel-leal Date: Mon, 19 Jan 2026 11:26:52 -0300 Subject: [PATCH 1/3] add setup logger --- server/.eslintrc.js | 1 + server/src/app.module.ts | 3 ++- server/src/core/logging/app-logger.service.ts | 22 +++++++++++++++++++ server/src/core/logging/logger.module.ts | 8 +++++++ server/src/system.service.ts | 2 -- 5 files changed, 33 insertions(+), 3 deletions(-) create mode 100644 server/src/core/logging/app-logger.service.ts create mode 100644 server/src/core/logging/logger.module.ts diff --git a/server/.eslintrc.js b/server/.eslintrc.js index 259de13..288aa6c 100644 --- a/server/.eslintrc.js +++ b/server/.eslintrc.js @@ -17,6 +17,7 @@ module.exports = { }, ignorePatterns: ['.eslintrc.js'], rules: { + 'no-console': 'error', '@typescript-eslint/interface-name-prefix': 'off', '@typescript-eslint/explicit-function-return-type': 'off', '@typescript-eslint/explicit-module-boundary-types': 'off', diff --git a/server/src/app.module.ts b/server/src/app.module.ts index aea6ad3..4415e8a 100644 --- a/server/src/app.module.ts +++ b/server/src/app.module.ts @@ -3,9 +3,10 @@ import { UsersModule } from './users/users.module'; import { VideosModule } from './videos/videos.module'; import { PrismaService } from './prisma.service'; import { SystemService } from './system.service'; +import { LoggerModule } from './core/logging/logger.module'; @Module({ - imports: [UsersModule, VideosModule], + imports: [UsersModule, VideosModule, LoggerModule], providers: [SystemService, PrismaService], // Do I need PrismaService here? }) export class AppModule {} diff --git a/server/src/core/logging/app-logger.service.ts b/server/src/core/logging/app-logger.service.ts new file mode 100644 index 0000000..af7fa0b --- /dev/null +++ b/server/src/core/logging/app-logger.service.ts @@ -0,0 +1,22 @@ +import { Injectable, Scope, ConsoleLogger } from '@nestjs/common'; + +type LogMeta = Record; + +@Injectable({ scope: Scope.TRANSIENT }) +export class AppLogger extends ConsoleLogger { + customLog(message: string, meta?: LogMeta) { + if (!meta || Object.keys(meta).length === 0) { + return super.log(message); + } + + return super.log(`${message} | meta=${this.safeStringify(meta)}`); + } + + private safeStringify(value: unknown): string { + try { + return JSON.stringify(value); + } catch { + return '[unserializable-meta]'; + } + } +} diff --git a/server/src/core/logging/logger.module.ts b/server/src/core/logging/logger.module.ts new file mode 100644 index 0000000..cef74ba --- /dev/null +++ b/server/src/core/logging/logger.module.ts @@ -0,0 +1,8 @@ +import { Module } from '@nestjs/common'; +import { AppLogger } from './app-logger.service'; + +@Module({ + providers: [AppLogger], + exports: [AppLogger], +}) +export class LoggerModule {} diff --git a/server/src/system.service.ts b/server/src/system.service.ts index eed9625..39c5fa8 100644 --- a/server/src/system.service.ts +++ b/server/src/system.service.ts @@ -6,14 +6,12 @@ import { import { promises as fs } from 'fs'; import { join, resolve } from 'path'; import { existsSync } from 'fs'; - @Injectable() export class SystemService { private readonly uploadsDir = join(process.cwd(), 'uploads'); constructor() { this.findOrCreateUserDirectory(this.uploadsDir); - console.log('uploadsDir', this.uploadsDir); } /** From 2293d0ce5eb44c43c2b19847fef2b880a1df0934 Mon Sep 17 00:00:00 2001 From: joel-leal Date: Fri, 30 Jan 2026 15:09:49 -0300 Subject: [PATCH 2/3] feat: add AppLogger with structure log to UsersService --- server/src/users/users.module.ts | 2 ++ server/src/users/users.service.ts | 47 +++++++++++++++++++++++++++---- 2 files changed, 43 insertions(+), 6 deletions(-) diff --git a/server/src/users/users.module.ts b/server/src/users/users.module.ts index 93c1e62..c8a6428 100644 --- a/server/src/users/users.module.ts +++ b/server/src/users/users.module.ts @@ -2,9 +2,11 @@ import { Module } from '@nestjs/common'; import { UsersService } from './users.service'; import { UsersController } from './users.controller'; import { PrismaService } from 'src/prisma.service'; +import { LoggerModule } from 'src/core/logging/logger.module'; @Module({ controllers: [UsersController], + imports: [LoggerModule], providers: [UsersService, PrismaService], }) export class UsersModule {} diff --git a/server/src/users/users.service.ts b/server/src/users/users.service.ts index 77ae2e7..dbb7fb5 100644 --- a/server/src/users/users.service.ts +++ b/server/src/users/users.service.ts @@ -2,20 +2,55 @@ import { Injectable } from '@nestjs/common'; import { User } from 'generated/prisma'; import { PrismaService } from 'src/prisma.service'; import { CreateUserDto } from './users.dto'; +import { AppLogger } from 'src/core/logging/app-logger.service'; @Injectable() export class UsersService { - constructor(private readonly prisma: PrismaService) {} + constructor( + private readonly prisma: PrismaService, + private readonly logger: AppLogger, + ) { + this.logger.setContext(UsersService.name); + } async get(): Promise { - return this.prisma.user.findMany(); + this.logger.customLog('Listing users', { + feature: 'users', + action: 'list', + }); + + const users = await this.prisma.user.findMany(); + + this.logger.customLog('Users listed', { + count: users.length, + }); + return users; } async upsert(user: CreateUserDto): Promise { - return this.prisma.user.upsert({ - where: { email: user.email }, - update: user, - create: user, + this.logger.customLog('Upserting user', { + feature: 'users', + action: 'upsert', + email: user.email, }); + + try { + const saved = await this.prisma.user.upsert({ + where: { email: user.email }, + update: user, + create: user, + }); + this.logger.customLog('User upserted', { + id: saved.id, + email: saved.email, + }); + return saved; + } catch (err) { + const message = err instanceof Error ? err.message : 'Unknown error'; + this.logger.customLog('Upsert failed', { + email: user.email, + error: message, + }); + } } } From 6eedda502d2f11ebb23703ab230f39e3a61a5edd Mon Sep 17 00:00:00 2001 From: joel-leal Date: Mon, 2 Feb 2026 13:06:44 -0300 Subject: [PATCH 3/3] ref: align AppLogger with NestJS patterns and standardize log usage --- server/src/core/logging/app-logger.service.ts | 9 ++--- server/src/system.service.ts | 11 ++++- server/src/users/users.service.ts | 40 +++++++++++-------- 3 files changed, 36 insertions(+), 24 deletions(-) diff --git a/server/src/core/logging/app-logger.service.ts b/server/src/core/logging/app-logger.service.ts index af7fa0b..be6d360 100644 --- a/server/src/core/logging/app-logger.service.ts +++ b/server/src/core/logging/app-logger.service.ts @@ -4,12 +4,9 @@ type LogMeta = Record; @Injectable({ scope: Scope.TRANSIENT }) export class AppLogger extends ConsoleLogger { - customLog(message: string, meta?: LogMeta) { - if (!meta || Object.keys(meta).length === 0) { - return super.log(message); - } - - return super.log(`${message} | meta=${this.safeStringify(meta)}`); + customLog(message: string, meta?: LogMeta): string { + if (!meta || Object.keys(meta).length === 0) return message; + return `${message} | meta=${this.safeStringify(meta)}`; } private safeStringify(value: unknown): string { diff --git a/server/src/system.service.ts b/server/src/system.service.ts index 39c5fa8..de5f348 100644 --- a/server/src/system.service.ts +++ b/server/src/system.service.ts @@ -6,12 +6,21 @@ import { import { promises as fs } from 'fs'; import { join, resolve } from 'path'; import { existsSync } from 'fs'; +import { AppLogger } from 'src/core/logging/app-logger.service'; + @Injectable() export class SystemService { private readonly uploadsDir = join(process.cwd(), 'uploads'); + constructor(private readonly logger: AppLogger) { + this.logger.setContext(SystemService.name); - constructor() { this.findOrCreateUserDirectory(this.uploadsDir); + + this.logger.debug( + this.logger.customLog('uploadsDir', { + uploadsDir: this.uploadsDir, + }), + ); } /** diff --git a/server/src/users/users.service.ts b/server/src/users/users.service.ts index dbb7fb5..4fb2c89 100644 --- a/server/src/users/users.service.ts +++ b/server/src/users/users.service.ts @@ -14,16 +14,18 @@ export class UsersService { } async get(): Promise { - this.logger.customLog('Listing users', { - feature: 'users', - action: 'list', - }); - + this.logger.log( + this.logger.customLog('Listing users', { + feature: 'users', + action: 'list', + }), + ); const users = await this.prisma.user.findMany(); - - this.logger.customLog('Users listed', { - count: users.length, - }); + this.logger.log( + this.logger.customLog('Users listed', { + count: users.length, + }), + ); return users; } @@ -40,17 +42,21 @@ export class UsersService { update: user, create: user, }); - this.logger.customLog('User upserted', { - id: saved.id, - email: saved.email, - }); + this.logger.log( + this.logger.customLog('User upserted', { + id: saved.id, + email: saved.email, + }), + ); return saved; } catch (err) { const message = err instanceof Error ? err.message : 'Unknown error'; - this.logger.customLog('Upsert failed', { - email: user.email, - error: message, - }); + this.logger.error( + this.logger.customLog('Upsert failed', { + email: user.email, + error: message, + }), + ); } } }