Commit ee207e6a Harvey

no message

1 个父辈 aa2bfd71
...@@ -3,4 +3,13 @@ Object.defineProperty(exports, "__esModule", { value: true }); ...@@ -3,4 +3,13 @@ Object.defineProperty(exports, "__esModule", { value: true });
exports.job_handlers = void 0; exports.job_handlers = void 0;
const job_handlers = new Map(); const job_handlers = new Map();
exports.job_handlers = job_handlers; exports.job_handlers = job_handlers;
const common_1 = require("../libs/common");
async function demoJobHandler(jobLogger, jobParams, context) {
jobLogger.debug('params: %o, context: %o', jobParams, context);
for (let i = 1; i < 10; i++) {
await (0, common_1.sleep)(1000);
jobLogger.debug(`${i}s passed`);
}
}
job_handlers.set('demoJobHandler', demoJobHandler);
//# sourceMappingURL=index.js.map //# sourceMappingURL=index.js.map
\ No newline at end of file \ No newline at end of file
"use strict"; "use strict";
Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "__esModule", { value: true });
exports.Executor = void 0; exports.Executor = void 0;
const JobManager = require('./job-manager'); const job_manager_1 = require("./job_manager");
const logger = require('./logger'); // const logger = require('./logger')
const log = logger('xxl-job-executor'); // const log = logger('xxl-job-executor')
const axios_1 = require("axios"); const axios_1 = require("axios");
class Executor { class Executor {
executorKey; executorKey;
...@@ -25,7 +25,7 @@ class Executor { ...@@ -25,7 +25,7 @@ class Executor {
this.scheduleCenterUrl = scheduleCenterUrl; this.scheduleCenterUrl = scheduleCenterUrl;
this.accessToken = accessToken; this.accessToken = accessToken;
this.jobHandlers = jobHandlers; this.jobHandlers = jobHandlers;
this.jobManager = new JobManager(jobLogPath, context); this.jobManager = new job_manager_1.JobManager(jobLogPath, context);
} }
/** /**
* 应用执行器中间件 * 应用执行器中间件
...@@ -223,7 +223,7 @@ class Executor { ...@@ -223,7 +223,7 @@ class Executor {
'Content-Type': 'application/json' 'Content-Type': 'application/json'
} }
}).then((response) => response.data).catch((err) => { }).then((response) => response.data).catch((err) => {
log.error(`callback error:${JSON.stringify(result)} ${err.message}`); console.error(`callback error:${JSON.stringify(result)} ${err.message}`);
}); });
} }
} }
......
const fs = require('fs'); "use strict";
const moment = require('moment'); Object.defineProperty(exports, "__esModule", { value: true });
const Path = require('path'); exports.JobManager = void 0;
const logger = require('./logger'); const moment = require("moment");
const { Task, tapTask } = require('./purefuncs'); const Path = require("path");
const { mkdir, searchInFile } = require('./file'); // const Path = require('path')
const log = logger('xxl-job-manager'); // const logger = require('./logger')
// const log = logger('xxl-job-manager')
// const { Task, tapTask } = require('./purefuncs')
// const { mkdir, searchInFile } = require('./file')
/** /**
* 任务管理 * 任务管理
*/ */
class JobManager { class JobManager {
context;
runningJobs;
jobLogPath;
/** /**
* @param {string} jobLogPath * @param {string} jobLogPath
* @param {*} context * @param {*} context
*/ */
constructor(jobLogPath, context) { constructor(jobLogPath, context) {
mkdir(jobLogPath); // mkdir(jobLogPath)
this.jobLogPath = jobLogPath; this.jobLogPath = jobLogPath;
this.context = context; this.context = context;
this.runningJobs = new Set(); this.runningJobs = new Set();
...@@ -44,39 +50,55 @@ class JobManager { ...@@ -44,39 +50,55 @@ class JobManager {
hasJob(jobId) { hasJob(jobId) {
return this.runningJobs.has(jobId); return this.runningJobs.has(jobId);
} }
/** async runJob(jobId, // 任务ID
* @param {number} jobId jobJsonParams, // 任务参数(JSON格式)
* @param {string} jobJsonParams logId, // 日志ID
* @param {number} logId logDateTime, // 日志时间
* @param {number} logDateTime executorTimeout, // 执行超时时间(秒)
* @param {number} executorTimeout handlerName, // 处理器名称
* @param {string} handlerName jobHandler, // 任务处理函数
* @param {function} jobHandler callback // 回调函数
* @param {function} callback ) {
*/ // 1. 初始化日志记录器
runJob(jobId, jobJsonParams, logId, logDateTime, executorTimeout, handlerName, jobHandler, callback) { // const loggerNamespace = this.getJobLoggerNamespace(handlerName, logDateTime, logId);
let timeout = undefined; // const logFilePath = this.getLogFilePath(logDateTime);
const logNameSpace = this.getJobLoggerNamespace(handlerName, logDateTime, logId); // const jobLogger = logger(loggerNamespace, logFilePath);
const logFilePath = this.getLogFilePath(logDateTime); let result, timeoutTimer, error;
const jobLogger = logger(logNameSpace, logFilePath); try {
Task.of(jobJsonParams) if (this.hasJob(jobId)) {
.chain((jobJsonParams) => Task.of(jobJsonParams ? JSON.parse(jobJsonParams) : {})) throw new Error('已有相同任务正在运行');
.chain((jobParams) => { }
jobLogger.trace('start');
// check duplicate job
if (this.hasJob(jobId))
return Task.rejected('There is already have a same job is running');
this.runningJobs.add(jobId); this.runningJobs.add(jobId);
// setup timeout let jobParams;
try {
jobParams = JSON.parse(jobJsonParams);
}
catch {
jobJsonParams = {};
}
if (executorTimeout) { if (executorTimeout) {
timeout = setTimeout(async () => await this.finishJob({ jobId, logId, jobLogger, callback, timeout, error: new Error('timeout') }), executorTimeout * 1000); timeoutTimer = setTimeout(() => this.finishJob({
jobId,
logId,
callback,
timeoutTimer,
result: null,
error: new Error('任务执行超时')
}), executorTimeout * 1000);
} }
return Task.fromPromised(jobHandler)(jobLogger, jobParams, this.context); result = await jobHandler(jobParams, this.context);
}) }
.chain((result) => Task.of({ result })) catch (error) {
.orElse((error) => Task.of({ error })) error = error;
.chain(tapTask(async ({ result, error }) => await this.finishJob({ jobId, logId, jobLogger, callback, timeout, result, error }))) }
.run().promise(); await this.finishJob({
jobId,
logId,
callback,
timeoutTimer,
result,
error
});
} }
/** /**
* @param {number} logDateTime * @param {number} logDateTime
...@@ -98,20 +120,18 @@ class JobManager { ...@@ -98,20 +120,18 @@ class JobManager {
* @param {*} error * @param {*} error
* @return {Promise<void>} * @return {Promise<void>}
*/ */
async finishJob({ jobId, logId, jobLogger, callback, timeout, result, error }) { async finishJob({ jobId, logId, callback, timeoutTimer, result, error }) {
try { try {
timeout && clearTimeout(timeout); timeoutTimer && clearTimeout(timeoutTimer);
result && jobLogger.trace('result: %o', result);
error && jobLogger.err('error: %o', error.message || error);
jobLogger.trace('end');
jobLogger.close();
await callback(error, { logId, result }); await callback(error, { logId, result });
} }
catch (err) { catch (err) {
log.err('finishJob error: %o', err.message || err); console.log(`finishJob error: ${err.message}`);
}
finally {
this.runningJobs.delete(jobId);
} }
this.runningJobs.delete(jobId);
} }
} }
module.exports = JobManager;
//# sourceMappingURL=job-manager.js.map
\ No newline at end of file \ No newline at end of file
exports.JobManager = JobManager;
//# sourceMappingURL=job_manager.js.map
\ No newline at end of file \ No newline at end of file
"use strict"; // import debug from 'debug';
Object.defineProperty(exports, "__esModule", { value: true }); // import fs from 'fs';
exports.createLogger = void 0; // import os from 'os';
const debug_1 = require("debug"); // import util from 'util';
const fs_1 = require("fs"); // // 类型定义
const os_1 = require("os"); // type LogLevel = 'error' | 'info' | 'warn' | 'debug' | 'trace';
const util_1 = require("util"); // type LoggerMethods = {
// 配置解析 // [key in LogLevel]: debug.Debugger;
const parseEnvBool = (envVar) => { // } & {
const value = process.env[envVar] || ''; // close: () => void;
return /^(yes|on|true|enable|enabled|1)$/i.test(value); // };
}; // interface LoggerOptions {
const getEnvValue = (envVar, defaultValue) => { // namespace: string;
return process.env[envVar] !== undefined ? process.env[envVar] : defaultValue; // logFilePath?: string;
}; // enabledLevels?: string;
// 默认配置 // debugEnabled?: boolean;
const DEFAULT_LOG_LEVELS = 'info:*,warn:*,error:*,debug:*,trace:*'; // }
const WRITE_STREAM_OPTIONS = { // // 配置解析
flags: 'a', // const parseEnvBool = (envVar: string): boolean => {
encoding: 'utf8', // const value = process.env[envVar] || '';
autoClose: true, // return /^(yes|on|true|enable|enabled|1)$/i.test(value);
emitClose: true // };
}; // const getEnvValue = (envVar: string, defaultValue: string): string => {
// 空日志函数 // return process.env[envVar] !== undefined ? process.env[envVar] : defaultValue;
const noop = (..._args) => { }; // };
const noopLogger = { // // 默认配置
error: noop, // const DEFAULT_LOG_LEVELS = 'info:*,warn:*,error:*,debug:*,trace:*';
info: noop, // const WRITE_STREAM_OPTIONS: fs.WriteStreamOptions = {
warn: noop, // flags: 'a',
debug: noop, // encoding: 'utf8',
trace: noop, // autoClose: true,
close: noop // emitClose: true
}; // };
// 创建基础日志函数 // // 空日志函数
const createBaseLoggers = (namespace) => { // const noop = (..._args: any[]): void => {};
return { // const noopLogger: LoggerMethods = {
error: (0, debug_1.default)('error').extend(namespace), // error: noop,
info: (0, debug_1.default)('info').extend(namespace), // info: noop,
warn: (0, debug_1.default)('warn').extend(namespace), // warn: noop,
debug: (0, debug_1.default)('debug').extend(namespace), // debug: noop,
trace: (0, debug_1.default)('trace').extend(namespace) // trace: noop,
}; // close: noop
}; // };
// 配置日志级别 // // 创建基础日志函数
const configureLogLevels = (logger, enabledLevels) => { // const createBaseLoggers = (namespace: string): Omit<LoggerMethods, 'close'> => {
Object.entries(logger).forEach(([level]) => { // return {
logger[level].enabled = enabledLevels.includes(level); // error: debug('error').extend(namespace),
}); // info: debug('info').extend(namespace),
}; // warn: debug('warn').extend(namespace),
// 创建文件日志写入器 // debug: debug('debug').extend(namespace),
const createFileLogger = (logFilePath, logger, enabledLevels) => { // trace: debug('trace').extend(namespace)
const writeStream = fs_1.default.createWriteStream(logFilePath, WRITE_STREAM_OPTIONS); // };
const logToFile = (...args) => { // };
writeStream.write(`${util_1.default.format(...args)}${os_1.default.EOL}`); // // 配置日志级别
}; // const configureLogLevels = (
const logToConsoleAndFile = (...args) => { // logger: Omit<LoggerMethods, 'close'>,
const message = util_1.default.format(...args); // enabledLevels: string
console.error(message); // ): void => {
writeStream.write(`${message}${os_1.default.EOL}`); // Object.entries(logger).forEach(([level]) => {
}; // logger[level as LogLevel].enabled = enabledLevels.includes(level);
// 配置日志输出方式 // });
Object.entries(logger).forEach(([level, logFn]) => { // };
logFn.log = enabledLevels.includes(level) ? logToConsoleAndFile : logToFile; // // 创建文件日志写入器
}); // const createFileLogger = (
// 返回完整logger对象 // logFilePath: string,
return { // logger: Omit<LoggerMethods, 'close'>,
...logger, // enabledLevels: string
close: () => { // ): LoggerMethods => {
writeStream.end(); // const writeStream = fs.createWriteStream(logFilePath, WRITE_STREAM_OPTIONS);
// 切换回仅控制台日志 // const logToFile = (...args: any[]): void => {
Object.values(logger).forEach((logFn) => { // writeStream.write(`${util.format(...args)}${os.EOL}`);
logFn.log = console.error; // };
}); // const logToConsoleAndFile = (...args: any[]): void => {
} // const message = util.format(...args);
}; // console.error(message);
}; // writeStream.write(`${message}${os.EOL}`);
// 主导出函数 // };
const createLogger = (options) => { // // 配置日志输出方式
// 处理参数重载 // Object.entries(logger).forEach(([level, logFn]) => {
const normalizedOptions = typeof options === 'string' // logFn.log = enabledLevels.includes(level) ? logToConsoleAndFile : logToFile;
? { namespace: options } // });
: options; // // 返回完整logger对象
const { namespace, logFilePath, enabledLevels = getEnvValue('DEBUG', DEFAULT_LOG_LEVELS), debugEnabled = parseEnvBool('XXL_JOB_DEBUG_LOG') } = normalizedOptions; // return {
if (!debugEnabled && !logFilePath) { // ...logger,
return noopLogger; // close: (): void => {
} // writeStream.end();
const logger = createBaseLoggers(namespace); // // 切换回仅控制台日志
// 配置日志级别 // Object.values(logger).forEach((logFn) => {
configureLogLevels(logger, enabledLevels); // logFn.log = console.error;
if (!logFilePath) { // });
return { // }
...logger, // };
close: noop // };
}; // // 主导出函数
} // export const createLogger = (
// 文件日志配置 // options: LoggerOptions | string
return createFileLogger(logFilePath, logger, enabledLevels); // ): LoggerMethods => {
}; // // 处理参数重载
exports.createLogger = createLogger; // const normalizedOptions = typeof options === 'string'
// 默认导出 // ? { namespace: options }
exports.default = exports.createLogger; // : options;
// const {
// namespace,
// logFilePath,
// enabledLevels = getEnvValue('DEBUG', DEFAULT_LOG_LEVELS),
// debugEnabled = parseEnvBool('XXL_JOB_DEBUG_LOG')
// } = normalizedOptions;
// if (!debugEnabled && !logFilePath) {
// return noopLogger;
// }
// const logger = createBaseLoggers(namespace);
// // 配置日志级别
// configureLogLevels(logger, enabledLevels);
// if (!logFilePath) {
// return {
// ...logger,
// close: noop
// };
// }
// // 文件日志配置
// return createFileLogger(logFilePath, logger, enabledLevels);
// };
// // 默认导出
// export default createLogger;
//# sourceMappingURL=logger.js.map //# sourceMappingURL=logger.js.map
\ No newline at end of file \ No newline at end of file
const Axios = require('axios');
const FC = require('folktale/concurrency');
const R = require('ramda');
const always = R.always;
const anyPass = R.anyPass;
const last = R.last;
const compose = R.compose;
const pick = R.pick;
const propOr = R.propOr;
const path = R.path;
const pathOr = R.pathOr;
const reject = R.reject;
const tap = R.tap;
const not = R.not;
const isNil = R.isNil;
const isEmpty = R.isEmpty;
const Task = FC.task;
const notEmpty = compose(not, isEmpty);
const omitNil = reject(isNil);
const isNilOrEmpty = anyPass([isNil, isEmpty]);
const tapTask = (f) => compose(Task.of, tap(f));
const postTask = Task.fromPromised(Axios.post);
module.exports = {
always, last, compose, pick, propOr, path, pathOr, tap, not, isNil, isEmpty, Task, notEmpty, omitNil,
isNilOrEmpty, tapTask, postTask,
};
//# sourceMappingURL=purefuncs.js.map
\ No newline at end of file \ No newline at end of file
...@@ -13,7 +13,8 @@ ...@@ -13,7 +13,8 @@
"dependencies": { "dependencies": {
"axios": "^1.9.0", "axios": "^1.9.0",
"body-parser": "^2.2.0", "body-parser": "^2.2.0",
"express": "^5.1.0" "express": "^5.1.0",
"moment": "^2.30.1"
}, },
"devDependencies": { "devDependencies": {
"@types/node": "^10.17.60" "@types/node": "^10.17.60"
......
const job_handlers = new Map(); const job_handlers = new Map();
import { sleep } from '../libs/common'
async function demoJobHandler(jobLogger, jobParams, context) {
jobLogger.debug('params: %o, context: %o', jobParams, context)
for (let i = 1; i < 10; i++) {
await sleep(1000)
jobLogger.debug(`${i}s passed`)
}
}
job_handlers.set('demoJobHandler', demoJobHandler)
export { job_handlers } export { job_handlers }
\ No newline at end of file \ No newline at end of file
const JobManager = require('./job-manager') import { JobManager } from './job_manager'
const logger = require('./logger')
const log = logger('xxl-job-executor') // const logger = require('./logger')
// const log = logger('xxl-job-executor')
import axios from 'axios'; import axios from 'axios';
export class Executor { export class Executor {
...@@ -262,7 +263,7 @@ export class Executor { ...@@ -262,7 +263,7 @@ export class Executor {
'Content-Type': 'application/json' 'Content-Type': 'application/json'
} }
}).then((response) => response.data).catch((err) => { }).then((response) => response.data).catch((err) => {
log.error(`callback error:${JSON.stringify(result)} ${err.message}`); console.error(`callback error:${JSON.stringify(result)} ${err.message}`);
}) })
} }
} }
const fs = require('fs') import * as moment from 'moment'
const moment = require('moment') import * as Path from 'path'
const Path = require('path')
const logger = require('./logger')
const { Task, tapTask } = require('./purefuncs') // const Path = require('path')
const { mkdir, searchInFile } = require('./file') // const logger = require('./logger')
// const log = logger('xxl-job-manager')
// const { Task, tapTask } = require('./purefuncs')
// const { mkdir, searchInFile } = require('./file')
const log = logger('xxl-job-manager')
/** /**
* 任务管理 * 任务管理
*/ */
class JobManager { export class JobManager {
context
runningJobs
jobLogPath
/** /**
* @param {string} jobLogPath * @param {string} jobLogPath
* @param {*} context * @param {*} context
*/ */
constructor(jobLogPath, context) { constructor(jobLogPath, context) {
mkdir(jobLogPath) // mkdir(jobLogPath)
this.jobLogPath = jobLogPath this.jobLogPath = jobLogPath
this.context = context this.context = context
this.runningJobs = new Set() this.runningJobs = new Set()
...@@ -50,41 +55,69 @@ class JobManager { ...@@ -50,41 +55,69 @@ class JobManager {
return this.runningJobs.has(jobId) return this.runningJobs.has(jobId)
} }
/** async runJob(
* @param {number} jobId jobId, // 任务ID
* @param {string} jobJsonParams jobJsonParams, // 任务参数(JSON格式)
* @param {number} logId logId, // 日志ID
* @param {number} logDateTime logDateTime, // 日志时间
* @param {number} executorTimeout executorTimeout, // 执行超时时间(秒)
* @param {string} handlerName handlerName, // 处理器名称
* @param {function} jobHandler jobHandler, // 任务处理函数
* @param {function} callback callback // 回调函数
*/ ) {
runJob(jobId, jobJsonParams, logId, logDateTime, executorTimeout, handlerName, jobHandler, callback) {
let timeout = undefined // 1. 初始化日志记录器
const logNameSpace = this.getJobLoggerNamespace(handlerName, logDateTime, logId) // const loggerNamespace = this.getJobLoggerNamespace(handlerName, logDateTime, logId);
const logFilePath = this.getLogFilePath(logDateTime) // const logFilePath = this.getLogFilePath(logDateTime);
const jobLogger = logger(logNameSpace, logFilePath) // const jobLogger = logger(loggerNamespace, logFilePath);
Task.of(jobJsonParams)
.chain((jobJsonParams) => Task.of(jobJsonParams ? JSON.parse(jobJsonParams) : {})) let result, timeoutTimer, error
.chain((jobParams) => {
jobLogger.trace('start') try {
// check duplicate job
if (this.hasJob(jobId)) return Task.rejected('There is already have a same job is running') if (this.hasJob(jobId)) {
this.runningJobs.add(jobId) throw new Error('已有相同任务正在运行')
// setup timeout }
if (executorTimeout) { this.runningJobs.add(jobId)
timeout = setTimeout(
async () => await this.finishJob({ jobId, logId, jobLogger, callback, timeout, error: new Error('timeout') }), let jobParams
executorTimeout * 1000) try {
} jobParams = JSON.parse(jobJsonParams);
return Task.fromPromised(jobHandler)(jobLogger, jobParams, this.context) } catch {
}) jobJsonParams = {}
.chain((result) => Task.of({ result })) }
.orElse((error) => Task.of({ error }))
.chain(tapTask(async ({ result, error }) => await this.finishJob({ jobId, logId, jobLogger, callback, timeout, result, error }))) if (executorTimeout) {
.run().promise() timeoutTimer = setTimeout(
() => this.finishJob({
jobId,
logId,
callback,
timeoutTimer,
result: null,
error: new Error('任务执行超时')
}),
executorTimeout * 1000
);
}
result = await jobHandler(jobParams, this.context);
} catch (error) {
error = error
}
await this.finishJob({
jobId,
logId,
callback,
timeoutTimer,
result,
error
});
} }
/** /**
...@@ -108,19 +141,16 @@ class JobManager { ...@@ -108,19 +141,16 @@ class JobManager {
* @param {*} error * @param {*} error
* @return {Promise<void>} * @return {Promise<void>}
*/ */
async finishJob({ jobId, logId, jobLogger, callback, timeout, result, error }) { async finishJob({ jobId, logId, callback, timeoutTimer, result, error }) {
try { try {
timeout && clearTimeout(timeout) timeoutTimer && clearTimeout(timeoutTimer)
result && jobLogger.trace('result: %o', result)
error && jobLogger.err('error: %o', error.message || error)
jobLogger.trace('end')
jobLogger.close()
await callback(error, { logId, result }) await callback(error, { logId, result })
} catch (err) { } catch (err) {
log.err('finishJob error: %o', err.message || err) console.log(`finishJob error: ${err.message}`)
} finally {
this.runningJobs.delete(jobId)
} }
this.runningJobs.delete(jobId)
} }
} }
module.exports = JobManager
\ No newline at end of file \ No newline at end of file
import debug from 'debug'; // import debug from 'debug';
import fs from 'fs'; // import fs from 'fs';
import os from 'os'; // import os from 'os';
import util from 'util'; // import util from 'util';
// 类型定义 // // 类型定义
type LogLevel = 'error' | 'info' | 'warn' | 'debug' | 'trace'; // type LogLevel = 'error' | 'info' | 'warn' | 'debug' | 'trace';
type LoggerMethods = { // type LoggerMethods = {
[key in LogLevel]: debug.Debugger; // [key in LogLevel]: debug.Debugger;
} & { // } & {
close: () => void; // close: () => void;
}; // };
interface LoggerOptions { // interface LoggerOptions {
namespace: string; // namespace: string;
logFilePath?: string; // logFilePath?: string;
enabledLevels?: string; // enabledLevels?: string;
debugEnabled?: boolean; // debugEnabled?: boolean;
} // }
// 配置解析 // // 配置解析
const parseEnvBool = (envVar: string): boolean => { // const parseEnvBool = (envVar: string): boolean => {
const value = process.env[envVar] || ''; // const value = process.env[envVar] || '';
return /^(yes|on|true|enable|enabled|1)$/i.test(value); // return /^(yes|on|true|enable|enabled|1)$/i.test(value);
}; // };
const getEnvValue = (envVar: string, defaultValue: string): string => { // const getEnvValue = (envVar: string, defaultValue: string): string => {
return process.env[envVar] !== undefined ? process.env[envVar] : defaultValue; // return process.env[envVar] !== undefined ? process.env[envVar] : defaultValue;
}; // };
// 默认配置 // // 默认配置
const DEFAULT_LOG_LEVELS = 'info:*,warn:*,error:*,debug:*,trace:*'; // const DEFAULT_LOG_LEVELS = 'info:*,warn:*,error:*,debug:*,trace:*';
const WRITE_STREAM_OPTIONS: fs.WriteStreamOptions = { // const WRITE_STREAM_OPTIONS: fs.WriteStreamOptions = {
flags: 'a', // flags: 'a',
encoding: 'utf8', // encoding: 'utf8',
autoClose: true, // autoClose: true,
emitClose: true // emitClose: true
}; // };
// 空日志函数 // // 空日志函数
const noop = (..._args: any[]): void => {}; // const noop = (..._args: any[]): void => {};
const noopLogger: LoggerMethods = { // const noopLogger: LoggerMethods = {
error: noop, // error: noop,
info: noop, // info: noop,
warn: noop, // warn: noop,
debug: noop, // debug: noop,
trace: noop, // trace: noop,
close: noop // close: noop
}; // };
// 创建基础日志函数 // // 创建基础日志函数
const createBaseLoggers = (namespace: string): Omit<LoggerMethods, 'close'> => { // const createBaseLoggers = (namespace: string): Omit<LoggerMethods, 'close'> => {
return { // return {
error: debug('error').extend(namespace), // error: debug('error').extend(namespace),
info: debug('info').extend(namespace), // info: debug('info').extend(namespace),
warn: debug('warn').extend(namespace), // warn: debug('warn').extend(namespace),
debug: debug('debug').extend(namespace), // debug: debug('debug').extend(namespace),
trace: debug('trace').extend(namespace) // trace: debug('trace').extend(namespace)
}; // };
}; // };
// 配置日志级别 // // 配置日志级别
const configureLogLevels = ( // const configureLogLevels = (
logger: Omit<LoggerMethods, 'close'>, // logger: Omit<LoggerMethods, 'close'>,
enabledLevels: string // enabledLevels: string
): void => { // ): void => {
Object.entries(logger).forEach(([level]) => { // Object.entries(logger).forEach(([level]) => {
logger[level as LogLevel].enabled = enabledLevels.includes(level); // logger[level as LogLevel].enabled = enabledLevels.includes(level);
}); // });
}; // };
// 创建文件日志写入器 // // 创建文件日志写入器
const createFileLogger = ( // const createFileLogger = (
logFilePath: string, // logFilePath: string,
logger: Omit<LoggerMethods, 'close'>, // logger: Omit<LoggerMethods, 'close'>,
enabledLevels: string // enabledLevels: string
): LoggerMethods => { // ): LoggerMethods => {
const writeStream = fs.createWriteStream(logFilePath, WRITE_STREAM_OPTIONS); // const writeStream = fs.createWriteStream(logFilePath, WRITE_STREAM_OPTIONS);
const logToFile = (...args: any[]): void => { // const logToFile = (...args: any[]): void => {
writeStream.write(`${util.format(...args)}${os.EOL}`); // writeStream.write(`${util.format(...args)}${os.EOL}`);
}; // };
const logToConsoleAndFile = (...args: any[]): void => { // const logToConsoleAndFile = (...args: any[]): void => {
const message = util.format(...args); // const message = util.format(...args);
console.error(message); // console.error(message);
writeStream.write(`${message}${os.EOL}`); // writeStream.write(`${message}${os.EOL}`);
}; // };
// 配置日志输出方式 // // 配置日志输出方式
Object.entries(logger).forEach(([level, logFn]) => { // Object.entries(logger).forEach(([level, logFn]) => {
logFn.log = enabledLevels.includes(level) ? logToConsoleAndFile : logToFile; // logFn.log = enabledLevels.includes(level) ? logToConsoleAndFile : logToFile;
}); // });
// 返回完整logger对象 // // 返回完整logger对象
return { // return {
...logger, // ...logger,
close: (): void => { // close: (): void => {
writeStream.end(); // writeStream.end();
// 切换回仅控制台日志 // // 切换回仅控制台日志
Object.values(logger).forEach((logFn) => { // Object.values(logger).forEach((logFn) => {
logFn.log = console.error; // logFn.log = console.error;
}); // });
} // }
}; // };
}; // };
// 主导出函数 // // 主导出函数
export const createLogger = ( // export const createLogger = (
options: LoggerOptions | string // options: LoggerOptions | string
): LoggerMethods => { // ): LoggerMethods => {
// 处理参数重载 // // 处理参数重载
const normalizedOptions = typeof options === 'string' // const normalizedOptions = typeof options === 'string'
? { namespace: options } // ? { namespace: options }
: options; // : options;
const { // const {
namespace, // namespace,
logFilePath, // logFilePath,
enabledLevels = getEnvValue('DEBUG', DEFAULT_LOG_LEVELS), // enabledLevels = getEnvValue('DEBUG', DEFAULT_LOG_LEVELS),
debugEnabled = parseEnvBool('XXL_JOB_DEBUG_LOG') // debugEnabled = parseEnvBool('XXL_JOB_DEBUG_LOG')
} = normalizedOptions; // } = normalizedOptions;
if (!debugEnabled && !logFilePath) { // if (!debugEnabled && !logFilePath) {
return noopLogger; // return noopLogger;
} // }
const logger = createBaseLoggers(namespace); // const logger = createBaseLoggers(namespace);
// 配置日志级别 // // 配置日志级别
configureLogLevels(logger, enabledLevels); // configureLogLevels(logger, enabledLevels);
if (!logFilePath) { // if (!logFilePath) {
return { // return {
...logger, // ...logger,
close: noop // close: noop
}; // };
} // }
// 文件日志配置 // // 文件日志配置
return createFileLogger(logFilePath, logger, enabledLevels); // return createFileLogger(logFilePath, logger, enabledLevels);
}; // };
// 默认导出
export default createLogger;
\ No newline at end of file \ No newline at end of file
// // 默认导出
// export default createLogger;
\ No newline at end of file \ No newline at end of file
支持 Markdown 格式
你添加了 0 到此讨论。请谨慎行事。
Finish editing this message first!