按日期创建log文件、error和res分别在两个文件夹
  1. // /config/log4js_config.js
  2. module.exports = {
  3. appenders: {
  4. // 默认日志
  5. console: {
  6. type: 'console',
  7. },
  8. //错误日志
  9. errorLogger: {
  10. // category: 'errorLogger', //logger名称
  11. type: 'dateFile', //日志类型
  12. filename: 'logs/error/error', // 日志输出位置
  13. alwaysIncludePattern: true, // 是否总是有后缀名
  14. pattern: 'yyyy-MM-dd.log', // 后缀
  15. },
  16. //响应日志
  17. resLogger: {
  18. // category: 'resLogger',
  19. type: 'dateFile',
  20. filename: 'logs/response/response',
  21. alwaysIncludePattern: true,
  22. pattern: 'yyyy-MM-dd.log',
  23. },
  24. },
  25. //设置logger名称对应的的日志等级
  26. categories: {
  27. default: {
  28. appenders: ['console'],
  29. level: 'All',
  30. },
  31. errorLogger: {
  32. appenders: ['errorLogger'],
  33. level: 'error',
  34. },
  35. resLogger: {
  36. appenders: ['resLogger'],
  37. level: 'all',
  38. },
  39. },
  40. };

封装打印内容
  1. // /utils/log_util.js
  2. const log4js = require('log4js');
  3. const loggerConfig = require('../config/log4js_config');
  4. // 加载配置文件
  5. log4js.configure(loggerConfig);
  6. const logger = {};
  7. const errorLogger = log4js.getLogger('errorLogger');
  8. const resLogger = log4js.getLogger('resLogger');
  9. // 封装错误日志
  10. logger.logError = (error, resTime, requestBody) => {
  11. if (error) {
  12. errorLogger.error(formatError(error, resTime, requestBody));
  13. }
  14. };
  15. // 封装响应日志
  16. logger.logResponse = (response, resTime, requestBody) => {
  17. if (response) {
  18. resLogger.info(formatRes(response, resTime, requestBody));
  19. }
  20. };
  21. // 封装控制台打印
  22. logger.log = title => {
  23. return log4js.getLogger(title);
  24. };
  25. // 格式化响应日志
  26. const formatRes = (response, resTime, requestBody) => {
  27. let logText = '';
  28. // 响应日志开始
  29. logText += '\n' + '*************** response log start ***************' + '\n';
  30. // 添加请求日志
  31. logText += formatReqLog(response.request, resTime, requestBody);
  32. // 响应状态码
  33. logText += 'response statusCode: ' + response.statusCode + '\n';
  34. // 响应内容
  35. logText += 'response body: ' + '\n' + JSON.stringify(response.body) + '\n';
  36. // 响应日志结束
  37. logText += '*************** response log end ***************' + '\n';
  38. return logText;
  39. };
  40. // 格式化错误日志
  41. const formatError = (err, resTime, requestBody) => {
  42. let logText = '';
  43. // 错误信息开始
  44. logText += '\n' + '*************** error log start ***************' + '\n';
  45. // 添加请求日志
  46. logText += formatReqLog(err.options, resTime, requestBody);
  47. // 错误名称
  48. logText += 'err name: ' + err.name + '\n';
  49. // 错误信息
  50. logText += 'err message: ' + err.message + '\n';
  51. // 错误详情
  52. logText += 'err stack: ' + err.stack + '\n';
  53. // 错误信息结束
  54. logText += '*************** error log end ***************' + '\n';
  55. return logText;
  56. };
  57. // 格式化请求日志
  58. const formatReqLog = (req, resTime, requestBody) => {
  59. let logText = '';
  60. const method = req.method;
  61. // 访问方法
  62. logText += 'request method: ' + method + '\n';
  63. // 请求原始地址
  64. logText += 'request originalUrl: ' + (req.uri && req.uri.href || req.uri) + '\n';
  65. // 请求参数
  66. if (method === 'GET') {
  67. logText += 'request query: ' + JSON.stringify(req.uri.query) + '\n';
  68. } else {
  69. logText += 'request body: ' + '\n' + JSON.stringify(requestBody) + '\n';
  70. }
  71. // 服务器响应时间
  72. logText += 'response time: ' + resTime + 'ms' + '\n';
  73. return logText;
  74. };
  75. module.exports = logger;

request时使用(同时也是node端请求封装)
  1. // /utils/request.js
  2. const rp = require('request-promise');
  3. const axios = require('axios');
  4. const config = require('../config/constants');
  5. const logger = require('./log_util');
  6. const requestConfig = {
  7. baseUrl: config.baseUrl,
  8. resolveWithFullResponse: false
  9. };
  10. const rpWithLogger = (options, bodyKey) => {
  11. const startTime = new Date();
  12. let ms = 0;
  13. return rp(options).then(
  14. res => {
  15. ms = new Date() - startTime;
  16. logger.logResponse(res, ms, options[bodyKey]);
  17. return res.body;
  18. },
  19. err => {
  20. ms = new Date() - startTime;
  21. logger.logError(err, ms, options[bodyKey]);
  22. return { code: 504, msg: '网关超时', err };
  23. }
  24. );
  25. };
  26. exports.get = (uri, param = {}, opts) => {
  27. const options = {
  28. uri,
  29. method: 'GET',
  30. qs: param,
  31. ...requestConfig,
  32. ...opts
  33. };
  34. return rpWithLogger(options, 'param');
  35. };
  36. exports.post = (uri, body, opts) => {
  37. const options = {
  38. uri,
  39. method: 'POST',
  40. body: body,
  41. ...requestConfig,
  42. ...opts,
  43. json: true,
  44. resolveWithFullResponse: true
  45. };
  46. return rpWithLogger(options, 'body');
  47. };
  48. exports.upload = (uri, formData, opts) => {
  49. const options = {
  50. uri,
  51. method: 'POST',
  52. formData: formData,
  53. ...requestConfig,
  54. ...opts
  55. };
  56. return rp(options);
  57. };
  58. exports.download = (uri, param = {}, opts) => {
  59. // 此处用 axios 请求,定义 responseType 为 stream 进行下载
  60. return axios.get(config.baseUrl + uri, {
  61. responseType: 'stream', // 注意此处要用 stream
  62. params: param,
  63. data: {},
  64. ...opts
  65. });
  66. };

配置内容需根据需求自行修改,当然不修改也能用。
完整koa模板示例:https://www.yuque.com/xiebugde/mbz0hg/tg5c7c