首页 > 其他分享 >express使用morgan+file-stream-rotator实现自定义日志+轮转

express使用morgan+file-stream-rotator实现自定义日志+轮转

时间:2024-11-12 10:45:40浏览次数:1  
标签:body 自定义 stream res req token morgan

import express, {json} from 'express';
import fs from 'fs';
import path from 'path';
import morgan from 'morgan';
import FileStreamRotator from 'file-stream-rotator';

const app = express();

//自动采集一些东西
// 自定义的 token 来获取请求头数据
morgan.token('auth', function (req) {
    return req.headers['token']; // 获取请求头的 token 值
});

// 自定义的 token 来获取本地时间
morgan.token('local-time', () => {
    let d = new Date();
    return d.toLocaleString() + '.' + d.getMilliseconds();
});

// 自定义 token 来获取请求体
morgan.token('request-body', (req) => {
    return JSON.stringify(req.body);
});

// 自定义 token 来记录响应体
morgan.token('response-body', (req, res) => {
    return res.body || '';
});

// 自定义中间件来捕获响应体
app.use((req, res, next) => {
    const originalSend = res.send.bind(res);
    res.send = function (body) {
        res.body = body;
        return originalSend(body);
    };
    next();
});

// 创建日志目录
const __dirname = path.resolve();
const logDirectory = path.join(__dirname, './logs');
fs.promises.access(logDirectory).catch(() => {
    fs.promises.mkdir(logDirectory, {recursive: true}).then(r => "无法创建文件夹");
});

// 配置日志流
const configs = (type) => ({
    date_format: 'YYYY-MM-DD',
    filename: path.join(logDirectory, `%DATE%-${type}`),
    frequency: 'daily',  //每日切分
    verbose: false,     //详细模式,会记录很多冗余信息
    extension: '.log', //文件结尾
    size: '20m',    //单个大小
    max_logs: '30', //最多保存多少
});

// 创建错误日志和自定义日志流
const errorLogStream = FileStreamRotator.getStream(configs('error'));
const dataLog = FileStreamRotator.getStream(configs('data'));

// 自定义 morgan 格式
//:local-time :request-body 这种是上面自定义的token方法
const customFormat =
    ':local-time :method :url :status :res[content-length]B :response-time ms :auth \n  请求 :request-body \n  响应 :response-body \n';
// 自定义中间件记录请求日志
function Log(req,info) {
    const { method, url, headers, body } = req;
    console.log(req)
    let a = {
        method: method,
        url: url,
        body: body,
        info: info
    }
    //由于上面多加了一堆自定义的参数,这里不是纯json
    dataLog.write(JSON.stringify(a))
}

// 使用 morgan
//中间件自动记录错误日志
app.use(morgan(customFormat, { immediate: false, stream: errorLogStream, skip: (req, res) => res.statusCode < 400 }));
//手动
app.use(morgan(':local-time :method :url :status :res[content-length]B :response-time ms :auth',
    { immediate: false, stream: dataLog }
));
//路由
app.get('/', (req, res) => {
    res.send('Hello world!');
    //dataLog.write("xxsax")
    Log(req,"xcxcxc")
});
//启动
app.listen(3000, () => {
    console.log('Server is running at port 3000');
});

标签:body,自定义,stream,res,req,token,morgan
From: https://www.cnblogs.com/qcy-blog/p/18541388

相关文章

  • 自定义 LangChain 组件:打造专属 RAG 应用
    引言在构建专业的检索增强生成(RAG)应用时,LangChain提供了丰富的内置组件。然而,有时我们需要根据特定需求定制自己的组件。本文将深入探讨如何自定义LangChain组件,特别是文档加载器、文档分割器和检索器,以打造更加个性化和高效的RAG应用。自定义文档加载器LangChain的文档......
  • 大数据Flink - StreamGraph
    ⭐简单说两句⭐✨正在努力的小新~......
  • RL 基础 | 如何使用 OpenAI Gym 接口,搭建自定义 RL 环境(详细版)
    参考:官方链接:Gymdocumentation|Makeyourowncustomenvironment腾讯云|OpenAIGym中级教程——环境定制与创建知乎|如何在Gym中注册自定义环境?g,写完了才发现自己曾经写过一篇:RL基础|如何搭建自定义gym环境(这篇博客适用于gym的接口,gymnasium接口也差不......
  • Java Lambda表达式与函数式接口和Stream API的常用方法
    JavaLambda表达式常与函数式接口和流(StreamAPI)一起使用,提供了非常强大的方式来处理集合和其他数据结构。以下是一些常用的Lambda表达式方法和它们的用途,特别是在结合java.util.stream.Stream时:1.map()用途:用于将流中的每个元素转换成另一种形式。示例:List<String>name......
  • 编写starrocks的自定义函数
    编写StarRocks的自定义函数前提条件StarRocks使用udf函数需要满足以下条件:安装jdk1.8开启udf功能,在FE的配置文件fe/conf/fe.conf中设置配置项enable_udf为true,并且重启FE节点使配置生效开发使用UDF函数创建maven项目,并且用java实现udf函数创建maven项目并且添加以......
  • SpringBoot集成SpringSecurity并实现自定义认证
    目录一、SpringSecurity简介二、集成SpringSecurity1、引入依赖2、编写核心配置类3、数据库建表4、自定义session失效策略5、自定义认证6、重写loadUserByUsername方法7、登录页面和接口三、总结一、SpringSecurity简介SpringSecurity是一个能够为基于Spring的企......
  • 「Java开发指南」如何自定义Spring代码生成?(二)
    搭建用户经常发现自己对生成的代码进行相同的修改,这些修改与个人风格/偏好、项目特定需求或公司标准有关,本教程演示自定义代码生成模板,您将学习如何:创建自定义项目修改现有模板来包含自定义注释使用JET和Skyway标记库中的标记配置项目来使用自定义在上文中,我们为大家介绍了......
  • 鸿蒙自定义组件生命周期
    在开始之前,我们先明确自定义组件和页面的关系:自定义组件:@Component装饰的UI单元,可以组合多个系统组件实现UI的复用,可以调用组件的生命周期。页面:即应用的UI页面。可以由一个或者多个自定义组件组成,@Entry装饰的自定义组件为页面的入口组件,即页面的根节点,一个页面有且仅能有一个......
  • 自定义类型那点事儿
    自定义类型:结构体,位段,枚举,联合目录自定义类型:结构体,位段,枚举,联合结构体1.结构体的声明2.结构体的特殊声明3.结构体的自引用4.结构体变量的定义和初始化5.结构体内存对齐6.修改默认对齐数7.结构体传参位段1.什么是位段?2.位段的内存分配3.位段的跨平台问题枚举......
  • 在Qt中创建和使用自定义控件类时,可能会遇到以下一些常见问题
    在Qt中创建和使用自定义控件类时,可能会遇到以下一些常见问题:一、布局相关问题大小调整不正确:问题描述:自定义控件在不同的布局环境下,可能无法按照预期调整大小。例如,当将自定义控件添加到一个水平布局或垂直布局中时,它可能不会随着布局的拉伸或收缩而正确地改变自身大小。原......