mirror of
https://git.joinsharkey.org/Sharkey/Sharkey.git
synced 2024-11-27 11:23:08 +02:00
ログをデータベースに保存して管理画面で見れるように
This commit is contained in:
parent
f3ceb32a7c
commit
977af0a24d
29 changed files with 326 additions and 99 deletions
|
@ -21,6 +21,7 @@
|
|||
<li @click="nav('dashboard')" :class="{ active: page == 'dashboard' }"><fa icon="home" fixed-width/>{{ $t('dashboard') }}</li>
|
||||
<li @click="nav('instance')" :class="{ active: page == 'instance' }"><fa icon="cog" fixed-width/>{{ $t('instance') }}</li>
|
||||
<li @click="nav('queue')" :class="{ active: page == 'queue' }"><fa :icon="faTasks" fixed-width/>{{ $t('queue') }}</li>
|
||||
<li @click="nav('logs')" :class="{ active: page == 'logs' }"><fa :icon="faStream" fixed-width/>{{ $t('logs') }}</li>
|
||||
<li @click="nav('moderators')" :class="{ active: page == 'moderators' }"><fa :icon="faHeadset" fixed-width/>{{ $t('moderators') }}</li>
|
||||
<li @click="nav('users')" :class="{ active: page == 'users' }"><fa icon="users" fixed-width/>{{ $t('users') }}</li>
|
||||
<li @click="nav('drive')" :class="{ active: page == 'drive' }"><fa icon="cloud" fixed-width/>{{ $t('@.drive') }}</li>
|
||||
|
@ -42,6 +43,7 @@
|
|||
<div v-if="page == 'dashboard'"><x-dashboard/></div>
|
||||
<div v-if="page == 'instance'"><x-instance/></div>
|
||||
<div v-if="page == 'queue'"><x-queue/></div>
|
||||
<div v-if="page == 'logs'"><x-logs/></div>
|
||||
<div v-if="page == 'moderators'"><x-moderators/></div>
|
||||
<div v-if="page == 'users'"><x-users/></div>
|
||||
<div v-if="page == 'emoji'"><x-emoji/></div>
|
||||
|
@ -62,6 +64,7 @@ import { version } from '../../config';
|
|||
import XDashboard from "./dashboard.vue";
|
||||
import XInstance from "./instance.vue";
|
||||
import XQueue from "./queue.vue";
|
||||
import XLogs from "./logs.vue";
|
||||
import XModerators from "./moderators.vue";
|
||||
import XEmoji from "./emoji.vue";
|
||||
import XAnnouncements from "./announcements.vue";
|
||||
|
@ -71,7 +74,7 @@ import XDrive from "./drive.vue";
|
|||
import XAbuse from "./abuse.vue";
|
||||
import XFederation from "./federation.vue";
|
||||
|
||||
import { faHeadset, faArrowLeft, faGlobe, faExclamationCircle, faTasks } from '@fortawesome/free-solid-svg-icons';
|
||||
import { faHeadset, faArrowLeft, faGlobe, faExclamationCircle, faTasks, faStream } from '@fortawesome/free-solid-svg-icons';
|
||||
import { faGrin } from '@fortawesome/free-regular-svg-icons';
|
||||
|
||||
// Detect the user agent
|
||||
|
@ -84,6 +87,7 @@ export default Vue.extend({
|
|||
XDashboard,
|
||||
XInstance,
|
||||
XQueue,
|
||||
XLogs,
|
||||
XModerators,
|
||||
XEmoji,
|
||||
XAnnouncements,
|
||||
|
@ -107,7 +111,8 @@ export default Vue.extend({
|
|||
faHeadset,
|
||||
faGlobe,
|
||||
faExclamationCircle,
|
||||
faTasks
|
||||
faTasks,
|
||||
faStream
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
|
|
101
src/client/app/admin/views/logs.vue
Normal file
101
src/client/app/admin/views/logs.vue
Normal file
|
@ -0,0 +1,101 @@
|
|||
<template>
|
||||
<div>
|
||||
<ui-card>
|
||||
<template #title><fa :icon="faStream"/> {{ $t('logs') }}</template>
|
||||
<section class="fit-top">
|
||||
<ui-horizon-group inputs>
|
||||
<ui-input v-model="domain">
|
||||
<span>{{ $t('domain') }}</span>
|
||||
</ui-input>
|
||||
<ui-select v-model="level">
|
||||
<template #label>{{ $t('level') }}</template>
|
||||
<option value="all">{{ $t('levels.all') }}</option>
|
||||
<option value="info">{{ $t('levels.info') }}</option>
|
||||
<option value="success">{{ $t('levels.success') }}</option>
|
||||
<option value="warning">{{ $t('levels.warning') }}</option>
|
||||
<option value="error">{{ $t('levels.error') }}</option>
|
||||
<option value="debug">{{ $t('levels.debug') }}</option>
|
||||
</ui-select>
|
||||
</ui-horizon-group>
|
||||
|
||||
<div class="nqjzuvev">
|
||||
<code v-for="log in logs" :key="log._id" :class="log.level">
|
||||
<mk-time :time="log.createdAt"/> [{{ log.domain.join(' ') }}] {{ log.message }}
|
||||
</code>
|
||||
</div>
|
||||
</section>
|
||||
</ui-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from 'vue';
|
||||
import i18n from '../../i18n';
|
||||
import { faStream } from '@fortawesome/free-solid-svg-icons';
|
||||
|
||||
export default Vue.extend({
|
||||
i18n: i18n('admin/views/logs.vue'),
|
||||
|
||||
data() {
|
||||
return {
|
||||
logs: [],
|
||||
level: 'all',
|
||||
domain: '',
|
||||
faStream
|
||||
};
|
||||
},
|
||||
|
||||
watch: {
|
||||
level() {
|
||||
this.logs = [];
|
||||
this.fetch();
|
||||
},
|
||||
|
||||
domain() {
|
||||
this.logs = [];
|
||||
this.fetch();
|
||||
}
|
||||
},
|
||||
|
||||
mounted() {
|
||||
this.fetch();
|
||||
},
|
||||
|
||||
methods: {
|
||||
fetch() {
|
||||
this.$root.api('admin/logs', {
|
||||
level: this.level === 'all' ? null : this.level,
|
||||
domain: this.domain === '' ? null : this.domain,
|
||||
limit: 50
|
||||
}).then(logs => {
|
||||
this.logs = logs;
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
.nqjzuvev
|
||||
white-space nowrap
|
||||
overflow auto
|
||||
padding 8px
|
||||
background #000
|
||||
color #fff
|
||||
|
||||
> code
|
||||
display block
|
||||
|
||||
&.error
|
||||
color #f00
|
||||
|
||||
&.warning
|
||||
color #ff0
|
||||
|
||||
&.success
|
||||
color #0f0
|
||||
|
||||
&.debug
|
||||
opacity 0.7
|
||||
|
||||
</style>
|
|
@ -1,6 +1,6 @@
|
|||
import * as elasticsearch from 'elasticsearch';
|
||||
import config from '../config';
|
||||
import Logger from '../misc/logger';
|
||||
import Logger from '../services/logger';
|
||||
|
||||
const esLogger = new Logger('es');
|
||||
|
||||
|
|
3
src/db/logger.ts
Normal file
3
src/db/logger.ts
Normal file
|
@ -0,0 +1,3 @@
|
|||
import Logger from '../services/logger';
|
||||
|
||||
export const dbLogger = new Logger('db');
|
|
@ -18,7 +18,6 @@ export default db;
|
|||
* MongoDB native module (officialy)
|
||||
*/
|
||||
import * as mongodb from 'mongodb';
|
||||
import Logger from '../misc/logger';
|
||||
|
||||
let mdb: mongodb.Db;
|
||||
|
||||
|
@ -38,5 +37,3 @@ const nativeDbConn = async (): Promise<mongodb.Db> => {
|
|||
};
|
||||
|
||||
export { nativeDbConn };
|
||||
|
||||
export const dbLogger = new Logger('db');
|
||||
|
|
28
src/index.ts
28
src/index.ts
|
@ -13,7 +13,7 @@ import * as portscanner from 'portscanner';
|
|||
import * as isRoot from 'is-root';
|
||||
import Xev from 'xev';
|
||||
|
||||
import Logger from './misc/logger';
|
||||
import Logger from './services/logger';
|
||||
import serverStats from './daemons/server-stats';
|
||||
import notesStats from './daemons/notes-stats';
|
||||
import loadConfig from './config/load';
|
||||
|
@ -25,7 +25,7 @@ import { checkMongoDB } from './misc/check-mongodb';
|
|||
import { showMachineInfo } from './misc/show-machine-info';
|
||||
|
||||
const logger = new Logger('core', 'cyan');
|
||||
const bootLogger = logger.createSubLogger('boot', 'magenta');
|
||||
const bootLogger = logger.createSubLogger('boot', 'magenta', false);
|
||||
const clusterLogger = logger.createSubLogger('cluster', 'orange');
|
||||
const ev = new Xev();
|
||||
|
||||
|
@ -73,7 +73,7 @@ function greet() {
|
|||
console.log(chalk`${os.hostname()} {gray (PID: ${process.pid.toString()})}`);
|
||||
|
||||
bootLogger.info('Welcome to Misskey!');
|
||||
bootLogger.info(`Misskey v${pkg.version}`, true);
|
||||
bootLogger.info(`Misskey v${pkg.version}`, null, true);
|
||||
bootLogger.info('Misskey is maintained by @syuilo, @AyaMorisawa, @mei23, and @acid-chicken.');
|
||||
}
|
||||
|
||||
|
@ -90,21 +90,21 @@ async function masterMain() {
|
|||
config = await init();
|
||||
|
||||
if (config.port == null) {
|
||||
bootLogger.error('The port is not configured. Please configure port.', true);
|
||||
bootLogger.error('The port is not configured. Please configure port.', null, true);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
if (process.platform === 'linux' && isWellKnownPort(config.port) && !isRoot()) {
|
||||
bootLogger.error('You need root privileges to listen on well-known port on Linux', true);
|
||||
bootLogger.error('You need root privileges to listen on well-known port on Linux', null, true);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
if (!await isPortAvailable(config.port)) {
|
||||
bootLogger.error(`Port ${config.port} is already in use`, true);
|
||||
bootLogger.error(`Port ${config.port} is already in use`, null, true);
|
||||
process.exit(1);
|
||||
}
|
||||
} catch (e) {
|
||||
bootLogger.error('Fatal error occurred during initialization', true);
|
||||
bootLogger.error('Fatal error occurred during initialization', null, true);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
|
@ -117,7 +117,7 @@ async function masterMain() {
|
|||
// start queue
|
||||
require('./queue').default();
|
||||
|
||||
bootLogger.succ(`Now listening on port ${config.port} on ${config.url}`, true);
|
||||
bootLogger.succ(`Now listening on port ${config.port} on ${config.url}`, null, true);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -140,7 +140,7 @@ async function queueMain() {
|
|||
// initialize app
|
||||
await init();
|
||||
} catch (e) {
|
||||
bootLogger.error('Fatal error occurred during initialization', true);
|
||||
bootLogger.error('Fatal error occurred during initialization', null, true);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
|
@ -150,7 +150,7 @@ async function queueMain() {
|
|||
const queue = require('./queue').default();
|
||||
|
||||
if (queue) {
|
||||
bootLogger.succ('Queue started', true);
|
||||
bootLogger.succ('Queue started', null, true);
|
||||
} else {
|
||||
bootLogger.error('Queue not available');
|
||||
}
|
||||
|
@ -175,7 +175,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!', null, true);
|
||||
}
|
||||
|
||||
logger.info(`You ${isRoot() ? '' : 'do not '}have root privileges`);
|
||||
|
@ -192,7 +192,7 @@ async function init(): Promise<Config> {
|
|||
nodejsLogger.info(`Version ${runningNodejsVersion.join('.')}`);
|
||||
|
||||
if (!satisfyNodejsVersion) {
|
||||
nodejsLogger.error(`Node.js version is less than ${requiredNodejsVersion.join('.')}. Please upgrade it.`, true);
|
||||
nodejsLogger.error(`Node.js version is less than ${requiredNodejsVersion.join('.')}. Please upgrade it.`, null, true);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
|
@ -209,7 +209,7 @@ async function init(): Promise<Config> {
|
|||
process.exit(1);
|
||||
}
|
||||
if (exception.code === 'ENOENT') {
|
||||
configLogger.error('Configuration file not found', true);
|
||||
configLogger.error('Configuration file not found', null, true);
|
||||
process.exit(1);
|
||||
}
|
||||
throw exception;
|
||||
|
@ -221,7 +221,7 @@ async function init(): Promise<Config> {
|
|||
try {
|
||||
await checkMongoDB(config, bootLogger);
|
||||
} catch (e) {
|
||||
bootLogger.error('Cannot connect to database', true);
|
||||
bootLogger.error('Cannot connect to database', null, true);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { nativeDbConn } from '../db/mongodb';
|
||||
import { Config } from '../config/types';
|
||||
import Logger from './logger';
|
||||
import Logger from '../services/logger';
|
||||
import { lessThan } from '../prelude/array';
|
||||
|
||||
const requiredMongoDBVersion = [3, 6];
|
||||
|
|
|
@ -1,59 +0,0 @@
|
|||
import * as cluster from 'cluster';
|
||||
import chalk from 'chalk';
|
||||
import * as dateformat from 'dateformat';
|
||||
import { program } from '../argv';
|
||||
|
||||
export default class Logger {
|
||||
private domain: string;
|
||||
private color?: string;
|
||||
private parentLogger: Logger;
|
||||
|
||||
constructor(domain: string, color?: string) {
|
||||
this.domain = domain;
|
||||
this.color = color;
|
||||
}
|
||||
|
||||
public createSubLogger(domain: string, color?: string): Logger {
|
||||
const logger = new Logger(domain, color);
|
||||
logger.parentLogger = this;
|
||||
return logger;
|
||||
}
|
||||
|
||||
private log(level: string, message: string, important = false, subDomains: string[] = []): void {
|
||||
if (program.quiet) return;
|
||||
if (process.env.NODE_ENV === 'test') return;
|
||||
const domain = this.color ? chalk.keyword(this.color)(this.domain) : chalk.white(this.domain);
|
||||
const domains = [domain].concat(subDomains);
|
||||
if (this.parentLogger) {
|
||||
this.parentLogger.log(level, message, important, domains);
|
||||
} else {
|
||||
const time = dateformat(new Date(), 'HH:MM:ss');
|
||||
const process = cluster.isMaster ? '*' : cluster.worker.id;
|
||||
let log = `${level} ${process}\t[${domains.join(' ')}]\t${message}`;
|
||||
if (program.withLogTime) log = chalk.gray(time) + ' ' + log;
|
||||
console.log(important ? chalk.bold(log) : log);
|
||||
}
|
||||
}
|
||||
|
||||
public error(message: string | Error, important = false): void { // 実行を継続できない状況で使う
|
||||
this.log(important ? chalk.bgRed.white('ERR ') : chalk.red('ERR '), chalk.red(message.toString()), important);
|
||||
}
|
||||
|
||||
public warn(message: string, important = false): void { // 実行を継続できるが改善すべき状況で使う
|
||||
this.log(chalk.yellow('WARN'), chalk.yellow(message), important);
|
||||
}
|
||||
|
||||
public succ(message: string, important = false): void { // 何かに成功した状況で使う
|
||||
this.log(important ? chalk.bgGreen.white('DONE') : chalk.green('DONE'), chalk.green(message), important);
|
||||
}
|
||||
|
||||
public debug(message: string, important = false): void { // デバッグ用に使う(開発者に必要だが利用者に不要な情報)
|
||||
if (process.env.NODE_ENV != 'production' || program.verbose) {
|
||||
this.log(chalk.gray('VERB'), chalk.gray(message), important);
|
||||
}
|
||||
}
|
||||
|
||||
public info(message: string, important = false): void { // それ以外
|
||||
this.log(chalk.blue('INFO'), message, important);
|
||||
}
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
import * as os from 'os';
|
||||
import * as sysUtils from 'systeminformation';
|
||||
import Logger from './logger';
|
||||
import Logger from '../services/logger';
|
||||
|
||||
export async function showMachineInfo(parentLogger: Logger) {
|
||||
const logger = parentLogger.createSubLogger('machine');
|
||||
|
|
|
@ -2,9 +2,10 @@ import * as mongo from 'mongodb';
|
|||
import * as deepcopy from 'deepcopy';
|
||||
import { pack as packFolder } from './drive-folder';
|
||||
import { pack as packUser } from './user';
|
||||
import monkDb, { nativeDbConn, dbLogger } from '../db/mongodb';
|
||||
import monkDb, { nativeDbConn } from '../db/mongodb';
|
||||
import isObjectId from '../misc/is-objectid';
|
||||
import getDriveFileUrl, { getOriginalUrl } from '../misc/get-drive-file-url';
|
||||
import { dbLogger } from '../db/logger';
|
||||
|
||||
const DriveFile = monkDb.get<IDriveFile>('driveFiles.files');
|
||||
DriveFile.createIndex('md5');
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
import * as mongo from 'mongodb';
|
||||
import * as deepcopy from 'deepcopy';
|
||||
import db, { dbLogger } from '../db/mongodb';
|
||||
import db from '../db/mongodb';
|
||||
import isObjectId from '../misc/is-objectid';
|
||||
import { pack as packNote } from './note';
|
||||
import { dbLogger } from '../db/logger';
|
||||
|
||||
const Favorite = db.get<IFavorite>('favorites');
|
||||
Favorite.createIndex('userId');
|
||||
|
|
17
src/models/log.ts
Normal file
17
src/models/log.ts
Normal file
|
@ -0,0 +1,17 @@
|
|||
import * as mongo from 'mongodb';
|
||||
import db from '../db/mongodb';
|
||||
|
||||
const Log = db.get<ILog>('logs');
|
||||
Log.createIndex('createdAt', { expireAfterSeconds: 3600 * 24 * 3 });
|
||||
export default Log;
|
||||
|
||||
export interface ILog {
|
||||
_id: mongo.ObjectID;
|
||||
createdAt: Date;
|
||||
machine: string;
|
||||
worker: string;
|
||||
domain: string[];
|
||||
level: string;
|
||||
message: string;
|
||||
data: any;
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
import * as mongo from 'mongodb';
|
||||
import * as deepcopy from 'deepcopy';
|
||||
import rap from '@prezzemolo/rap';
|
||||
import db, { dbLogger } from '../db/mongodb';
|
||||
import db from '../db/mongodb';
|
||||
import isObjectId from '../misc/is-objectid';
|
||||
import { length } from 'stringz';
|
||||
import { IUser, pack as packUser } from './user';
|
||||
|
@ -11,6 +11,7 @@ import Reaction from './note-reaction';
|
|||
import { packMany as packFileMany, IDriveFile } from './drive-file';
|
||||
import Following from './following';
|
||||
import Emoji from './emoji';
|
||||
import { dbLogger } from '../db/logger';
|
||||
|
||||
const Note = db.get<INote>('notes');
|
||||
Note.createIndex('uri', { sparse: true, unique: true });
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
import * as mongo from 'mongodb';
|
||||
import * as deepcopy from 'deepcopy';
|
||||
import db, { dbLogger } from '../db/mongodb';
|
||||
import db from '../db/mongodb';
|
||||
import isObjectId from '../misc/is-objectid';
|
||||
import { IUser, pack as packUser } from './user';
|
||||
import { pack as packNote } from './note';
|
||||
import { dbLogger } from '../db/logger';
|
||||
|
||||
const Notification = db.get<INotification>('notifications');
|
||||
Notification.createIndex('notifieeId');
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import * as mongo from 'mongodb';
|
||||
import * as deepcopy from 'deepcopy';
|
||||
import rap from '@prezzemolo/rap';
|
||||
import db, { dbLogger } from '../db/mongodb';
|
||||
import db from '../db/mongodb';
|
||||
import isObjectId from '../misc/is-objectid';
|
||||
import { packMany as packNoteMany } from './note';
|
||||
import Following from './following';
|
||||
|
@ -12,6 +12,7 @@ import config from '../config';
|
|||
import FollowRequest from './follow-request';
|
||||
import fetchMeta from '../misc/fetch-meta';
|
||||
import Emoji from './emoji';
|
||||
import { dbLogger } from '../db/logger';
|
||||
|
||||
const User = db.get<IUser>('users');
|
||||
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
import Logger from '../misc/logger';
|
||||
import Logger from '../services/logger';
|
||||
|
||||
export const queueLogger = new Logger('queue', 'orange');
|
||||
|
|
|
@ -7,7 +7,7 @@ import { resolvePerson, updatePerson } from '../../../remote/activitypub/models/
|
|||
import { toUnicode } from 'punycode';
|
||||
import { URL } from 'url';
|
||||
import { publishApLogStream } from '../../../services/stream';
|
||||
import Logger from '../../../misc/logger';
|
||||
import Logger from '../../../services/logger';
|
||||
import { registerOrFetchInstanceDoc } from '../../../services/register-or-fetch-instance-doc';
|
||||
import Instance from '../../../models/instance';
|
||||
import instanceChart from '../../../services/chart/instance';
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
import Logger from "../misc/logger";
|
||||
import Logger from "../services/logger";
|
||||
|
||||
export const remoteLogger = new Logger('remote', 'cyan');
|
||||
|
|
51
src/server/api/endpoints/admin/logs.ts
Normal file
51
src/server/api/endpoints/admin/logs.ts
Normal file
|
@ -0,0 +1,51 @@
|
|||
import $ from 'cafy';
|
||||
import define from '../../define';
|
||||
import Log from '../../../../models/log';
|
||||
|
||||
export const meta = {
|
||||
tags: ['admin'],
|
||||
|
||||
requireCredential: true,
|
||||
requireModerator: true,
|
||||
|
||||
params: {
|
||||
limit: {
|
||||
validator: $.optional.num.range(1, 100),
|
||||
default: 30
|
||||
},
|
||||
|
||||
level: {
|
||||
validator: $.optional.nullable.str,
|
||||
default: null as any
|
||||
},
|
||||
|
||||
domain: {
|
||||
validator: $.optional.nullable.str,
|
||||
default: null as any
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export default define(meta, async (ps) => {
|
||||
const sort = {
|
||||
_id: -1
|
||||
};
|
||||
const query = {} as any;
|
||||
|
||||
if (ps.level) query.level = ps.level;
|
||||
if (ps.domain) {
|
||||
let i = 0;
|
||||
for (const d of ps.domain.split(' ')) {
|
||||
query[`domain.${i}`] = d;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
const logs = await Log
|
||||
.find(query, {
|
||||
limit: ps.limit,
|
||||
sort: sort
|
||||
});
|
||||
|
||||
return logs;
|
||||
});
|
|
@ -3,7 +3,7 @@ import limiterDB from '../../db/redis';
|
|||
import { IEndpoint } from './endpoints';
|
||||
import getAcct from '../../misc/acct/render';
|
||||
import { IUser } from '../../models/user';
|
||||
import Logger from '../../misc/logger';
|
||||
import Logger from '../../services/logger';
|
||||
|
||||
const logger = new Logger('limiter');
|
||||
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
import Logger from "../../misc/logger";
|
||||
import Logger from "../../services/logger";
|
||||
|
||||
export const apiLogger = new Logger('api');
|
||||
|
|
|
@ -23,10 +23,10 @@ import networkChart from '../services/chart/network';
|
|||
import apiServer from './api';
|
||||
import { sum } from '../prelude/array';
|
||||
import User from '../models/user';
|
||||
import Logger from '../misc/logger';
|
||||
import Logger from '../services/logger';
|
||||
import { program } from '../argv';
|
||||
|
||||
export const serverLogger = new Logger('server', 'gray');
|
||||
export const serverLogger = new Logger('server', 'gray', false);
|
||||
|
||||
// Init app
|
||||
const app = new Koa();
|
||||
|
|
|
@ -2,7 +2,7 @@ import * as Koa from 'koa';
|
|||
import * as request from 'request-promise-native';
|
||||
import summaly from 'summaly';
|
||||
import fetchMeta from '../../misc/fetch-meta';
|
||||
import Logger from '../../misc/logger';
|
||||
import Logger from '../../services/logger';
|
||||
|
||||
const logger = new Logger('url-preview');
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@ import { renderActivity } from '../../remote/activitypub/renderer';
|
|||
import renderBlock from '../../remote/activitypub/renderer/block';
|
||||
import renderUndo from '../../remote/activitypub/renderer/undo';
|
||||
import { deliver } from '../../queue';
|
||||
import Logger from '../../misc/logger';
|
||||
import Logger from '../logger';
|
||||
|
||||
const logger = new Logger('blocking/delete');
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ import autobind from 'autobind-decorator';
|
|||
import * as mongo from 'mongodb';
|
||||
import db from '../../db/mongodb';
|
||||
import { ICollection } from 'monk';
|
||||
import Logger from '../../misc/logger';
|
||||
import Logger from '../logger';
|
||||
import { Schema } from '../../misc/schema';
|
||||
|
||||
const logger = new Logger('chart');
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
import Logger from "../../misc/logger";
|
||||
import Logger from "../logger";
|
||||
|
||||
export const driveLogger = new Logger('drive', 'blue');
|
||||
|
|
|
@ -13,7 +13,7 @@ import perUserFollowingChart from '../../services/chart/per-user-following';
|
|||
import { registerOrFetchInstanceDoc } from '../register-or-fetch-instance-doc';
|
||||
import Instance from '../../models/instance';
|
||||
import instanceChart from '../../services/chart/instance';
|
||||
import Logger from '../../misc/logger';
|
||||
import Logger from '../logger';
|
||||
import FollowRequest from '../../models/follow-request';
|
||||
import { IdentifiableError } from '../../misc/identifiable-error';
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ import renderFollow from '../../remote/activitypub/renderer/follow';
|
|||
import renderUndo from '../../remote/activitypub/renderer/undo';
|
||||
import { deliver } from '../../queue';
|
||||
import perUserFollowingChart from '../../services/chart/per-user-following';
|
||||
import Logger from '../../misc/logger';
|
||||
import Logger from '../logger';
|
||||
import { registerOrFetchInstanceDoc } from '../register-or-fetch-instance-doc';
|
||||
import Instance from '../../models/instance';
|
||||
import instanceChart from '../../services/chart/instance';
|
||||
|
|
107
src/services/logger.ts
Normal file
107
src/services/logger.ts
Normal file
|
@ -0,0 +1,107 @@
|
|||
import * as cluster from 'cluster';
|
||||
import * as os from 'os';
|
||||
import chalk from 'chalk';
|
||||
import * as dateformat from 'dateformat';
|
||||
import { program } from '../argv';
|
||||
import Log from '../models/log';
|
||||
|
||||
type Domain = {
|
||||
name: string;
|
||||
color: string;
|
||||
};
|
||||
|
||||
type Level = 'error' | 'success' | 'warning' | 'debug' | 'info';
|
||||
|
||||
export default class Logger {
|
||||
private domain: Domain;
|
||||
private parentLogger: Logger;
|
||||
private store: boolean;
|
||||
|
||||
constructor(domain: string, color?: string, store = true) {
|
||||
this.domain = {
|
||||
name: domain,
|
||||
color: color,
|
||||
};
|
||||
this.store = store;
|
||||
}
|
||||
|
||||
public createSubLogger(domain: string, color?: string, store = true): Logger {
|
||||
const logger = new Logger(domain, color, store);
|
||||
logger.parentLogger = this;
|
||||
return logger;
|
||||
}
|
||||
|
||||
private log(level: Level, message: string, data: Record<string, any>, important = false, subDomains: Domain[] = [], store = true): void {
|
||||
if (program.quiet) return;
|
||||
if (process.env.NODE_ENV === 'test') return;
|
||||
if (!this.store) store = false;
|
||||
|
||||
if (this.parentLogger) {
|
||||
this.parentLogger.log(level, message, data, important, [this.domain].concat(subDomains), store);
|
||||
return;
|
||||
}
|
||||
|
||||
const time = dateformat(new Date(), 'HH:MM:ss');
|
||||
const worker = cluster.isMaster ? '*' : cluster.worker.id;
|
||||
const l =
|
||||
level === 'error' ? important ? chalk.bgRed.white('ERR ') : chalk.red('ERR ') :
|
||||
level === 'warning' ? chalk.yellow('WARN') :
|
||||
level === 'success' ? important ? chalk.bgGreen.white('DONE') : chalk.green('DONE') :
|
||||
level === 'debug' ? chalk.gray('VERB') :
|
||||
level === 'info' ? chalk.blue('INFO') :
|
||||
null;
|
||||
const domains = [this.domain].concat(subDomains).map(d => d.color ? chalk.keyword(d.color)(d.name) : chalk.white(d.name));
|
||||
const m =
|
||||
level === 'error' ? chalk.red(message) :
|
||||
level === 'warning' ? chalk.yellow(message) :
|
||||
level === 'success' ? chalk.green(message) :
|
||||
level === 'debug' ? chalk.gray(message) :
|
||||
level === 'info' ? message :
|
||||
null;
|
||||
|
||||
let log = `${l} ${worker}\t[${domains.join(' ')}]\t${m}`;
|
||||
if (program.withLogTime) log = chalk.gray(time) + ' ' + log;
|
||||
|
||||
console.log(important ? chalk.bold(log) : log);
|
||||
|
||||
if (store) {
|
||||
Log.insert({
|
||||
createdAt: new Date(),
|
||||
machine: os.hostname(),
|
||||
worker: worker,
|
||||
domain: [this.domain].concat(subDomains).map(d => d.name),
|
||||
level: level,
|
||||
message: message,
|
||||
data: data,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public error(x: string | Error, data?: Record<string, any>, important = false): void { // 実行を継続できない状況で使う
|
||||
if (x instanceof Error) {
|
||||
data = data || {};
|
||||
data.e = x;
|
||||
this.log('error', x.toString(), data, important);
|
||||
} else {
|
||||
this.log('error', x, data, important);
|
||||
}
|
||||
}
|
||||
|
||||
public warn(message: string, data?: Record<string, any>, important = false): void { // 実行を継続できるが改善すべき状況で使う
|
||||
this.log('warning', message, data, important);
|
||||
}
|
||||
|
||||
public succ(message: string, data?: Record<string, any>, important = false): void { // 何かに成功した状況で使う
|
||||
this.log('success', message, data, important);
|
||||
}
|
||||
|
||||
public debug(message: string, data?: Record<string, any>, important = false): void { // デバッグ用に使う(開発者に必要だが利用者に不要な情報)
|
||||
if (process.env.NODE_ENV != 'production' || program.verbose) {
|
||||
this.log('debug', message, data, important);
|
||||
}
|
||||
}
|
||||
|
||||
public info(message: string, data?: Record<string, any>, important = false): void { // それ以外
|
||||
this.log('info', message, data, important);
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue