apostrophe
Version:
The Apostrophe Content Management System.
1,764 lines (1,585 loc) • 46.4 kB
JavaScript
/* eslint-disable no-console */
const t = require('../test-lib/test.js');
const assert = require('assert/strict');
const testModule = {
'test-module': {
options: {
alias: 'testModule'
},
init() { }
}
};
describe('structured logging', function () {
this.timeout(t.timeout);
let apos;
after(function () {
return t.destroy(apos);
});
describe('defaults', function () {
before(async function () {
apos = await t.create({
modules: { ...testModule }
});
});
after(async function () {
await t.destroy(apos);
apos = null;
});
it('should register structured log and module log handlers', function () {
assert(apos.structuredLog);
assert(apos.testModule);
assert.equal(typeof apos.testModule.logDebug, 'function');
assert.equal(typeof apos.testModule.logInfo, 'function');
assert.equal(typeof apos.testModule.logWarn, 'function');
assert.equal(typeof apos.testModule.logError, 'function');
assert.deepEqual(apos.structuredLog.filters, {
'*': { severity: [ 'debug', 'info', 'warn', 'error' ] }
});
});
it('should format entries for readability', function () {
// id spy
const id = apos.util.generateId;
apos.util.generateId = () => 'test-id';
let savedArgs = [];
// ### DEBUG
const debug = console.debug;
console.debug = (...args) => {
savedArgs = args;
};
// Validate formatting
savedArgs = [];
apos.testModule.logDebug('event-type');
assert.equal(savedArgs[0], 'test-module: event-type\n');
assert.equal(
savedArgs[1],
`{
"module": "test-module",
"type": "event-type",
"severity": "debug"
}`
);
// Message as
savedArgs = [];
apos.structuredLog.options.messageAs = 'msg';
apos.testModule.logDebug('event-type', 'some message');
assert.equal(
savedArgs[0],
`{
"msg": "test-module: event-type: some message",
"module": "test-module",
"type": "event-type",
"severity": "debug"
}`
);
assert.equal(typeof savedArgs[1], 'undefined');
delete apos.structuredLog.options.messageAs;
// ### INFO
const info = console.info;
console.info = (...args) => {
savedArgs = args;
};
// Validate formatting
savedArgs = [];
apos.testModule.logInfo('event-type');
assert.equal(savedArgs[0], 'test-module: event-type\n');
assert.equal(
savedArgs[1],
`{
"module": "test-module",
"type": "event-type",
"severity": "info"
}`
);
// ### WARN
const warn = console.warn;
console.warn = (...args) => {
savedArgs = args;
};
// Validate formatting
savedArgs = [];
apos.testModule.logWarn('event-type');
assert.equal(savedArgs[0], 'test-module: event-type\n');
assert.equal(
savedArgs[1],
`{
"module": "test-module",
"type": "event-type",
"severity": "warn"
}`
);
// ### ERROR
const error = console.error;
console.error = (...args) => {
savedArgs = args;
};
// Validate formatting
savedArgs = [];
apos.testModule.logError('event-type');
assert.equal(savedArgs[0], 'test-module: event-type\n');
assert.equal(
savedArgs[1],
`{
"module": "test-module",
"type": "event-type",
"severity": "error"
}`
);
// With req
savedArgs = [];
apos.testModule.logError(
apos.task.getReq({
originalUrl: '/module/test',
path: '/test',
method: 'GET',
ip: '1.2.3.4',
query: { foo: 'bar' }
}),
'event-type'
);
assert.equal(savedArgs[0], 'test-module: event-type\n');
assert.equal(
savedArgs[1],
`{
"module": "test-module",
"type": "event-type",
"severity": "error",
"url": "/module/test",
"path": "/test",
"method": "GET",
"ip": "1.2.3.4",
"query": {
"foo": "bar"
},
"requestId": "test-id"
}`
);
// With req and message as
savedArgs = [];
apos.structuredLog.options.messageAs = 'message';
apos.testModule.logError(
apos.task.getReq({
originalUrl: '/module/test',
path: '/test',
method: 'GET',
ip: '1.2.3.4',
query: { foo: 'bar' }
}),
'event-type'
);
assert.equal(savedArgs.length, 1);
assert.equal(
savedArgs[0],
`{
"message": "test-module: event-type",
"module": "test-module",
"type": "event-type",
"severity": "error",
"url": "/module/test",
"path": "/test",
"method": "GET",
"ip": "1.2.3.4",
"query": {
"foo": "bar"
},
"requestId": "test-id"
}`
);
delete apos.structuredLog.options.messageAs;
apos.util.generateId = id;
console.debug = debug;
console.info = info;
console.warn = warn;
console.error = error;
});
it('should log formatted entry: logDebug', function () {
// id spy
const id = apos.util.generateId;
apos.util.generateId = () => 'test-id';
// debug spy
const debug = apos.util.logger.debug;
let savedArgs = [];
apos.util.logger.debug = (...args) => {
savedArgs = args;
};
// Validate
assert.throws(() => {
apos.testModule.logDebug();
}, function (err) {
assert.equal(err.message, 'Event type must be a string');
return true;
});
assert.throws(() => {
apos.testModule.logDebug(apos.task.getReq());
}, function (err) {
assert.equal(err.message, 'Event type must be a string');
return true;
});
assert.throws(() => {
apos.testModule.logDebug(null);
}, function (err) {
assert.equal(err.message, 'Event type must be a string');
return true;
});
assert.throws(() => {
apos.testModule.logDebug(1);
}, function (err) {
assert.equal(err.message, 'Event type must be a string');
return true;
});
// Format
apos.testModule.logDebug('event-type');
assert.equal(savedArgs[0], 'test-module: event-type');
assert.deepEqual(savedArgs[1], {
type: 'event-type',
severity: 'debug',
module: 'test-module'
});
apos.testModule.logDebug('event-type', 'a message');
assert.equal(savedArgs[0], 'test-module: event-type: a message');
assert.deepEqual(savedArgs[1], {
type: 'event-type',
severity: 'debug',
module: 'test-module'
});
apos.testModule.logDebug('event-type', 'a message', { foo: 'bar' });
assert.equal(savedArgs[0], 'test-module: event-type: a message');
assert.deepEqual(savedArgs[1], {
type: 'event-type',
severity: 'debug',
module: 'test-module',
foo: 'bar'
});
apos.testModule.logDebug('event-type', { foo: 'bar' });
assert.equal(savedArgs[0], 'test-module: event-type');
assert.deepEqual(savedArgs[1], {
type: 'event-type',
severity: 'debug',
module: 'test-module',
foo: 'bar'
});
apos.testModule.logDebug(apos.task.getReq({
originalUrl: '/module/test',
path: '/test',
method: 'GET',
ip: '1.2.3.4',
query: { foo: 'bar' }
}), 'event-type');
assert.equal(savedArgs[0], 'test-module: event-type');
assert.deepEqual(savedArgs[1], {
url: '/module/test',
path: '/test',
method: 'GET',
ip: '1.2.3.4',
query: { foo: 'bar' },
requestId: 'test-id',
type: 'event-type',
severity: 'debug',
module: 'test-module'
});
apos.testModule.logDebug(apos.task.getReq({
originalUrl: '/module/test',
path: '/test',
method: 'GET',
ip: '1.2.3.4',
query: { foo: 'bar' }
}), 'event-type', 'some message');
assert.equal(savedArgs[0], 'test-module: event-type: some message');
assert.deepEqual(savedArgs[1], {
url: '/module/test',
path: '/test',
method: 'GET',
ip: '1.2.3.4',
query: { foo: 'bar' },
requestId: 'test-id',
type: 'event-type',
severity: 'debug',
module: 'test-module'
});
apos.testModule.logDebug(apos.task.getReq({
originalUrl: '/module/test',
path: '/test',
method: 'GET',
ip: '1.2.3.4',
query: { foo: 'bar' }
}), 'event-type', 'some message', { foo: 'bar' });
assert.equal(savedArgs[0], 'test-module: event-type: some message');
assert.deepEqual(savedArgs[1], {
url: '/module/test',
path: '/test',
method: 'GET',
ip: '1.2.3.4',
query: { foo: 'bar' },
requestId: 'test-id',
type: 'event-type',
severity: 'debug',
module: 'test-module',
foo: 'bar'
});
apos.testModule.logDebug(apos.task.getReq({
originalUrl: '/module/test',
path: '/test',
method: 'GET',
ip: '1.2.3.4',
query: { foo: 'bar' }
}), 'event-type', { foo: 'bar' });
assert.equal(savedArgs[0], 'test-module: event-type');
assert.deepEqual(savedArgs[1], {
url: '/module/test',
path: '/test',
method: 'GET',
ip: '1.2.3.4',
query: { foo: 'bar' },
requestId: 'test-id',
type: 'event-type',
severity: 'debug',
module: 'test-module',
foo: 'bar'
});
apos.util.logger.debug = debug;
apos.util.generateId = id;
});
it('should log formatted entry: logInfo', function () {
// id spy
const id = apos.util.generateId;
apos.util.generateId = () => 'test-id';
// debug spy
const info = apos.util.logger.info;
let savedArgs = [];
apos.util.logger.info = (...args) => {
savedArgs = args;
};
// Validate
assert.throws(() => {
apos.testModule.logInfo();
}, function (err) {
assert.equal(err.message, 'Event type must be a string');
return true;
});
// Format
apos.testModule.logInfo('event-type', 'a message', { foo: 'bar' });
assert.equal(savedArgs[0], 'test-module: event-type: a message');
assert.deepEqual(savedArgs[1], {
type: 'event-type',
severity: 'info',
module: 'test-module',
foo: 'bar'
});
apos.testModule.logInfo(apos.task.getReq({
originalUrl: '/module/test',
path: '/test',
method: 'GET',
ip: '1.2.3.4',
query: { foo: 'bar' }
}), 'event-type', 'some message', { foo: 'bar' });
assert.equal(savedArgs[0], 'test-module: event-type: some message');
assert.deepEqual(savedArgs[1], {
url: '/module/test',
path: '/test',
method: 'GET',
ip: '1.2.3.4',
query: { foo: 'bar' },
requestId: 'test-id',
type: 'event-type',
severity: 'info',
module: 'test-module',
foo: 'bar'
});
apos.util.logger.info = info;
apos.util.generateId = id;
});
it('should log formatted entry: logWarn', function () {
// id spy
const id = apos.util.generateId;
apos.util.generateId = () => 'test-id';
// debug spy
const warn = apos.util.logger.warn;
let savedArgs = [];
apos.util.logger.warn = (...args) => {
savedArgs = args;
};
// Validate
assert.throws(() => {
apos.testModule.logWarn();
}, function (err) {
assert.equal(err.message, 'Event type must be a string');
return true;
});
// Format
apos.testModule.logWarn('event-type', 'a message', { foo: 'bar' });
assert.equal(savedArgs[0], 'test-module: event-type: a message');
assert.deepEqual(savedArgs[1], {
type: 'event-type',
severity: 'warn',
module: 'test-module',
foo: 'bar'
});
apos.testModule.logWarn(apos.task.getReq({
originalUrl: '/module/test',
path: '/test',
method: 'GET',
ip: '1.2.3.4',
query: { foo: 'bar' }
}), 'event-type', 'some message', { foo: 'bar' });
assert.equal(savedArgs[0], 'test-module: event-type: some message');
assert.deepEqual(savedArgs[1], {
url: '/module/test',
path: '/test',
method: 'GET',
ip: '1.2.3.4',
query: { foo: 'bar' },
requestId: 'test-id',
type: 'event-type',
severity: 'warn',
module: 'test-module',
foo: 'bar'
});
apos.util.logger.warn = warn;
apos.util.generateId = id;
});
it('should log formatted entry: logError', function () {
// id spy
const id = apos.util.generateId;
apos.util.generateId = () => 'test-id';
// debug spy
const error = apos.util.logger.error;
let savedArgs = [];
apos.util.logger.error = (...args) => {
savedArgs = args;
};
// Validate
assert.throws(() => {
apos.testModule.logError();
}, function (err) {
assert.equal(err.message, 'Event type must be a string');
return true;
});
// Format
apos.testModule.logError('event-type', 'a message', { foo: 'bar' });
assert.equal(savedArgs[0], 'test-module: event-type: a message');
assert.deepEqual(savedArgs[1], {
type: 'event-type',
severity: 'error',
module: 'test-module',
foo: 'bar'
});
apos.testModule.logError(apos.task.getReq({
originalUrl: '/module/test',
path: '/test',
method: 'GET',
ip: '1.2.3.4',
query: { foo: 'bar' }
}), 'event-type', 'some message', { foo: 'bar' });
assert.equal(savedArgs[0], 'test-module: event-type: some message');
assert.deepEqual(savedArgs[1], {
url: '/module/test',
path: '/test',
method: 'GET',
ip: '1.2.3.4',
query: { foo: 'bar' },
requestId: 'test-id',
type: 'event-type',
severity: 'error',
module: 'test-module',
foo: 'bar'
});
apos.util.logger.error = error;
apos.util.generateId = id;
});
it('should filter entries with minimal config', async function () {
await t.destroy(apos);
apos = await t.create({
modules: {
...testModule,
'@apostrophecms/log': {
options: {
filter: {
'*': {
severity: [ 'error' ]
},
'test-module': {
events: [ 'type1' ]
}
}
}
}
}
});
assert.deepEqual(apos.structuredLog.filters, {
'*': {
severity: [ 'error' ]
},
'test-module': {
events: [ 'type1' ]
}
});
let savedArgs = [];
const debug = apos.util.logger.debug;
apos.util.logger.debug = (...args) => {
savedArgs = args;
};
const info = apos.util.logger.info;
apos.util.logger.info = (...args) => {
savedArgs = args;
};
const warn = apos.util.logger.warn;
apos.util.logger.warn = (...args) => {
savedArgs = args;
};
const error = apos.util.logger.error;
apos.util.logger.error = (...args) => {
savedArgs = args;
};
// ### DEBUG
// No match
apos.global.logDebug('type2');
assert.equal(savedArgs.length, 0);
// No match - type from another module
savedArgs = [];
apos.global.logDebug('type1');
assert.equal(savedArgs.length, 0);
// Matches the global severity
savedArgs = [];
apos.global.logError('type1');
assert.equal(savedArgs.length, 2);
savedArgs = [];
apos.global.logError('type2');
assert.equal(savedArgs.length, 2);
// Matches the module type only
savedArgs = [];
apos.testModule.logDebug('type1');
assert.equal(savedArgs.length, 2);
// Matches the global severity and module type
savedArgs = [];
apos.testModule.logError('type1');
assert.equal(savedArgs.length, 2);
// Matches the global severity only
savedArgs = [];
apos.testModule.logError('type2');
assert.equal(savedArgs.length, 2);
// No match
savedArgs = [];
apos.testModule.logWarn('type3');
assert.equal(savedArgs.length, 0);
apos.util.logger.debug = debug;
apos.util.logger.info = info;
apos.util.logger.warn = warn;
apos.util.logger.error = error;
});
it('should match all with wildcard global config', async function () {
await t.destroy(apos);
apos = await t.create({
modules: {
...testModule,
'@apostrophecms/log': {
options: {
filter: {
'*': true
}
}
}
}
});
assert.deepEqual(apos.structuredLog.filters, {
'*': {
severity: [ 'debug', 'info', 'warn', 'error' ]
}
});
let savedArgs = [];
const debug = apos.util.logger.debug;
apos.util.logger.debug = (...args) => {
savedArgs = args;
};
const info = apos.util.logger.info;
apos.util.logger.info = (...args) => {
savedArgs = args;
};
const warn = apos.util.logger.warn;
apos.util.logger.warn = (...args) => {
savedArgs = args;
};
const error = apos.util.logger.error;
apos.util.logger.error = (...args) => {
savedArgs = args;
};
// ### DEBUG
savedArgs = [];
apos.testModule.logDebug('type1');
assert.equal(savedArgs.length, 2);
savedArgs = [];
apos.testModule.logInfo('type1');
assert.equal(savedArgs.length, 2);
apos.testModule.logWarn('type1');
assert.equal(savedArgs.length, 2);
apos.testModule.logError('type1');
assert.equal(savedArgs.length, 2);
apos.util.logger.debug = debug;
apos.util.logger.info = info;
apos.util.logger.warn = warn;
apos.util.logger.error = error;
});
it('should filter entries with wildcard module events config', async function () {
await t.destroy(apos);
apos = await t.create({
modules: {
...testModule,
'@apostrophecms/log': {
options: {
filter: {
'*': {
severity: [ 'error' ],
events: [ 'type1' ]
},
'test-module': {
events: '*'
}
}
}
}
}
});
assert.deepEqual(apos.structuredLog.filters, {
'*': {
severity: [ 'error' ],
events: [ 'type1' ]
},
'test-module': {
events: [ '*' ]
}
});
let savedArgs = [];
const debug = apos.util.logger.debug;
apos.util.logger.debug = (...args) => {
savedArgs = args;
};
const info = apos.util.logger.info;
apos.util.logger.info = (...args) => {
savedArgs = args;
};
const warn = apos.util.logger.warn;
apos.util.logger.warn = (...args) => {
savedArgs = args;
};
const error = apos.util.logger.error;
apos.util.logger.error = (...args) => {
savedArgs = args;
};
// ### DEBUG
savedArgs = [];
// Match the global type only
apos.global.logDebug('type1');
assert.equal(savedArgs.length, 2);
savedArgs = [];
// No match
apos.global.logDebug('type2');
assert.equal(savedArgs.length, 0);
// Always match because of the event type wildcard
savedArgs = [];
apos.testModule.logDebug('any-type');
assert.equal(savedArgs.length, 2);
savedArgs = [];
apos.testModule.logInfo('any-type');
assert.equal(savedArgs.length, 2);
apos.testModule.logWarn('any-type');
assert.equal(savedArgs.length, 2);
apos.testModule.logError('any-type');
assert.equal(savedArgs.length, 2);
apos.util.logger.debug = debug;
apos.util.logger.info = info;
apos.util.logger.warn = warn;
apos.util.logger.error = error;
});
it('should filter entries with verbose config', async function () {
await t.destroy(apos);
apos = await t.create({
modules: {
...testModule,
'@apostrophecms/log': {
options: {
filter: {
'*': {
severity: [ 'error' ],
events: [ 'type1' ]
},
'test-module': {
severity: [ 'debug' ],
events: [ 'type2' ]
}
}
}
}
}
});
assert.deepEqual(apos.structuredLog.filters, {
'*': {
severity: [ 'error' ],
events: [ 'type1' ]
},
'test-module': {
severity: [ 'debug' ],
events: [ 'type2' ]
}
});
let savedArgs = [];
const debug = apos.util.logger.debug;
apos.util.logger.debug = (...args) => {
savedArgs = args;
};
const info = apos.util.logger.info;
apos.util.logger.info = (...args) => {
savedArgs = args;
};
const warn = apos.util.logger.warn;
apos.util.logger.warn = (...args) => {
savedArgs = args;
};
const error = apos.util.logger.error;
apos.util.logger.error = (...args) => {
savedArgs = args;
};
// ### DEBUG
// No match
apos.global.logDebug('type2');
assert.equal(savedArgs.length, 0);
// Matches the type only
savedArgs = [];
apos.global.logDebug('type1');
assert.equal(savedArgs.length, 2);
// Matches the type and severity
savedArgs = [];
apos.global.logError('type1');
assert.equal(savedArgs.length, 2);
// Matches the global type and module severity
savedArgs = [];
apos.testModule.logDebug('type1');
assert.equal(savedArgs.length, 2);
// Matches the global type and severity
savedArgs = [];
apos.testModule.logError('type1');
assert.equal(savedArgs.length, 2);
// Matches the global type only
savedArgs = [];
apos.testModule.logInfo('type1');
assert.equal(savedArgs.length, 2);
// Matches the module type only
savedArgs = [];
apos.testModule.logInfo('type2');
assert.equal(savedArgs.length, 2);
// No match
savedArgs = [];
apos.testModule.logWarn('type3');
assert.equal(savedArgs.length, 0);
apos.util.logger.debug = debug;
apos.util.logger.info = info;
apos.util.logger.warn = warn;
apos.util.logger.error = error;
});
it('it should shutdown logger', async function () {
await t.destroy(apos);
apos = await t.create({});
let called = false;
apos.util.logger.destroy = async () => {
called = true;
};
await t.destroy(apos);
apos = null;
assert.equal(called, true);
});
});
describe('production', function () {
before(async function () {
process.env.NODE_ENV = 'production';
apos = await t.create({
modules: { ...testModule }
});
});
after(async function () {
delete process.env.NODE_ENV;
await t.destroy(apos);
apos = null;
});
it('should set filter configuration', function () {
assert.deepEqual(apos.structuredLog.filters, {
'*': { severity: [ 'warn', 'error' ] }
});
});
it('should filter and format entries', function () {
// id spy
const id = apos.util.generateId;
apos.util.generateId = () => 'test-id';
let savedArgs = [];
// ### DEBUG
const debug = console.debug;
console.debug = (...args) => {
savedArgs = args;
};
// Validate formatting
savedArgs = [];
apos.testModule.logDebug('event-type');
assert.equal(typeof savedArgs[0], 'undefined');
assert.equal(typeof savedArgs[1], 'undefined');
// Message as
savedArgs = [];
apos.structuredLog.options.messageAs = 'msg';
apos.testModule.logDebug('event-type', 'some message');
assert.equal(typeof savedArgs[0], 'undefined');
assert.equal(typeof savedArgs[1], 'undefined');
delete apos.structuredLog.options.messageAs;
// ### INFO
const info = console.info;
console.info = (...args) => {
savedArgs = args;
};
// Validate formatting
savedArgs = [];
apos.testModule.logInfo('event-type');
assert.equal(typeof savedArgs[0], 'undefined');
assert.equal(typeof savedArgs[1], 'undefined');
// ### WARN
const warn = console.warn;
console.warn = (...args) => {
savedArgs = args;
};
// Validate formatting
savedArgs = [];
apos.testModule.logWarn('event-type');
assert.equal(savedArgs[0], 'test-module: event-type');
assert.equal(
savedArgs[1],
'{"module":"test-module","type":"event-type","severity":"warn"}'
);
// ### ERROR
const error = console.error;
console.error = (...args) => {
savedArgs = args;
};
// Validate formatting
savedArgs = [];
apos.testModule.logError('event-type');
assert.equal(savedArgs[0], 'test-module: event-type');
assert.equal(
savedArgs[1],
'{"module":"test-module","type":"event-type","severity":"error"}'
);
apos.util.generateId = id;
console.debug = debug;
console.info = info;
console.warn = warn;
console.error = error;
});
it('should override default filter configuration', async function () {
await t.destroy(apos);
apos = await t.create({
modules: {
...testModule,
'@apostrophecms/log': {
options: {
filter: {
'*': { severity: [ 'info', 'warn', 'error' ] }
}
}
}
}
});
assert.deepEqual(apos.structuredLog.filters, {
'*': { severity: [ 'info', 'warn', 'error' ] }
});
});
});
describe('APOS_FILTER_LOGS', function () {
beforeEach(async function () {
await t.destroy(apos);
apos = null;
});
after(async function () {
delete process.env.APOS_FILTER_LOGS;
await t.destroy(apos);
apos = null;
});
it('should override default filter configuration (wildcard)', async function () {
process.env.APOS_FILTER_LOGS = '*';
apos = await t.create({
modules: {
...testModule,
'@apostrophecms/log': {
options: {
filter: {
'*': { severity: [ 'info', 'warn', 'error' ] },
'test-module': { events: [ 'type1' ] }
}
}
}
}
});
assert.deepEqual(apos.structuredLog.filters, {
'*': {
severity: [ 'debug', 'info', 'warn', 'error' ]
}
});
});
it('should override filter configuration via env', async function () {
process.env.APOS_FILTER_LOGS = '*:severity:warn,error;test-module:events:type1,type2:severity:info';
apos = await t.create({
modules: {
...testModule,
'@apostrophecms/log': {
options: {
filter: {
'*': { severity: [ 'info', 'warn', 'error' ] },
'test-module': { events: [ 'type3' ] }
}
}
}
}
});
assert.deepEqual(apos.structuredLog.filters, {
'*': {
severity: [ 'warn', 'error' ]
},
'test-module': {
severity: [ 'info' ],
events: [ 'type1', 'type2' ]
}
});
});
});
describe('legacy logging with :messageAs"', function () {
before(async function () {
await t.destroy(apos);
apos = await t.create({
modules: {
'@apostrophecms/log': {
options: {
messageAs: 'msg'
}
}
}
});
});
after(async function () {
delete process.env.APOS_FILTER_LOGS;
await t.destroy(apos);
apos = null;
});
it('should log object: debug', function () {
let savedArgs = [];
const saved = apos.util.logger.debug;
apos.util.logger.debug = (...args) => {
savedArgs = args;
};
savedArgs = [];
apos.util.debug('some message');
assert.deepEqual(savedArgs, [ { msg: 'some message' } ]);
savedArgs = [];
apos.util.debug({ foo: 'bar' });
assert.deepEqual(savedArgs, [ { foo: 'bar' } ]);
savedArgs = [];
apos.util.debug('some message', { foo: 'bar' });
assert.deepEqual(savedArgs, [ {
foo: 'bar',
msg: 'some message'
} ]);
savedArgs = [];
apos.util.debug('some message', 'more', { foo: 'bar' });
assert.deepEqual(savedArgs, [ {
foo: 'bar',
msg: 'some message',
args: [ 'more' ]
} ]);
savedArgs = [];
apos.util.debug({ foo: 'bar' }, 'some message', 'more');
assert.deepEqual(savedArgs, [ {
foo: 'bar',
msg: 'some message',
args: [ 'more' ]
} ]);
apos.util.logger.debug = saved;
});
it('should log object: log', function () {
let savedArgs = [];
const saved = apos.util.logger.log;
apos.util.logger.log = (...args) => {
savedArgs = args;
};
savedArgs = [];
apos.util.log('some message');
assert.deepEqual(savedArgs, [ { msg: 'some message' } ]);
savedArgs = [];
apos.util.log({ foo: 'bar' });
assert.deepEqual(savedArgs, [ { foo: 'bar' } ]);
savedArgs = [];
apos.util.log('some message', { foo: 'bar' });
assert.deepEqual(savedArgs, [ {
foo: 'bar',
msg: 'some message'
} ]);
savedArgs = [];
apos.util.log('some message', 'more', { foo: 'bar' });
assert.deepEqual(savedArgs, [ {
foo: 'bar',
msg: 'some message',
args: [ 'more' ]
} ]);
savedArgs = [];
apos.util.log({ foo: 'bar' }, 'some message', 'more');
assert.deepEqual(savedArgs, [ {
foo: 'bar',
msg: 'some message',
args: [ 'more' ]
} ]);
apos.util.logger.log = saved;
});
it('should log object: info', function () {
let savedArgs = [];
const saved = apos.util.logger.info;
apos.util.logger.info = (...args) => {
savedArgs = args;
};
savedArgs = [];
apos.util.info('some message');
assert.deepEqual(savedArgs, [ { msg: 'some message' } ]);
savedArgs = [];
apos.util.info({ foo: 'bar' });
assert.deepEqual(savedArgs, [ { foo: 'bar' } ]);
savedArgs = [];
apos.util.info('some message', { foo: 'bar' });
assert.deepEqual(savedArgs, [ {
foo: 'bar',
msg: 'some message'
} ]);
savedArgs = [];
apos.util.info('some message', 'more', { foo: 'bar' });
assert.deepEqual(savedArgs, [ {
foo: 'bar',
msg: 'some message',
args: [ 'more' ]
} ]);
savedArgs = [];
apos.util.info({ foo: 'bar' }, 'some message', 'more');
assert.deepEqual(savedArgs, [ {
foo: 'bar',
msg: 'some message',
args: [ 'more' ]
} ]);
apos.util.logger.info = saved;
});
it('should log object: warn', function () {
let savedArgs = [];
const saved = apos.util.logger.warn;
apos.util.logger.warn = (...args) => {
savedArgs = args;
};
savedArgs = [];
apos.util.warn('some message');
assert.deepEqual(savedArgs, [ { msg: 'some message' } ]);
savedArgs = [];
apos.util.warn({ foo: 'bar' });
assert.deepEqual(savedArgs, [ { foo: 'bar' } ]);
savedArgs = [];
apos.util.warn('some message', { foo: 'bar' });
assert.deepEqual(savedArgs, [ {
foo: 'bar',
msg: 'some message'
} ]);
savedArgs = [];
apos.util.warn('some message', 'more', { foo: 'bar' });
assert.deepEqual(savedArgs, [ {
foo: 'bar',
msg: 'some message',
args: [ 'more' ]
} ]);
savedArgs = [];
apos.util.warn({ foo: 'bar' }, 'some message', 'more');
assert.deepEqual(savedArgs, [ {
foo: 'bar',
msg: 'some message',
args: [ 'more' ]
} ]);
apos.util.logger.warn = saved;
});
it('should log object: error', function () {
let savedArgs = [];
const saved = apos.util.logger.error;
apos.util.logger.error = (...args) => {
savedArgs = args;
};
savedArgs = [];
apos.util.error('some message');
assert.deepEqual(savedArgs, [ { msg: 'some message' } ]);
savedArgs = [];
apos.util.error({ foo: 'bar' });
assert.deepEqual(savedArgs, [ { foo: 'bar' } ]);
savedArgs = [];
apos.util.error('some message', { foo: 'bar' });
assert.deepEqual(savedArgs, [ {
foo: 'bar',
msg: 'some message'
} ]);
savedArgs = [];
apos.util.error('some message', 'more', { foo: 'bar' });
assert.deepEqual(savedArgs, [ {
foo: 'bar',
msg: 'some message',
args: [ 'more' ]
} ]);
savedArgs = [];
apos.util.error({ foo: 'bar' }, 'some message', 'more');
assert.deepEqual(savedArgs, [ {
foo: 'bar',
msg: 'some message',
args: [ 'more' ]
} ]);
apos.util.logger.error = saved;
});
it('should log object: warnDev', function () {
let savedArgs = [];
const saved = apos.util.logger.warn;
apos.util.logger.warn = (...args) => {
savedArgs = args;
};
savedArgs = [];
apos.util.warnDev('some message');
assert.deepEqual(savedArgs, [ {
msg: '⚠️ some message'
} ]);
savedArgs = [];
apos.util.warnDev({ foo: 'bar' });
assert.deepEqual(savedArgs, [ {
foo: 'bar'
}
]);
savedArgs = [];
apos.util.warnDev('some message', { foo: 'bar' });
assert.deepEqual(savedArgs, [ {
foo: 'bar',
msg: '⚠️ some message'
} ]);
savedArgs = [];
apos.util.warnDev('some message', 'more', { foo: 'bar' });
assert.deepEqual(savedArgs, [ {
foo: 'bar',
msg: '⚠️ some message',
args: [ 'more' ]
} ]);
savedArgs = [];
apos.util.warnDev({ foo: 'bar' }, 'some message', 'more');
assert.deepEqual(savedArgs, [ {
foo: 'bar',
msg: 'some message',
args: [ 'more' ]
} ]);
apos.util.logger.warn = saved;
});
});
describe('route error', function () {
let user;
let jar;
let aposError;
let consoleError;
let generateId;
async function login() {
// Create user and initialize session.
if (!user) {
user = await t.createAdmin(apos, {
username: 'admin',
password: 'admin'
});
}
jar = await t.getUserJar(apos, user);
await apos.http.get('/', { jar });
}
before(async function () {
await t.destroy(apos);
apos = await t.create({
modules: {
'test-piece': {
extend: '@apostrophecms/piece-type',
fields: {
add: {
field1: {
type: 'string',
label: 'Field1',
required: true
},
field2: {
type: 'string',
label: 'Field2',
required: true
}
}
}
},
'test-module': {
apiRoutes(self) {
return {
post: {
async conflict(req) {
const err = self.apos.error(
'conflict',
'Conflict error',
{ some: 'data' }
);
err.path = 'some.field';
throw err;
}
}
};
}
}
}
});
await login();
aposError = apos.util.logger.error;
generateId = apos.util.generateId;
consoleError = console.error;
});
beforeEach(async function () {
apos.util.logger.error = aposError;
apos.util.generateId = generateId;
console.error = consoleError;
});
after(async function () {
await t.destroy(apos);
apos = null;
});
it('should log invalid error', async function () {
apos.util.generateId = () => 'test-id';
let savedArgs = [];
apos.util.logger.error = (...args) => {
savedArgs = args;
};
try {
await apos.http.post('/api/v1/test-piece', {
body: {},
jar
});
} catch (e) {
//
}
assert.equal(savedArgs[0], 'test-piece: api-error-invalid: invalid');
assert.equal(savedArgs[1].module, 'test-piece');
assert.equal(savedArgs[1].type, 'api-error-invalid');
assert.equal(savedArgs[1].severity, 'error');
assert.equal(savedArgs[1].url, '/api/v1/test-piece');
assert.equal(savedArgs[1].path, '/api/v1/test-piece');
assert.equal(savedArgs[1].method, 'POST');
assert(savedArgs[1].ip);
assert.deepEqual(savedArgs[1].query, {});
assert.equal(savedArgs[1].requestId, 'test-id');
assert.equal(savedArgs[1].name, 'invalid');
assert.equal(Array.isArray(savedArgs[1].stack), true);
assert.equal(savedArgs[1].errorPath, undefined);
assert.deepEqual(savedArgs[1].data.errors, [
{
name: 'required',
code: 422,
message: 'required',
data: {},
path: 'title'
},
{
name: 'required',
code: 422,
message: 'required',
data: {},
path: 'field1'
},
{
name: 'required',
code: 422,
message: 'required',
data: {},
path: 'field2'
}
]);
// Test the property order
savedArgs = [];
apos.util.logger.error = aposError;
console.error = (...args) => {
savedArgs = args;
};
try {
await apos.http.post('/api/v1/test-piece', {
body: {},
jar
});
} catch (e) {
//
}
// Skip IP as it might get changed in CI
assert.equal(savedArgs[0], 'test-piece: api-error-invalid: invalid\n');
assert.equal(
savedArgs[1].startsWith(
`{
"module": "test-piece",
"type": "api-error-invalid",
"severity": "error",
"url": "/api/v1/test-piece",
"path": "/api/v1/test-piece",
"method": "POST",
`
),
true
);
assert.equal(
savedArgs[1].includes(
`
"query": {},
"requestId": "test-id",
"name": "invalid",
"status": 400,
"stack": [
`
),
true
);
assert.equal(
savedArgs[1].endsWith(
`
],
"data": {
"errors": [
{
"name": "required",
"code": 422,
"message": "required",
"data": {},
"path": "title"
},
{
"name": "required",
"code": 422,
"message": "required",
"data": {},
"path": "field1"
},
{
"name": "required",
"code": 422,
"message": "required",
"data": {},
"path": "field2"
}
]
}
}`
),
true
);
});
it('should log conflict error with data and custom message', async function () {
apos.util.generateId = () => 'test-id';
let savedArgs = [];
apos.util.logger.error = (...args) => {
savedArgs = args;
};
try {
await apos.http.post('/api/v1/test-module/conflict', {
qs: { foo: 'bar' },
jar
});
} catch (e) {
//
}
assert.equal(savedArgs[0], 'test-module: api-error-conflict: Conflict error');
assert.equal(savedArgs[1].module, 'test-module');
assert.equal(savedArgs[1].type, 'api-error-conflict');
assert.equal(savedArgs[1].severity, 'error');
assert.equal(savedArgs[1].url, '/api/v1/test-module/conflict?foo=bar');
assert.equal(savedArgs[1].path, '/api/v1/test-module/conflict');
assert.equal(savedArgs[1].method, 'POST');
assert(savedArgs[1].ip);
assert.deepEqual(savedArgs[1].query, { foo: 'bar' });
assert.equal(savedArgs[1].requestId, 'test-id');
assert.equal(savedArgs[1].name, 'conflict');
assert.equal(Array.isArray(savedArgs[1].stack), true);
assert.equal(savedArgs[1].errorPath, 'some.field');
assert.deepEqual(savedArgs[1].data, { some: 'data' });
});
});
describe('login', function () {
let user;
let aposInfo;
async function createInstance() {
apos = await t.create({
modules: {
'@apostrophecms/log': {
options: {
filter: {
'*': {
severity: [ 'info' ]
},
'@apostrophecms/login': {
events: [
'incorrect-username',
'incorrect-password',
'correct-password',
'complete'
]
}
}
}
}
}
});
aposInfo = apos.util.logger.info;
user = await t.createAdmin(apos, {
username: 'admin',
password: 'admin'
});
user.password = 'admin';
}
before(async function () {
await t.destroy(apos);
await createInstance();
});
beforeEach(async function () {
apos.util.logger.info = aposInfo;
});
after(async function () {
await t.destroy(apos);
apos = null;
});
it('should log incorrect username', async function () {
let savedArgs = [];
apos.util.logger.info = (...args) => {
savedArgs = args;
};
const jar = apos.http.jar();
try {
await apos.http.post('/api/v1/@apostrophecms/login/login', {
body: {
username: 'incorrect',
password: user.password,
session: true
},
jar
});
} catch (e) {
//
}
assert.equal(savedArgs[0], '@apostrophecms/login: incorrect-username');
assert(savedArgs[1].ip);
assert(savedArgs[1].requestId);
delete savedArgs[1].ip;
delete savedArgs[1].requestId;
assert.deepEqual(savedArgs[1], {
module: '@apostrophecms/login',
type: 'incorrect-username',
severity: 'info',
username: 'incorrect',
attempts: 1
});
savedArgs = [];
try {
await apos.http.post('/api/v1/@apostrophecms/login/login', {
body: {
username: 'incorrect',
password: user.password,
session: true
},
jar
});
} catch (e) {
//
}
assert.equal(savedArgs[1].attempts, 2);
});
it('should log incorrect password', async function () {
await t.destroy(apos);
await createInstance();
let savedArgs = [];
apos.util.logger.info = (...args) => {
savedArgs = args;
};
const jar = apos.http.jar();
try {
await apos.http.post('/api/v1/@apostrophecms/login/login', {
body: {
username: user.password,
password: 'incorrect',
session: true
},
jar
});
} catch (e) {
//
}
assert.equal(savedArgs[0], '@apostrophecms/login: incorrect-password');
assert(savedArgs[1].ip);
assert(savedArgs[1].requestId);
delete savedArgs[1].ip;
delete savedArgs[1].requestId;
assert.deepEqual(savedArgs[1], {
module: '@apostrophecms/login',
type: 'incorrect-password',
severity: 'info',
username: user.username,
attempts: 1
});
savedArgs = [];
try {
await apos.http.post('/api/v1/@apostrophecms/login/login', {
body: {
username: user.password,
password: 'incorrect',
session: true
},
jar
});
} catch (e) {
//
}
assert.equal(savedArgs[1].attempts, 2);
});
it('should log login complete', async function () {
await t.destroy(apos);
await createInstance();
const jar = apos.http.jar();
try {
await apos.http.post('/api/v1/@apostrophecms/login/login', {
body: {
username: user.password,
password: 'incorrect',
session: true
},
jar
});
} catch (e) {
//
}
let savedArgs = [];
apos.util.logger.info = (...args) => {
savedArgs = args;
};
savedArgs = [];
try {
await apos.http.post('/api/v1/@apostrophecms/login/login', {
body: {
username: user.password,
password: user.password,
session: true
},
jar
});
} catch (e) {
//
}
assert.equal(savedArgs[0], '@apostrophecms/login: complete');
assert(savedArgs[1].ip);
assert(savedArgs[1].requestId);
delete savedArgs[1].ip;
delete savedArgs[1].requestId;
assert.deepEqual(savedArgs[1], {
module: '@apostrophecms/login',
type: 'complete',
severity: 'info',
url: '/api/v1/@apostrophecms/login/login',
path: '/api/v1/@apostrophecms/login/login',
method: 'POST',
query: {},
username: 'admin',
attempts: 1
});
});
});
});