winston
실제 서버를 운영할 때 console.log와 console.error를 대체하기 위한 모듈입니다.
console.log와 console.error를 사용하면 개발 중에는 편리하게 서버의 상황을 파악할 수 있지만, 실제 배포 시에는 사용하기 어렵습니다. console 객체의 메서드들이 언제 호출되었는지 파악하기 힘들 뿐만 아니라 서버가 종료되는 순간 로그들도 사라지기 때문입니다. 에러가 발생하면 에러 메시지를 확인해야 하는데, 서버가 종료되어 에러 메시지들이 날아가버리는 황당한 일이 일어나게 됩니다. 이와 같은 상황을 방지하려면 로그를 파일이나 다른 데이터베이스에 저장해야 합니다. 이떄 winston을 사용합니다.
winston을 설치하고 사용 방법을 간단히 알아보겠습니다. 너무나 다양한 방식으로 활용할 수 있어 기본적인 것만 살펴봅니다.
$ npm i winston
winston을 설치한 뒤, logger.js를 작성합니다.
const { createLogger, format, transports } = require("winston");
const logger = createLogger({
level: "info",
format: format.json(),
transports: [
new transports.File({ filename: "combined.log" }),
new transports.File({ filename: "error.log", level: "error" }),
],
});
if (process.env.NODE_ENV !== "production") {
logger.add(new transports.Console({ format: format.simple() }));
}
module.exports = logger;
winston 패키지의 createLogger 메서드를 logger를 만듭니다. 인수로 logger에 대한 설정을 넣어줄 수 있습니다. 설정으로는 level, format, transports 등이 있습니다.
• level은 로그의 심각도를 의미합니다. error, warn, info, verbose, debug, silly가 있습니 다. 심각도순(error가 가장 심각)이므로 위 순서를 참고하여 기록하길 원하는 유형의 로그를 고르면 됩니다. info를 고른 경우, info보다 심각한 단계의 로그(error, warn)도 함께 기록됩니다.
• format은 로그의 형식입니다. json, label, timestamp, printf, simple, combine 등의 다양 한 형식이 있습니다. 기본적으로는 JSON 형식으로 기록하지만, 로그 기록 시간을 표시하려 면 timestamp를 쓰는 것이 좋습니다. combine은 여러 형식을 혼합해서 사용할 때 씁니다. 활 용법이 다양하므로 공식 문서를 참고하길 바랍니다.
• transports는 로그 저장 방식을 의미합니다. new transports. File은 파일로 저장한다는 뜻 이고, new transports. Console은 콘솔에 출력한다는 뜻입니다. 여러 로깅 방식을 동시에 사 용할 수도 있습니다. 배포 환경이 아닌 경우 파일뿐만 아니라 콘솔에도 출력하도록 되어 있 습니다. 이 메서드들에도 level, format 등을 설정할 수 있습니다. new transports.File인 경우에는 로그 파일의 이름인 filename도 설정할 수 있습니다.
이렇게 logger 객체를 만들어 다른 파일에서 사용하면 됩니다. info, warn, error 등의 메서드를 사용하면 해당 심각도가 적용된 로그가 기록됩니다.
app.js
const express = require("express");
const cookieParser = require("cookie-parser");
const morgan = require("morgan");
const path = require("path");
const session = require("express-session");
const nunjucks = require("nunjucks");
const dotenv = require("dotenv");
const passport = require("passport");
dotenv.config();
const pageRouter = require("./routes/page");
const authRouter = require("./routes/auth");
const postRouter = require("./routes/post");
const userRouter = require("./routes/user");
const { sequelize } = require("./models");
const passportConfig = require("./passport");
const logger = require("./logger");
const app = express();
passportConfig(); // 패스포트 설정
app.set("port", process.env.PORT || 8001);
app.set("view engine", "html");
nunjucks.configure("views", {
express: app,
watch: true,
});
sequelize
.sync({ force: false })
.then(() => {
console.log("데이터베이스 연결 성공");
})
.catch((err) => {
console.error(err);
});
if (proccess.env.NODE_ENV === "production") {
app.use(morgan("combined"));
} else {
app.use(morgan("dev"));
}
app.use(express.static(path.join(__dirname, "public")));
app.use(morgan("dev"));
app.use(express.static(path.join(__dirname, "public")));
app.use("/img", express.static(path.join(__dirname, "uploads")));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser(process.env.COOKIE_SECRET));
const sessionOption = {
resave: false,
saveUninitialized: false,
secret: process.env.COOKIE_SECRET,
cookie: {
httpOnly: true,
secure: false,
},
};
if (process.env.NODE_ENV === "production") {
sessionOption.proxy = true;
}
app.use(session(sessionOption));
app.use(passport.initialize());
app.use(passport.session());
app.use("/", pageRouter);
app.use("/auth", authRouter);
app.use("/post", postRouter);
app.use("/user", userRouter);
app.use((req, res, next) => {
const error = new Error(`${req.method} ${req.url} 라우터가 없습니다.`);
error.status = 404;
logger.info("hello");
logger.error(error.message);
next(error);
});
app.use((err, req, res, next) => {
console.error(err);
res.locals.message = err.message;
res.locals.error = process.env.NODE_ENV !== "production" ? err : {};
res.status(err.status || 500);
res.render("error");
});
module.exports = app;
npm run dev 명령어로 개발용 서버를 실행한 후 http://localhost:8001/abcd에 접속합니다. 없는 주소이므로 404 Not Found 에러가 발생합니다.
nodebird 폴더에 생성된 로그를 살펴봅시다.
combined.log
{"level":"info","message":"hello"}
{"level":"error","message":"GET /abcd 라우터가 없습니다."}
{"level":"info","message":"hello"}
{"level":"error","message":"GET /favicon.ico 라우터가 없습니다."}
error.log
{"level":"error","message":"GET /abcd 라우터가 없습니다."}
{"level":"error","message":"GET /favicon.ico 라우터가 없습니다."}
info 이상 단계의 모든 로그를 기록하도록 되어 있는 combined.log 파일에는 info와 error 단계의 로그가 저장되어 있습니다. error 단계의 로그만 기록하도록 되어 있는 error.log에는 error 단계의 로그만 저장되었습니다. 이렇게 로그를 콘솔에만 출력하는 것이 아니라, 파일로도 저장할 수 있어 실제 서비스를 운영할 때 유용합니다.
'프로그래밍 언어 > NODE JS' 카테고리의 다른 글
| connect-redis (0) | 2026.04.29 |
|---|---|
| helmet, hpp (0) | 2026.04.26 |
| pm(2) (0) | 2026.04.20 |
| pm2(1) (0) | 2026.04.17 |
| sanitize-html, csurf (0) | 2026.04.14 |