Compare commits

..

5 Commits

Author SHA1 Message Date
22d7d982ac
v2.3.4 2023-06-15 13:13:46 +03:00
45b1f8c2df
v2.3.3 2023-05-03 23:16:02 +03:00
33b1087671
v2.3.2 2023-04-16 16:55:02 +03:00
477315dc72
v2.3.1 2023-04-16 16:53:50 +03:00
2dd9ebb379
export types 2023-04-16 16:53:37 +03:00
14 changed files with 342 additions and 189 deletions

View File

@ -1,31 +1,56 @@
{
"plugins": [
"@typescript-eslint"
],
"env": {
"es6": true,
"node": true
},
"extends": [ "eslint:recommended", "plugin:@typescript-eslint/recommended" ],
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/recommended"
],
"globals": {
"Atomics": "readonly",
"SharedArrayBuffer": "readonly"
},
"parser": "@typescript-eslint/parser",
"plugins": [ "@typescript-eslint" ],
"parserOptions": {
"ecmaVersion": 2022,
"sourceType": "module"
},
"rules": {
"@typescript-eslint/no-unused-vars": "off",
"accessor-pairs": "warn",
"array-callback-return": "warn",
"array-bracket-newline": [ "warn", "consistent" ],
"array-bracket-spacing": [ "warn", "always", { "objectsInArrays": false, "arraysInArrays": false }],
"array-bracket-newline": [
"warn",
"consistent"
],
"array-bracket-spacing": [
"warn",
"always",
{
"objectsInArrays": false,
"arraysInArrays": false
}
],
"arrow-spacing": "warn",
"block-scoped-var": "warn",
"block-spacing": [ "warn", "always" ],
"brace-style": [ "warn", "1tbs" ],
"block-spacing": [
"warn",
"always"
],
"brace-style": [
"warn",
"allman"
],
"callback-return": "warn",
"camelcase": "warn",
"comma-dangle": [ "warn", "only-multiline" ],
"comma-dangle": [
"warn",
"only-multiline"
],
"comma-spacing": [
"warn",
{
@ -68,9 +93,25 @@
"implicit-arrow-linebreak": "warn",
"indent": "warn",
"init-declarations": "warn",
"jsx-quotes": [ "warn", "prefer-single" ],
"key-spacing": [ "warn", { "beforeColon": false, "afterColon": true }],
"keyword-spacing": [ "warn", { "after": true, "before": true }],
"quotes": ["error" , "single"],
"jsx-quotes": [
"warn",
"prefer-single"
],
"key-spacing": [
"warn",
{
"beforeColon": false,
"afterColon": true
}
],
"keyword-spacing": [
"warn",
{
"after": true,
"before": true
}
],
"linebreak-style": [
"error",
"unix"
@ -79,6 +120,24 @@
"lines-around-directive": "warn",
"max-classes-per-file": "warn",
"max-nested-callbacks": "warn",
"max-len": [
"warn",
{
"code": 140,
"ignoreComments": true,
"ignoreStrings": true,
"ignoreTemplateLiterals": true,
"ignoreRegExpLiterals": true
}
],
"max-lines-per-function": [
"warn",
100
],
"max-depth": [
"warn",
3
],
"new-parens": "warn",
"no-alert": "warn",
"no-array-constructor": "warn",
@ -96,7 +155,6 @@
"no-extend-native": "warn",
"no-extra-bind": "warn",
"no-extra-label": "warn",
"no-extra-parens": "warn",
"no-floating-decimal": "warn",
"no-implicit-coercion": "warn",
"no-implicit-globals": "warn",
@ -147,7 +205,7 @@
"no-unmodified-loop-condition": "warn",
"no-unneeded-ternary": "error",
"no-unused-expressions": "warn",
"no-use-before-define": "error",
"@typescript-eslint/no-use-before-define": "error",
"no-useless-call": "warn",
"no-useless-computed-key": "warn",
"no-useless-concat": "warn",
@ -155,20 +213,39 @@
"no-useless-rename": "warn",
"no-useless-return": "warn",
"no-var": "warn",
"no-void": "warn",
// "no-void": "warn",
"no-whitespace-before-property": "error",
"nonblock-statement-body-position": [ "warn", "below" ],
"nonblock-statement-body-position": [
"warn",
"below"
],
"object-curly-spacing": [
"warn",
"always"
],
"object-property-newline": [ "warn", { "allowAllPropertiesOnSameLine": true }],
"object-property-newline": [
"warn",
{
"allowAllPropertiesOnSameLine": true
}
],
"object-shorthand": "warn",
"one-var-declaration-per-line": "warn",
"operator-assignment": "warn",
"operator-linebreak": [ "warn", "before" ],
"operator-linebreak": [
"warn",
"before"
],
"padding-line-between-statements": "warn",
"padded-blocks": [ "warn", { "switches": "never" }, { "allowSingleLineBlocks": true }],
"padded-blocks": [
"warn",
{
"switches": "never"
},
{
"allowSingleLineBlocks": true
}
],
"prefer-arrow-callback": "warn",
"prefer-const": "warn",
"prefer-destructuring": "warn",
@ -189,12 +266,18 @@
"last"
],
"space-before-blocks": "warn",
"space-before-function-paren": [ "error", "always" ],
"space-before-function-paren": [
"error",
"always"
],
"space-in-parens": [
"warn",
"never"
],
"spaced-comment": [ "warn", "always" ],
"spaced-comment": [
"warn",
"always"
],
"strict": "warn",
"switch-colon-spacing": "warn",
"symbol-description": "warn",

View File

@ -1,8 +1,12 @@
import MasterLogger from "./src/MasterLogger.js";
import MasterLogger from './src/MasterLogger.js';
import LoggerClient from './src/LoggerClient.js';
import Defaults, { LogLevel } from "./src/Defaults.js";
import Defaults, { LogLevel } from './src/Defaults.js';
const addLogLevel = (name: string, level: number) => {
export { WriteOptions, LogFunction } from './src/Types.js';
export { LoggerClientOptions, LoggerMasterOptions } from './src/Defaults.js';
const addLogLevel = (name: string, level: number) =>
{
if (typeof name !== 'string')
throw new Error('Name must be a string');
if (typeof level !== 'number')
@ -12,9 +16,9 @@ const addLogLevel = (name: string, level: number) => {
LogLevel[LogLevel[name] = level] = name;
};
export {
MasterLogger,
LoggerClient, Defaults, LogLevel, addLogLevel,
LoggerClient,
Defaults, LogLevel, addLogLevel,
};
export { LoggerClientOptions, LoggerMasterOptions } from './src/Defaults.js';

View File

@ -1,6 +1,6 @@
{
"name": "@navy.gif/logger",
"version": "2.3.0",
"version": "2.3.4",
"description": "Logging thing",
"author": "Navy.gif",
"license": "MIT",
@ -36,6 +36,6 @@
"scripts": {
"test": "node test/test.js",
"build": "tsc && tsc -p tsconfig.cjs.json && node ./scripts/declareTypes.js",
"release": "tsc && yarn publish"
"release": "yarn build && yarn publish"
}
}

View File

@ -1,4 +1,4 @@
import { WebhookClientOptions } from "@navy.gif/discord-webhook/build/esm/src/types/Webhook";
import { WebhookClientOptions } from '@navy.gif/discord-webhook/build/esm/src/types/Webhook';
enum LogLevel {
debug = 0,

View File

@ -1,9 +1,10 @@
// const { inspect } = require('node:util');
// const Defaults = require('./Defaults');
import Defaults from "./Defaults.js";
import { inspect } from "node:util";
import { LogFunction, WriteOptions } from "./Types.js";
import { Logger } from "./LoggerInterface.js";
import Defaults from './Defaults.js';
import { inspect } from 'node:util';
import { LogFunction, WriteOptions } from './Types.js';
import { Logger } from './LoggerInterface.js';
import { makePlainError } from './Shared.js';
type ClientOptions = {
name?: string,
@ -19,7 +20,8 @@ type TransportOptions = {
type: string
}
class LoggerClient implements Logger {
class LoggerClient implements Logger
{
static MaxChars = 0;
@ -27,11 +29,12 @@ class LoggerClient implements Logger {
#_guard: string;
#_logLevel: number;
#_logLevelMapping: {[key: string]: number};
#_logLevelMapping: { [key: string]: number };
#_name: string;
#types: string[];
constructor (opts: ClientOptions = Defaults.ClientOptions) {
constructor (opts: ClientOptions = Defaults.ClientOptions)
{
this.#_name = opts.name || opts.constructor.name;
if (this.#_name === 'Object')
@ -43,7 +46,8 @@ class LoggerClient implements Logger {
const { customTypes = [] } = opts;
this.#types = [ ...customTypes, ...Defaults.Types ];
for (const type of this.#types) {
for (const type of this.#types)
{
Object.defineProperty(this, type, {
value: (msg: string, o: WriteOptions) => this.transport(msg, { ...o, type })
});
@ -55,15 +59,18 @@ class LoggerClient implements Logger {
}
get logLevel () {
get logLevel ()
{
return this.#_logLevel;
}
get logLevels () {
get logLevels ()
{
return Object.keys(this.#_logLevelMapping);
}
setLogLevel (level = 'info') {
setLogLevel (level = 'info')
{
if (typeof level === 'number')
this.#_logLevel = level;
else if (typeof level === 'string')
@ -72,42 +79,51 @@ class LoggerClient implements Logger {
throw new Error(`Invalid log level type, expected string or number, got ${typeof level}`);
}
transport (message: string, opts: TransportOptions) {
transport (message: string | Error, opts: TransportOptions)
{
if (this.#_logLevelMapping[opts.type] < this.#_logLevel)
return;
if (message instanceof Error)
message = makePlainError(message);
if (typeof message !== 'string')
message = inspect(message);
const spacer = ' '.repeat(LoggerClient.MaxChars - this.#_name.length);
const header = `${`[${this.#_name.substring(0, LoggerClient.MaxChars)}]${spacer}`} `;
if (!process.send || !process.connected)
throw new Error(`Missing connection to master proces`);
throw new Error('Missing connection to master proces');
else
process.send({ [this.#_guard]: true, header, message, ...opts });
}
// These methods are dynamically implemented by the constructor
// These methods are dynamically implemented by the constructor, simply here to provide IDE hints
// eslint-disable-next-line @typescript-eslint/no-unused-vars
error (_str: string, _opts?: WriteOptions): void {
error (_str: string | Error, _opts?: WriteOptions): void
{
throw new Error('Method not implemented.');
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
warn (_str: string, _opts?: WriteOptions): void {
warn (_str: string | Error, _opts?: WriteOptions): void
{
throw new Error('Method not implemented.');
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
status (_str: string, _opts?: WriteOptions): void {
status (_str: string | Error, _opts?: WriteOptions): void
{
throw new Error('Method not implemented.');
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
info (_str: string, _opts?: WriteOptions): void {
info (_str: string | Error, _opts?: WriteOptions): void
{
throw new Error('Method not implemented.');
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
debug (_str: string, _opts?: WriteOptions): void {
debug (_str: string | Error, _opts?: WriteOptions): void
{
throw new Error('Method not implemented.');
}

View File

@ -1,4 +1,4 @@
import { WriteOptions } from "./Types";
import { WriteOptions } from './Types';
export interface Logger {
error(str: string, opts?: WriteOptions): void

View File

@ -13,6 +13,7 @@ import Defaults, { LogLevel } from './Defaults.js';
import { IPCMessage, LogFunction, Shard, WriteOptions } from './Types.js';
import { addLogLevel } from '../index.js';
import { Logger } from './LoggerInterface.js';
import { makePlainError } from './Shared.js';
const DAY = 1000 * 60 * 60 * 24;
@ -27,7 +28,8 @@ type WriteStreams = {
[key:string]: fs.WriteStream
}
class MasterLogger implements Logger {
class MasterLogger implements Logger
{
[key: string]: LogFunction | unknown;
@ -48,7 +50,8 @@ class MasterLogger implements Logger {
#startDay: number;
#rotateTO: NodeJS.Timeout;
constructor (config = Defaults.MasterOptions) {
constructor (config = Defaults.MasterOptions)
{
const {
directory, customTypes = [], customStreams = [], customTypeMapping,
@ -65,20 +68,23 @@ class MasterLogger implements Logger {
this.#_logLevel = logLevel as number;
this.#_logLevelMapping = { ...Defaults.MasterOptions.logLevelMapping, ...logLevelMapping };
if (logLevelMapping)
Object.entries(logLevelMapping).forEach(([ name, level ]) => {
Object.entries(logLevelMapping).forEach(([ name, level ]) =>
{
addLogLevel(name, level);
});
this.#_guard = guard as string;
this.#types = [ ...customTypes, ...Defaults.Types ];
for (const type of this.#types) {
for (const type of this.#types)
{
Object.defineProperty(this, type, {
value: (msg: string, opts: WriteOptions) => this.write(type, msg, opts)
});
}
this.#colours = { ...Defaults.Colours, ...customColours };
this.#colourFuncs = Object.entries(this.#colours).reduce((prev: FuncsType, [ type, colour ]: (string | number)[]) => {
this.#colourFuncs = Object.entries(this.#colours).reduce((prev: FuncsType, [ type, colour ]: (string | number)[]) =>
{
if (typeof colour === 'number')
colour = `#${colour.toString(16)}`;
else if (typeof colour !== 'string')
@ -96,7 +102,8 @@ class MasterLogger implements Logger {
this.#streamTypes = [ ...customStreams, 'error', 'default' ];
this.#streamTypeMapping = { ...Defaults.TypeStream, ...customTypeMapping };
this.#writeStreams = this.#streamTypes.reduce((acc, type) => {
this.#writeStreams = this.#streamTypes.reduce((acc, type) =>
{
acc[type] = this.loadFile(type);
return acc;
}, {} as WriteStreams);
@ -106,41 +113,49 @@ class MasterLogger implements Logger {
this.#startDay = Math.floor(Date.now() / this.#rotationFreq) * this.#rotationFreq;
this.#rotateTO = setTimeout(this.rotateLogFiles.bind(this), this.#startDay + this.#rotationFreq - Date.now());
if (webhook && webhook.url) {
if (webhook && webhook.url)
{
this.#webhook = new DiscordWebhook(webhook);
this.#webhook.fetch();
}
}
get guard () {
get guard ()
{
return this.#_guard;
}
get logLevel () {
get logLevel ()
{
return this.#_logLevel;
}
get logLevels () {
get logLevels ()
{
return Object.keys(this.#_logLevelMapping);
}
setLogLevel (level: number) {
setLogLevel (level: number)
{
if (LogLevel[level] in this.#_logLevelMapping)
this.#_logLevel = level;
else
throw new Error(`Not a valid log level`);
throw new Error('Not a valid log level');
}
setBroadcastLevel (level: number) {
setBroadcastLevel (level: number)
{
if (LogLevel[level] in this.#_logLevelMapping)
this.#_broadcastLevel = level;
else
throw new Error('Not a valid log level');
}
attach (shard: Shard) {
shard.on('message', (msg: IPCMessage) => {
attach (shard: Shard)
{
shard.on('message', (msg: IPCMessage) =>
{
if (!msg[this.#_guard])
return;
const { message, type, header, broadcast } = msg;
@ -151,13 +166,17 @@ class MasterLogger implements Logger {
});
}
write (type = 'info', text: string, { subheader = '', shard, broadcast = false }: WriteOptions = {}) {
write (type = 'info', text: string | Error, { subheader = '', shard, broadcast = false }: WriteOptions = {})
{
type = type.toLowerCase();
let colour = this.#colourFuncs[type];
if (!colour)
colour = this.#colourFuncs.info;
if (text instanceof Error)
text = makePlainError(text);
if (typeof text !== 'string')
text = inspect(text);
@ -169,13 +188,16 @@ class MasterLogger implements Logger {
console.log(`${colour.func(type)}${spacer} ${colour.func(header)}: ${chalk.bold(subheader)}${text}`); // eslint-disable-line no-console
if ((broadcast || this.#_broadcastLevel <= this.#_logLevelMapping[type]) && this.#webhook)
{
const description = (subheader.length ? `**${subheader}**\n` : '') + `\`\`\`${text}\`\`\``;
this.#webhook.send({
embeds: [{
title: `[__${type.toUpperCase()}__] ${this._shard(shard)}`,
description: `**${subheader}**\n\`\`\`${text}\`\`\``,
description,
color: colour.int
}]
});
}
const streamType = this.#streamTypeMapping[type] || 'default';
if (this.#writeStreams[streamType])
@ -185,9 +207,11 @@ class MasterLogger implements Logger {
}
rotateLogFiles () {
rotateLogFiles ()
{
const streams = Object.keys(this.#writeStreams);
for (const type of streams) {
for (const type of streams)
{
this.#writeStreams[type].write('\nRotating log file');
this.#writeStreams[type].end();
this.#writeStreams[type] = this.loadFile(type);
@ -198,7 +222,8 @@ class MasterLogger implements Logger {
this.#rotateTO = setTimeout(this.rotateLogFiles.bind(this), nextTime - Date.now());
}
loadFile (type: string, date = Date.now()) {
loadFile (type: string, date = Date.now())
{
if (!type)
throw new Error('Missing file type');
@ -212,7 +237,8 @@ class MasterLogger implements Logger {
}
_shard (shard?: Shard) {
_shard (shard?: Shard)
{
if (!shard)
return 'controller';
let id = '??';
@ -221,29 +247,35 @@ class MasterLogger implements Logger {
return `shard-${id}`;
}
get date () {
get date ()
{
return moment().format('YYYY-MM-DD HH:mm:ss');
}
// These methods are dynamically implemented by the constructor
// eslint-disable-next-line @typescript-eslint/no-unused-vars
error (_str: string, _opts?: WriteOptions): void {
error (_str: string | Error, _opts?: WriteOptions): void
{
throw new Error('Method not implemented.');
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
warn (_str: string, _opts?: WriteOptions): void {
warn (_str: string | Error, _opts?: WriteOptions): void
{
throw new Error('Method not implemented.');
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
status (_str: string, _opts?: WriteOptions): void {
status (_str: string | Error, _opts?: WriteOptions): void
{
throw new Error('Method not implemented.');
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
info (_str: string, _opts?: WriteOptions): void {
info (_str: string | Error, _opts?: WriteOptions): void
{
throw new Error('Method not implemented.');
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
debug (_str: string, _opts?: WriteOptions): void {
debug (_str: string | Error, _opts?: WriteOptions): void
{
throw new Error('Method not implemented.');
}

8
src/Shared.ts Normal file
View File

@ -0,0 +1,8 @@
export const makePlainError = (err: Error) =>
{
return {
name: err.name,
message: err.message,
stack: err.stack
};
};

View File

@ -1,4 +1,4 @@
import EventEmitter from "node:events";
import EventEmitter from 'node:events';
type Shard = {
id: number
@ -19,6 +19,6 @@ type IPCMessage = {
broadcast: boolean
}
type LogFunction = (str: string, opts: WriteOptions) => void
type LogFunction = (str: string, opts?: WriteOptions) => void
export { WriteOptions, Shard, IPCMessage, LogFunction };

View File

@ -1,5 +1,5 @@
// const { LoggerClient } = require('../');
import { LoggerClient } from "../build/esm/index.js";
import { LoggerClient } from '../build/esm/index.js';
const logger = new LoggerClient({
customTypes: [ 'access' ],
@ -9,8 +9,10 @@ const logger = new LoggerClient({
logLevelMapping: { access: 2 }
});
const main = async () => {
for (let i = 0; i < 5; i++) {
const main = async () =>
{
for (let i = 0; i < 5; i++)
{
// if (i % 500 === 0)
await new Promise(resolve => setTimeout(resolve, 1000));
logger.info('Info test');

View File

@ -28,8 +28,10 @@ console.log(logger.logLevel);
// process.exit();
logger.info('Test');
const spawn = (child) => {
return new Promise((resolve) => {
const spawn = (child) =>
{
return new Promise((resolve) =>
{
child.once('spawn', resolve);
});
@ -37,12 +39,14 @@ const spawn = (child) => {
// eslint-disable-next-line @typescript-eslint/no-var-requires
const ChildProcess = require('node:child_process');
const main = async () => {
const main = async () =>
{
const child = ChildProcess.fork('./test/otherProcess.js');
logger.attach(child);
await spawn(child);
for (let i = 0; i < 10; i++) {
for (let i = 0; i < 10; i++)
{
await new Promise((resolve) => setTimeout(resolve, 1000));
logger.info(`Iteration ${i}`);
}

View File

@ -1,17 +1,20 @@
/* eslint-disable no-console */
// const { MasterLogger } = require('../build');
// const ChildProcess = require('node:child_process');
import { MasterLogger } from "../build/index.js";
import ChildProcess from "node:child_process";
import { MasterLogger } from '../build/esm/index.js';
import ChildProcess from 'node:child_process';
const spawn = (child) => {
return new Promise((resolve) => {
const spawn = (child) =>
{
return new Promise((resolve) =>
{
child.on('spawn', resolve);
});
};
const main = async () => {
const main = async () =>
{
const logger = new MasterLogger({
debug: true,
customTypes: [ 'access' ],
@ -36,7 +39,8 @@ const main = async () => {
const { types, colours, streamTypes, streamTypeMapping } = logger; // , writeStreams
console.log(types, colours, streamTypes, streamTypeMapping); // , writeStreams
for (let i = 0; i < 10; i++) {
for (let i = 0; i < 10; i++)
{
await new Promise((resolve) => setTimeout(resolve, 1000));
logger.info(`Iteration ${i}`);
}