Skip to content

Commit

Permalink
Merge pull request #16 from kitesjs/dev-logger
Browse files Browse the repository at this point in the history
Dev logger
  • Loading branch information
vunb authored Aug 1, 2019
2 parents f89e05f + dc937cf commit 5b6ccee
Show file tree
Hide file tree
Showing 6 changed files with 161 additions and 33 deletions.
42 changes: 38 additions & 4 deletions packages/core/engine/kites-instance.spec.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import * as appRoot from 'app-root-path';
import { assert, expect } from 'chai';
import { assert, expect, should } from 'chai';
import * as fs from 'fs';
import * as path from 'path';
import { IKites, KitesInstance } from './kites-instance';

import * as stdMocks from 'std-mocks';
import { transports } from 'winston';
import { KitesExtension } from '../extensions/extensions';
import { DebugTransport } from '../logger';
import { engine } from './kites-factory';

function safeUnlink(fn: string) {
Expand Down Expand Up @@ -108,15 +110,23 @@ describe('kites logs', () => {

stdMocks.restore();
let stdoutContent = stdMocks.flush();
expect(stdoutContent.stdout.length).eq(0, 'stdout is empty');
expect(stdoutContent.stdout.length).eq(0, 'stdout must be empty');

let allTransportAreSilent = Object.keys(app.logger.transports).every((name) => app.logger.transports[name].silent === true);
let allTransportAreSilent = app.logger.transports.every((x) => x.silent === true);
expect(allTransportAreSilent).eq(true, 'all transports are silent');
});

it('should have Debug transport enabled by default', () => {
return engine()
.init()
.then((app) => {
expect(app.logger.transports.some(x => x instanceof transports.Console)).eq(true, 'default transport');
});
});

it('should fail to configure custom transport that does not have enough options', async () => {

await engine({
return await engine({
logger: {
console: {
transport: 'console'
Expand All @@ -130,6 +140,30 @@ describe('kites logs', () => {
});
});

it('should not load disabled transports', async () => {

return await engine({
logger: {
console: {
level: 'debug',
transport: 'console'
},
file: {
enabled: false,
level: 'debug',
transport: 'file',
filename: './test.log'
}
}
})
.init()
.then((app) => {
expect(app.logger.transports.length).eq(1);
expect(app.logger.transports.some(x => x instanceof transports.Console)).eq(true);
expect(app.logger.transports.some(x => x instanceof transports.File)).eq(false);
});
});

});

describe('kites initializeListeners', () => {
Expand Down
98 changes: 86 additions & 12 deletions packages/core/engine/kites-instance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@ import * as fs from 'fs';
import * as _ from 'lodash';
// import * as nconf from 'nconf';
import * as path from 'path';
import { Logger } from 'winston';
import { Logger, transports } from 'winston';

import { EventEmitter } from 'events';
import { ExtensionsManager } from '../extensions/extensions-manager';
import createDebugLogger, { DebugTransport } from '../logger';
import { createLogger } from '../logger';
import { EventCollectionEmitter } from './event-collection';

import { Type } from '@kites/common';
Expand Down Expand Up @@ -92,7 +92,7 @@ export class KitesInstance extends EventEmitter implements IKites {
this.iocContainer = new Container();

// properties
this.logger = createDebugLogger(this.name);
this.logger = createLogger(this.name, this.options.logger);
this.fnAfterConfigLoaded = () => this;
this.isReady = new Promise((resolve) => {
this.on('initialized', resolve);
Expand Down Expand Up @@ -255,13 +255,14 @@ export class KitesInstance extends EventEmitter implements IKites {
* Kites initialize
*/
async init() {
this._initOptions();
this.logger.info(`Initializing ${this.name}@${this.version} in mode "${this.options.env}"${this.options.loadConfig ? ', using configuration file ' + this.options.configFile : ''}`);

// Keep silent if the option configured
if (this.options.logger && this.options.logger.silent === true) {
this._silentLogs(this.logger);
}

this._initOptions();
this.logger.info(`Initializing ${this.name}@${this.version} in mode "${this.options.env}"${this.options.loadConfig ? ', using configuration file ' + this.options.configFile : ''}`);

await this.extensionsManager.init();
await this.initializeListeners.fire();

Expand All @@ -278,15 +279,13 @@ export class KitesInstance extends EventEmitter implements IKites {
this.fnAfterConfigLoaded(this);
}

// return this._configureWinstonTransports(this.options.logger);
return this._configureWinstonTransports(this.options.logger);
}

private _silentLogs(logger: Logger) {
if (logger.transports) {
_.keys(logger.transports).forEach((name) => {
logger.transports[name].silent = true;
});
}
logger.transports.forEach(x => {
x.silent = true;
});
}

private _loadConfig() {
Expand Down Expand Up @@ -329,4 +328,79 @@ export class KitesInstance extends EventEmitter implements IKites {
this.options = nconf.get();
}

private _configureWinstonTransports(options: any) {
options = options || {};

var knownTransports: any = {
console: transports.Console,
file: transports.File,
http: transports.Http,
stream: transports.Stream,
};

var knownOptions = ['transport', 'module', 'enabled'];

// tslint:disable-next-line:forin
for (let trName in options) {
var tranOpts = options[trName];
if (!tranOpts || typeof tranOpts !== 'object' || _.isArray(tranOpts)) {
continue;
}

if (!tranOpts.transport || typeof tranOpts.transport !== 'string') {
throw new Error(`invalid option for transport object ${trName}, option "transport" is not specified or has an incorrect value, must be a string with a valid value. check your "logger" config`);
}

if (!tranOpts.level || typeof tranOpts.level !== 'string') {
throw new Error(`invalid option for transport object ${trName}, option "level" is not specified or has an incorrect value, must be a string with a valid value. check your "logger" config`);
}

if (tranOpts.enabled === false) {
continue;
}

// add transport
if (knownTransports[tranOpts.transport]) {
if (this.logger.transports.some((x: any) => x.name === trName)) {
continue;
}
const transport = knownTransports[tranOpts.transport] as any;
const opts = _.extend(_.omit(tranOpts, knownOptions), { name: trName });
this.logger.add(new transport(opts));
} else {
if (typeof tranOpts.module !== 'string') {
throw new Error(`invalid option for transport object "${trName}", option "module" has an incorrect value, must be a string with a module name. check your "logger" config`);
}

try {
let transportModule = require(tranOpts.module);
let winstonTransport: any = transports;
if (typeof winstonTransport[tranOpts.transport] === 'function') {
transportModule = winstonTransport[tranOpts.transport];
} else if (typeof transportModule[tranOpts.transport] === 'function') {
transportModule = transportModule[tranOpts.transport];
}

if (typeof transportModule !== 'function') {
throw new Error(`invalid option for transport object "${trName}", option module "${tranOpts.module}" does not export a valid transport. check your "logger" config`);
}

const opts = _.extend(_.omit(tranOpts, knownOptions), { name: trName });

this.logger.add(new transportModule(opts));

} catch (err) {
if (err.code === 'MODULE_NOT_FOUND') {
throw new Error(
`invalid option for transport object "${trName}", module "${tranOpts.module}" in "module" option could not be found. are you sure that you have installed it?. check your "logger" config`);
}

throw err;
}
}

}

}

}
4 changes: 2 additions & 2 deletions packages/core/extensions/discover.spec.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { expect } from 'chai';
import { join } from 'path';
import createDebugLogger from '../logger';
import { createLogger } from '../logger';
import { discover } from './discover';

describe('Discover extensions', () => {
it('should load an extension', async () => {
const rootDirectory = join(__dirname, '../test');
let extensions: any = await discover({
logger: createDebugLogger('discover'),
logger: createLogger('discover'),
rootDirectory: rootDirectory
});
console.log('rootDirectory: ', rootDirectory);
Expand Down
6 changes: 3 additions & 3 deletions packages/core/extensions/location-cache.spec.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { expect } from 'chai';
import { join, resolve } from 'path';
import { join } from 'path';

import createDebugLogger from '../logger';
import { createLogger } from '../logger';
import * as cache from './location-cache';

describe('Location cache', () => {
Expand All @@ -13,7 +13,7 @@ describe('Location cache', () => {
it('should get one and save it!', async () => {
const rootDirectory = join(__dirname, '../test');
let extensions: any = await cache.get({
logger: createDebugLogger('location-cache'),
logger: createLogger('location-cache'),
rootDirectory: rootDirectory
});
console.log('Found: ', extensions, rootDirectory);
Expand Down
4 changes: 3 additions & 1 deletion packages/core/logger/debug-transport.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@ import debug from 'debug';
import Transport from 'winston-transport';

export class DebugTransport extends Transport {
public name: string;

private debugger: debug.IDebugger;

constructor(options?: Transport.TransportStreamOptions) {
constructor(options?: Transport.TransportStreamOptions, name?: string) {
super(options);
this.debugger = debug('kites');
this.name = name || 'debug';
}

public log(info, callback: Function) {
Expand Down
40 changes: 29 additions & 11 deletions packages/core/logger/index.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,27 @@
import * as path from 'path';
import * as winston from 'winston';
import { format, Logger, loggers } from 'winston';
import { DebugTransport } from './debug-transport';

export { DebugTransport } from './debug-transport';
function createLogger(name: string, options?: any): Logger {
if (!loggers.has(name)) {
// add default Debug transport?
const defaultTransports = Object.keys(options || {}).length > 0 ? [] : [
new DebugTransport(options, name),
];

export default function createDebugLogger(name: string, options?: any): winston.Logger {
if (!winston.loggers.has(name)) {
const debugTransport = new DebugTransport();
winston.loggers.add(name, {
transports: [debugTransport],
loggers.add(name, {
exitOnError: false,
level: 'info',
format: format.combine(
format.label({ label: name }),
format.colorize(),
format.timestamp(),
format.printf(({ level, message, label, timestamp }) => `${timestamp} [${label}] ${level}: ${message}`)
),
transports: defaultTransports,
});

winston.loggers.get(name).on('error', (err: any) => {
loggers.get(name).on('error', (err: any) => {
if (err.code === 'ENOENT') {
let msg = err;
if (path.dirname(err.path) === '.') {
Expand All @@ -28,9 +38,17 @@ export default function createDebugLogger(name: string, options?: any): winston.
});
} else {
// remove all transports and add default Debug transport
winston.loggers.get(name).clear();
winston.loggers.get(name).add(new DebugTransport(options));
loggers.get(name).clear();

if (Object.keys(options || {}).length === 0) {
loggers.get(name).add(new DebugTransport(options, name));
}
}

return winston.loggers.get(name);
return loggers.get(name);
}

export {
createLogger,
DebugTransport
};

0 comments on commit 5b6ccee

Please sign in to comment.