log4js-knex
Advanced tools
Comparing version 0.2.0 to 0.2.1
@@ -9,3 +9,3 @@ const log4js = require('log4js'); | ||
const layouts = { | ||
messagePassThrough: jest.fn((data) => JSON.stringify(data)) | ||
messagePassThroughLayout: jest.fn((data) => JSON.stringify(data)) | ||
}; | ||
@@ -47,41 +47,2 @@ | ||
it('should initialize knex correctly when insert fails initially', () => { | ||
const insert = jest.fn(); | ||
insert.mockImplementationOnce(() => Promise.reject(new Error("Missing table"))); | ||
insert.mockImplementationOnce(() => Promise.resolve()); | ||
const handler = {insert: insert}; | ||
const connection = jest.fn(() => handler); | ||
connection.schema = { | ||
createTable: jest.fn(() => Promise.resolve()) | ||
}; | ||
require('knex').__setMockConnection(connection); | ||
const appender = log4jsKnex.configure(knexConfig, layouts); | ||
return appender({data: [], level: {level: "HIGH"}, logger: {category: "default"}}) | ||
.then(() => { | ||
expect(insert).toBeCalledTimes(2); | ||
expect(connection.schema.createTable).toBeCalled(); | ||
}) | ||
}); | ||
it('should fail when table creation fails', () => { | ||
const insert = jest.fn(); | ||
insert.mockImplementationOnce(() => Promise.reject(new Error("Missing table"))); | ||
insert.mockImplementationOnce(() => Promise.resolve()); | ||
const handler = {insert: insert}; | ||
const connection = jest.fn(() => handler); | ||
connection.schema = { | ||
createTable: jest.fn(() => Promise.reject(new Error("Can't create table"))) | ||
}; | ||
require('knex').__setMockConnection(connection); | ||
const appender = log4jsKnex.configure(knexConfig, layouts); | ||
const result = appender({data: [], level: {level: "HIGH"}, logger: {category: "default"}}) | ||
.then(() => { | ||
expect(insert).toBeCalledTimes(2); | ||
expect(connection.schema.createTable).toBeCalled(); | ||
}); | ||
return expect(result).rejects.toThrow(/Missing table/); | ||
}); | ||
it('should handle a configured layout', () => { | ||
@@ -111,47 +72,2 @@ const insert = jest.fn(); | ||
it('should throw the original error if needed', () => { | ||
const insert = jest.fn(); | ||
insert.mockImplementationOnce(() => Promise.reject(new Error("Unexpected error"))); | ||
insert.mockImplementationOnce(() => Promise.reject(new Error("Something else"))); | ||
const handler = {insert: insert}; | ||
const connection = jest.fn(() => handler); | ||
connection.schema = { | ||
createTable: jest.fn(() => Promise.resolve()) | ||
}; | ||
require('knex').__setMockConnection(connection); | ||
const appender = log4jsKnex.configure(knexConfig, layouts); | ||
const result = appender({data: [], level: {level: "HIGH"}, logger: {category: "default"}}); | ||
return expect(result).rejects.toThrow(/Unexpected error/); | ||
}); | ||
it('should handle the table creation', () => { | ||
const insert = jest.fn(); | ||
insert.mockImplementationOnce(() => Promise.reject(new Error("Missing table"))); | ||
insert.mockImplementationOnce(() => Promise.resolve()); | ||
const handler = {insert: insert}; | ||
const connection = jest.fn(() => handler); | ||
connection.schema = { | ||
createTable: jest.fn(() => Promise.resolve()) | ||
}; | ||
require('knex').__setMockConnection(connection); | ||
const appender = log4jsKnex.configure(knexConfig, layouts); | ||
return appender({data: [], level: {level: "HIGH"}, logger: {category: "default"}}) | ||
.then(() => { | ||
expect(insert).toBeCalledTimes(2); | ||
expect(connection.schema.createTable).toBeCalledWith('log', expect.any(Function)); | ||
const callback = connection.schema.createTable.mock.calls[0][1]; | ||
expect(callback).toBeInstanceOf(Function); | ||
const table = {}; | ||
table.increments = jest.fn(); | ||
table.timestamp = jest.fn(() => table); | ||
table.string = jest.fn(() => table); | ||
table.integer = jest.fn(() => table); | ||
table.notNullable = jest.fn(() => table); | ||
return callback(table); | ||
}) | ||
}); | ||
}); |
@@ -5,2 +5,8 @@ Change log | ||
### Version 0.2.1 - 31th October 2018 | ||
* Fixed issues in category and level logging. See #4, #5 | ||
* Removed table creation logic, which was a bad idea anyway. See #6 | ||
### Version 0.2.0 - 30th October 2018 | ||
@@ -7,0 +13,0 @@ |
'use strict'; | ||
var log4js = require('log4js'); | ||
var Knex = require('knex'); | ||
@@ -26,3 +25,3 @@ | ||
} else { | ||
layout = layouts.messagePassThrough; | ||
layout = layouts.messagePassThroughLayout; | ||
} | ||
@@ -33,44 +32,9 @@ | ||
// Solution to the performance issues of testing for an existing table before logging | ||
// is to write the damn row and check after. This is probably (definitely) a bit of a | ||
// risk for portability, but loggers aren't that good for one-off configuration, and | ||
// reaally, it should be a decent solution. | ||
// The naive logic is as follows. If we get an error on insert -- any error -- then we | ||
// try to add a table. If we fail to do that, throw the original error. If we succeed, | ||
// try a second time to add the row, but this time without any safety net. | ||
// Logically, there could be a timing issue here on startup. If two processes attempt | ||
// to log, both fail, and both attempt to create, one will signal an error. | ||
function createTableIfNeeded(loggingEvent, originalError) { | ||
return knex.schema.createTable(tableName, function (table) { | ||
table.increments(); | ||
table.timestamp('time').notNullable(); | ||
table.string('data', 4096).notNullable(); | ||
table.integer('rank').notNullable(); | ||
table.string('level', 12).notNullable(); | ||
table.string('category', 64).notNullable(); | ||
}) | ||
.catch((err) => { | ||
throw originalError; | ||
}) | ||
.then(() => writeEvent(loggingEvent, originalError)); | ||
} | ||
function writeEvent(loggingEvent, originalError) { | ||
const formatted = layout(loggingEvent); | ||
function writeEvent(loggingEvent) { | ||
return knex(tableName).insert({ | ||
time: loggingEvent.startTime, | ||
data: formatted, | ||
data: layout(loggingEvent), | ||
rank: loggingEvent.level.level, | ||
level: loggingEvent.level.levelStr, | ||
category: loggingEvent.logger.category | ||
}) | ||
.catch(function(err) { | ||
if (originalError) { | ||
throw originalError; | ||
} else { | ||
return createTableIfNeeded(loggingEvent, err); | ||
} | ||
category: loggingEvent.categoryName | ||
}); | ||
@@ -77,0 +41,0 @@ }; |
{ | ||
"name": "log4js-knex", | ||
"version": "0.2.0", | ||
"version": "0.2.1", | ||
"description": "A Knex.js backend for log4js, with sqlite3/mysql support", | ||
@@ -5,0 +5,0 @@ "keywords": [ |
@@ -7,12 +7,23 @@ log4js-knex | ||
You can use it either with a set of connection values: | ||
You can use it with a standard configuration as follows: | ||
``` | ||
var log4js = require('log4js'); | ||
var log4jsKnex = require('log4js-knex'); | ||
log4js.configure({ | ||
appenders: { | ||
database: { | ||
"type": "log4js-knex", | ||
"table": "log", | ||
"knex": { | ||
"client": "sqlite", | ||
"connection": { | ||
"filename": "./log.sqlite3" | ||
}, | ||
"useNullAsDefault": true | ||
} | ||
} | ||
}, | ||
categories: { default: { appenders: ['database'], level: 'debug' } } | ||
}) | ||
log4js.addAppender( | ||
log4jsKnex.appender({table: 'log', knex: {client: 'sqlite', connection: {filename: './test.db'}}}) | ||
); | ||
var logger = log4js.getLogger(); | ||
@@ -22,21 +33,20 @@ logger.debug("Added debug"); | ||
Or, if you have an existing `knex` connection, you can pass that directly: | ||
The default table name is `log`, although that can be overridden by passing the `table` | ||
option as shown above. The appender does not attempt to create this table. | ||
This is a change from previous versions, but it's more sensible for security reasons | ||
to limit permissions to those needed to manage data insertion only. If you're using | ||
Knex.js, one extra migration is simple anyway. In Knex.js, a schema change like this | ||
can be used: | ||
``` | ||
var log4js = require('log4js'); | ||
var log4jsKnex = require('log4js-knex'); | ||
var knex = require('knex')(...); | ||
return knex.schema.createTable(tableName, function (table) { | ||
table.increments(); | ||
table.timestamp('time').notNullable(); | ||
table.string('data', 4096).notNullable(); | ||
table.integer('rank').notNullable(); | ||
table.string('level', 12).notNullable(); | ||
table.string('category', 64).notNullable(); | ||
table.index('time'); | ||
}); | ||
log4js.addAppender( | ||
log4jsKnex.appender({table: 'log', knex: knex}); | ||
); | ||
var logger = log4js.getLogger(); | ||
logger.warn("You have been warned"); | ||
``` | ||
The default table name is `log`, and if there's an error when writing, the appender | ||
will attempt to create the table before having a second attempt at writing. This | ||
should create the table for you if it doesn't already exist. | ||
Author | ||
@@ -43,0 +53,0 @@ ------ |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
80
0
0
8956
7
101