浏览代码

日志插件重写,优化部分逻辑

zhusiqing 3 年之前
父节点
当前提交
3e7b01d769
共有 8 个文件被更改,包括 181 次插入162 次删除
  1. 5 1
      package.json
  2. 1 1
      pm2.config.js
  3. 2 2
      src/app.ts
  4. 16 0
      src/controllers/index.ts
  5. 4 4
      src/middlewares/logs.ts
  6. 31 32
      src/plugins/index.ts
  7. 120 107
      src/plugins/logger.ts
  8. 2 15
      src/typings/index.d.ts

+ 5 - 1
package.json

@@ -20,7 +20,11 @@
   "license": "MIT",
   "scripts": {
     "dev": "cross-env NODE_ENV=development nodemon -e ts --exec ts-node -r tsconfig-paths/register src/app.ts",
-    "start": "rm -rf ./dist && cross-env NODE_ENV=prod tsc --inlineSourceMap false"
+    "start": "rm -rf ./dist && cross-env NODE_ENV=prod tsc --inlineSourceMap false",
+    "pm2:start": "pm2 start ./pm2.config.js",
+    "pm2:list": "pm2 list",
+    "pm2:stop": "pm2 stop gateway && pm2 delete gateway",
+    "pm2:restart": "pm2 restart gateway"
   },
   "dependencies": {
     "consola": "^2.15.0",

+ 1 - 1
pm2.config.js

@@ -2,7 +2,7 @@
 module.exports = {
   apps: [
     {
-      name: 'demo',
+      name: 'gateway',
       script: 'dist/app.js',
       exec_mode: 'cluster',
       watch: false,

+ 2 - 2
src/app.ts

@@ -44,7 +44,7 @@ app.use(responseMiddleware());
 // post params解析
 app.use(bodyParser());
 // 日志
-app.use(logsMiddleware(plugins.logger));
+app.use(logsMiddleware(plugins.logger.middleware));
 
 // 本地嵌入式数据库
 app.use(localDbMiddleware(plugins.db))
@@ -71,7 +71,7 @@ app.on('error', (err, ctx: Context) => {
   const errMsg: string = err.message || '服务出错';
   console.log(errMsg);
   console.log(ctx);
-  plugins.logger(ctx).error(errMsg)
+  plugins.logger.middleware(ctx).error(errMsg)
 });
 
 // 注册路由

+ 16 - 0
src/controllers/index.ts

@@ -4,9 +4,25 @@ import document from './document';
 import services from '../services';
 import path from 'path';
 import { readFileSync } from 'fs';
+import http from 'http';
+
 const home = async (ctx: Context) => {
+  let a: string
+  await new Promise<void>((resolve) => {
+    http.get('http://dev.ldy.client.qihoo.net/api/client/thirdapi/filedownload?id=1002&f_key=QEzedKKG9w3ljmtWYbwDaXz1d1hKgI6U_2019070310081642.zip&timestamp=1625652728&vulid=LDY-2021-00001795&token=515A016F0BEA3DBA5A7D9A0E5C776808', res => {
+      res.on('data', d => {
+        a += d
+      })
+      res.on('end', () => {
+        console.log(typeof a);
+        resolve()
+        // writeFileSync(path.resolve(__dirname, './test.zip'), a)
+      })
+    })
+  })
   ctx.body = 'home';
 };
+// TODO: ws 待开发状态
 const ws = async (ctx:Context) => {
   ctx.body = readFileSync(path.resolve(__dirname, '../../example/ws.html')).toString()
 }

+ 4 - 4
src/middlewares/logs.ts

@@ -1,7 +1,7 @@
 import { Context, Next } from 'koa';
-import { InterfaceLogger, commonInfo, output } from '@/plugins/logger';
+import { interfaceLogger, interfaceLogInfo, formatOutputHandle } from '@/plugins/logger';
 
-export default (logger: InterfaceLogger) => {
+export default (logger: interfaceLogger) => {
   const loggerMiddleware = async(ctx, next) => {
     const $log = logger(ctx)
     ctx.$log = $log;
@@ -9,14 +9,14 @@ export default (logger: InterfaceLogger) => {
     await next();
     const b = Date.now()
     if (ctx.response && ctx.status < 400) {
-      const commonInfo: commonInfo = {
+      const commonInfo: interfaceLogInfo = {
         ip: ctx.ip,
         time: b - a
       };
       if (ctx.request.body) {
         commonInfo.params = ctx.request.body;
       };
-      $log.info(output(ctx, null, commonInfo))
+      $log.info(formatOutputHandle(ctx, null, commonInfo))
     }
     else {
       ctx.throw(ctx.status, ctx.response);

+ 31 - 32
src/plugins/index.ts

@@ -3,51 +3,50 @@ import config from '@config';
 import RedisPlugin from '@/plugins/redis';
 import MemoryCachePlugin from '@/plugins/memoryCache';
 import LocalDbPlugin from '@/plugins/localDb';
-// TODO: 后面也采用class封装一下
-import { loggerInstance } from '@/plugins/logger';
+import MyLogger, { interfaceLog } from '@/plugins/logger';
 
 export type Redis = RedisPlugin
 export type MemoryCache = MemoryCachePlugin
 export type LocalDb = LocalDbPlugin
+export type Log = interfaceLog
 const { redis: redisOpt, localDb: localDbOpt } = config
-export default () => {
-  const redisOption = {
-    host: redisOpt.host,
-    port: redisOpt.port,
-    password: redisOpt.password,
-    auth_pass: redisOpt.password,
-    retry_strategy: function(this: RedisPlugin, opts: RetryStrategyOptions) {
-      if (opts.error && opts.error.code === "ECONNREFUSED") {
-        opts.error.code
-        // redis连接失败时使用内存存储
-        this.isUseRedis = false
-        // End reconnecting on a specific error and flush all commands with
-        // a individual error
-        return new Error("The server refused the connection");
-      }
-      if (opts.total_retry_time > 1000 * 60 * 60) {
-        // End reconnecting after a specific timeout and flush all commands
-        // with a individual error
-        return new Error("Retry time exhausted");
-      }
-      if (opts.attempt > 10) {
-        // End reconnecting with built in error
-        return;
-      }
-      // reconnect after
-      return Math.min(opts.attempt * 1000, 3000);
+const redisOption = {
+  host: redisOpt.host,
+  port: redisOpt.port,
+  password: redisOpt.password,
+  auth_pass: redisOpt.password,
+  retry_strategy: function(this: RedisPlugin, opts: RetryStrategyOptions) {
+    if (opts.error && opts.error.code === "ECONNREFUSED") {
+      opts.error.code
+      // redis连接失败时使用内存存储
+      this.isUseRedis = false
+      // End reconnecting on a specific error and flush all commands with
+      // a individual error
+      return new Error("The server refused the connection");
+    }
+    if (opts.total_retry_time > 1000 * 60 * 60) {
+      // End reconnecting after a specific timeout and flush all commands
+      // with a individual error
+      return new Error("Retry time exhausted");
     }
+    if (opts.attempt > 10) {
+      // End reconnecting with built in error
+      return;
+    }
+    // reconnect after
+    return Math.min(opts.attempt * 1000, 3000);
   }
-  const localDbOption = localDbOpt
-
+}
+const localDbOption = localDbOpt
+export default () => {
   const redis = new RedisPlugin(redisOption)
   const memoryCache = new MemoryCachePlugin()
   const localDb = new LocalDbPlugin(localDbOption)
-
+  const logger = new MyLogger()
   return {
     redis,
     memoryCache,
     db: localDb,
-    logger: loggerInstance
+    logger
   }
 }

+ 120 - 107
src/plugins/logger.ts

@@ -1,14 +1,33 @@
-import log4js, { DateFileAppender, ConsoleAppender } from 'log4js';
+import log4js, { DateFileAppender, ConsoleAppender, Logger } from 'log4js';
 import path from 'path';
 import { Context } from 'koa';
 import config from '@config';
-export interface commonInfo {
+export interface interfaceLogInfo {
   ip: string,
   params?: any,
   time?: number
 }
-// 输出配置
-export const output = (ctx, message: string | null | undefined , commonInfo: commonInfo) => {
+export interface interfaceLogger {
+  (ctx: Context): interfaceLog
+}
+export interface interfaceLog {
+  trace: interfaceLogFn
+  debug: interfaceLogFn
+  info: interfaceLogFn
+  warn: interfaceLogFn
+  error: interfaceLogFn
+  fatal: interfaceLogFn
+  mark: interfaceLogFn
+}
+interface interfaceLogFn {
+  (message: any): void;
+}
+interface interfaceAppenders {
+  [key: string]: DateFileAppender | ConsoleAppender
+}
+
+// 输出格式化配置
+export const formatOutputHandle = (ctx, message: string | null | undefined , commonInfo: interfaceLogInfo) => {
   const {
     method, // 请求方式
     headers, // 请求headers
@@ -34,8 +53,7 @@ export const output = (ctx, message: string | null | undefined , commonInfo: com
   let text = `[${method}] ${ctx.status} [${origin}${originalUrl}] ${time ? time + 'ms' : ''}
 req: ${JSON.stringify(Object.assign(client, newCommonInfo))}`;
 
-  if (Object.prototype.toString.call(message) === '[object Object]'
-  || Object.prototype.toString.call(message) === '[object Error]') {
+  if (['[object Object]', '[object Array]', '[object Error]'].includes(Object.prototype.toString.call(message))) {
     message = JSON.stringify(message);
   };
 
@@ -44,6 +62,7 @@ req: ${JSON.stringify(Object.assign(client, newCommonInfo))}`;
   };
   return text;
 };
+
 // 日志级别
 const methods: string[] = ['trace', 'debug', 'info', 'warn', 'error', 'fatal', 'mark'];
 
@@ -54,108 +73,102 @@ const defaultConfig = {
   env: 'development' // 指定当前环境,当开发时控制台也输出
 };
 
-// log配置
-const opt = Object.assign({}, defaultConfig, config.logs);
-const { env, appLogLevel, dir } = opt;
-/**
- * 记录日志的方式
- * 指定要记录的日志分类 log
- * 展示方式为文件类型 dateFile
- * 日志输出的文件名 s-yyyy-MM-dd.log
- */
-// interface appenders {
-//   [key: string]: {
-//     type: string,
-//     filename?: string,
-//     pattern?: string,
-//     alwaysIncludePattern?: boolean,
-//     ip?: string,
-//     layout: object
-//   }
-// }
-interface appenders {
-  [key: string]: DateFileAppender | ConsoleAppender
-}
-const appenders: appenders = {
-  log: {
-    // 按日期进行输出log
-    type: 'dateFile',
-    // 路径和文件名
-    filename: `${dir}/z`,
-    pattern: 'yyyy-MM-dd.log',
-    alwaysIncludePattern: true,
-    // 日志输出格式
-    layout: {
-      type: 'pattern',
-      pattern: '[%d{yyyy-MM-dd hh:mm:ss}] [%p] %c %m%n'
-    }
+export default class MyLogger {
+  // log配置
+  logConfig = Object.assign({}, defaultConfig, config.logs);
+  // 记录日志的方式
+  appenders: interfaceAppenders = {}
+  // 记录日志的类型
+  categories
+  // 是否是开发环境
+  isDev: boolean = false
+  // log4js实例
+  logger: Logger = {} as Logger
+  constructor() {
   }
-};
-// 开发和本地同时启用console
-if (env === 'dev' || env === 'local' || env === 'development') {
-  appenders.out = {
-    type: 'console',
-    layout: {
-      type: 'pattern',
-      pattern: '%[[%d{yyyy-MM-dd hh:mm:ss}] [%p] %c%] %m%n'
-    }
-  };
-};
-const isDev = env === 'dev' || env === 'local' || env === 'development';
-
-/**
-   * 指定日志的默认配置项
-   * 如果 log4js.getLogger 中没有指定,默认为 appenders中的日志配置项, 数组
-   * 指定日志的记录内容显示 某级别 及 某级别 以上级别的信息
-   */
-const categories = {
-  default: {
-    appenders: Object.keys(appenders),
-    level: appLogLevel
+  init() {
+    const { env, appLogLevel, dir } = this.logConfig;
+    /**
+     * 记录日志的方式
+     * 指定要记录的日志分类 log
+     * 展示方式为文件类型 dateFile
+     * 日志输出的文件名 s-yyyy-MM-dd.log
+     */
+    // interface appenders {
+    //   [key: string]: {
+    //     type: string,
+    //     filename?: string,
+    //     pattern?: string,
+    //     alwaysIncludePattern?: boolean,
+    //     ip?: string,
+    //     layout: object
+    //   }
+    // }
+    const appenders: interfaceAppenders = {
+      log: {
+        // 按日期进行输出log
+        type: 'dateFile',
+        // 路径和文件名
+        filename: `${dir}/z`,
+        pattern: 'yyyy-MM-dd.log',
+        alwaysIncludePattern: true,
+        // 日志输出格式
+        layout: {
+          type: 'pattern',
+          pattern: '[%d{yyyy-MM-dd hh:mm:ss}] [%p] %c %m%n'
+        }
+      }
+    };
+    // 开发和本地同时启用console
+    const isDev = env === 'dev' || env === 'local' || env === 'development';
+    if (isDev) {
+      appenders.out = {
+        type: 'console',
+        layout: {
+          type: 'pattern',
+          pattern: '%[[%d{yyyy-MM-dd hh:mm:ss}] [%p] %c%] %m%n'
+        }
+      };
+    };
+    this.isDev = isDev
+    this.appenders = appenders
+    /**
+     * 指定日志的默认配置项
+     * 如果 log4js.getLogger 中没有指定,默认为 appenders中的日志配置项, 数组
+     * 指定日志的记录内容显示 某级别 及 某级别 以上级别的信息
+     */
+    const categories = {
+      default: {
+        appenders: Object.keys(appenders),
+        level: appLogLevel
+      }
+    };
+    this.categories = categories
+    // log4js配置
+    log4js.configure({
+      appenders,
+      categories,
+      pm2: !isDev,
+      pm2InstanceVar: 'INSTANCE_ID'
+    });
+    // 初始化log4js
+    this.logger = log4js.getLogger('log');
   }
-};
-
-// log4js配置
-log4js.configure({
-  appenders,
-  categories,
-  pm2: !isDev,
-  pm2InstanceVar: 'INSTANCE_ID'
-});
-// 初始化log4js
-const logger = log4js.getLogger('log');
-
-interface logFn {
-  (message: any, ...args: any[]): void;
-}
-export interface InterfaceLog {
-  trace: logFn
-  debug: logFn
-  info: logFn
-  warn: logFn
-  error: logFn
-  fatal: logFn
-  mark: logFn
-}
-
-export interface InterfaceLogger {
-  (ctx: Context): InterfaceLog
-}
-
-export const loggerInstance: InterfaceLogger = (ctx: Context): InterfaceLog => {
-  const $log: InterfaceLog = {
-    trace: () => {},
-    debug: () => {},
-    info: () => {},
-    warn: () => {},
-    error: () => {},
-    fatal: () => {},
-    mark: () => {}
-  };
-  methods.map(el => {
-    $log[el] = (message) => {
-      logger[el](output(ctx, message, { ip: ctx.ip }));
+  middleware(ctx: Context): interfaceLog {
+    const $log: interfaceLog = {
+      trace: () => {},
+      debug: () => {},
+      info: () => {},
+      warn: () => {},
+      error: () => {},
+      fatal: () => {},
+      mark: () => {}
     };
-  });
-  return $log;
+    methods.map(el => {
+      $log[el] = (message) => {
+        this.logger[el](formatOutputHandle(ctx, message, { ip: ctx.ip }));
+      };
+    });
+    return $log;
+  }
 }

+ 2 - 15
src/typings/index.d.ts

@@ -3,26 +3,13 @@ import { IMiddleware } from 'koa-router';
 import { RedisClient } from 'redis';
 import { responseHandle } from '@utils/response';
 import { InterfaceDB } from '../middlewares/localDb';
-import { Redis } from '@/plugins';
-
-interface logFn {
-  (message: any, ...args: any[]): void;
-}
-interface interfaceLog {
-  trace: logFn
-  debug: logFn
-  info: logFn
-  warn: logFn
-  error: logFn
-  fatal: logFn
-  mark: logFn
-}
+import { Redis, Log } from '@/plugins';
 
 declare module 'koa' {
   export interface Context extends DefaultContext {
     $redis: Redis
     $response: responseHandle
-    $log: interfaceLog
+    $log: Log
     $db: InterfaceDB
   }
 }