UNPKG

node-red-contrib-knx-ultimate

Version:

Control your KNX and KNX Secure intallation via Node-Red! A bunch of KNX nodes, with integrated Philips HUE control, ETS group address importer, and KNX routing between interfaces. Easy to use and highly configurable.

161 lines (142 loc) 4.55 kB
/** * (C) 2024 Supergiovane */ const util = require('util') const logger = require('node-color-log') const DEBUG_BUFFER_LIMIT = 5000 const debugBuffer = [] let debugSequence = 0 const cloneEntry = (entry) => ({ seq: entry.seq, level: entry.level, prefix: entry.prefix, message: entry.message, timestamp: entry.timestamp, isoTimestamp: entry.isoTimestamp, sessionStart: entry.sessionStart }) const normaliseLevel = (level) => { const allowed = ['success', 'debug', 'info', 'warn', 'error'] if (allowed.includes(level)) return level return 'info' } const stringifyArg = (arg) => { if (arg === null) return 'null' if (arg === undefined) return 'undefined' if (arg instanceof Error) return arg.stack || `${arg.name || 'Error'}: ${arg.message}` const type = typeof arg if (type === 'string') return arg if (type === 'number' || type === 'boolean' || type === 'bigint') return String(arg) if (type === 'symbol') return arg.toString() try { return util.inspect(arg, { depth: 6, breakLength: 120, compact: false }) } catch (error) { return String(arg) } } const formatArgs = (args) => { if (!args || !args.length) return '' return args.map(stringifyArg).join(' ') } const pushDebugEntry = (level, prefix, args, meta = {}) => { try { const effectiveLevel = normaliseLevel(level) const timestamp = Date.now() const isoTimestamp = new Date(timestamp).toISOString() const message = formatArgs(args) debugSequence += 1 debugBuffer.push({ seq: debugSequence, level: effectiveLevel, prefix: prefix || '', message, timestamp, isoTimestamp, sessionStart: !!meta.sessionStart }) if (debugBuffer.length > DEBUG_BUFFER_LIMIT) { debugBuffer.splice(0, debugBuffer.length - DEBUG_BUFFER_LIMIT) } } catch (error) { // As a last resort, make sure the failure itself is recorded. debugSequence += 1 debugBuffer.push({ seq: debugSequence, level: 'error', prefix: prefix || '', message: `Logger buffer failure: ${error.message || error}`, timestamp: Date.now(), isoTimestamp: new Date().toISOString(), sessionStart: false }) if (debugBuffer.length > DEBUG_BUFFER_LIMIT) { debugBuffer.splice(0, debugBuffer.length - DEBUG_BUFFER_LIMIT) } } } class loggerClass { logLevel = 'info' prefix = '' constructor (options = {}) { const possibleLevels = ['success', 'debug', 'info', 'warn', 'error', 'disable'] this.prefix = options.setPrefix || '' if (this.prefix) { this.logger = logger.createNamedLogger(this.prefix) } else { this.logger = logger } let requestedLevel = options.loglevel if (!possibleLevels.includes(requestedLevel)) requestedLevel = 'info' if (requestedLevel === 'trace') requestedLevel = 'debug' // Backward compatibility if (requestedLevel === 'silent') requestedLevel = 'disable' // Backward compatibility this.logger.setLevel(requestedLevel) this.logger.setDate(() => (new Date()).toLocaleString()) this.logLevel = requestedLevel pushDebugEntry('info', this.prefix, [`--- Logger session started (level: ${this.logLevel}) ---`], { sessionStart: true }) } destroy = () => { // Placeholder for backward compatibility; kept for API symmetry. } record = (level, args) => { pushDebugEntry(level, this.prefix, args) } success = (...args) => { this.record('success', args) this.logger.success(...args) } debug = (...args) => { this.record('debug', args) this.logger.debug(...args) } info = (...args) => { this.record('info', args) this.logger.info(...args) } warn = (...args) => { this.record('warn', args) this.logger.warn(...args) } error = (...args) => { this.record('error', args) this.logger.error(...args) } } loggerClass.getDebugSnapshot = (options = {}) => { const sinceSeqRaw = options.sinceSeq const sinceSeq = Number.isInteger(sinceSeqRaw) ? sinceSeqRaw : null const source = sinceSeq === null ? debugBuffer : debugBuffer.filter((entry) => entry.seq > sinceSeq) const entries = source.map(cloneEntry) const latestSeq = debugBuffer.length ? debugBuffer[debugBuffer.length - 1].seq : (sinceSeq || 0) return { entries, latestSeq, total: debugBuffer.length, limit: DEBUG_BUFFER_LIMIT } } loggerClass.clearDebugBuffer = () => { debugBuffer.length = 0 debugSequence = 0 } loggerClass.DEBUG_BUFFER_LIMIT = DEBUG_BUFFER_LIMIT module.exports = loggerClass