Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: Add logger package for node server side apps #6188

Merged
merged 9 commits into from
Dec 13, 2024
3 changes: 3 additions & 0 deletions packages/logger/.eslintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
build/*
dist/*
out/*
9 changes: 9 additions & 0 deletions packages/logger/.eslintrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/** @type {import("eslint").Linter.Config} */
module.exports = {
root: true,
extends: ["@plane/eslint-config/library.js"],
parser: "@typescript-eslint/parser",
parserOptions: {
project: true,
},
};
5 changes: 5 additions & 0 deletions packages/logger/.prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"printWidth": 120,
"tabWidth": 2,
"trailingComma": "es5"
}
58 changes: 58 additions & 0 deletions packages/logger/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# Logger Package

This package provides a singleton-based logger utility built using [Winston](https://github.com/winstonjs/winston). It offers customizable log levels and supports structured logging for general application logs and HTTP requests.

## Features
- Singleton pattern ensures a single logger instance.
- Dynamic log level configuration and log filename prefix.
- Pre-configured winston logger for general usage (`logger`).

## Usage

### Adding as a package
Add this package as a dependency in package.json
```typescript
dependency: {
...
@plane/logger":"*",
...
}
sriramveeraghanta marked this conversation as resolved.
Show resolved Hide resolved
```

### Importing the Logger
```typescript
import PlaneLogger from "@plane/logger";
```

### `logger`: General Logger
Use this for general application logs.

```typescript
const loggerOptions: ILoggerOptions = { logLevel:"info", logFilePrefix: "log-file-prefix" }

import ClientLogger from "@plane/logger/client"
const logger = ClientLogger.getLogger(loggerOptions);
logger.log("test logs on web")


import ServerLogger from "@plane/logger/server"
const logger = ServerLogger.getLogger(loggerOptions);
logger.log("test logs on server")

logger.info("This is an info log");
logger.warn("This is a warning");
logger.error("This is an error");
```

## Available Log Levels
- `error`
- `warn`
- `info` (default)
- `http`
- `verbose`
- `debug`
- `silly`

## Configuration
- By default, the log level is set to `info`.
- You can specify a log level during the first import of logger by passing optional logLevel param in getLogger function.
sriramveeraghanta marked this conversation as resolved.
Show resolved Hide resolved
21 changes: 21 additions & 0 deletions packages/logger/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"name": "@plane/logger",
"version": "0.24.1",
"description": "Logger shared across multiple apps internally",
"private": true,
"main": "./src/index.ts",
"types": "./src/index.ts",
"scripts": {
"lint": "eslint src --ext .ts,.tsx",
"lint:errors": "eslint src --ext .ts,.tsx --quiet"
},
"dependencies": {
"winston": "^3.17.0",
"winston-daily-rotate-file": "^5.0.0"
},
"devDependencies": {
"@plane/eslint-config": "*",
"@types/node": "^22.5.4",
"typescript": "^5.3.3"
}
}
66 changes: 66 additions & 0 deletions packages/logger/src/config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import winston from "winston";
import DailyRotateFile from "winston-daily-rotate-file";
import path from "path";

// Define log levels
const levels = {
error: 0,
warn: 1,
info: 2,
http: 3,
debug: 4,
};

// Define colors for each level
const colors = {
error: "red",
warn: "yellow",
info: "green",
http: "magenta",
debug: "white",
};

// Tell winston about our colors
winston.addColors(colors);

// Custom format for logging
const format = winston.format.combine(
winston.format.timestamp({ format: "YYYY-MM-DD HH:mm:ss:ms" }),
winston.format.colorize({ all: true }),
winston.format.printf(
(info: winston.Logform.TransformableInfo) => `[${info?.timestamp}] ${info.level}: ${info.message}`
)
);

// Define which transports to use
const transports = [
// Console transport
new winston.transports.Console(),

// Rotating file transport for errors
new DailyRotateFile({
filename: path.join(process.cwd(), "logs", "error-%DATE%.log"),
datePattern: "YYYY-MM-DD",
zippedArchive: true,
maxSize: "20m",
maxFiles: "7d",
level: "error",
}),
sriramveeraghanta marked this conversation as resolved.
Show resolved Hide resolved

// Rotating file transport for all logs
new DailyRotateFile({
filename: path.join(process.cwd(), "logs", "combined-%DATE%.log"),
datePattern: "YYYY-MM-DD",
zippedArchive: true,
maxSize: "20m",
maxFiles: "7d",
}),
];

// Create the logger
export const logger = winston.createLogger({
level: process.env.LOG_LEVEL || "info",
levels,
format,
transports,
});
sriramveeraghanta marked this conversation as resolved.
Show resolved Hide resolved
2 changes: 2 additions & 0 deletions packages/logger/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from "./config";
export * from "./middleware";
23 changes: 23 additions & 0 deletions packages/logger/src/middleware.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { Request, Response, NextFunction } from "express";
import { logger } from "./config";

export const requestLogger = (req: Request, res: Response, next: NextFunction) => {
// Log when the request starts
const startTime = Date.now();

// Log request details
logger.http(`Incoming ${req.method} request to ${req.url} from ${req.ip}`);

// Log request body if present
if (Object.keys(req.body).length > 0) {
logger.debug("Request body:", req.body);
}
sriramveeraghanta marked this conversation as resolved.
Show resolved Hide resolved

// Capture response
res.on("finish", () => {
const duration = Date.now() - startTime;
logger.http(`Completed ${req.method} ${req.url} with status ${res.statusCode} in ${duration}ms`);
});

sriramveeraghanta marked this conversation as resolved.
Show resolved Hide resolved
next();
};
sriramveeraghanta marked this conversation as resolved.
Show resolved Hide resolved
19 changes: 19 additions & 0 deletions packages/logger/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"extends": "@plane/typescript-config/base.json",
"compilerOptions": {
"module": "ESNext",
"target": "ESNext",
"moduleResolution": "node",
"esModuleInterop": true,
"outDir": "./dist",
"rootDir": "./src",
"baseUrl": ".",
"paths": {
"@/*": ["./src/*"]
},
"experimentalDecorators": true,
"sourceMap": true
},
"include": ["src/**/*"],
"exclude": ["node_modules"]
}
Loading
Loading