npm i morgan winston
npm i -D @types/morgan
import morgan, { StreamOptions } from 'morgan';
import winston from 'winston';
import { currentENV } from '../utils';
// This parameter returns 'deveopment' or other NODE_ENV
// export const currentENV = process.env.NODE_ENV || 'development';
const levels: { [key: string]: number } = {
error: 0,
warn: 1,
info: 2,
http: 3,
debug: 4
};
// write only error log in development mode, write all logs in other mode
const level = () => {
const env = currentENV;
const isDevelopment = env === 'development';
return isDevelopment ? 'error' : 'debug';
};
type IWinstonColors = 'red' | 'yellow' | 'green' | 'magenta' | 'white';
const colors: { [key: string]: IWinstonColors } = {
error: 'red',
warn: 'yellow',
info: 'green',
http: 'magenta',
debug: 'white'
};
winston.addColors(colors);
const format = winston.format.combine(
winston.format.timestamp({ format: 'DD-MM-YYYY HH:mm:ss' }),
winston.format.printf(
msg => `${[msg.timestamp]} ${msg.level}: ${msg.message}`
)
);
// only add color in console
// because if we add color in log file, the format will be unreadable
const transports = [
new winston.transports.Console({
format: winston.format.combine(winston.format.colorize({ all: true })),
level: 'debug'
}),
new winston.transports.File({
filename: 'error.log',
level: 'error'
}),
new winston.transports.File({ filename: 'all.log' })
];
export const logger = winston.createLogger({
level: level(),
levels,
format,
transports
});
const stream: StreamOptions = {
write: message => logger.http(message) // morgan will log the http request
// so we use 'http' level for logging
};
export const morganMiddleware = morgan(
':method :url :status :res[content-length] - :response-time ms - :remote-addr',
// Options: in this case, I overwrote the stream and the skip logic.
// See the methods above.
{ stream }
);
...
import { logger, morganMiddleware } from './config/winston';
....
const app = express();
app.use(cors());
app.use(morganMiddleware); // use log middleware before other route settings
// otherwise it will behave strangely
// only routes which aren't defined will trigger the log
// Body parser middleware
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use('/api', routes);
app.use('/swagger', swaggerUi.serve, swaggerUi.setup(swaggerSpec));
app.enable('trust proxy');
const PORT = process.env.PORT || 5000;
app.listen(PORT, () => {
const message = `server running on port ${PORT}`;
logger.info(message); // log info
});
(async () => {
try {
const options = await getConnectionOptions(currentENV);
await createConnection({
...options,
name: 'default',
synchronize: false
});
const message = 'database ok';
logger.info(message); // log info
} catch (e) {
console.log(e);
const message = 'database connection failed!';
logger.error(message); // log error
}
})();
import { response, Response } from 'express';
import { ICustomResponse, IResponseFormat } from '../../@types';
import { logger } from '../../config/winston';
response.customResponse = function (
httpStatusCode: ICustomResponse['httpStatusCode'],
message: ICustomResponse['message'],
data: ICustomResponse['data'] = null,
errors: ICustomResponse['error'] = null
): Response {
const res: IResponseFormat = {
status: httpStatusCode,
code: httpStatusCode === 200 ? 1 : 0,
message
};
const validData = data && (typeof data === 'object' || Array.isArray(data));
if (validData) {
res.data = data;
}
if (errors) {
res.error = errors;
}
if (res.code === 0) {
let errorMessage = message;
if (errors && typeof errors === 'object') {
errorMessage = `${errorMessage} - ${JSON.stringify(errors)}`;
}
logger.error(errorMessage); // Use here to log the error message
}
return this.status(httpStatusCode).json(res);
};
| | Amount | Calories | Protein | Fat| Fiber |
Jun 9, 202509:13/09:06離開機場, 搭乘S1或S8到München Hbf/ Ost車站旁邊的 EDEKA 跟 dm 採買10:55 Hbf/ 11:04 Ost 出發Salzburg, 12:42 抵達
Nov 26, 2024Generate AI
Jun 8, 2024You can later watch this video to recap
May 1, 2024or
By clicking below, you agree to our terms of service.
New to HackMD? Sign up