lrf 3 lat temu
commit
ce1be4973c

+ 29 - 0
.autod.conf.js

@@ -0,0 +1,29 @@
+'use strict';
+
+module.exports = {
+  write: true,
+  prefix: '^',
+  plugin: 'autod-egg',
+  test: [
+    'test',
+    'benchmark',
+  ],
+  dep: [
+    'egg',
+    'egg-scripts',
+  ],
+  devdep: [
+    'egg-ci',
+    'egg-bin',
+    'egg-mock',
+    'autod',
+    'autod-egg',
+    'eslint',
+    'eslint-config-egg',
+  ],
+  exclude: [
+    './test/fixtures',
+    './dist',
+  ],
+};
+

+ 1 - 0
.eslintignore

@@ -0,0 +1 @@
+coverage

+ 3 - 0
.eslintrc

@@ -0,0 +1,3 @@
+{
+  "extends": "eslint-config-egg"
+}

+ 46 - 0
.github/workflows/nodejs.yml

@@ -0,0 +1,46 @@
+# This workflow will do a clean install of node dependencies, build the source code and run tests across different versions of node
+# For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions
+
+name: Node.js CI
+
+on:
+  push:
+    branches:
+      - main
+      - master
+  pull_request:
+    branches:
+      - main
+      - master
+  schedule:
+    - cron: '0 2 * * *'
+
+jobs:
+  build:
+    runs-on: ${{ matrix.os }}
+
+    strategy:
+      fail-fast: false
+      matrix:
+        node-version: [10]
+        os: [ubuntu-latest, windows-latest, macos-latest]
+
+    steps:
+    - name: Checkout Git Source
+      uses: actions/checkout@v2
+
+    - name: Use Node.js ${{ matrix.node-version }}
+      uses: actions/setup-node@v1
+      with:
+        node-version: ${{ matrix.node-version }}
+
+    - name: Install Dependencies
+      run: npm i -g npminstall && npminstall
+
+    - name: Continuous Integration
+      run: npm run ci
+
+    - name: Code Coverage
+      uses: codecov/codecov-action@v1
+      with:
+        token: ${{ secrets.CODECOV_TOKEN }}

+ 14 - 0
.gitignore

@@ -0,0 +1,14 @@
+logs/
+npm-debug.log
+yarn-error.log
+node_modules/
+package-lock.json
+yarn.lock
+coverage/
+.idea/
+run/
+.DS_Store
+*.sw*
+*.un~
+typings/
+.nyc_output/

+ 12 - 0
.travis.yml

@@ -0,0 +1,12 @@
+
+language: node_js
+node_js:
+  - '10'
+before_install:
+  - npm i npminstall -g
+install:
+  - npminstall
+script:
+  - npm run ci
+after_script:
+  - npminstall codecov && codecov

+ 3 - 0
README.md

@@ -0,0 +1,3 @@
+# server-logs
+
+服务-日志管理

+ 13 - 0
app.js

@@ -0,0 +1,13 @@
+'use strict';
+class AppBootHook {
+  constructor(app) {
+    this.app = app;
+  }
+
+  async serverDidReady() {
+    // 应用已经启动完毕
+    const ctx = await this.app.createAnonymousContext();
+    await ctx.service.util.rabbitMq.mission();
+  }
+}
+module.exports = AppBootHook;

+ 43 - 0
app/controller/.logs.js

@@ -0,0 +1,43 @@
+module.exports = {
+  create: {
+    requestBody: ['user_id', 'account', 'name', '_tenant', 'opera', 'path'],
+  },
+  destroy: {
+    params: ['!id'],
+    service: 'delete',
+  },
+  update: {
+    params: ['!id'],
+    requestBody: ['user_id', 'account', 'name', '_tenant', 'opera', 'path'],
+  },
+  show: {
+    parameters: {
+      params: ['!id'],
+    },
+    service: 'fetch',
+  },
+  index: {
+    parameters: {
+      query: {
+        user_id: 'user_id',
+        account: 'account',
+        name: 'name',
+        _tenant: '_tenant',
+        opera: 'opera',
+        path: 'path',
+        'meta.createdAt@start': 'meta.createdAt@start',
+        'meta.createdAt@end': 'meta.createdAt@end',
+      },
+      // options: {
+      //   "meta.state": 0 // 默认条件
+      // },
+    },
+    service: 'query',
+    options: {
+      query: ['skip', 'limit'],
+      sort: ['meta.createdAt'],
+      desc: true,
+      count: true,
+    },
+  },
+};

+ 12 - 0
app/controller/home.js

@@ -0,0 +1,12 @@
+'use strict';
+
+const Controller = require('egg').Controller;
+
+class HomeController extends Controller {
+  async index() {
+    const { ctx } = this;
+    ctx.body = 'hi, egg';
+  }
+}
+
+module.exports = HomeController;

+ 13 - 0
app/controller/logs.js

@@ -0,0 +1,13 @@
+'use strict';
+const meta = require('./.logs.js');
+const Controller = require('egg').Controller;
+const { CrudController } = require('naf-framework-mongoose-free/lib/controller');
+
+// 日志
+class LogsController extends Controller {
+  constructor(ctx) {
+    super(ctx);
+    this.service = this.ctx.service.logs;
+  }
+}
+module.exports = CrudController(LogsController, meta);

+ 27 - 0
app/model/logs.js

@@ -0,0 +1,27 @@
+'use strict';
+const Schema = require('mongoose').Schema;
+const metaPlugin = require('naf-framework-mongoose-free/lib/model/meta-plugin');
+// 日志表
+const logs = {
+  user_id: { type: String }, // 用户id
+  account: { type: String }, // 账号
+  name: { type: String }, // 账号名称
+  _tenant: { type: String }, // 所属分站
+  opera: { type: String }, // 操作
+  path: { type: String }, // 请求地址
+  module: { type: String }, // 模块
+  remark: { type: String },
+};
+const schema = new Schema(logs, { toJSON: { virtuals: true } });
+schema.index({ id: 1 });
+schema.index({ user_id: 1 });
+schema.index({ account: 1 });
+schema.index({ name: 1 });
+schema.index({ _tenant: 1 });
+schema.index({ opera: 1 });
+schema.index({ 'meta.createdAt': 1 });
+schema.plugin(metaPlugin);
+module.exports = app => {
+  const { mongoose } = app;
+  return mongoose.model('Logs', schema, 'logs');
+};

+ 10 - 0
app/router.js

@@ -0,0 +1,10 @@
+'use strict';
+
+/**
+ * @param {Egg.Application} app - egg application
+ */
+module.exports = app => {
+  const { router, controller } = app;
+  router.get('/', controller.home.index);
+  require('./z_router/logs')(app); // 日志
+};

+ 15 - 0
app/service/logs.js

@@ -0,0 +1,15 @@
+'use strict';
+const { CrudService } = require('naf-framework-mongoose-free/lib/service');
+const { BusinessError, ErrorCode } = require('naf-core').Error;
+const _ = require('lodash');
+const assert = require('assert');
+
+// 日志
+class LogsService extends CrudService {
+  constructor(ctx) {
+    super(ctx, 'logs');
+    this.model = this.ctx.model.Logs;
+  }
+}
+
+module.exports = LogsService;

+ 67 - 0
app/service/util/rabbitMq.js

@@ -0,0 +1,67 @@
+'use strict';
+
+const Service = require('egg').Service;
+const _ = require('lodash');
+
+class RabbitmqService extends Service {
+  // mission队列处理
+  async mission() {
+    const { mq } = this.ctx;
+    const { queue } = this.ctx.app.config;
+    if (mq && queue) {
+      const ch = await mq.conn.createChannel();
+      try {
+        // 创建队列:在没有队列的情况,直接获取会导致程序无法启动
+        await ch.assertQueue(queue, { durable: false });
+        await ch.consume(queue, msg => this.dealMission(msg), { noAck: true });
+      } catch (error) {
+        this.ctx.logger.error('未找到订阅的队列');
+      }
+    } else {
+      this.ctx.logger.error('!!!!!!没有配置MQ插件!!!!!!');
+    }
+  }
+  // 执行任务
+  async dealMission(bdata) {
+    if (!bdata) this.ctx.logger.error('mission队列中信息不存在');
+    let data = bdata.content.toString();
+    try {
+      data = JSON.parse(data);
+    } catch (error) {
+      this.ctx.logger.error('数据转换错误');
+    }
+    // 因为这个地址只管添加日志,所以就直接走创建就行
+    this.ctx.service.logs.create(data);
+  }
+  /**
+   * 发送队列消息
+   * @param {Any} data 消息队列数据
+   * @param {String} queueKey 消息队列可以
+   */
+  async sendToMqQueue(data, queueKey) {
+    const { mq } = this.ctx;
+    const { sendQueue } = this.ctx.app.config;
+    let queue;
+    // 获取队列名称
+    if (_.isObject(sendQueue)) {
+      queue = sendQueue[queueKey];
+    }
+    if (mq && queue) {
+      if (!_.isString(data)) data = JSON.stringify(data);
+      const ch = await mq.conn.createChannel();
+      try {
+        // 创建队列:在没有队列的情况,直接获取会导致程序无法启动
+        await ch.assertQueue(queue, { durable: false });
+        await ch.sendToQueue(queue, Buffer.from(data));
+        await ch.close();
+      } catch (error) {
+        console.error(error);
+        this.ctx.logger.error('未找到订阅的队列');
+      }
+    } else {
+      this.ctx.logger.error('!!!!!!没有配置MQ插件!!!!!!');
+    }
+  }
+}
+
+module.exports = RabbitmqService;

+ 25 - 0
app/z_router/logs.js

@@ -0,0 +1,25 @@
+'use strict';
+// 路由配置
+const routes = [
+  { method: 'get', path: '/logs', controller: 'logs.index', name: 'logsQuery', zh: '日志列表查询' },
+  { method: 'get', path: '/logs/:id', controller: 'logs.show', name: 'logsShow', zh: '日志查询' },
+  { method: 'post', path: '/logs', controller: 'logs.create', name: 'logsCreate', zh: '创建日志' },
+  // { method: 'post', path: '/logs/:id', controller: 'logs.update', middleware: [ 'password' ], name: 'logsQuery', zh: '修改用户' },
+  // { method: 'delete', path: '/logs/:id', controller: 'logs.destroy', name: 'logsQuery', zh: '删除用户' },
+];
+
+module.exports = app => {
+  const { router, config } = app;
+  const mwares = app.middleware;
+  for (const route of routes) {
+    const { method, path, controller: ctl, zh } = route;
+    let { middleware = [] } = route;
+    if (!method || !path || !ctl) continue;
+    // 拼全路径
+    const allPath = `${config.routePrefix}${path}`;
+    // 处理中间件
+    if (middleware.length > 0) middleware = middleware.map(i => mwares[i]());
+    // 注册路由
+    router[method](zh, allPath, ...middleware, ctl);
+  }
+};

+ 14 - 0
appveyor.yml

@@ -0,0 +1,14 @@
+environment:
+  matrix:
+    - nodejs_version: '10'
+
+install:
+  - ps: Install-Product node $env:nodejs_version
+  - npm i npminstall && node_modules\.bin\npminstall
+
+test_script:
+  - node --version
+  - npm --version
+  - npm run test
+
+build: off

+ 72 - 0
config/config.default.js

@@ -0,0 +1,72 @@
+/* eslint valid-jsdoc: "off" */
+
+'use strict';
+
+/**
+ * @param {Egg.EggAppInfo} appInfo app info
+ */
+module.exports = appInfo => {
+  /**
+   * built-in config
+   * @type {Egg.EggAppConfig}
+   **/
+  const config = (exports = {});
+
+  // use for cookie sign key, should change to your own and keep security
+  config.keys = appInfo.name + '_1640765645851_7833';
+
+  // add your middleware config here
+  config.middleware = [];
+
+  // add your user config here
+  const userConfig = {
+    // myAppName: 'egg',
+  };
+
+  // mq设置
+  config.amqp = {
+    client: {
+      hostname: '127.0.0.1',
+      username: 'freeAdmin',
+      password: '1qaz2wsx',
+      vhost: 'freeAdmin',
+    },
+    app: true,
+    agent: true,
+  };
+
+  // 进程设置
+  config.cluster = {
+    listen: {
+      port: 13002,
+    },
+  };
+
+  // 数据库设置
+  config.dbName = 'freeAdmin-logs';
+  config.mongoose = {
+    url: `mongodb://localhost:27017/${config.dbName}`,
+    options: {
+      user: 'admin',
+      pass: 'admin',
+      authSource: 'admin',
+      useNewUrlParser: true,
+      useCreateIndex: true,
+    },
+  };
+
+  // 路由设置
+  config.routePrefix = '/freeAdminLog/api';
+
+  // 接收队列名称
+  config.queue = 'freeAdmin/server-logs';
+  // 发送队列名称
+  config.sendQueue = {
+    user: 'freeAdmin/server-user',
+  };
+
+  return {
+    ...config,
+    ...userConfig,
+  };
+};

+ 7 - 0
config/plugin.js

@@ -0,0 +1,7 @@
+'use strict';
+
+// rabbitMq
+exports.amqp = {
+  enable: true,
+  package: 'egg-naf-amqp',
+};

+ 52 - 0
package.json

@@ -0,0 +1,52 @@
+{
+  "name": "server-logs",
+  "version": "1.0.0",
+  "description": "服务-日志管理",
+  "private": true,
+  "egg": {
+    "framework": "naf-framework-mongoose-free"
+  },
+  "dependencies": {
+    "egg": "^2.15.1",
+    "egg-scripts": "^2.11.0",
+    "egg-naf-amqp": "0.0.13",
+    "egg-redis": "^2.4.0",
+    "lodash": "^4.17.21",
+    "moment": "^2.29.1",
+    "naf-framework-mongoose-free": "^0.0.10"
+  },
+  "devDependencies": {
+    "autod": "^3.0.1",
+    "autod-egg": "^1.1.0",
+    "egg-bin": "^4.11.0",
+    "egg-ci": "^1.11.0",
+    "egg-mock": "^3.21.0",
+    "eslint": "^5.13.0",
+    "eslint-config-egg": "^7.1.0",
+    "jsonwebtoken": "^8.5.1"
+  },
+  "engines": {
+    "node": ">=10.0.0"
+  },
+  "scripts": {
+    "start": "egg-scripts start --daemon --title=egg-server-server-logs",
+    "stop": "egg-scripts stop --title=egg-server-server-logs",
+    "dev": "egg-bin dev",
+    "debug": "egg-bin debug",
+    "test": "npm run lint -- --fix && npm run test-local",
+    "test-local": "egg-bin test",
+    "cov": "egg-bin cov",
+    "lint": "eslint .",
+    "ci": "npm run lint && npm run cov",
+    "autod": "autod"
+  },
+  "ci": {
+    "version": "10"
+  },
+  "repository": {
+    "type": "git",
+    "url": ""
+  },
+  "author": "lrf",
+  "license": "MIT"
+}

+ 20 - 0
test/app/controller/home.test.js

@@ -0,0 +1,20 @@
+'use strict';
+
+const { app, assert } = require('egg-mock/bootstrap');
+
+describe('test/app/controller/home.test.js', () => {
+  it('should assert', () => {
+    const pkg = require('../../../package.json');
+    assert(app.config.keys.startsWith(pkg.name));
+
+    // const ctx = app.mockContext({});
+    // yield ctx.service.xx();
+  });
+
+  it('should GET /', () => {
+    return app.httpRequest()
+      .get('/')
+      .expect('hi, egg')
+      .expect(200);
+  });
+});