chore(log): remove build step
It also helps with compatibility with native ESM for default exports.
This commit is contained in:
parent
a126b5b61b
commit
0c6d920682
@ -1 +0,0 @@
|
|||||||
module.exports = require('../../@xen-orchestra/babel-config')(require('./package.json'))
|
|
@ -1 +0,0 @@
|
|||||||
../../scripts/babel-eslintrc.js
|
|
@ -1 +1,107 @@
|
|||||||
module.exports = require('./dist/configure')
|
const createConsoleTransport = require('./transports/console')
|
||||||
|
const { LEVELS, resolve } = require('./levels')
|
||||||
|
const { compileGlobPattern } = require('./utils')
|
||||||
|
|
||||||
|
// ===================================================================
|
||||||
|
|
||||||
|
const createTransport = config => {
|
||||||
|
if (typeof config === 'function') {
|
||||||
|
return config
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Array.isArray(config)) {
|
||||||
|
const transports = config.map(createTransport)
|
||||||
|
const { length } = transports
|
||||||
|
return function () {
|
||||||
|
for (let i = 0; i < length; ++i) {
|
||||||
|
transports[i].apply(this, arguments)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let { filter } = config
|
||||||
|
let transport = createTransport(config.transport)
|
||||||
|
const level = resolve(config.level)
|
||||||
|
|
||||||
|
if (filter !== undefined) {
|
||||||
|
if (typeof filter === 'string') {
|
||||||
|
const re = compileGlobPattern(filter)
|
||||||
|
filter = log => re.test(log.namespace)
|
||||||
|
}
|
||||||
|
|
||||||
|
const orig = transport
|
||||||
|
transport = function (log) {
|
||||||
|
if ((level !== undefined && log.level >= level) || filter(log)) {
|
||||||
|
return orig.apply(this, arguments)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (level !== undefined) {
|
||||||
|
const orig = transport
|
||||||
|
transport = function (log) {
|
||||||
|
if (log.level >= level) {
|
||||||
|
return orig.apply(this, arguments)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return transport
|
||||||
|
}
|
||||||
|
|
||||||
|
const symbol = typeof Symbol !== 'undefined' ? Symbol.for('@xen-orchestra/log') : '@@@xen-orchestra/log'
|
||||||
|
|
||||||
|
const { env } = process
|
||||||
|
global[symbol] = createTransport({
|
||||||
|
// display warnings or above, and all that are enabled via DEBUG or
|
||||||
|
// NODE_DEBUG env
|
||||||
|
filter: [env.DEBUG, env.NODE_DEBUG].filter(Boolean).join(','),
|
||||||
|
level: resolve(env.LOG_LEVEL, LEVELS.INFO),
|
||||||
|
|
||||||
|
transport: createConsoleTransport(),
|
||||||
|
})
|
||||||
|
|
||||||
|
const configure = config => {
|
||||||
|
global[symbol] = createTransport(config)
|
||||||
|
}
|
||||||
|
exports.configure = configure
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------
|
||||||
|
|
||||||
|
const catchGlobalErrors = logger => {
|
||||||
|
// patch process
|
||||||
|
const onUncaughtException = error => {
|
||||||
|
logger.error('uncaught exception', { error })
|
||||||
|
}
|
||||||
|
const onUnhandledRejection = error => {
|
||||||
|
logger.warn('possibly unhandled rejection', { error })
|
||||||
|
}
|
||||||
|
const onWarning = error => {
|
||||||
|
logger.warn('Node warning', { error })
|
||||||
|
}
|
||||||
|
process.on('uncaughtException', onUncaughtException)
|
||||||
|
process.on('unhandledRejection', onUnhandledRejection)
|
||||||
|
process.on('warning', onWarning)
|
||||||
|
|
||||||
|
// patch EventEmitter
|
||||||
|
const EventEmitter = require('events')
|
||||||
|
const { prototype } = EventEmitter
|
||||||
|
const { emit } = prototype
|
||||||
|
function patchedEmit(event, error) {
|
||||||
|
if (event === 'error' && this.listenerCount(event) === 0) {
|
||||||
|
logger.error('unhandled error event', { error })
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return emit.apply(this, arguments)
|
||||||
|
}
|
||||||
|
prototype.emit = patchedEmit
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
process.removeListener('uncaughtException', onUncaughtException)
|
||||||
|
process.removeListener('unhandledRejection', onUnhandledRejection)
|
||||||
|
process.removeListener('warning', onWarning)
|
||||||
|
|
||||||
|
if (prototype.emit === patchedEmit) {
|
||||||
|
prototype.emit = emit
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
exports.catchGlobalErrors = catchGlobalErrors
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import createTransport from './transports/console'
|
const createTransport = require('./transports/console')
|
||||||
import LEVELS, { resolve } from './levels'
|
const { LEVELS, resolve } = require('./levels')
|
||||||
|
|
||||||
const symbol = typeof Symbol !== 'undefined' ? Symbol.for('@xen-orchestra/log') : '@@@xen-orchestra/log'
|
const symbol = typeof Symbol !== 'undefined' ? Symbol.for('@xen-orchestra/log') : '@@@xen-orchestra/log'
|
||||||
if (!(symbol in global)) {
|
if (!(symbol in global)) {
|
||||||
@ -68,5 +68,7 @@ prototype.wrap = function (message, fn) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const createLogger = namespace => new Logger(namespace)
|
const createLogger = namespace => new Logger(namespace)
|
||||||
export { createLogger as default }
|
|
||||||
|
module.exports = exports = createLogger
|
||||||
|
exports.createLogger = createLogger
|
@ -1,5 +1,5 @@
|
|||||||
const LEVELS = Object.create(null)
|
const LEVELS = Object.create(null)
|
||||||
export { LEVELS as default }
|
exports.LEVELS = LEVELS
|
||||||
|
|
||||||
// https://github.com/trentm/node-bunyan#levels
|
// https://github.com/trentm/node-bunyan#levels
|
||||||
LEVELS.FATAL = 60 // service/app is going down
|
LEVELS.FATAL = 60 // service/app is going down
|
||||||
@ -8,7 +8,8 @@ LEVELS.WARN = 40 // something went wrong but it's not fatal
|
|||||||
LEVELS.INFO = 30 // detail on unusual but normal operation
|
LEVELS.INFO = 30 // detail on unusual but normal operation
|
||||||
LEVELS.DEBUG = 20
|
LEVELS.DEBUG = 20
|
||||||
|
|
||||||
export const NAMES = Object.create(null)
|
const NAMES = Object.create(null)
|
||||||
|
exports.NAMES = NAMES
|
||||||
for (const name in LEVELS) {
|
for (const name in LEVELS) {
|
||||||
NAMES[LEVELS[name]] = name
|
NAMES[LEVELS[name]] = name
|
||||||
}
|
}
|
||||||
@ -16,7 +17,7 @@ for (const name in LEVELS) {
|
|||||||
// resolves to the number representation of a level
|
// resolves to the number representation of a level
|
||||||
//
|
//
|
||||||
// returns `defaultLevel` if invalid
|
// returns `defaultLevel` if invalid
|
||||||
export const resolve = (level, defaultLevel) => {
|
const resolve = (level, defaultLevel) => {
|
||||||
const type = typeof level
|
const type = typeof level
|
||||||
if (type === 'number') {
|
if (type === 'number') {
|
||||||
if (level in NAMES) {
|
if (level in NAMES) {
|
||||||
@ -30,6 +31,7 @@ export const resolve = (level, defaultLevel) => {
|
|||||||
}
|
}
|
||||||
return defaultLevel
|
return defaultLevel
|
||||||
}
|
}
|
||||||
|
exports.resolve = resolve
|
||||||
|
|
||||||
Object.freeze(LEVELS)
|
Object.freeze(LEVELS)
|
||||||
Object.freeze(NAMES)
|
Object.freeze(NAMES)
|
@ -1,8 +1,8 @@
|
|||||||
/* eslint-env jest */
|
/* eslint-env jest */
|
||||||
|
|
||||||
import { forEach, isInteger } from 'lodash'
|
const { forEach, isInteger } = require('lodash')
|
||||||
|
|
||||||
import LEVELS, { NAMES, resolve } from './levels'
|
const { LEVELS, NAMES, resolve } = require('./levels')
|
||||||
|
|
||||||
describe('LEVELS', () => {
|
describe('LEVELS', () => {
|
||||||
it('maps level names to their integer values', () => {
|
it('maps level names to their integer values', () => {
|
@ -16,7 +16,6 @@
|
|||||||
"url": "https://vates.fr"
|
"url": "https://vates.fr"
|
||||||
},
|
},
|
||||||
"preferGlobal": false,
|
"preferGlobal": false,
|
||||||
"main": "dist/",
|
|
||||||
"browserslist": [
|
"browserslist": [
|
||||||
">2%"
|
">2%"
|
||||||
],
|
],
|
||||||
@ -27,21 +26,7 @@
|
|||||||
"lodash": "^4.17.4",
|
"lodash": "^4.17.4",
|
||||||
"promise-toolbox": "^0.19.2"
|
"promise-toolbox": "^0.19.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
|
||||||
"@babel/cli": "^7.0.0",
|
|
||||||
"@babel/core": "^7.0.0",
|
|
||||||
"@babel/preset-env": "^7.0.0",
|
|
||||||
"babel-plugin-lodash": "^3.3.2",
|
|
||||||
"cross-env": "^7.0.2",
|
|
||||||
"rimraf": "^3.0.0"
|
|
||||||
},
|
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "cross-env NODE_ENV=production babel --source-maps --out-dir=dist/ src/",
|
|
||||||
"clean": "rimraf dist/",
|
|
||||||
"dev": "cross-env NODE_ENV=development babel --watch --source-maps --out-dir=dist/ src/",
|
|
||||||
"prebuild": "yarn run clean",
|
|
||||||
"predev": "yarn run prebuild",
|
|
||||||
"prepublishOnly": "yarn run build",
|
|
||||||
"postversion": "npm publish"
|
"postversion": "npm publish"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,105 +0,0 @@
|
|||||||
import createConsoleTransport from './transports/console'
|
|
||||||
import LEVELS, { resolve } from './levels'
|
|
||||||
import { compileGlobPattern } from './utils'
|
|
||||||
|
|
||||||
// ===================================================================
|
|
||||||
|
|
||||||
const createTransport = config => {
|
|
||||||
if (typeof config === 'function') {
|
|
||||||
return config
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Array.isArray(config)) {
|
|
||||||
const transports = config.map(createTransport)
|
|
||||||
const { length } = transports
|
|
||||||
return function () {
|
|
||||||
for (let i = 0; i < length; ++i) {
|
|
||||||
transports[i].apply(this, arguments)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let { filter } = config
|
|
||||||
let transport = createTransport(config.transport)
|
|
||||||
const level = resolve(config.level)
|
|
||||||
|
|
||||||
if (filter !== undefined) {
|
|
||||||
if (typeof filter === 'string') {
|
|
||||||
const re = compileGlobPattern(filter)
|
|
||||||
filter = log => re.test(log.namespace)
|
|
||||||
}
|
|
||||||
|
|
||||||
const orig = transport
|
|
||||||
transport = function (log) {
|
|
||||||
if ((level !== undefined && log.level >= level) || filter(log)) {
|
|
||||||
return orig.apply(this, arguments)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (level !== undefined) {
|
|
||||||
const orig = transport
|
|
||||||
transport = function (log) {
|
|
||||||
if (log.level >= level) {
|
|
||||||
return orig.apply(this, arguments)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return transport
|
|
||||||
}
|
|
||||||
|
|
||||||
const symbol = typeof Symbol !== 'undefined' ? Symbol.for('@xen-orchestra/log') : '@@@xen-orchestra/log'
|
|
||||||
|
|
||||||
const { env } = process
|
|
||||||
global[symbol] = createTransport({
|
|
||||||
// display warnings or above, and all that are enabled via DEBUG or
|
|
||||||
// NODE_DEBUG env
|
|
||||||
filter: [env.DEBUG, env.NODE_DEBUG].filter(Boolean).join(','),
|
|
||||||
level: resolve(env.LOG_LEVEL, LEVELS.INFO),
|
|
||||||
|
|
||||||
transport: createConsoleTransport(),
|
|
||||||
})
|
|
||||||
|
|
||||||
export const configure = config => {
|
|
||||||
global[symbol] = createTransport(config)
|
|
||||||
}
|
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
|
||||||
|
|
||||||
export const catchGlobalErrors = logger => {
|
|
||||||
// patch process
|
|
||||||
const onUncaughtException = error => {
|
|
||||||
logger.error('uncaught exception', { error })
|
|
||||||
}
|
|
||||||
const onUnhandledRejection = error => {
|
|
||||||
logger.warn('possibly unhandled rejection', { error })
|
|
||||||
}
|
|
||||||
const onWarning = error => {
|
|
||||||
logger.warn('Node warning', { error })
|
|
||||||
}
|
|
||||||
process.on('uncaughtException', onUncaughtException)
|
|
||||||
process.on('unhandledRejection', onUnhandledRejection)
|
|
||||||
process.on('warning', onWarning)
|
|
||||||
|
|
||||||
// patch EventEmitter
|
|
||||||
const EventEmitter = require('events')
|
|
||||||
const { prototype } = EventEmitter
|
|
||||||
const { emit } = prototype
|
|
||||||
function patchedEmit(event, error) {
|
|
||||||
if (event === 'error' && this.listenerCount(event) === 0) {
|
|
||||||
logger.error('unhandled error event', { error })
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return emit.apply(this, arguments)
|
|
||||||
}
|
|
||||||
prototype.emit = patchedEmit
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
process.removeListener('uncaughtException', onUncaughtException)
|
|
||||||
process.removeListener('unhandledRejection', onUnhandledRejection)
|
|
||||||
process.removeListener('warning', onWarning)
|
|
||||||
|
|
||||||
if (prototype.emit === patchedEmit) {
|
|
||||||
prototype.emit = emit
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,79 +0,0 @@
|
|||||||
import LEVELS, { NAMES } from '../levels'
|
|
||||||
|
|
||||||
const { DEBUG, ERROR, FATAL, INFO, WARN } = LEVELS
|
|
||||||
|
|
||||||
let formatLevel, formatNamespace
|
|
||||||
if (process.stdout !== undefined && process.stdout.isTTY && process.stderr !== undefined && process.stderr.isTTY) {
|
|
||||||
const ansi = (style, str) => `\x1b[${style}m${str}\x1b[0m`
|
|
||||||
|
|
||||||
const LEVEL_STYLES = {
|
|
||||||
[DEBUG]: '2',
|
|
||||||
[ERROR]: '1;31',
|
|
||||||
[FATAL]: '1;31',
|
|
||||||
[INFO]: '1',
|
|
||||||
[WARN]: '1;33',
|
|
||||||
}
|
|
||||||
formatLevel = level => {
|
|
||||||
const style = LEVEL_STYLES[level]
|
|
||||||
const name = NAMES[level]
|
|
||||||
return style === undefined ? name : ansi(style, name)
|
|
||||||
}
|
|
||||||
|
|
||||||
const NAMESPACE_COLORS = [
|
|
||||||
196,
|
|
||||||
202,
|
|
||||||
208,
|
|
||||||
214,
|
|
||||||
220,
|
|
||||||
226,
|
|
||||||
190,
|
|
||||||
154,
|
|
||||||
118,
|
|
||||||
82,
|
|
||||||
46,
|
|
||||||
47,
|
|
||||||
48,
|
|
||||||
49,
|
|
||||||
50,
|
|
||||||
51,
|
|
||||||
45,
|
|
||||||
39,
|
|
||||||
33,
|
|
||||||
27,
|
|
||||||
21,
|
|
||||||
57,
|
|
||||||
93,
|
|
||||||
129,
|
|
||||||
165,
|
|
||||||
201,
|
|
||||||
200,
|
|
||||||
199,
|
|
||||||
198,
|
|
||||||
197,
|
|
||||||
]
|
|
||||||
formatNamespace = namespace => {
|
|
||||||
// https://werxltd.com/wp/2010/05/13/javascript-implementation-of-javas-string-hashcode-method/
|
|
||||||
let hash = 0
|
|
||||||
for (let i = 0, n = namespace.length; i < n; ++i) {
|
|
||||||
hash = ((hash << 5) - hash + namespace.charCodeAt(i)) | 0
|
|
||||||
}
|
|
||||||
return ansi(`1;38;5;${NAMESPACE_COLORS[Math.abs(hash) % NAMESPACE_COLORS.length]}`, namespace)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
formatLevel = str => NAMES[str]
|
|
||||||
formatNamespace = str => str
|
|
||||||
}
|
|
||||||
|
|
||||||
const consoleTransport = ({ data, level, namespace, message, time }) => {
|
|
||||||
const fn =
|
|
||||||
/* eslint-disable no-console */
|
|
||||||
level < INFO ? console.log : level < WARN ? console.info : level < ERROR ? console.warn : console.error
|
|
||||||
/* eslint-enable no-console */
|
|
||||||
|
|
||||||
const args = [time.toISOString(), formatNamespace(namespace), formatLevel(level), message]
|
|
||||||
if (data != null) {
|
|
||||||
args.push(data)
|
|
||||||
}
|
|
||||||
fn.apply(console, args)
|
|
||||||
}
|
|
||||||
export default () => consoleTransport
|
|
@ -1,64 +0,0 @@
|
|||||||
import fromCallback from 'promise-toolbox/fromCallback'
|
|
||||||
import prettyFormat from 'pretty-format' // eslint-disable-line node/no-extraneous-import
|
|
||||||
import { createTransport } from 'nodemailer' // eslint-disable-line node/no-extraneous-import
|
|
||||||
|
|
||||||
import { evalTemplate, required } from '../utils'
|
|
||||||
import { NAMES } from '../levels'
|
|
||||||
|
|
||||||
export default ({
|
|
||||||
// transport options (https://nodemailer.com/smtp/)
|
|
||||||
auth,
|
|
||||||
authMethod,
|
|
||||||
host,
|
|
||||||
ignoreTLS,
|
|
||||||
port,
|
|
||||||
proxy,
|
|
||||||
requireTLS,
|
|
||||||
secure,
|
|
||||||
service,
|
|
||||||
tls,
|
|
||||||
|
|
||||||
// message options (https://nodemailer.com/message/)
|
|
||||||
bcc,
|
|
||||||
cc,
|
|
||||||
from = required('from'),
|
|
||||||
to = required('to'),
|
|
||||||
subject = '[{{level}} - {{namespace}}] {{time}} {{message}}',
|
|
||||||
}) => {
|
|
||||||
const transporter = createTransport(
|
|
||||||
{
|
|
||||||
auth,
|
|
||||||
authMethod,
|
|
||||||
host,
|
|
||||||
ignoreTLS,
|
|
||||||
port,
|
|
||||||
proxy,
|
|
||||||
requireTLS,
|
|
||||||
secure,
|
|
||||||
service,
|
|
||||||
tls,
|
|
||||||
|
|
||||||
disableFileAccess: true,
|
|
||||||
disableUrlAccess: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
bcc,
|
|
||||||
cc,
|
|
||||||
from,
|
|
||||||
to,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
return log =>
|
|
||||||
fromCallback(cb =>
|
|
||||||
transporter.sendMail(
|
|
||||||
{
|
|
||||||
subject: evalTemplate(subject, key =>
|
|
||||||
key === 'level' ? NAMES[log.level] : key === 'time' ? log.time.toISOString() : log[key]
|
|
||||||
),
|
|
||||||
text: prettyFormat(log.data),
|
|
||||||
},
|
|
||||||
cb
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
@ -1,7 +0,0 @@
|
|||||||
export default () => {
|
|
||||||
const memoryLogger = log => {
|
|
||||||
logs.push(log)
|
|
||||||
}
|
|
||||||
const logs = (memoryLogger.logs = [])
|
|
||||||
return memoryLogger
|
|
||||||
}
|
|
@ -1,41 +0,0 @@
|
|||||||
import fromCallback from 'promise-toolbox/fromCallback'
|
|
||||||
import splitHost from 'split-host'
|
|
||||||
import { createClient, Facility, Severity, Transport } from 'syslog-client'
|
|
||||||
|
|
||||||
import LEVELS from '../levels'
|
|
||||||
|
|
||||||
// https://github.com/paulgrove/node-syslog-client#syslogseverity
|
|
||||||
const LEVEL_TO_SEVERITY = {
|
|
||||||
[LEVELS.FATAL]: Severity.Critical,
|
|
||||||
[LEVELS.ERROR]: Severity.Error,
|
|
||||||
[LEVELS.WARN]: Severity.Warning,
|
|
||||||
[LEVELS.INFO]: Severity.Informational,
|
|
||||||
[LEVELS.DEBUG]: Severity.Debug,
|
|
||||||
}
|
|
||||||
|
|
||||||
const facility = Facility.User
|
|
||||||
|
|
||||||
export default target => {
|
|
||||||
const opts = {}
|
|
||||||
if (target !== undefined) {
|
|
||||||
if (target.startsWith('tcp://')) {
|
|
||||||
target = target.slice(6)
|
|
||||||
opts.transport = Transport.Tcp
|
|
||||||
} else if (target.startsWith('udp://')) {
|
|
||||||
target = target.slice(6)
|
|
||||||
opts.transport = Transport.Udp
|
|
||||||
}
|
|
||||||
|
|
||||||
;({ host: target, port: opts.port } = splitHost(target))
|
|
||||||
}
|
|
||||||
|
|
||||||
const client = createClient(target, opts)
|
|
||||||
|
|
||||||
return log =>
|
|
||||||
fromCallback(cb =>
|
|
||||||
client.log(log.message, {
|
|
||||||
facility,
|
|
||||||
severity: LEVEL_TO_SEVERITY[log.level],
|
|
||||||
})
|
|
||||||
)
|
|
||||||
}
|
|
@ -1 +1,82 @@
|
|||||||
module.exports = require('../dist/transports/console.js')
|
const { LEVELS, NAMES } = require('../levels')
|
||||||
|
|
||||||
|
const { DEBUG, ERROR, FATAL, INFO, WARN } = LEVELS
|
||||||
|
|
||||||
|
let formatLevel, formatNamespace
|
||||||
|
if (process.stdout !== undefined && process.stdout.isTTY && process.stderr !== undefined && process.stderr.isTTY) {
|
||||||
|
const ansi = (style, str) => `\x1b[${style}m${str}\x1b[0m`
|
||||||
|
|
||||||
|
const LEVEL_STYLES = {
|
||||||
|
[DEBUG]: '2',
|
||||||
|
[ERROR]: '1;31',
|
||||||
|
[FATAL]: '1;31',
|
||||||
|
[INFO]: '1',
|
||||||
|
[WARN]: '1;33',
|
||||||
|
}
|
||||||
|
formatLevel = level => {
|
||||||
|
const style = LEVEL_STYLES[level]
|
||||||
|
const name = NAMES[level]
|
||||||
|
return style === undefined ? name : ansi(style, name)
|
||||||
|
}
|
||||||
|
|
||||||
|
const NAMESPACE_COLORS = [
|
||||||
|
196,
|
||||||
|
202,
|
||||||
|
208,
|
||||||
|
214,
|
||||||
|
220,
|
||||||
|
226,
|
||||||
|
190,
|
||||||
|
154,
|
||||||
|
118,
|
||||||
|
82,
|
||||||
|
46,
|
||||||
|
47,
|
||||||
|
48,
|
||||||
|
49,
|
||||||
|
50,
|
||||||
|
51,
|
||||||
|
45,
|
||||||
|
39,
|
||||||
|
33,
|
||||||
|
27,
|
||||||
|
21,
|
||||||
|
57,
|
||||||
|
93,
|
||||||
|
129,
|
||||||
|
165,
|
||||||
|
201,
|
||||||
|
200,
|
||||||
|
199,
|
||||||
|
198,
|
||||||
|
197,
|
||||||
|
]
|
||||||
|
formatNamespace = namespace => {
|
||||||
|
// https://werxltd.com/wp/2010/05/13/javascript-implementation-of-javas-string-hashcode-method/
|
||||||
|
let hash = 0
|
||||||
|
for (let i = 0, n = namespace.length; i < n; ++i) {
|
||||||
|
hash = ((hash << 5) - hash + namespace.charCodeAt(i)) | 0
|
||||||
|
}
|
||||||
|
return ansi(`1;38;5;${NAMESPACE_COLORS[Math.abs(hash) % NAMESPACE_COLORS.length]}`, namespace)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
formatLevel = str => NAMES[str]
|
||||||
|
formatNamespace = str => str
|
||||||
|
}
|
||||||
|
|
||||||
|
const consoleTransport = ({ data, level, namespace, message, time }) => {
|
||||||
|
const fn =
|
||||||
|
/* eslint-disable no-console */
|
||||||
|
level < INFO ? console.log : level < WARN ? console.info : level < ERROR ? console.warn : console.error
|
||||||
|
/* eslint-enable no-console */
|
||||||
|
|
||||||
|
const args = [time.toISOString(), formatNamespace(namespace), formatLevel(level), message]
|
||||||
|
if (data != null) {
|
||||||
|
args.push(data)
|
||||||
|
}
|
||||||
|
fn.apply(console, args)
|
||||||
|
}
|
||||||
|
|
||||||
|
const createTransport = () => consoleTransport
|
||||||
|
|
||||||
|
module.exports = exports = createTransport
|
||||||
|
@ -1 +1,66 @@
|
|||||||
module.exports = require('../dist/transports/email.js')
|
const fromCallback = require('promise-toolbox/fromCallback')
|
||||||
|
const nodemailer = require('nodemailer') // eslint-disable-line node/no-extraneous-import
|
||||||
|
const prettyFormat = require('pretty-format') // eslint-disable-line node/no-extraneous-import
|
||||||
|
|
||||||
|
const { evalTemplate, required } = require('../utils')
|
||||||
|
const { NAMES } = require('../levels')
|
||||||
|
|
||||||
|
function createTransport({
|
||||||
|
// transport options (https://nodemailer.com/smtp/)
|
||||||
|
auth,
|
||||||
|
authMethod,
|
||||||
|
host,
|
||||||
|
ignoreTLS,
|
||||||
|
port,
|
||||||
|
proxy,
|
||||||
|
requireTLS,
|
||||||
|
secure,
|
||||||
|
service,
|
||||||
|
tls,
|
||||||
|
|
||||||
|
// message options (https://nodemailer.com/message/)
|
||||||
|
bcc,
|
||||||
|
cc,
|
||||||
|
from = required('from'),
|
||||||
|
to = required('to'),
|
||||||
|
subject = '[{{level}} - {{namespace}}] {{time}} {{message}}',
|
||||||
|
}) {
|
||||||
|
const transporter = nodemailer.createTransport(
|
||||||
|
{
|
||||||
|
auth,
|
||||||
|
authMethod,
|
||||||
|
host,
|
||||||
|
ignoreTLS,
|
||||||
|
port,
|
||||||
|
proxy,
|
||||||
|
requireTLS,
|
||||||
|
secure,
|
||||||
|
service,
|
||||||
|
tls,
|
||||||
|
|
||||||
|
disableFileAccess: true,
|
||||||
|
disableUrlAccess: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
bcc,
|
||||||
|
cc,
|
||||||
|
from,
|
||||||
|
to,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
return log =>
|
||||||
|
fromCallback(cb =>
|
||||||
|
transporter.sendMail(
|
||||||
|
{
|
||||||
|
subject: evalTemplate(subject, key =>
|
||||||
|
key === 'level' ? NAMES[log.level] : key === 'time' ? log.time.toISOString() : log[key]
|
||||||
|
),
|
||||||
|
text: prettyFormat(log.data),
|
||||||
|
},
|
||||||
|
cb
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = exports = createTransport
|
||||||
|
@ -1 +1,9 @@
|
|||||||
module.exports = require('../dist/transports/memory.js')
|
function createTransport() {
|
||||||
|
const memoryLogger = log => {
|
||||||
|
logs.push(log)
|
||||||
|
}
|
||||||
|
const logs = (memoryLogger.logs = [])
|
||||||
|
return memoryLogger
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = exports = createTransport
|
||||||
|
@ -1 +1,43 @@
|
|||||||
module.exports = require('../dist/transports/syslog.js')
|
const fromCallback = require('promise-toolbox/fromCallback')
|
||||||
|
const splitHost = require('split-host')
|
||||||
|
const { createClient, Facility, Severity, Transport } = require('syslog-client')
|
||||||
|
|
||||||
|
const LEVELS = require('../levels')
|
||||||
|
|
||||||
|
// https://github.com/paulgrove/node-syslog-client#syslogseverity
|
||||||
|
const LEVEL_TO_SEVERITY = {
|
||||||
|
[LEVELS.FATAL]: Severity.Critical,
|
||||||
|
[LEVELS.ERROR]: Severity.Error,
|
||||||
|
[LEVELS.WARN]: Severity.Warning,
|
||||||
|
[LEVELS.INFO]: Severity.Informational,
|
||||||
|
[LEVELS.DEBUG]: Severity.Debug,
|
||||||
|
}
|
||||||
|
|
||||||
|
const facility = Facility.User
|
||||||
|
|
||||||
|
function createTransport(target) {
|
||||||
|
const opts = {}
|
||||||
|
if (target !== undefined) {
|
||||||
|
if (target.startsWith('tcp://')) {
|
||||||
|
target = target.slice(6)
|
||||||
|
opts.transport = Transport.Tcp
|
||||||
|
} else if (target.startsWith('udp://')) {
|
||||||
|
target = target.slice(6)
|
||||||
|
opts.transport = Transport.Udp
|
||||||
|
}
|
||||||
|
|
||||||
|
;({ host: target, port: opts.port } = splitHost(target))
|
||||||
|
}
|
||||||
|
|
||||||
|
const client = createClient(target, opts)
|
||||||
|
|
||||||
|
return log =>
|
||||||
|
fromCallback(cb =>
|
||||||
|
client.log(log.message, {
|
||||||
|
facility,
|
||||||
|
severity: LEVEL_TO_SEVERITY[log.level],
|
||||||
|
})
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = exports = createTransport
|
||||||
|
@ -1,19 +1,20 @@
|
|||||||
import escapeRegExp from 'lodash/escapeRegExp'
|
const escapeRegExp = require('lodash/escapeRegExp')
|
||||||
|
|
||||||
// ===================================================================
|
// ===================================================================
|
||||||
|
|
||||||
const TPL_RE = /\{\{(.+?)\}\}/g
|
const TPL_RE = /\{\{(.+?)\}\}/g
|
||||||
export const evalTemplate = (tpl, data) => {
|
const evalTemplate = (tpl, data) => {
|
||||||
const getData = typeof data === 'function' ? (_, key) => data(key) : (_, key) => data[key]
|
const getData = typeof data === 'function' ? (_, key) => data(key) : (_, key) => data[key]
|
||||||
|
|
||||||
return tpl.replace(TPL_RE, getData)
|
return tpl.replace(TPL_RE, getData)
|
||||||
}
|
}
|
||||||
|
exports.evalTemplate = evalTemplate
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
|
|
||||||
const compileGlobPatternFragment = pattern => pattern.split('*').map(escapeRegExp).join('.*')
|
const compileGlobPatternFragment = pattern => pattern.split('*').map(escapeRegExp).join('.*')
|
||||||
|
|
||||||
export const compileGlobPattern = pattern => {
|
const compileGlobPattern = pattern => {
|
||||||
const no = []
|
const no = []
|
||||||
const yes = []
|
const yes = []
|
||||||
pattern.split(/[\s,]+/).forEach(pattern => {
|
pattern.split(/[\s,]+/).forEach(pattern => {
|
||||||
@ -40,19 +41,22 @@ export const compileGlobPattern = pattern => {
|
|||||||
|
|
||||||
return new RegExp(raw.join(''))
|
return new RegExp(raw.join(''))
|
||||||
}
|
}
|
||||||
|
exports.compileGlobPattern = compileGlobPattern
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
|
|
||||||
export const required = name => {
|
const required = name => {
|
||||||
throw new Error(`missing required arg ${name}`)
|
throw new Error(`missing required arg ${name}`)
|
||||||
}
|
}
|
||||||
|
exports.required = required
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
|
|
||||||
export const serializeError = error => ({
|
const serializeError = error => ({
|
||||||
...error, // Copy enumerable properties.
|
...error, // Copy enumerable properties.
|
||||||
code: error.code,
|
code: error.code,
|
||||||
message: error.message,
|
message: error.message,
|
||||||
name: error.name,
|
name: error.name,
|
||||||
stack: error.stack,
|
stack: error.stack,
|
||||||
})
|
})
|
||||||
|
exports.serializeError = serializeError
|
@ -1,6 +1,6 @@
|
|||||||
/* eslint-env jest */
|
/* eslint-env jest */
|
||||||
|
|
||||||
import { compileGlobPattern } from './utils'
|
const { compileGlobPattern } = require('./utils')
|
||||||
|
|
||||||
describe('compileGlobPattern()', () => {
|
describe('compileGlobPattern()', () => {
|
||||||
it('works', () => {
|
it('works', () => {
|
@ -33,6 +33,7 @@
|
|||||||
>
|
>
|
||||||
> In case of conflict, the highest (lowest in previous list) `$version` wins.
|
> In case of conflict, the highest (lowest in previous list) `$version` wins.
|
||||||
|
|
||||||
|
- @xen-orchestra/log patch
|
||||||
- xen-api minor
|
- xen-api minor
|
||||||
- xo-server-auth-saml minor
|
- xo-server-auth-saml minor
|
||||||
- xo-server-backup-reports patch
|
- xo-server-backup-reports patch
|
||||||
|
Loading…
Reference in New Issue
Block a user