diff --git a/Manager.js b/Manager.js index 44a1635..34b9fc9 100644 --- a/Manager.js +++ b/Manager.js @@ -11,10 +11,9 @@ class Manager extends EventEmitter { super(); this.shardManager = new ShardManager('./structure/client/DiscordClient.js', options); + this.logger = new Logger(this); this.storageManager = new StorageManager(this, options.storage) .initialize(); - - this.logger = new Logger(this); this._built = false; diff --git a/logs/error.log b/logs/error.log new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/logs/error.log @@ -0,0 +1 @@ + diff --git a/middleware/logger/Logger.js b/middleware/logger/Logger.js index 9fa78ee..52be859 100644 --- a/middleware/logger/Logger.js +++ b/middleware/logger/Logger.js @@ -1,11 +1,9 @@ -const { createLogger, format, transports, config } = require('winston'); +const { createLogger, format, transports: { Console }, config } = require('winston'); const { combine, label, printf } = format; const moment = require('moment'); const chalk = require('chalk'); -const { DiscordWebhook, ExtendedConsole } = require('./transports/'); - -const regex = /[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g //removes chalk formatting, will be used for the log FILES. +const { DiscordWebhook, FileExtension } = require('./transports/'); class Logger { @@ -15,25 +13,32 @@ class Logger { this.shardManager = manager.shardManager; this.logger = createLogger({ + levels: config.npm.levels, format: ( - format.simple() + format.cli({ + colors: { + error: 'red', + warn: 'yellow', + info: 'blue', + verbose: 'cyan', + debug: 'magenta', + silly: 'magentaBright' + } + }) ), transports: [ - new ExtendedConsole(), - //new transports.Console(), - new transports.File({ filename: `logs/what.log` }), - new transports.File({ filename: `logs/${this.date.replace(/ /g, '-')}-error.log`, level: 'error' }), + new FileExtension({ filename: `logs/what.log`, level: 'debug'}), //Will NOT log "silly" logs, could change in future. + new FileExtension({ filename: `logs/error.log` , level: 'error' }), + new Console({ level: 'silly' }), //Will log EVERYTHING. new DiscordWebhook({ level: 'error' }) //Broadcast errors to a discord webhook. ] }); - this.shardManager - .on('shardCreate', (shard) => this.write(shard, "Shard created.", 'debug')) - .on('message', (shard, message) => this._handleMessage(shard, message)); + //TODO: Add proper date-oriented filenames and add a daily rotation file (?). - //console.log("FUCK"); - this.logger.log('info', "Why tf isnt this working..."); - this.logger.log('error', "THERES A FUCKIN ERROR"); + this.shardManager + .on('shardCreate', (shard) => this.write('debug', "Shard created.", shard)) + .on('message', (shard, message) => this._handleMessage(shard, message)); } @@ -44,21 +49,21 @@ class Logger { || message._reconnecting || message._sFetchProp || message._sEval - || message._sRespawnAll) return undefined; //Properties used for discord.js internal sharding, must filter for. + || message._sRespawnAll + || message._storage + || message._webhook) return undefined; //Properties used for discord.js internal sharding & our own structures. must filter for. - await this.write(shard, message.message, message.type); + this.write(message.type, message.message, shard); } - //The MAIN function for writing everything to the logger. - async write(shard, string = '', type = 'silly') { - if(!config.npm.levels[type]) return undefined; + write(type = 'silly', string = '', shard = null) { const color = Constants.Colors[type]; - const header = `[${this.date}][shard-${this._shardId(shard)}]`;//`${chalk[color](`[${this.date}][shard-${this._shardId(shard)}]`)}`; - //[04/02/2020 12:52:20][shard-00] + const header = `${chalk[color](`[${this.date}][${shard ? `shard${this._shardId(shard)}` : 'manager'}]`)}`; - this.logger.log(type, `${header} ${string}`); + + this.logger.log(type, `${header} : ${string}`); } @@ -86,13 +91,12 @@ const Constants = { } }; -/* -const levels = { - error: 0, - warn: 1, - info: 2, - http: 3, - verbose: 4, - debug: 5, - silly: 6 -};*/ \ No newline at end of file +// const levels = { +// error: 0, +// warn: 1, +// info: 2, +// http: 3, +// verbose: 4, +// debug: 5, +// silly: 6 +// }; \ No newline at end of file diff --git a/middleware/logger/transports/ExtendedConsole.js b/middleware/logger/transports/ExtendedConsole.js deleted file mode 100644 index af5a2e5..0000000 --- a/middleware/logger/transports/ExtendedConsole.js +++ /dev/null @@ -1,56 +0,0 @@ -const Transport = require('winston-transport'); -const moment = require('moment'); -const chalk = require('chalk'); - -const Constants = { - Colors: { - error: 'red', - warn: 'yellow', - info: 'blue', - verbose: 'cyan', - debug: 'magenta', - silly: 'magentaBright' - } -}; - -class ExtendedConsole extends Transport { - - constructor(opts) { - super(opts); - // - // Consume any custom options here. e.g.: - // - Connection information for databases - // - Authentication information for APIs (e.g. loggly, papertrail, - // logentries, etc.). - // - } - - log(info, callback) { - setImmediate(() => { - this.emit('logged', info); - }); - - //console.log('Extended console:'); - //console.log(info); - - const hdr = info.message.match(/^(\[[0-9\-: ]{19}\](\[shard-[0-9]{2}\])?)/); - if(hdr) info.message = info.message.replace(hdr[1], '').trim(); - - const color = Constants.Colors[info.level]; - const header = `${chalk[color](hdr ? hdr[1] : `[${this.date}]`)}`; - - console.log(`${header} ${info.message}`); - - if (callback) { - callback(); // eslint-disable-line callback-return - } - - } - - get date() { - return moment().format("MM-DD-YYYY hh:mm:ss"); - } - -} - -module.exports = ExtendedConsole; \ No newline at end of file diff --git a/middleware/logger/transports/FileExtension.js b/middleware/logger/transports/FileExtension.js new file mode 100644 index 0000000..ef48f80 --- /dev/null +++ b/middleware/logger/transports/FileExtension.js @@ -0,0 +1,118 @@ +const { transports: { File }} = require('winston'); +const debug = require('diagnostics')('winston:file'); +const { MESSAGE } = require('triple-beam'); +const moment = require('moment'); +const chalk = require('chalk'); + +const regex = /[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g + +class FileExtension extends File { + + constructor(opts) { + super(opts); + } + + log(info, callback = () => {}) { + // Remark: (jcrugzz) What is necessary about this callback(null, true) now + // when thinking about 3.x? Should silent be handled in the base + // TransportStream _write method? + if (this.silent) { + callback(); + return true; + } + + // Output stream buffer is full and has asked us to wait for the drain event + if (this._drain) { + this._stream.once('drain', () => { + this._drain = false; + this.log(info, callback); + }); + return; + } + if (this._rotate) { + this._stream.once('rotate', () => { + this._rotate = false; + this.log(info, callback); + }); + return; + } + + // Grab the raw string and append the expected EOL. + const output = `${info[MESSAGE]}${this.eol}`.replace(regex, '') + const bytes = Buffer.byteLength(output); + + // After we have written to the PassThrough check to see if we need + // to rotate to the next file. + // + // Remark: This gets called too early and does not depict when data + // has been actually flushed to disk. + function logged() { + this._size += bytes; + this._pendingSize -= bytes; + + debug('logged %s %s', this._size, output); + this.emit('logged', info); + + // Do not attempt to rotate files while opening + if (this._opening) { + return; + } + + // Check to see if we need to end the stream and create a new one. + if (!this._needsNewFile()) { + return; + } + + // End the current stream, ensure it flushes and create a new one. + // This could potentially be optimized to not run a stat call but its + // the safest way since we are supporting `maxFiles`. + this._rotate = true; + this._endStream(() => this._rotateFile()); + } + + // Keep track of the pending bytes being written while files are opening + // in order to properly rotate the PassThrough this._stream when the file + // eventually does open. + this._pendingSize += bytes; + if (this._opening + && !this.rotatedWhileOpening + && this._needsNewFile(this._size + this._pendingSize)) { + this.rotatedWhileOpening = true; + } + + const written = this._stream.write(output, logged.bind(this)); + if (!written) { + this._drain = true; + this._stream.once('drain', () => { + this._drain = false; + callback(); + }); + } else { + callback(); // eslint-disable-line callback-return + } + + debug('written', written, this._drain); + + this.finishIfEnding(); + + return written; + } + + get date() { + return moment().format("MM-DD-YYYY hh:mm:ss"); + } + +} + +module.exports = FileExtension; + +const Constants = { + Colors: { + error: 'red', + warn: 'yellow', + info: 'blue', + verbose: 'cyan', + debug: 'magenta', + silly: 'magentaBright' + } +}; \ No newline at end of file diff --git a/middleware/logger/transports/index.js b/middleware/logger/transports/index.js index 1f87e7e..9602b2f 100644 --- a/middleware/logger/transports/index.js +++ b/middleware/logger/transports/index.js @@ -1,5 +1,5 @@ /* eslint-disable linebreak-style */ module.exports = { DiscordWebhook: require('./DiscordWebhook.js'), - ExtendedConsole: require('./ExtendedConsole.js') + FileExtension: require('./FileExtension.js') }; \ No newline at end of file diff --git a/storage/StorageManager.js b/storage/StorageManager.js index 00c65e3..1e5bcdd 100644 --- a/storage/StorageManager.js +++ b/storage/StorageManager.js @@ -6,15 +6,17 @@ class StorageManager { constructor(manager, options = {}) { - this.providers = new Collection(); this.manager = manager; + + this.providers = new Collection(); this.options = options; } async initialize() { - console.log('Initiating storage providers'); + this.manager.logger.write('debug', "Initializing storage providers."); + let _providers = path.join(process.cwd(), 'storage', 'providers'); let providers = fs.readdirSync(_providers); diff --git a/structure/client/DiscordClient.js b/structure/client/DiscordClient.js index 8a99de0..76d8be8 100644 --- a/structure/client/DiscordClient.js +++ b/structure/client/DiscordClient.js @@ -32,8 +32,6 @@ class DiscordClient extends Client { if(this._built) return undefined; - console.log('Building Discord client'); - await super.login(this._options.bot.token); await this.registry.loadComponents('components/commands/', Command); @@ -43,12 +41,6 @@ class DiscordClient extends Client { this._built = true; - this.on('ready', () => { - console.log('Client websocket is ready.'); - }); - - console.log('Client built'); - } diff --git a/structure/client/Logger.js b/structure/client/Logger.js index d1fca62..5885d98 100644 --- a/structure/client/Logger.js +++ b/structure/client/Logger.js @@ -7,7 +7,8 @@ class Logger { this.client = client; this.client.eventHooker.hook('ready', () => { - this.info(`Client connected to ${chalk.bold(this.client.user.tag)} with ${chalk.bold(`${this.client.guilds.size} guild${this.client.guilds.size === 1 ? '' : 's'}`)}.`); + const guilds = this.client.guilds.cache.size; + this.info(`Client connected to ${chalk.bold(this.client.user.tag)} with ${chalk.bold(`${guilds} guild${guilds === 1 ? '' : 's'}`)}.`); }); this.client.eventHooker.hook('componentUpdate', ({ component, type }) => { diff --git a/structure/client/Registry.js b/structure/client/Registry.js index 4fe713c..4431147 100644 --- a/structure/client/Registry.js +++ b/structure/client/Registry.js @@ -23,13 +23,13 @@ class Registry { for(const path of files) { const func = require(path); if(typeof func !== 'function') { - //this.client.logger.error("Attempted to index an invalid function as a component."); + this.client.logger.warn("Attempted to index an invalid function as a component."); continue; } const component = new func(this.client); //Instantiates the component class. if(classToHandle && !(component instanceof classToHandle)) { - //this.client.logger.error("Attempted to load an invalid class."); + this.client.logger.warn("Attempted to load an invalid class."); continue; } @@ -44,12 +44,12 @@ class Registry { async loadComponent(component, directory) { if(!(component instanceof Component)) { - //this.client.logger.error("Attempted to load an invalid component."); + this.client.logger.warn("Attempted to load an invalid component."); return null; } if(this.components.has(component.resolveable)) { - //this.client.logger.error("Attempted to reload an existing component."); + this.client.logger.warn("Attempted to reload an existing component."); return null; } diff --git a/structure/client/components/observers/CommandHandler.js b/structure/client/components/observers/CommandHandler.js index 8e34537..5a6c590 100644 --- a/structure/client/components/observers/CommandHandler.js +++ b/structure/client/components/observers/CommandHandler.js @@ -95,8 +95,6 @@ class CommandHandler extends Observer { const parsedArguments = await this._parseArguments(message, args); - - } async _handleInhibitors(message) {