1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-01-31 00:16:47 +01:00

fix: LogProvider as option injected to unleash.

Instead of instructing users to do static calls
in to Unleash, she should instead be allwed to
specify the log provider as an option to Unleash.

This commit introduces the "getLogger" option,
a function responsible for creating a logger.
This commit is contained in:
ivaosthu 2019-04-30 21:14:23 +02:00 committed by Ivar Conradi Østhus
parent 4410d5389b
commit de16a7854d
46 changed files with 167 additions and 138 deletions

View File

@ -58,6 +58,7 @@ Available unleash options include:
- `unsecure` - (default) will use simple cookie based authentication. UI will require the user to specify an email in order to use unleash.
- `custom` - use this when you implement your own custom authentication logic.
- **ui** (object) - Set of UI specific overrides. You may set the following keys: `headerBackground`, `environment`, `slogan`.
- **getLogger** (function) - Used to register a [custom log provider](#How do I configure the log output).
### 3. Docker
@ -69,14 +70,10 @@ docker run -d -e DATABASE_URL=postgres://user:pass@10.200.221.11:5432/unleash un
## 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 programmatically). 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:
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 programmatically). You do this by providing an implementation of the **getLogger** function as This enables filtering of log levels and easy redirection of output streams.
```javascript
function consoleLoggerProvider(name) {
function getLogger(name) {
// do something with the name
return {
debug: console.log,
@ -88,16 +85,3 @@ function consoleLoggerProvider(name) {
```
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/lib/logger');
unleashLogger.setLoggerProvider(consoleLoggerProvider);
// then require unleash-server and continue as normal
const unleash = require('unleash-server');
```

View File

@ -3,6 +3,7 @@
const test = require('ava');
const express = require('express');
const proxyquire = require('proxyquire');
const getLogger = require('../test/fixtures/no-logger');
const getApp = proxyquire('./app', {
'./routes': class Index {
router() {
@ -12,13 +13,14 @@ const getApp = proxyquire('./app', {
});
test('should not throw when valid config', t => {
const app = getApp({});
const app = getApp({ getLogger });
t.true(typeof app.listen === 'function');
});
test('should call preHook', t => {
let called = 0;
getApp({
getLogger,
preHook: () => {
called++;
},
@ -29,6 +31,7 @@ test('should call preHook', t => {
test('should call preRouterHook', t => {
let called = 0;
getApp({
getLogger,
preRouterHook: () => {
called++;
},

View File

@ -1,7 +1,6 @@
/* eslint camelcase: "off" */
'use strict';
const logger = require('../logger')('client-instance-store.js');
const COLUMNS = [
'app_name',
'instance_id',
@ -24,8 +23,9 @@ const mapRow = row => ({
});
class ClientInstanceStore {
constructor(db) {
constructor(db, getLogger) {
this.db = db;
this.logger = getLogger('client-instance-store.js');
const clearer = () => this._removeInstancesOlderThanTwoDays();
setTimeout(clearer, 10).unref();
setInterval(clearer, ONE_DAY).unref();
@ -35,7 +35,9 @@ class ClientInstanceStore {
this.db(TABLE)
.whereRaw("created_at < now() - interval '2 days'")
.del()
.then(res => res > 0 && logger.info(`Deleted ${res} instances`));
.then(
res => res > 0 && this.logger.info(`Deleted ${res} instances`)
);
}
updateRow(details) {

View File

@ -1,7 +1,5 @@
'use strict';
const logger = require('../logger')('client-metrics-db.js');
const METRICS_COLUMNS = ['id', 'created_at', 'metrics'];
const TABLE = 'client_metrics';
@ -14,8 +12,9 @@ const mapRow = row => ({
});
class ClientMetricsDb {
constructor(db) {
constructor(db, getLogger) {
this.db = db;
this.logger = getLogger('client-metrics-db.js');
// Clear old metrics regulary
const clearer = () => this.removeMetricsOlderThanOneHour();
@ -27,7 +26,7 @@ class ClientMetricsDb {
this.db(TABLE)
.whereRaw("created_at < now() - interval '1 hour'")
.del()
.then(res => res > 0 && logger.info(`Deleted ${res} metrics`));
.then(res => res > 0 && this.logger.info(`Deleted ${res} metrics`));
}
// Insert new client metrics

View File

@ -1,14 +1,13 @@
'use strict';
const logger = require('../logger')('client-metrics-store.js');
const { EventEmitter } = require('events');
const TEN_SECONDS = 10 * 1000;
class ClientMetricsStore extends EventEmitter {
constructor(metricsDb, pollInterval = TEN_SECONDS) {
constructor(metricsDb, getLogger, pollInterval = TEN_SECONDS) {
super();
this.logger = getLogger('client-metrics-store.js');
this.metricsDb = metricsDb;
this.highestIdSeen = 0;
@ -20,7 +19,7 @@ class ClientMetricsStore extends EventEmitter {
const metrics = await this.metricsDb.getMetricsLastHour();
this._emitMetrics(metrics);
} catch (err) {
logger.error('Error fetching metrics last hour', err);
this.logger.error('Error fetching metrics last hour', err);
}
this._startPoller(pollInterval);
this.emit('ready');

View File

@ -3,6 +3,7 @@
const test = require('ava');
const ClientMetricStore = require('./client-metrics-store');
const lolex = require('lolex');
const getLogger = require('../../test/fixtures/no-logger');
function getMockDb() {
const list = [
@ -24,7 +25,7 @@ function getMockDb() {
test.cb('should call database on startup', t => {
const mock = getMockDb();
const store = new ClientMetricStore(mock);
const store = new ClientMetricStore(mock, getLogger);
t.plan(2);
@ -42,7 +43,7 @@ test.cb('should start poller even if inital database fetch fails', t => {
const mock = getMockDb();
mock.getMetricsLastHour = () => Promise.reject('oops');
const store = new ClientMetricStore(mock, 100);
const store = new ClientMetricStore(mock, getLogger, 100);
const metrics = [];
store.on('metrics', m => metrics.push(m));
@ -63,7 +64,7 @@ test.cb('should poll for updates', t => {
const clock = lolex.install();
const mock = getMockDb();
const store = new ClientMetricStore(mock, 100);
const store = new ClientMetricStore(mock, getLogger, 100);
const metrics = [];
store.on('metrics', m => metrics.push(m));

View File

@ -8,7 +8,6 @@ const {
FEATURE_IMPORT,
DROP_FEATURES,
} = require('../event-type');
const logger = require('../logger')('client-toggle-store.js');
const NotFoundError = require('../error/notfound-error');
const FEATURE_COLUMNS = [
'name',
@ -21,8 +20,9 @@ const FEATURE_COLUMNS = [
const TABLE = 'features';
class FeatureToggleStore {
constructor(db, eventStore) {
constructor(db, eventStore, getLogger) {
this.db = db;
this.getLogger = getLogger('client-toggle-store.js');
eventStore.on(FEATURE_CREATED, event =>
this._createFeature(event.data)
);
@ -111,7 +111,7 @@ class FeatureToggleStore {
return this.db(TABLE)
.insert(this.eventDataToRow(data))
.catch(err =>
logger.error('Could not insert feature, error was: ', err)
this.logger.error('Could not insert feature, error: ', err)
);
}
@ -120,7 +120,7 @@ class FeatureToggleStore {
.where({ name: data.name })
.update(this.eventDataToRow(data))
.catch(err =>
logger.error('Could not update feature, error was: ', err)
this.logger.error('Could not update feature, error: ', err)
);
}
@ -129,7 +129,7 @@ class FeatureToggleStore {
.where({ name })
.update({ archived: 1, enabled: 0 })
.catch(err => {
logger.error('Could not archive feature, error was: ', err);
this.logger.error('Could not archive feature, error: ', err);
});
}
@ -138,7 +138,7 @@ class FeatureToggleStore {
.where({ name })
.update({ archived: 0, enabled: 0 })
.catch(err =>
logger.error('Could not archive feature, error was: ', err)
this.logger.error('Could not archive feature, error: ', err)
);
}
@ -151,7 +151,7 @@ class FeatureToggleStore {
result === 0 ? this.db(TABLE).insert(rowData) : result
)
.catch(err =>
logger.error('Could not import feature, error was: ', err)
this.logger.error('Could not import feature, error: ', err)
);
}
@ -159,7 +159,7 @@ class FeatureToggleStore {
return this.db(TABLE)
.delete()
.catch(err =>
logger.error('Could not drop features, error was: ', err)
this.logger.error('Could not drop features, error: ', err)
);
}
}

View File

@ -10,17 +10,18 @@ const ClientMetricsStore = require('./client-metrics-store');
const ClientApplicationsStore = require('./client-applications-store');
module.exports.createStores = config => {
const getLogger = config.getLogger;
const db = createDb(config);
const eventStore = new EventStore(db);
const clientMetricsDb = new ClientMetricsDb(db);
const eventStore = new EventStore(db, getLogger);
const clientMetricsDb = new ClientMetricsDb(db, getLogger);
return {
db,
eventStore,
featureToggleStore: new FeatureToggleStore(db, eventStore),
strategyStore: new StrategyStore(db, eventStore),
clientApplicationsStore: new ClientApplicationsStore(db),
clientInstanceStore: new ClientInstanceStore(db),
clientMetricsStore: new ClientMetricsStore(clientMetricsDb),
featureToggleStore: new FeatureToggleStore(db, eventStore, getLogger),
strategyStore: new StrategyStore(db, eventStore, getLogger),
clientApplicationsStore: new ClientApplicationsStore(db, getLogger),
clientInstanceStore: new ClientInstanceStore(db, getLogger),
clientMetricsStore: new ClientMetricsStore(clientMetricsDb, getLogger),
};
};

View File

@ -7,14 +7,14 @@ const {
STRATEGY_IMPORT,
DROP_STRATEGIES,
} = require('../event-type');
const logger = require('../logger')('strategy-store.js');
const NotFoundError = require('../error/notfound-error');
const STRATEGY_COLUMNS = ['name', 'description', 'parameters', 'built_in'];
const TABLE = 'strategies';
class StrategyStore {
constructor(db, eventStore) {
constructor(db, eventStore, getLogger) {
this.db = db;
this.logger = getLogger('strategy-store.js');
eventStore.on(STRATEGY_CREATED, event =>
this._createStrategy(event.data)
);
@ -90,7 +90,7 @@ class StrategyStore {
this.db(TABLE)
.insert(this.eventDataToRow(data))
.catch(err =>
logger.error('Could not insert strategy, error was: ', err)
this.logger.error('Could not insert strategy, error: ', err)
);
}
@ -99,7 +99,7 @@ class StrategyStore {
.where({ name: data.name })
.update(this.eventDataToRow(data))
.catch(err =>
logger.error('Could not update strategy, error was: ', err)
this.logger.error('Could not update strategy, error: ', err)
);
}
@ -108,7 +108,7 @@ class StrategyStore {
.where({ name })
.del()
.catch(err => {
logger.error('Could not delete strategy, error was: ', err);
this.logger.error('Could not delete strategy, error: ', err);
});
}
@ -121,7 +121,7 @@ class StrategyStore {
result === 0 ? this.db(TABLE).insert(rowData) : result
)
.catch(err =>
logger.error('Could not import strategy, error was: ', err)
this.logger.error('Could not import strategy, error: ', err)
);
}
@ -130,7 +130,7 @@ class StrategyStore {
.where({ built_in: 0 }) // eslint-disable-line
.delete()
.catch(err =>
logger.error('Could not drop strategies, error was: ', err)
this.logger.error('Could not drop strategies, error: ', err)
);
}
}

View File

@ -4,22 +4,27 @@ const log4js = require('log4js');
let loggerProvider = getDefaultLogProvider();
module.exports = exports = function getLogger(name) {
return loggerProvider(name);
};
module.exports.defaultLogProvider = loggerProvider;
exports.setLoggerProvider = function setLoggerProvider(provider) {
function validateLogProvider(provider) {
validate(typeof provider == 'function', 'Provider needs to be a function');
const logger = provider('unleash:logger');
validate(typeof logger.debug == 'function', 'Logger must implement debug');
validate(typeof logger.info == 'function', 'Logger must implement info');
validate(typeof logger.warn == 'function', 'Logger must implement warn');
validate(typeof logger.error == 'function', 'Logger must implement error');
}
exports.validateLogProvider = validateLogProvider;
// Deprecated
exports.setLoggerProvider = function setLoggerProvider(provider) {
validateLogProvider(provider);
loggerProvider = provider;
logger.info('Custom Logger Provider initalized.');
const logger = provider('unleash:logger');
logger.info(`Your way of configuring a logProvider is depreacted.
See https://unleash.github.io/docs/getting_started for details`);
};
function getDefaultLogProvider() {

View File

@ -1,29 +1,12 @@
'use strict';
const test = require('ava');
const createLogger = require('./logger');
const logger = require('../logger');
const logger = require('./logger');
test('should expose a setLoggerProvider function', t => {
t.true(logger.setLoggerProvider instanceof Function);
});
test('should create logger via custom logger provider', t => {
const loggerName = 'test';
const loggerImpl = {
debug: () => {},
info: () => {},
warn: () => {},
error: () => {},
};
const provider = () => loggerImpl;
logger.setLoggerProvider(provider);
const log = createLogger(loggerName);
t.is(log, loggerImpl);
});
test('should require custom logger to implement info', t => {
const loggerImpl = {
debug: () => {},

View File

@ -5,6 +5,7 @@ const store = require('../../test/fixtures/store');
const checkPermission = require('./permission-checker');
const supertest = require('supertest');
const getApp = require('../app');
const getLogger = require('../../test/fixtures/no-logger');
const { EventEmitter } = require('events');
const eventBus = new EventEmitter();
@ -16,6 +17,7 @@ function getSetup(preRouterHook) {
baseUriPath: base,
stores,
eventBus,
getLogger,
preRouterHook(_app) {
preRouterHook(_app);

View File

@ -1,9 +1,9 @@
'use strict';
const url = require('url');
const logger = require('../logger')('HTTP');
module.exports = function(config) {
const logger = config.getLogger('HTTP');
return (req, res, next) => {
next();
if (config.enableRequestLogger) {

View File

@ -1,6 +1,7 @@
'use strict';
const { publicFolder } = require('unleash-frontend');
const { defaultLogProvider, validateLogProvider } = require('./logger');
const isDev = () => process.env.NODE_ENV === 'development';
const THIRTY_DAYS = 30 * 24 * 60 * 60 * 1000;
@ -23,6 +24,7 @@ const DEFAULT_OPTIONS = {
ui: {},
importFile: undefined,
dropBeforeImport: false,
getLogger: defaultLogProvider,
};
module.exports = {
@ -45,6 +47,8 @@ module.exports = {
? { path: options.pipe }
: { port: options.port, host: options.host };
validateLogProvider(options.getLogger);
return options;
},
};

View File

@ -2,7 +2,6 @@
const Controller = require('../controller');
const logger = require('../../logger')('/admin-api/archive.js');
const { FEATURE_REVIVED } = require('../../event-type');
const extractUser = require('../../extract-user');
const { UPDATE_FEATURE } = require('../../permissions');
@ -10,6 +9,7 @@ const { UPDATE_FEATURE } = require('../../permissions');
class ArchiveController extends Controller {
constructor(config) {
super(config);
this.logger = config.getLogger('/admin-api/archive.js');
this.featureToggleStore = config.stores.featureToggleStore;
this.eventStore = config.stores.eventStore;
@ -33,7 +33,7 @@ class ArchiveController extends Controller {
});
res.status(200).end();
} catch (error) {
logger.error('Server failed executing request', error);
this.logger.error('Server failed executing request', error);
return res.status(500).end();
}
}

View File

@ -3,6 +3,7 @@
const test = require('ava');
const store = require('./../../../test/fixtures/store');
const permissions = require('../../../test/fixtures/permissions');
const getLogger = require('../../../test/fixtures/no-logger');
const supertest = require('supertest');
const getApp = require('../../app');
const { UPDATE_FEATURE } = require('../../permissions');
@ -20,6 +21,7 @@ function getSetup() {
eventBus,
extendedPermissions: true,
preRouterHook: perms.hook,
getLogger,
});
return {

View File

@ -2,6 +2,7 @@
const test = require('ava');
const store = require('./../../../test/fixtures/store');
const getLogger = require('../../../test/fixtures/no-logger');
const supertest = require('supertest');
const getApp = require('../../app');
@ -22,6 +23,7 @@ function getSetup() {
eventBus,
extendedPermissions: false,
ui: uiConfig,
getLogger,
});
return {

View File

@ -3,6 +3,8 @@
const test = require('ava');
const store = require('./../../../test/fixtures/store');
const getLogger = require('../../../test/fixtures/no-logger');
const supertest = require('supertest');
const getApp = require('../../app');
@ -16,6 +18,7 @@ function getSetup() {
baseUriPath: base,
stores,
eventBus,
getLogger,
});
return { base, eventStore: stores.eventStore, request: supertest(app) };

View File

@ -24,6 +24,7 @@ class FeatureController extends Controller {
super(config);
this.featureToggleStore = config.stores.featureToggleStore;
this.eventStore = config.stores.eventStore;
this.logger = config.getLogger('/admin-api/feature.js');
this.get('/', this.getAllToggles);
this.post('/', this.createToggle, CREATE_FEATURE);
@ -59,7 +60,7 @@ class FeatureController extends Controller {
await this.validateUniqueName(name);
res.status(201).end();
} catch (error) {
handleErrors(res, error);
handleErrors(res, this.logger, error);
}
}
@ -94,7 +95,7 @@ class FeatureController extends Controller {
});
res.status(201).end();
} catch (error) {
handleErrors(res, error);
handleErrors(res, this.logger, error);
}
}
@ -115,7 +116,7 @@ class FeatureController extends Controller {
});
res.status(200).end();
} catch (error) {
handleErrors(res, error);
handleErrors(res, this.logger, error);
}
}
@ -127,7 +128,7 @@ class FeatureController extends Controller {
const enabled = !feature.enabled;
this._toggle(enabled, req, res);
} catch (error) {
handleErrors(res, error);
handleErrors(res, this.logger, error);
}
}
@ -156,7 +157,7 @@ class FeatureController extends Controller {
});
res.json(feature).end();
} catch (error) {
handleErrors(res, error);
handleErrors(res, this.logger, error);
}
}
@ -175,7 +176,7 @@ class FeatureController extends Controller {
});
res.status(200).end();
} catch (error) {
handleErrors(res, error);
handleErrors(res, this.logger, error);
}
}
}

View File

@ -3,6 +3,7 @@
const test = require('ava');
const store = require('./../../../test/fixtures/store');
const permissions = require('../../../test/fixtures/permissions');
const getLogger = require('../../../test/fixtures/no-logger');
const supertest = require('supertest');
const getApp = require('../../app');
const { UPDATE_FEATURE, CREATE_FEATURE } = require('../../permissions');
@ -20,6 +21,7 @@ function getSetup() {
eventBus,
extendedPermissions: true,
preRouterHook: perms.hook,
getLogger,
});
return {

View File

@ -2,7 +2,6 @@
const joi = require('joi');
const Controller = require('../controller');
const logger = require('../../logger')('/admin-api/metrics.js');
const ClientMetrics = require('../../client-metrics');
const schema = require('./metrics-schema');
const { UPDATE_APPLICATION } = require('../../permissions');
@ -10,6 +9,7 @@ const { UPDATE_APPLICATION } = require('../../permissions');
class MetricsController extends Controller {
constructor(config) {
super(config);
this.logger = config.getLogger('/admin-api/metrics.js');
const {
clientMetricsStore,
clientInstanceStore,
@ -83,7 +83,7 @@ class MetricsController extends Controller {
const { value: applicationData, error } = joi.validate(input, schema);
if (error) {
logger.warn('Invalid application data posted', error);
this.logger.warn('Invalid application data posted', error);
return res.status(400).json(error);
}
@ -91,7 +91,7 @@ class MetricsController extends Controller {
await this.clientApplicationsStore.upsert(applicationData);
res.status(202).end();
} catch (err) {
logger.error(err);
this.logger.error(err);
res.status(500).end();
}
}
@ -103,7 +103,7 @@ class MetricsController extends Controller {
);
res.json({ applications });
} catch (err) {
logger.error(err);
this.logger.error(err);
res.status(500).end();
}
}
@ -147,7 +147,7 @@ class MetricsController extends Controller {
};
res.json(appDetails);
} catch (err) {
logger.error(err);
this.logger.error(err);
res.status(500).end();
}
}

View File

@ -3,6 +3,7 @@
const test = require('ava');
const store = require('./../../../test/fixtures/store');
const permissions = require('../../../test/fixtures/permissions');
const getLogger = require('../../../test/fixtures/no-logger');
const supertest = require('supertest');
const getApp = require('../../app');
const { UPDATE_APPLICATION } = require('../../permissions');
@ -19,6 +20,7 @@ function getSetup() {
eventBus,
extendedPermissions: true,
preRouterHook: perms.hook,
getLogger,
});
return {

View File

@ -13,6 +13,7 @@ const upload = multer({ limits: { fileSize: 5242880 } });
class StateController extends Controller {
constructor(config) {
super(config);
this.logger = config.getLogger('/admin-api/state.js');
this.fileupload('/import', upload.single('file'), this.import, ADMIN);
this.get('/export', this.export, ADMIN);
}
@ -40,7 +41,7 @@ class StateController extends Controller {
});
res.sendStatus(202);
} catch (err) {
handleErrors(res, err);
handleErrors(res, this.logger, err);
}
}
@ -75,7 +76,7 @@ class StateController extends Controller {
res.json(data);
}
} catch (err) {
handleErrors(res, err);
handleErrors(res, this.logger, err);
}
}
}

View File

@ -18,6 +18,7 @@ const version = 1;
class StrategyController extends Controller {
constructor(config) {
super(config);
this.logger = config.getLogger('/admin-api/strategy.js');
this.strategyStore = config.stores.strategyStore;
this.eventStore = config.stores.eventStore;
@ -58,7 +59,7 @@ class StrategyController extends Controller {
});
res.status(200).end();
} catch (error) {
handleErrors(res, error);
handleErrors(res, this.logger, error);
}
}
@ -73,7 +74,7 @@ class StrategyController extends Controller {
});
res.status(201).end();
} catch (error) {
handleErrors(res, error);
handleErrors(res, this.logger, error);
}
}
@ -92,7 +93,7 @@ class StrategyController extends Controller {
});
res.status(200).end();
} catch (error) {
handleErrors(res, error);
handleErrors(res, this.logger, error);
}
}

View File

@ -3,6 +3,7 @@
const test = require('ava');
const store = require('./../../../test/fixtures/store');
const permissions = require('../../../test/fixtures/permissions');
const getLogger = require('../../../test/fixtures/no-logger');
const supertest = require('supertest');
const getApp = require('../../app');
const {
@ -22,6 +23,7 @@ function getSetup() {
baseUriPath: base,
stores,
eventBus,
getLogger,
extendedPermissions: true,
preRouterHook: perms.hook,
});

View File

@ -2,6 +2,7 @@
const test = require('ava');
const store = require('./../../../test/fixtures/store');
const getLogger = require('../../../test/fixtures/no-logger');
const supertest = require('supertest');
const getApp = require('../../app');
const User = require('../../user');
@ -18,6 +19,7 @@ function getSetup() {
baseUriPath: base,
stores,
eventBus,
getLogger,
preHook: a => {
a.use((req, res, next) => {
req.user = currentUser;

View File

@ -1,7 +1,5 @@
'use strict';
const logger = require('../../logger')('/admin-api/util.js');
const joi = require('joi');
const customJoi = joi.extend(j => ({
@ -36,7 +34,7 @@ const nameType = customJoi
.max(100)
.required();
const handleErrors = (res, error) => {
const handleErrors = (res, logger, error) => {
logger.warn(error.message);
switch (error.name) {
case 'NotFoundError':

View File

@ -2,6 +2,7 @@
const test = require('ava');
const store = require('./../../test/fixtures/store');
const getLogger = require('../../test/fixtures/no-logger');
const supertest = require('supertest');
const getApp = require('../app');
@ -16,6 +17,7 @@ test('should use enable prometheus', t => {
serverMetrics: true,
stores,
eventBus,
getLogger,
});
const request = supertest(app);

View File

@ -2,6 +2,7 @@
const test = require('ava');
const store = require('./../../../test/fixtures/store');
const getLogger = require('../../../test/fixtures/no-logger');
const supertest = require('supertest');
const getApp = require('../../app');
@ -15,6 +16,7 @@ function getSetup() {
baseUriPath: base,
stores,
eventBus,
getLogger,
});
return {

View File

@ -11,11 +11,12 @@ class ClientApi extends Controller {
super();
const stores = config.stores;
const getLogger = config.getLogger;
this.get('/', this.index);
this.use('/features', new FeatureController(stores).router);
this.use('/metrics', new MetricsController(stores).router);
this.use('/register', new RegisterController(stores).router);
this.use('/features', new FeatureController(stores, getLogger).router);
this.use('/metrics', new MetricsController(stores, getLogger).router);
this.use('/register', new RegisterController(stores, getLogger).router);
}
index(req, res) {

View File

@ -1,14 +1,14 @@
'use strict';
const joi = require('joi');
const logger = require('../../logger')('client-api/metrics.js');
const Controller = require('../controller');
const { clientMetricsSchema } = require('./metrics-schema');
class ClientMetricsController extends Controller {
constructor({ clientMetricsStore, clientInstanceStore }) {
constructor({ clientMetricsStore, clientInstanceStore }, getLogger) {
super();
this.logger = getLogger('/api/client/metrics');
this.clientMetricsStore = clientMetricsStore;
this.clientInstanceStore = clientInstanceStore;
@ -22,7 +22,7 @@ class ClientMetricsController extends Controller {
const { error, value } = joi.validate(data, clientMetricsSchema);
if (error) {
logger.warn('Invalid metrics posted', error);
this.logger.warn('Invalid metrics posted', error);
return res.status(400).json(error);
}
@ -35,7 +35,7 @@ class ClientMetricsController extends Controller {
});
res.status(202).end();
} catch (e) {
logger.error('failed to store metrics', e);
this.logger.error('failed to store metrics', e);
res.status(500).end();
}
}

View File

@ -2,6 +2,7 @@
const test = require('ava');
const store = require('./../../../test/fixtures/store');
const getLogger = require('../../../test/fixtures/no-logger');
const supertest = require('supertest');
const getApp = require('../../app');
@ -14,6 +15,7 @@ function getSetup() {
baseUriPath: '',
stores,
eventBus,
getLogger,
});
return {

View File

@ -1,14 +1,14 @@
'use strict';
const joi = require('joi');
const logger = require('../../logger')('/client-api/register.js');
const Controller = require('../controller');
const { clientRegisterSchema: schema } = require('./register-schema');
class RegisterController extends Controller {
constructor({ clientInstanceStore, clientApplicationsStore }) {
constructor({ clientInstanceStore, clientApplicationsStore }, getLogger) {
super();
this.logger = getLogger('/api/client/register');
this.clientInstanceStore = clientInstanceStore;
this.clientApplicationsStore = clientApplicationsStore;
@ -20,7 +20,7 @@ class RegisterController extends Controller {
const { value: clientRegistration, error } = joi.validate(data, schema);
if (error) {
logger.warn('Invalid client data posted', error);
this.logger.warn('Invalid client data posted', error);
return res.status(400).json(error);
}
@ -29,14 +29,14 @@ class RegisterController extends Controller {
try {
await this.clientApplicationsStore.upsert(clientRegistration);
await this.clientInstanceStore.insert(clientRegistration);
logger.info(
this.logger.info(
`New client registered with appName=${
clientRegistration.appName
} and instanceId=${clientRegistration.instanceId}`
);
return res.status(202).end();
} catch (err) {
logger.error('failed to register client', err);
this.logger.error('failed to register client', err);
return res.status(500).end();
}
}

View File

@ -2,6 +2,7 @@
const test = require('ava');
const store = require('./../../../test/fixtures/store');
const getLogger = require('../../../test/fixtures/no-logger');
const supertest = require('supertest');
const getApp = require('../../app');
@ -14,6 +15,7 @@ function getSetup() {
baseUriPath: '',
stores,
eventBus,
getLogger,
});
return {
@ -89,6 +91,7 @@ test('should fail if store fails', t => {
baseUriPath: '',
stores,
eventBus,
getLogger,
});
// --- end custom config

View File

@ -1,12 +1,12 @@
'use strict';
const logger = require('../logger')('health-check.js');
const Controller = require('./controller');
class HealthCheckController extends Controller {
constructor(config) {
super();
this.db = config.stores.db;
this.logger = config.getLogger('health-check.js');
this.get('/', (req, res) => this.index(req, res));
}
@ -16,7 +16,7 @@ class HealthCheckController extends Controller {
await this.db.select(1).from('features');
res.json({ health: 'GOOD' });
} catch (e) {
logger.error('Could not select from features, error was: ', e);
this.logger.error('Could not select from features, error was: ', e);
res.status(500).json({ health: 'BAD' });
}
}

View File

@ -2,6 +2,7 @@
const test = require('ava');
const store = require('./../../test/fixtures/store');
const getLogger = require('../../test/fixtures/no-logger');
const supertest = require('supertest');
const getApp = require('../app');
@ -15,6 +16,7 @@ function getSetup() {
baseUriPath: '',
stores,
eventBus,
getLogger,
});
return {

View File

@ -2,6 +2,7 @@
const test = require('ava');
const store = require('./../../test/fixtures/store');
const getLogger = require('../../test/fixtures/no-logger');
const supertest = require('supertest');
const getApp = require('../app');
@ -16,6 +17,7 @@ function getSetup() {
stores,
eventBus,
enableLegacyRoutes: true,
getLogger,
});
return {

View File

@ -2,8 +2,6 @@
const { EventEmitter } = require('events');
const logFactory = require('./logger');
const logger = require('./logger')('server-impl.js');
const migrator = require('../migrator');
const getApp = require('./app');
@ -16,6 +14,7 @@ const AuthenticationRequired = require('./authentication-required');
async function createApp(options) {
// Database dependecies (statefull)
const logger = options.getLogger('server-impl.js');
const stores = createStores(options);
const eventBus = new EventEmitter();
@ -23,7 +22,7 @@ async function createApp(options) {
{
stores,
eventBus,
logFactory,
logFactory: options.getLogger, // TODO: remove in v4.x
},
options
);
@ -65,6 +64,7 @@ async function createApp(options) {
async function start(opts) {
const options = createOptions(opts);
const logger = options.getLogger('server-impl.js');
try {
await migrator(options);

View File

@ -3,6 +3,7 @@
const test = require('ava');
const proxyquire = require('proxyquire');
const express = require('express');
const getLogger = require('../test/fixtures/no-logger');
const getApp = proxyquire('./app', {
'./routes': class Index {
@ -38,6 +39,7 @@ test('should call preHook', async t => {
let called = 0;
await serverImpl.start({
port: 0,
getLogger,
preHook: () => {
called++;
},
@ -49,6 +51,7 @@ test('should call preRouterHook', async t => {
let called = 0;
await serverImpl.start({
port: 0,
getLogger,
preRouterHook: () => {
called++;
},

View File

@ -5,7 +5,6 @@ const fs = require('fs');
const mime = require('mime');
const { featureShema } = require('./routes/admin-api/feature-schema');
const strategySchema = require('./routes/admin-api/strategy-schema');
const getLogger = require('./logger');
const YAML = require('js-yaml');
const {
FEATURE_IMPORT,
@ -14,8 +13,6 @@ const {
DROP_STRATEGIES,
} = require('./event-type');
const logger = getLogger('state-service.js');
const dataSchema = joi.object().keys({
version: joi.number(),
features: joi
@ -43,6 +40,7 @@ function parseFile(file, data) {
class StateService {
constructor(config) {
this.config = config;
this.logger = config.getLogger('state-service.js');
}
importFile({ file, dropBeforeImport, userName }) {
@ -57,9 +55,11 @@ class StateService {
const importData = await joi.validate(data, dataSchema);
if (importData.features) {
logger.info(`Importing ${importData.features.length} features`);
this.logger.info(
`Importing ${importData.features.length} features`
);
if (dropBeforeImport) {
logger.info(`Dropping existing features`);
this.logger.info(`Dropping existing features`);
await eventStore.store({
type: DROP_FEATURES,
createdBy: userName,
@ -78,9 +78,11 @@ class StateService {
}
if (importData.strategies) {
logger.info(`Importing ${importData.strategies.length} strategies`);
this.logger.info(
`Importing ${importData.strategies.length} strategies`
);
if (dropBeforeImport) {
logger.info(`Dropping existing strategies`);
this.logger.info(`Dropping existing strategies`);
await eventStore.store({
type: DROP_STRATEGIES,
createdBy: userName,

View File

@ -3,6 +3,8 @@
const test = require('ava');
const store = require('./../test/fixtures/store');
const getLogger = require('./../test/fixtures/no-logger');
const StateService = require('./state-service');
const {
FEATURE_IMPORT,
@ -13,7 +15,7 @@ const {
function getSetup() {
const stores = store.createStores();
return { stateService: new StateService({ stores }), stores };
return { stateService: new StateService({ stores, getLogger }), stores };
}
test('should import a feature', async t => {

View File

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

View File

@ -34,7 +34,7 @@
"scripts": {
"start": "node server.js",
"start:google": "node examples/google-auth-unleash.js",
"start:dev": "NODE_ENV=development supervisor --ignore ./node_modules/ server.js",
"start:dev": "NODE_ENV=development supervisor --ignore ./node_modules/,website server.js",
"start:dev:pg": "pg_virtualenv npm run start:dev:pg-chain",
"start:dev:pg-chain": "export DATABASE_URL=postgres://$PGUSER:$PGPASSWORD@localhost:$PGPORT/postgres ; db-migrate up && npm run start:dev",
"db-migrate": "db-migrate",

View File

@ -49,12 +49,13 @@ function createFeatures(store) {
return dbState.features.map(f => store._createFeature(f));
}
module.exports = async function init(databaseSchema = 'test') {
module.exports = async function init(databaseSchema = 'test', getLogger) {
const options = {
databaseUrl: require('./database-config').getDatabaseUrl(),
databaseSchema,
minPool: 0,
maxPool: 0,
getLogger,
};
const db = createDb(options);

View File

@ -6,6 +6,7 @@ const supertest = require('supertest');
const getApp = require('../../../lib/app');
const dbInit = require('./database-init');
const getLogger = require('../../fixtures/no-logger');
const StateService = require('../../../lib/state-service');
const { EventEmitter } = require('events');
@ -19,13 +20,14 @@ function createApp(stores, adminAuthentication = 'none', preHook) {
adminAuthentication,
secret: 'super-secret',
sessionAge: 4000,
stateService: new StateService({ stores }),
stateService: new StateService({ stores, getLogger }),
getLogger,
});
}
module.exports = {
async setupApp(name) {
const stores = await dbInit(name);
const stores = await dbInit(name, getLogger);
const app = createApp(stores);
return {
@ -34,7 +36,7 @@ module.exports = {
};
},
async setupAppWithAuth(name) {
const stores = await dbInit(name);
const stores = await dbInit(name, getLogger);
const app = createApp(stores, 'unsecure');
return {
@ -44,7 +46,7 @@ module.exports = {
},
async setupAppWithCustomAuth(name, preHook) {
const stores = await dbInit(name);
const stores = await dbInit(name, getLogger);
const app = createApp(stores, 'custom', preHook);
return {

11
test/fixtures/no-logger.js vendored Normal file
View File

@ -0,0 +1,11 @@
'use strict';
module.exports = function noLoggerProvider() {
// do something with the name
return {
debug: () => {},
info: () => {},
warn: () => {},
error: () => {},
};
};