diff --git a/agent.js b/agent.js new file mode 100644 index 0000000000..17fbdc32eb --- /dev/null +++ b/agent.js @@ -0,0 +1,11 @@ +'use strict'; + +const BaseHookClass = require('./lib/core/base_hook_class'); + +class EggAgentHook extends BaseHookClass { + configDidLoad() { + this.agent._wrapMessenger(); + } +} + +module.exports = EggAgentHook; diff --git a/index.d.ts b/index.d.ts index 83dce6358a..fac192b06c 100644 --- a/index.d.ts +++ b/index.d.ts @@ -11,9 +11,9 @@ import { HttpClient2, RequestOptions } from 'urllib'; import { EggCoreBase, FileLoaderOption, - EggLoader as CoreLoader, - EggCoreOptions as CoreOptions, - EggLoaderOptions as CoreLoaderOptions, + EggLoader as CoreLoader, + EggCoreOptions as CoreOptions, + EggLoaderOptions as CoreLoaderOptions, BaseContextClass as CoreBaseContextClass, } from 'egg-core'; import EggCookies = require('egg-cookies'); @@ -59,6 +59,32 @@ declare module 'egg' { protected logger: EggLogger; } + export class Boot { + /** + * logger + * @member {EggLogger} + */ + protected logger: EggLogger; + + /** + * The configuration of application + * @member {EggAppConfig} + */ + protected config: EggAppConfig; + + /** + * The instance of agent + * @member {Agent} + */ + protected agent: Agent; + + /** + * The instance of app + * @member {Application} + */ + protected app: Application; + } + export type RequestArrayBody = any[]; export type RequestObjectBody = PlainObject; export interface Request extends KoaApplication.Request { // tslint:disable-line @@ -636,7 +662,7 @@ declare module 'egg' { truncated: boolean; } - + interface GetFileStreamOptions { requireFile?: boolean; // required file submit, default is true defCharset?: string; @@ -664,7 +690,7 @@ declare module 'egg' { * special properties (e.g: encrypted). So we must remove this property and * create our own with the same name. * @see https://github.com/eggjs/egg/pull/2958 - * + * * However, the latest version of Koa has "[key: string]: any" on the * context, and there'll be a type error for "keyof koa.Context". * So we have to directly inherit from "KoaApplication.BaseContext" and diff --git a/index.js b/index.js index b62b40aafa..f74cb54ebf 100644 --- a/index.js +++ b/index.js @@ -63,3 +63,8 @@ exports.Subscription = require('./lib/core/base_context_class'); * @since 1.2.0 */ exports.BaseContextClass = require('./lib/core/base_context_class'); + +/** + * @member {Boot} Egg#Boot + */ +exports.Boot = require('./lib/core/base_hook_class'); diff --git a/lib/agent.js b/lib/agent.js index 5dbbb8d106..9003c1b38a 100644 --- a/lib/agent.js +++ b/lib/agent.js @@ -21,8 +21,6 @@ class Agent extends EggApplication { options.type = 'agent'; super(options); - this._wrapMessenger(); - this.loader.load(); // dump config after loaded, ensure all the dynamic modifications will be recorded diff --git a/lib/core/base_hook_class.js b/lib/core/base_hook_class.js new file mode 100644 index 0000000000..2bda13bf60 --- /dev/null +++ b/lib/core/base_hook_class.js @@ -0,0 +1,31 @@ +'use strict'; + +const assert = require('assert'); +const INSTANCE = Symbol('BaseHookClass#instance'); + +class BaseHookClass { + + constructor(instance) { + this[INSTANCE] = instance; + } + + get logger() { + return this[INSTANCE].logger; + } + + get config() { + return this[INSTANCE].config; + } + + get app() { + assert(this[INSTANCE].type === 'application', 'agent boot should not use app instance'); + return this[INSTANCE]; + } + + get agent() { + assert(this[INSTANCE].type === 'agent', 'app boot should not use agent instance'); + return this[INSTANCE]; + } +} + +module.exports = BaseHookClass; diff --git a/lib/egg.js b/lib/egg.js index b4421e4654..920c5f1496 100644 --- a/lib/egg.js +++ b/lib/egg.js @@ -18,6 +18,7 @@ const createLoggers = require('./core/logger'); const Singleton = require('./core/singleton'); const utils = require('./core/utils'); const BaseContextClass = require('./core/base_context_class'); +const BaseHookClass = require('./core/base_hook_class'); const HTTPCLIENT = Symbol('EggApplication#httpclient'); const LOGGERS = Symbol('EggApplication#loggers'); @@ -133,7 +134,7 @@ class EggApplication extends EggCore { /** * Retreive base context class - * @member {Controller} BaseContextClass + * @member {BaseContextClass} BaseContextClass * @since 1.0.0 */ this.BaseContextClass = BaseContextClass; @@ -158,6 +159,18 @@ class EggApplication extends EggCore { * @since 2.12.0 */ this.Subscription = BaseContextClass; + + /** + * Retreive base context class + * @member {BaseHookClass} BaseHookClass + */ + this.BaseHookClass = BaseHookClass; + + /** + * Retreive base boot + * @member {Boot} + */ + this.Boot = BaseHookClass; } /** diff --git a/package.json b/package.json index 3c7dacf8f1..31abd0d096 100644 --- a/package.json +++ b/package.json @@ -91,6 +91,7 @@ "lib", "app", "config", + "agent.js", "index.d.ts" ], "scripts": { diff --git a/test/agent.test.js b/test/agent.test.js new file mode 100644 index 0000000000..5cd9a2ae01 --- /dev/null +++ b/test/agent.test.js @@ -0,0 +1,22 @@ +'use strict'; + +const assert = require('assert'); +const mock = require('egg-mock'); +const path = require('path'); +const utils = require('./utils'); + +describe('test/agent.test.js', () => { + afterEach(mock.restore); + let app; + + before(() => { + app = utils.app('apps/agent-logger-config'); + return app.ready(); + }); + after(() => app.close()); + + it('agent logger config should work', () => { + const fileTransport = app._agent.logger.get('file'); + assert(fileTransport.options.file === path.join('/tmp/foo', 'egg-agent.log')); + }); +}); diff --git a/test/fixtures/apps/agent-logger-config/config/config.default.js b/test/fixtures/apps/agent-logger-config/config/config.default.js new file mode 100644 index 0000000000..3935505932 --- /dev/null +++ b/test/fixtures/apps/agent-logger-config/config/config.default.js @@ -0,0 +1,7 @@ +'use strict'; + +module.exports = { + logger: { + dir: '/tmp/foo', + }, +}; diff --git a/test/fixtures/apps/agent-logger-config/package.json b/test/fixtures/apps/agent-logger-config/package.json new file mode 100644 index 0000000000..3c0c0670a1 --- /dev/null +++ b/test/fixtures/apps/agent-logger-config/package.json @@ -0,0 +1,3 @@ +{ + "name": "agent-logger-config" +} diff --git a/test/fixtures/apps/boot-app/agent.js b/test/fixtures/apps/boot-app/agent.js index 04ede16266..69c61c4738 100644 --- a/test/fixtures/apps/boot-app/agent.js +++ b/test/fixtures/apps/boot-app/agent.js @@ -1,39 +1,43 @@ 'use strict'; +const assert = require('assert'); const sleep = require('mz-modules/sleep'); +const BaseHookClass = require('../../../../lib/core/base_hook_class'); -module.exports = class { - constructor(app) { - app.bootLog = []; - this.app = app; +module.exports = class extends BaseHookClass { + constructor(agent) { + super(agent); + agent.bootLog = []; + assert(this.config); } configDidLoad() { - this.app.bootLog.push('configDidLoad'); + this.agent.bootLog.push('configDidLoad'); } async didLoad() { await sleep(1); - this.app.bootLog.push('didLoad'); + this.agent.bootLog.push('didLoad'); } async willReady() { await sleep(1); - this.app.bootLog.push('willReady'); + this.agent.bootLog.push('willReady'); } async didReady() { await sleep(1); - this.app.bootLog.push('didReady'); + this.agent.bootLog.push('didReady'); + this.logger.info('agent is ready'); } async beforeClose() { await sleep(1); - this.app.bootLog.push('beforeClose'); + this.agent.bootLog.push('beforeClose'); } async serverDidReady() { await sleep(1); - this.app.bootLog.push('serverDidReady'); + this.agent.bootLog.push('serverDidReady'); } }; diff --git a/test/fixtures/apps/boot-app/app.js b/test/fixtures/apps/boot-app/app.js index 04ede16266..fdd495a054 100644 --- a/test/fixtures/apps/boot-app/app.js +++ b/test/fixtures/apps/boot-app/app.js @@ -1,11 +1,14 @@ 'use strict'; +const assert = require('assert'); const sleep = require('mz-modules/sleep'); +const BaseHookClass = require('../../../../lib/core/base_hook_class'); -module.exports = class { +module.exports = class extends BaseHookClass { constructor(app) { + super(app); app.bootLog = []; - this.app = app; + assert(this.config); } configDidLoad() { @@ -25,6 +28,7 @@ module.exports = class { async didReady() { await sleep(1); this.app.bootLog.push('didReady'); + this.logger.info('app is ready'); } async beforeClose() { diff --git a/test/index.test.js b/test/index.test.js index b18199c967..6b52ae6fee 100644 --- a/test/index.test.js +++ b/test/index.test.js @@ -11,6 +11,7 @@ describe('test/index.test.js', () => { 'AppWorkerLoader', 'Application', 'BaseContextClass', + 'Boot', 'Controller', 'Service', 'Subscription', diff --git a/test/lib/core/loader/load_boot.test.js b/test/lib/core/loader/load_boot.test.js index f99ee87e9d..b1c3432f6c 100644 --- a/test/lib/core/loader/load_boot.test.js +++ b/test/lib/core/loader/load_boot.test.js @@ -12,7 +12,9 @@ describe('test/lib/core/loader/load_boot.test.js', () => { }); it('should load app.js', async () => { + app.mockLog(); await app.close(); + app.expectLog('app is ready'); assert.deepStrictEqual(app.bootLog, [ 'configDidLoad', 'didLoad', 'willReady', diff --git a/test/lib/egg.test.js b/test/lib/egg.test.js index efedb144f9..8e3523aae3 100644 --- a/test/lib/egg.test.js +++ b/test/lib/egg.test.js @@ -135,7 +135,7 @@ describe('test/lib/egg.test.js', () => { it('should read timing data', function* () { let json = readJson(path.join(baseDir, `run/agent_timing_${process.pid}.json`)); - assert(json.length === 39); + assert(json.length === 40); assert(json[0].name === 'Application Start'); assert(json[0].pid === process.pid);