Next.js ile Kütüphane Kullanmadan Loglama Sistemi

Loglama, uygulamanın davranışlarını izlemek, hataları anlamak ve performansı ölçmek için kritik bir araçtır. Üç temel amaca hizmet eder:

  • Debugging: Hataları bulmak ve çözmek,
  • Monitoring: Uygulamanın nasıl çalıştığını gözlemlemek,
  • Auditing: Kullanıcı aktivitelerini ve sistem olaylarını kayetmek.

Çoğu projede winston, pino, sentry gibi profesyonel paketler kullanılır. Ancak bazı durumlarda:

  • Performans kontrolü tamamen sende olsun,
  • Log formatı %100 sana özel olsun,
  • Bağımlılık istemiyorum,

diyorsan bu makalemde yazdığım sistem sizlere mükemmel bir çözüm olacağını düşünüyorum.

Not: Bu loglama sisteminde veritabanına kayıt işlemi yapacağım için sequelize ORM aracını baz alarak yazmaya çalıştım.

1. Sequelize Modeli Tasarımı

/lib/models/log.ts


    import {
      Model,
      DataTypes,
      InferAttributes,
      InferCreationAttributes,
      CreationOptional
    } from "sequelize";
    import { sequelize } from "@/lib/sequelize";

    export class Log extends Model<
      InferAttributes<Log>,
      InferCreationAttributes<Log>
    > {
      declare id: CreationOptional<number>;
      declare level: "info" | "warn" | "error";
      declare message: string;
      declare method: string;
      declare path: string;
      declare ip: string | null;
      declare userAgent: string | null;
      declare requestBody: object | null;
      declare responseStatus: number | null;
      declare createdAt: CreationOptional<Date>;
    }

    Log.init(
      {
        id: { type: DataTypes.INTEGER, autoIncrement: true, primaryKey: true },
        level: { type: DataTypes.STRING },
        message: { type: DataTypes.TEXT },
        method: { type: DataTypes.STRING },
        path: { type: DataTypes.STRING },
        ip: { type: DataTypes.STRING },
        userAgent: { type: DataTypes.TEXT },
        requestBody: { type: DataTypes.JSON },
        responseStatus: { type: DataTypes.INTEGER },
        createdAt: DataTypes.DATE
      },
      {
        sequelize,
        tableName: "logs",
        updatedAt: false
      }
    );

2. Core Logger Fonksiyonu

Bu yapı, heryerden çağrılabilir bir yapıda olacaktır.

/lib/logger.ts


    import { Log } from "@/lib/models/Log";

    type LogLevel = "info" | "warn" | "error";

    interface LoggerPayload {
      level: LogLevel;
      message: string;
      method: string;
      path: string;
      ip?: string | null;
      userAgent?: string | null;
      requestBody?: object | null;
      responseStatus?: number | null;
    }

    export async function logger(payload: LoggerPayload) {
      try {
        await Log.create({
          level: payload.level,
          message: payload.message,
          method: payload.method,
          path: payload.path,
          ip: payload.ip ?? null,
          userAgent: payload.userAgent ?? null,
          requestBody: payload.requestBody ?? null,
          responseStatus: payload.responseStatus ?? null
        });
      } catch (err) {
        // Loglama hatası uygulamayı patlatmamalı
        console.error("LOG ERROR:", err);
      }
    }

3. API Route İçinde Loglama İşlemi (App Router)


    import { NextRequest, NextResponse } from "next/server";
    import { logger } from "@/lib/logger";

    export async function POST(req: NextRequest) {
      const body = await req.json();

      const userAgent = req.headers.get("user-agent");
      const ip = req.headers.get("x-forwarded-for");

      try {
        // iş mantığı
        if (!body.email) {
          throw new Error("Email zorunlu");
        }

        await logger({
          level: "info",
          message: "Kullanıcı kayıt isteği başarılı",
          method: "POST",
          path: "/api/example",
          ip,
          userAgent,
          requestBody: body,
          responseStatus: 200
        });

        return NextResponse.json({ ok: true });
      } catch (error: any) {
        await logger({
          level: "error",
          message: error.message,
          method: "POST",
          path: "/api/example",
          ip,
          userAgent,
          requestBody: body,
          responseStatus: 400
        });

        return NextResponse.json(
          { error: error.message },
          { status: 400 }
        );
      }
    }

4. Log Level Stratejisi

Level Ne Zaman
info Başarılı durum
warn Beklenmeyen ama hataya düşmeyen durum
error Exception / Validation fail

5. Bu Sistemin Avantajları

  • Ek paket yok,
  • Tümüyle kontrol sizde,
  • Kolayca test edilebilir,
  • Sequelize ile birebir uyumlu.

Sonuç

Bu makalemde, Next.js App Router ile hiçbir loglama paketi kullanmadan, Sequelize ORM uyumlu, profesyonel seviyede ve genişletilebilir loglama sistemi kurmuş olduk.


25 Ara 2025
Yorum