server: remove direct chalk dependency
ci/woodpecker/push/lint-backend Pipeline failed Details
ci/woodpecker/push/build Pipeline was successful Details
ci/woodpecker/push/lint-sw Pipeline failed Details
ci/woodpecker/push/lint-foundkey-js Pipeline was successful Details
ci/woodpecker/push/lint-client Pipeline failed Details
ci/woodpecker/push/test Pipeline failed Details

Colouring of logs is not important to me because if I view them in journalctl
there are no colours anyway.
This commit is contained in:
Johann150 2024-04-01 19:10:55 +02:00
parent c9759a3a79
commit f245b6e517
Signed by: Johann150
GPG Key ID: 9EE6577A2A06F8F1
19 changed files with 66 additions and 124 deletions

View File

@ -36,8 +36,6 @@
"bull": "4.8.4",
"cacheable-lookup": "6.0.4",
"cbor": "8.1.0",
"chalk": "5.0.1",
"chalk-template": "0.4.0",
"cli-highlight": "2.1.11",
"color-convert": "2.0.1",
"content-disposition": "0.5.4",

View File

@ -9,8 +9,8 @@ import 'reflect-metadata';
import { masterMain } from './master.js';
import { workerMain } from './worker.js';
const logger = new Logger('core', 'cyan');
const clusterLogger = logger.createSubLogger('cluster', 'orange', false);
const logger = new Logger('core');
const clusterLogger = logger.createSubLogger('cluster', false);
const ev = new Xev();
/**

View File

@ -3,8 +3,6 @@ import { fileURLToPath } from 'node:url';
import { dirname } from 'node:path';
import * as os from 'node:os';
import cluster from 'node:cluster';
import chalk from 'chalk';
import chalkTemplate from 'chalk-template';
import semver from 'semver';
import Logger from '@/services/logger.js';
@ -19,29 +17,27 @@ const _dirname = dirname(_filename);
const meta = JSON.parse(fs.readFileSync(`${_dirname}/../../../../built/meta.json`, 'utf-8'));
const logger = new Logger('core', 'cyan');
const bootLogger = logger.createSubLogger('boot', 'magenta', false);
const themeColor = chalk.hex('#86b300');
const logger = new Logger('core');
const bootLogger = logger.createSubLogger('boot', false);
function greet(): void {
if (envOption.logLevel !== LOG_LEVELS.quiet) {
//#region FoundKey logo
console.log(themeColor(' ___ _ _ __ '));
console.log(themeColor(' | __|__ _ _ _ _ __| | |/ /___ _ _ '));
console.log(themeColor(' | _/ _ \\ || | \' \\/ _` | \' </ -_) || |'));
console.log(themeColor(' |_|\\___/\\_,_|_||_\\__,_|_|\\_\\___|\\_, |'));
console.log(themeColor(' |__/ '));
console.log(' ___ _ _ __ ');
console.log(' | __|__ _ _ _ _ __| | |/ /___ _ _ ');
console.log(' | _/ _ \\ || | \' \\/ _` | \' </ -_) || |');
console.log(' |_|\\___/\\_,_|_||_\\__,_|_|\\_\\___|\\_, |');
console.log(' |__/ ');
//#endregion
console.log(' FoundKey is an open-source decentralized microblogging platform.');
console.log('');
console.log(chalkTemplate`--- ${os.hostname()} {gray (PID: ${process.pid.toString()})} ---`);
console.log(`--- ${os.hostname()} (PID: ${process.pid.toString()}) ---`);
}
bootLogger.info('Welcome to FoundKey!');
bootLogger.info(`FoundKey v${meta.version}`, true);
bootLogger.info(`FoundKey v${meta.version}`);
}
/**
@ -59,7 +55,7 @@ export async function masterMain(): Promise<void> {
config = loadConfigBoot();
await connectDb();
} catch (e) {
bootLogger.error('Fatal error occurred during initialization', true);
bootLogger.error('Fatal error occurred during initialization');
process.exit(1);
}
@ -69,7 +65,7 @@ export async function masterMain(): Promise<void> {
await spawnWorkers(config.clusterLimits);
}
bootLogger.succ(`Now listening on port ${config.port} on ${config.url}`, true);
bootLogger.succ(`Now listening on port ${config.port} on ${config.url}`);
if (!envOption.noDaemons) {
import('../daemons/server-stats.js').then(x => x.serverStats());
@ -84,7 +80,7 @@ function showEnvironment(): void {
if (env !== 'production') {
logger.warn('The environment is not in production mode.');
logger.warn('DO NOT USE FOR PRODUCTION PURPOSE!', true);
logger.warn('DO NOT USE FOR PRODUCTION PURPOSE!');
}
}
@ -109,7 +105,7 @@ function loadConfigBoot(): Config {
} catch (exception) {
const e = exception as Partial<NodeJS.ErrnoException> | Error;
if ('code' in e && e.code === 'ENOENT') {
configLogger.error('Configuration file not found', true);
configLogger.error('Configuration file not found');
process.exit(1);
} else if (e instanceof Error) {
configLogger.error(e.message);
@ -133,7 +129,7 @@ async function connectDb(): Promise<void> {
const v = await db.query('SHOW server_version').then(x => x[0].server_version);
dbLogger.succ(`Connected: v${v}`);
} catch (e) {
dbLogger.error('Cannot connect', true);
dbLogger.error('Cannot connect');
dbLogger.error(e as Error | string);
process.exit(1);
}

View File

@ -1,7 +1,7 @@
import Logger from '@/services/logger.js';
import config from './index.js';
const logger = new Logger('config:redis', 'gray', false);
const logger = new Logger('config:redis', false);
function getRedisFamily(family?: string | number): number {
const familyMap = {

View File

@ -72,7 +72,7 @@ import { getRedisOptions } from '@/config/redis.js';
import { dbLogger } from './logger.js';
import { redisClient } from './redis.js';
const sqlLogger = dbLogger.createSubLogger('sql', 'gray', false);
const sqlLogger = dbLogger.createSubLogger('sql', false);
class MyCustomLogger implements Logger {
private highlight(sql: string): string {

View File

@ -1,7 +1,6 @@
import * as fs from 'node:fs';
import * as stream from 'node:stream';
import * as util from 'node:util';
import chalk from 'chalk';
import got, * as Got from 'got';
import { SECOND, MINUTE } from '@/const.js';
import config from '@/config/index.js';
@ -13,7 +12,7 @@ const pipeline = util.promisify(stream.pipeline);
export async function downloadUrl(url: string, path: string): Promise<void> {
const logger = new Logger('download');
logger.info(`Downloading ${chalk.cyan(url)} ...`);
logger.info(`Downloading ${url} ...`);
const timeout = 30 * SECOND;
const operationTimeout = MINUTE;
@ -65,5 +64,5 @@ export async function downloadUrl(url: string, path: string): Promise<void> {
}
}
logger.succ(`Download finished: ${chalk.cyan(url)}`);
logger.succ(`Download finished: ${url}`);
}

View File

@ -1,3 +1,3 @@
import Logger from '@/services/logger.js';
export const queueLogger = new Logger('queue', 'orange');
export const queueLogger = new Logger('queue');

View File

@ -45,6 +45,6 @@ export default async function cleanRemoteFiles(job: Bull.Job<Record<string, unkn
job.progress(deletedCount / total);
}
logger.succ('All cahced remote files has been deleted.');
logger.succ('All cached remote files have been deleted.');
done();
}

View File

@ -1,3 +1,3 @@
import { remoteLogger } from '../logger.js';
export const apLogger = remoteLogger.createSubLogger('ap', 'magenta');
export const apLogger = remoteLogger.createSubLogger('ap');

View File

@ -1,3 +1,3 @@
import Logger from '@/services/logger.js';
export const remoteLogger = new Logger('remote', 'cyan');
export const remoteLogger = new Logger('remote');

View File

@ -1,5 +1,4 @@
import { URL } from 'node:url';
import chalk from 'chalk';
import { IsNull } from 'typeorm';
import { DAY } from '@/const.js';
import { isSelfHost, toPuny } from '@/misc/convert-host.js';
@ -46,7 +45,7 @@ export async function resolveUser(username: string, idnHost: string | null, reso
if (user == null) {
const self = await resolveSelf(acctLower);
logger.succ(`return new remote user: ${chalk.magenta(acctLower)}`);
logger.succ(`return new remote user: ${acctLower}`);
return await createPerson(self, resolver);
}
@ -101,16 +100,16 @@ export async function resolveUser(username: string, idnHost: string | null, reso
* Gets the Webfinger href matching rel="self".
*/
async function resolveSelf(acctLower: string): string {
logger.info(`WebFinger for ${chalk.yellow(acctLower)}`);
logger.info(`WebFinger for ${acctLower}`);
// get webfinger response for user
const finger = await webFinger(acctLower).catch(e => {
logger.error(`Failed to WebFinger for ${chalk.yellow(acctLower)}: ${ e.statusCode || e.message }`);
logger.error(`Failed to WebFinger for ${acctLower}: ${ e.statusCode || e.message }`);
throw new Error(`Failed to WebFinger for ${acctLower}: ${ e.statusCode || e.message }`);
});
// try to find the rel="self" link
const self = finger.links.find(link => link.rel?.toLowerCase() === 'self');
if (!self?.href) {
logger.error(`Failed to WebFinger for ${chalk.yellow(acctLower)}: self link not found`);
logger.error(`Failed to WebFinger for ${acctLower}: self link not found`);
throw new Error('self link not found');
}
return self.href;

View File

@ -29,7 +29,7 @@ import proxyServer from './proxy/index.js';
import webServer from './web/index.js';
import { initializeStreamingServer } from './api/streaming.js';
export const serverLogger = new Logger('server', 'gray', false);
export const serverLogger = new Logger('server', false);
// Init app
const app = new Koa();

View File

@ -15,7 +15,7 @@ export default async function(blocker: User, blockee: User) {
});
if (blocking == null) {
logger.warn('ブロック解除がリクエストされましたがブロックしていませんでした');
logger.warn('Unblock requested but not blocked');
return;
}

View File

@ -12,7 +12,7 @@ import { getChartInsertLock } from '@/misc/app-lock.js';
import { db } from '@/db/postgre.js';
import Logger from '../logger.js';
const logger = new Logger('chart', 'white', process.env.NODE_ENV !== 'test');
const logger = new Logger('chart', process.env.NODE_ENV !== 'test');
const columnPrefix = '___' as const;
const uniqueTempColumnPrefix = 'unique_temp___' as const;

View File

@ -25,7 +25,7 @@ import { IImage, convertSharpToJpeg, convertSharpToWebp, convertSharpToPng } fro
import { InternalStorage } from './internal-storage.js';
import { getS3 } from './s3.js';
const logger = driveLogger.createSubLogger('register', 'yellow');
const logger = driveLogger.createSubLogger('register');
/***
* Save file
@ -230,7 +230,7 @@ export async function generateAlts(path: string, type: string, generateWeb: bool
logger.debug('web image not created (not an required image)');
}
} catch (err) {
logger.warn('web image not created (an error occured)', err as Error);
logger.warn('web image not created (an error occured)');
}
} else {
if (satisfyWebpublic) logger.info('web image not created (original satisfies webpublic)');

View File

@ -1,3 +1,3 @@
import Logger from '../logger.js';
export const driveLogger = new Logger('drive', 'blue');
export const driveLogger = new Logger('drive');

View File

@ -9,7 +9,7 @@ import { Instances } from '@/models/index.js';
import { getFetchInstanceMetadataLock } from '@/misc/app-lock.js';
import Logger from './logger.js';
const logger = new Logger('metadata', 'cyan');
const logger = new Logger('metadata');
export async function fetchInstanceMetadata(instance: Instance, force = false): Promise<void> {
const unlock = await getFetchInstanceMetadataLock(instance.host);

View File

@ -1,15 +1,7 @@
import cluster from 'node:cluster';
import chalk from 'chalk';
import convertColor from 'color-convert';
import { format as dateFormat } from 'date-fns';
import config from '@/config/index.js';
import { envOption, LOG_LEVELS } from '@/env.js';
import type { KEYWORD } from 'color-convert/conversions.js';
type Domain = {
name: string;
color?: KEYWORD;
};
export type Level = LOG_LEVELS[keyof LOG_LEVELS];
@ -17,7 +9,7 @@ export type Level = LOG_LEVELS[keyof LOG_LEVELS];
* Class that facilitates recording log messages to the console.
*/
export default class Logger {
private domain: Domain;
private domain: string;
private parentLogger: Logger | null = null;
private store: boolean;
/**
@ -28,14 +20,10 @@ export default class Logger {
/**
* Create a logger instance.
* @param domain Logging domain
* @param color Log message color
* @param store Whether to store messages
*/
constructor(domain: string, color?: KEYWORD, store = true, minLevel?: Level) {
this.domain = {
name: domain,
color,
};
constructor(domain: string, store = true, minLevel?: Level) {
this.domain = domain;
this.store = store;
this.minLevel = minLevel ?? envOption.logLevel;
}
@ -43,12 +31,11 @@ export default class Logger {
/**
* Create a child logger instance.
* @param domain Logging domain
* @param color Log message color
* @param store Whether to store messages
* @returns A Logger instance whose parent logger is this instance.
*/
public createSubLogger(domain: string, color?: KEYWORD, store = true, minLevel?: Level): Logger {
const logger = new Logger(domain, color, store, minLevel);
public createSubLogger(domain: string, store = true, minLevel?: Level): Logger {
const logger = new Logger(domain, store, minLevel);
logger.parentLogger = this;
return logger;
}
@ -58,10 +45,9 @@ export default class Logger {
* @param level Indicates the level of this particular message. If it is
* less than the minimum level configured, the message will be discarded.
* @param message The message to be logged.
* @param important Whether to highlight this message as especially important.
* @param subDomains Names of sub-loggers to be added.
*/
private log(level: Level, message: string, important = false, subDomains: Domain[] = [], _store = true): void {
private log(level: Level, message: string, subDomains: Domain[] = [], _store = true): void {
const store = _store && this.store;
// Check against the configured log level.
@ -70,66 +56,52 @@ export default class Logger {
// If this logger has a parent logger, delegate the actual logging to it,
// so the parent domain(s) will be logged properly.
if (this.parentLogger) {
this.parentLogger.log(level, message, important, [this.domain].concat(subDomains), store);
this.parentLogger.log(level, message, [this.domain].concat(subDomains), store);
return;
}
const time = dateFormat(new Date(), 'HH:mm:ss');
const worker = cluster.isPrimary ? '*' : cluster.worker?.id;
const domains = [this.domain].concat(subDomains).map(d => d.color ? chalk.rgb(...convertColor.keyword.rgb(d.color))(d.name) : chalk.white(d.name));
const domains = [this.domain].concat(subDomains);
let levelDisplay;
let messageDisplay;
switch (level) {
case LOG_LEVELS.error:
if (important) {
levelDisplay = chalk.bgRed.white('ERR ');
} else {
levelDisplay = chalk.red('ERR ');
}
messageDisplay = chalk.red(message);
levelDisplay = 'ERR ';
break;
case LOG_LEVELS.warning:
levelDisplay = chalk.yellow('WARN');
messageDisplay = chalk.yellow(message);
levelDisplay = 'WARN';
break;
case LOG_LEVELS.success:
if (important) {
levelDisplay = chalk.bgGreen.white('DONE');
} else {
levelDisplay = chalk.green('DONE');
}
messageDisplay = chalk.green(message);
levelDisplay = 'DONE';
break;
case LOG_LEVELS.info:
levelDisplay = chalk.blue('INFO');
messageDisplay = message;
levelDisplay = 'INFO';
break;
case LOG_LEVELS.debug: default:
levelDisplay = chalk.gray('VERB');
messageDisplay = chalk.gray(message);
case LOG_LEVELS.debug:
default:
levelDisplay = 'VERB';
break;
}
let log = `${levelDisplay} ${worker}\t[${domains.join(' ')}]\t${messageDisplay}`;
if (envOption.withLogTime) log = chalk.gray(time) + ' ' + log;
let log = `${levelDisplay} ${worker}\t[${domains.join(' ')}]\t${message}`;
if (envOption.withLogTime) log = time + ' ' + log;
console.log(important ? chalk.bold(log) : log);
console.log(log);
}
/**
* Log an error message.
* Use in situations where execution cannot be continued.
* @param err Error or string containing an error message
* @param important Whether this error is important
*/
public error(err: string | Error, important = false): void {
public error(err: string | Error): void {
if (err instanceof Error) {
this.log(LOG_LEVELS.error, err.toString(), important);
this.log(LOG_LEVELS.error, err.toString());
} else if (typeof err === 'object') {
this.log(LOG_LEVELS.error, `${(err as any).message || (err as any).name || err}`, important);
this.log(LOG_LEVELS.error, `${(err as any).message || (err as any).name || err}`);
} else {
this.log(LOG_LEVELS.error, `${err}`, important);
this.log(LOG_LEVELS.error, `${err}`);
}
}
@ -137,39 +109,35 @@ export default class Logger {
* Log a warning message.
* Use in situations where execution can continue but needs to be improved.
* @param message Warning message
* @param important Whether this warning is important
*/
public warn(message: string, important = false): void {
this.log(LOG_LEVELS.warning, message, important);
public warn(message: string): void {
this.log(LOG_LEVELS.warning, message);
}
/**
* Log a success message.
* Use in situations where something has been successfully done.
* @param message Success message
* @param important Whether this success message is important
*/
public succ(message: string, important = false): void {
this.log(LOG_LEVELS.success, message, important);
public succ(message: string): void {
this.log(LOG_LEVELS.success, message);
}
/**
* Log a debug message.
* Use for debugging (information needed by developers but not required by users).
* @param message Debug message
* @param important Whether this debug message is important
*/
public debug(message: string, important = false): void {
this.log(LOG_LEVELS.debug, message, important);
public debug(message: string): void {
this.log(LOG_LEVELS.debug, message);
}
/**
* Log an informational message.
* Use when something needs to be logged but doesn't fit into other levels.
* @param message Info message
* @param important Whether this info message is important
*/
public info(message: string, important = false): void {
this.log(LOG_LEVELS.info, message, important);
public info(message: string): void {
this.log(LOG_LEVELS.info, message);
}
}

View File

@ -3675,8 +3675,6 @@ __metadata:
bull: 4.8.4
cacheable-lookup: 6.0.4
cbor: 8.1.0
chalk: 5.0.1
chalk-template: 0.4.0
cli-highlight: 2.1.11
color-convert: 2.0.1
content-disposition: 0.5.4
@ -4344,15 +4342,6 @@ __metadata:
languageName: node
linkType: hard
"chalk-template@npm:0.4.0":
version: 0.4.0
resolution: "chalk-template@npm:0.4.0"
dependencies:
chalk: ^4.1.2
checksum: 6c706802a79a7963cbce18f022b046fe86e438a67843151868852f80ea7346e975a6a9749991601e7e5d3b6a6c4852a04c53dc966a9a3d04031bd0e0ed53c819
languageName: node
linkType: hard
"chalk@npm:4.0.0":
version: 4.0.0
resolution: "chalk@npm:4.0.0"
@ -4363,13 +4352,6 @@ __metadata:
languageName: node
linkType: hard
"chalk@npm:5.0.1":
version: 5.0.1
resolution: "chalk@npm:5.0.1"
checksum: 7b45300372b908f0471fbf7389ce2f5de8d85bb949026fd51a1b95b10d0ed32c7ed5aab36dd5e9d2bf3191867909b4404cef75c5f4d2d1daeeacd301dd280b76
languageName: node
linkType: hard
"chalk@npm:^1.1.3":
version: 1.1.3
resolution: "chalk@npm:1.1.3"
@ -4394,7 +4376,7 @@ __metadata:
languageName: node
linkType: hard
"chalk@npm:^4.0.0, chalk@npm:^4.0.2, chalk@npm:^4.1.0, chalk@npm:^4.1.2":
"chalk@npm:^4.0.0, chalk@npm:^4.0.2, chalk@npm:^4.1.0":
version: 4.1.2
resolution: "chalk@npm:4.1.2"
dependencies: