1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-02-04 00:18:01 +01:00

Implement support for logger provider.

This allows the users of 'unleash-server' to programatically
change the logger implemnentation. #175
This commit is contained in:
ivaosthu 2017-08-04 16:03:15 +02:00 committed by Ivar Conradi Østhus
parent a70f7f7046
commit f5e9ca3bbe
38 changed files with 108 additions and 127 deletions

View File

@ -37,4 +37,37 @@ Available unleash options includes:
- databaseUrl
- port
- logLevel - ('INFO', 'ERROR',)
## How do I configure the log output?
By default, `unleash` uses [log4js](https://github.com/nomiddlename/log4js-node) to log important information. It is possible to swap out the logger provider (only when using Unleash programatically). This enables filtering of log levels and easy redirection of output streams.
### What is a logger provider?
A logger provider is a function which takes the name of a logger and returns a logger implementation. For instance, the following code snippet shows how a logger provider for the global `console` object could be written:
```javascript
function consoleLoggerProvider (name) {
// do something with the name
return {
debug: console.debug.bind(console),
info: console.info.bind(console),
warn: console.warn.bind(console),
error: console.error.bind(console)
};
}
```
The logger interface with its `debug`, `info`, `warn` and `error` methods expects format string support as seen in `debug` or the JavaScript `console` object. Many commonly used logging implementations cover this API, e.g. bunyan, pino or winston.
### How do I set a logger provider?
Custom logger providers need to be set *before requiring the `unleash-server` module*. The following example shows how this can be done:
```javascript
// first configure the logger provider
const unleashLogger = require('unleash-server/logger');
unleashLogger.setLoggerProvider(consoleLoggerProvider);
// then require unleash-server and continue as normal
const unleash = require('unleash-server');

View File

@ -6,8 +6,7 @@ const bodyParser = require('body-parser');
const cookieParser = require('cookie-parser');
const validator = require('express-validator');
const responseTime = require('response-time');
const log4js = require('log4js');
const logger = require('./logger');
const logger = require('./logger')('app.js');
const routes = require('./routes');
const path = require('path');
const errorHandler = require('errorhandler');
@ -56,12 +55,10 @@ module.exports = function(config) {
app.use(bodyParser.json({ strict: false }));
if (config.enableRequestLogger) {
app.use(
log4js.connectLogger(logger, {
format: ':status :method :url :response-timems',
level: 'auto', // 3XX=WARN, 4xx/5xx=ERROR
})
);
app.use((req, res, next) => {
next();
logger.info(`${res.statusCode} ${req.method} ${req.path}`);
});
}
if (typeof config.preRouterHook === 'function') {

View File

@ -1,7 +1,7 @@
/* eslint camelcase: "off" */
'use strict';
const logger = require('../logger');
const logger = require('../logger')('client-instance-store.js');
const COLUMNS = [
'app_name',
'instance_id',

View File

@ -1,6 +1,6 @@
'use strict';
const logger = require('../logger');
const logger = require('../logger')('client-metrics-db.js');
const METRICS_COLUMNS = ['id', 'created_at', 'metrics'];
const TABLE = 'client_metrics';

View File

@ -1,6 +1,6 @@
'use strict';
const logger = require('../logger');
const logger = require('../logger')('client-metrics-store.js');
const { EventEmitter } = require('events');

View File

@ -6,7 +6,7 @@ const {
FEATURE_ARCHIVED,
FEATURE_REVIVED,
} = require('../event-type');
const logger = require('../logger');
const logger = require('../logger')('client-toggle-store.js');
const NotFoundError = require('../error/notfound-error');
const FEATURE_COLUMNS = [
'name',

View File

@ -5,7 +5,7 @@ const {
STRATEGY_DELETED,
STRATEGY_UPDATED,
} = require('../event-type');
const logger = require('../logger');
const logger = require('../logger')('strategy-store.js');
const NotFoundError = require('../error/notfound-error');
const STRATEGY_COLUMNS = ['name', 'description', 'parameters', 'built_in'];
const TABLE = 'strategies';

View File

@ -3,11 +3,6 @@
const { test } = require('ava');
const eventDiffer = require('./event-differ');
const { FEATURE_CREATED, FEATURE_UPDATED } = require('./event-type');
const logger = require('./logger');
test.beforeEach(() => {
logger.setLevel('FATAL');
});
test('fails if events include an unknown event type', t => {
const events = [

View File

@ -1,19 +1,33 @@
'use strict';
const log4js = require('log4js');
log4js.configure({
appenders: [{ type: 'console' }],
});
const logger = log4js.getLogger('unleash');
let loggerProvider = getDefaultLogProvider();
// TODO: make level configurable
module.exports = exports = function getLogger(name) {
return loggerProvider(name);
};
exports.setLoggerProvider = function setLoggerProvider(provider) {
loggerProvider = provider;
};
function getDefaultLogProvider() {
let level;
if (process.env.NODE_ENV === 'production') {
logger.setLevel(log4js.levels.ERROR);
level = log4js.levels.ERROR;
} else if (process.env.NODE_ENV === 'test') {
logger.setLevel(log4js.levels.ERROR);
level = log4js.levels.FATAL;
} else {
logger.setLevel(log4js.levels.DEBUG);
level = log4js.levels.DEBUG;
}
module.exports = logger;
log4js.configure({
appenders: [{ type: 'console' }],
levels: {
'[all]': level,
},
});
return log4js.getLogger;
}

22
lib/logger.test.js Normal file
View File

@ -0,0 +1,22 @@
'use strict';
const { test } = require('ava');
const createLogger = require('./logger');
const logger = require('../logger');
const sinon = require('sinon');
test('should expose a setLoggerProvider function', t => {
t.true(logger.setLoggerProvider instanceof Function);
});
test('should create logger via custom logger provider', t => {
const provider = sinon.stub();
const loggerName = 'test';
const loggerImpl = {};
provider.withArgs(loggerName).returns(loggerImpl);
logger.setLoggerProvider(provider);
const log = createLogger(loggerName);
t.is(log, loggerImpl);
});

View File

@ -3,16 +3,11 @@
const { test } = require('ava');
const store = require('./../../../test/fixtures/store');
const supertest = require('supertest');
const logger = require('../../logger');
const getApp = require('../../app');
const { EventEmitter } = require('events');
const eventBus = new EventEmitter();
test.beforeEach(() => {
logger.setLevel('FATAL');
});
function getSetup() {
const stores = store.createStores();
const app = getApp({

View File

@ -2,7 +2,7 @@
const { Router } = require('express');
const logger = require('../../logger');
const logger = require('../../logger')('/admin-api/archive.js');
const { FEATURE_REVIVED } = require('../../event-type');
const ValidationError = require('../../error/validation-error');
const validateRequest = require('../../error/validate-request');

View File

@ -4,7 +4,6 @@ const { test } = require('ava');
const store = require('./../../../test/fixtures/store');
const supertest = require('supertest');
const logger = require('../../logger');
const getApp = require('../../app');
const { EventEmitter } = require('events');
@ -22,10 +21,6 @@ function getSetup() {
return { base, eventStore: stores.eventStore, request: supertest(app) };
}
test.beforeEach(() => {
logger.setLevel('FATAL');
});
test('should get empty events list via admin', t => {
t.plan(1);
const { request, base } = getSetup();

View File

@ -3,7 +3,7 @@
const { Router } = require('express');
const joi = require('joi');
const logger = require('../../logger');
const logger = require('../../logger')('/admin-api/feature.js');
const {
FEATURE_CREATED,
FEATURE_UPDATED,

View File

@ -3,16 +3,11 @@
const { test } = require('ava');
const store = require('./../../../test/fixtures/store');
const supertest = require('supertest');
const logger = require('../../logger');
const getApp = require('../../app');
const { EventEmitter } = require('events');
const eventBus = new EventEmitter();
test.beforeEach(() => {
logger.setLevel('FATAL');
});
function getSetup() {
const base = `/random${Math.round(Math.random() * 1000)}`;
const stores = store.createStores();

View File

@ -2,7 +2,7 @@
const { Router } = require('express');
const logger = require('../../logger');
const logger = require('../../logger')('/admin-api/metrics.js');
const ClientMetrics = require('../../client-metrics');
const { catchLogAndSendErrorResponse } = require('./route-utils');

View File

@ -3,16 +3,11 @@
const { test } = require('ava');
const store = require('./../../../test/fixtures/store');
const supertest = require('supertest');
const logger = require('../../logger');
const getApp = require('../../app');
const { EventEmitter } = require('events');
const eventBus = new EventEmitter();
test.beforeEach(() => {
logger.setLevel('FATAL');
});
function getSetup() {
const stores = store.createStores();
const app = getApp({

View File

@ -1,6 +1,6 @@
'use strict';
const logger = require('../../logger');
const logger = require('../../logger')('route-utils.js');
const catchLogAndSendErrorResponse = (err, res) => {
logger.error(err);

View File

@ -4,7 +4,7 @@ const { Router } = require('express');
const joi = require('joi');
const eventType = require('../../event-type');
const logger = require('../../logger');
const logger = require('../../logger')('/admin-api/strategy.js');
const NameExistsError = require('../../error/name-exists-error');
const extractUser = require('../../extract-user');
const strategySchema = require('./strategy-schema');

View File

@ -4,7 +4,6 @@ const { test } = require('ava');
const store = require('./../../../test/fixtures/store');
const supertest = require('supertest');
const getApp = require('../../app');
const logger = require('../../logger');
const { EventEmitter } = require('events');
const eventBus = new EventEmitter();
@ -25,10 +24,6 @@ function getSetup() {
};
}
test.beforeEach(() => {
logger.setLevel('FATAL');
});
test('add version numbers for /stategies', t => {
t.plan(1);
const { request, base } = getSetup();

View File

@ -3,16 +3,11 @@
const { test } = require('ava');
const store = require('./../../test/fixtures/store');
const supertest = require('supertest');
const logger = require('../logger');
const getApp = require('../app');
const { EventEmitter } = require('events');
const eventBus = new EventEmitter();
test.beforeEach(() => {
logger.setLevel('FATAL');
});
test('should use enable prometheus', t => {
t.plan(0);
const stores = store.createStores();

View File

@ -3,16 +3,11 @@
const { test } = require('ava');
const store = require('./../../../test/fixtures/store');
const supertest = require('supertest');
const logger = require('../../logger');
const getApp = require('../../app');
const { EventEmitter } = require('events');
const eventBus = new EventEmitter();
test.beforeEach(() => {
logger.setLevel('FATAL');
});
function getSetup() {
const base = `/random${Math.round(Math.random() * 1000)}`;
const stores = store.createStores();

View File

@ -2,7 +2,7 @@
const { Router } = require('express');
const joi = require('joi');
const logger = require('../../logger');
const logger = require('../../logger')('client-api/metrics.js');
const { clientMetricsSchema } = require('./metrics-schema');

View File

@ -3,16 +3,11 @@
const { test } = require('ava');
const store = require('./../../../test/fixtures/store');
const supertest = require('supertest');
const logger = require('../../logger');
const getApp = require('../../app');
const { EventEmitter } = require('events');
const eventBus = new EventEmitter();
test.beforeEach(() => {
logger.setLevel('FATAL');
});
function getSetup() {
const stores = store.createStores();
const app = getApp({

View File

@ -2,7 +2,7 @@
const { Router } = require('express');
const joi = require('joi');
const logger = require('../../logger');
const logger = require('../../logger')('/client-api/register.js');
const { clientRegisterSchema } = require('./register-schema');

View File

@ -3,16 +3,11 @@
const { test } = require('ava');
const store = require('./../../../test/fixtures/store');
const supertest = require('supertest');
const logger = require('../../logger');
const getApp = require('../../app');
const { EventEmitter } = require('events');
const eventBus = new EventEmitter();
test.beforeEach(() => {
logger.setLevel('FATAL');
});
function getSetup() {
const stores = store.createStores();
const app = getApp({

View File

@ -1,6 +1,6 @@
'use strict';
const logger = require('../logger');
const logger = require('../logger')('health-check.js');
const { Router } = require('express');
exports.router = function(config) {

View File

@ -3,16 +3,11 @@
const { test } = require('ava');
const store = require('./../../test/fixtures/store');
const supertest = require('supertest');
const logger = require('../logger');
const getApp = require('../app');
const { EventEmitter } = require('events');
const eventBus = new EventEmitter();
test.beforeEach(() => {
logger.setLevel('FATAL');
});
function getSetup() {
const stores = store.createStores();
const db = stores.db;

View File

@ -3,16 +3,11 @@
const { test } = require('ava');
const store = require('./../../test/fixtures/store');
const supertest = require('supertest');
const logger = require('../logger');
const getApp = require('../app');
const { EventEmitter } = require('events');
const eventBus = new EventEmitter();
test.beforeEach(() => {
logger.setLevel('FATAL');
});
function getSetup() {
const base = `/random${Math.round(Math.random() * 1000)}`;
const stores = store.createStores();

View File

@ -2,7 +2,7 @@
const { EventEmitter } = require('events');
const logger = require('./logger');
const logger = require('./logger')('server-impl.js');
const migrator = require('../migrator');
const getApp = require('./app');

5
logger.js Normal file
View File

@ -0,0 +1,5 @@
'use strict';
const logger = require('./lib/logger');
exports.setLoggerProvider = logger.setLoggerProvider;

View File

@ -39,7 +39,7 @@
"db-migrate": "db-migrate",
"lint": "eslint .",
"pretest": "npm run lint",
"test": "PORT=4243 ava lib/*.test.js lib/**/*.test.js lib/**/**/*.test.js lib/**/**/**/*.test.js test",
"test": "NODE_ENV=test PORT=4243 ava lib/*.test.js lib/**/*.test.js lib/**/**/*.test.js lib/**/**/**/*.test.js test",
"test:docker": "./scripts/docker-postgres.sh",
"test:watch": "npm run test -- --watch",
"test:pg-virtualenv": "pg_virtualenv npm run test:pg-virtualenv-chai",

View File

@ -2,11 +2,6 @@
const { test } = require('ava');
const { setupApp } = require('./../../helpers/test-helper');
const logger = require('../../../../lib/logger');
test.beforeEach(() => {
logger.setLevel('FATAL');
});
test.serial('returns events', async t => {
t.plan(0);

View File

@ -2,11 +2,6 @@
const { test } = require('ava');
const { setupApp } = require('./../../helpers/test-helper');
const logger = require('../../../../lib/logger');
test.beforeEach(() => {
logger.setLevel('FATAL');
});
test.serial('returns three archived toggles', async t => {
t.plan(1);

View File

@ -2,11 +2,6 @@
const { test } = require('ava');
const { setupApp } = require('./../../helpers/test-helper');
const logger = require('../../../../lib/logger');
test.beforeEach(() => {
logger.setLevel('FATAL');
});
test.serial('returns three feature toggles', async t => {
const { request, destroy } = await setupApp('feature_api_serial');

View File

@ -2,11 +2,6 @@
const { test } = require('ava');
const { setupApp } = require('./../../helpers/test-helper');
const logger = require('../../../../lib/logger');
test.beforeEach(() => {
logger.setLevel('FATAL');
});
test.serial('should register client', async t => {
t.plan(0);

View File

@ -2,11 +2,6 @@
const { test } = require('ava');
const { setupApp } = require('./../../helpers/test-helper');
const logger = require('../../../../lib/logger');
test.beforeEach(() => {
logger.setLevel('FATAL');
});
test.serial('gets all strategies', async t => {
t.plan(1);

View File

@ -2,11 +2,6 @@
const { test } = require('ava');
const { setupApp } = require('./helpers/test-helper');
const logger = require('../../lib/logger');
test.beforeEach(() => {
logger.setLevel('FATAL');
});
test('returns health good', async t => {
t.plan(0);