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);
}
result = await jobHandler(jobParams, this.context);
} }
return Task.fromPromised(jobHandler)(jobLogger, jobParams, this.context); catch (error) {
}) error = error;
.chain((result) => Task.of({ result })) }
.orElse((error) => Task.of({ error })) await this.finishJob({
.chain(tapTask(async ({ result, error }) => await this.finishJob({ jobId, logId, jobLogger, callback, timeout, result, error }))) jobId,
.run().promise(); 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)) {
throw new Error('已有相同任务正在运行')
}
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( timeoutTimer = setTimeout(
async () => await this.finishJob({ jobId, logId, jobLogger, callback, timeout, error: new Error('timeout') }), () => this.finishJob({
executorTimeout * 1000) jobId,
logId,
callback,
timeoutTimer,
result: null,
error: new Error('任务执行超时')
}),
executorTimeout * 1000
);
}
result = await jobHandler(jobParams, this.context);
} catch (error) {
error = error
} }
return Task.fromPromised(jobHandler)(jobLogger, jobParams, this.context)
}) await this.finishJob({
.chain((result) => Task.of({ result })) jobId,
.orElse((error) => Task.of({ error })) logId,
.chain(tapTask(async ({ result, error }) => await this.finishJob({ jobId, logId, jobLogger, callback, timeout, result, error }))) callback,
.run().promise() 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)
} }
}
} }
\ No newline at end of file \ No newline at end of file
module.exports = JobManager
import debug from 'debug';
import fs from 'fs';
import os from 'os';
import util from 'util';
// 类型定义
type LogLevel = 'error' | 'info' | 'warn' | 'debug' | 'trace';
type LoggerMethods = {
[key in LogLevel]: debug.Debugger;
} & {
close: () => void;
};
interface LoggerOptions {
namespace: string;
logFilePath?: string;
enabledLevels?: string;
debugEnabled?: boolean;
}
// 配置解析
const parseEnvBool = (envVar: string): boolean => {
const value = process.env[envVar] || '';
return /^(yes|on|true|enable|enabled|1)$/i.test(value);
};
const getEnvValue = (envVar: string, defaultValue: string): string => {
return process.env[envVar] !== undefined ? process.env[envVar] : defaultValue;
};
// 默认配置
const DEFAULT_LOG_LEVELS = 'info:*,warn:*,error:*,debug:*,trace:*';
const WRITE_STREAM_OPTIONS: fs.WriteStreamOptions = {
flags: 'a',
encoding: 'utf8',
autoClose: true,
emitClose: true
};
// 空日志函数
const noop = (..._args: any[]): void => {};
const noopLogger: LoggerMethods = {
error: noop,
info: noop,
warn: noop,
debug: noop,
trace: noop,
close: noop
};
// 创建基础日志函数
const createBaseLoggers = (namespace: string): Omit<LoggerMethods, 'close'> => {
return {
error: debug('error').extend(namespace),
info: debug('info').extend(namespace),
warn: debug('warn').extend(namespace),
debug: debug('debug').extend(namespace),
trace: debug('trace').extend(namespace)
};
};
// 配置日志级别
const configureLogLevels = (
logger: Omit<LoggerMethods, 'close'>,
enabledLevels: string
): void => {
Object.entries(logger).forEach(([level]) => {
logger[level as LogLevel].enabled = enabledLevels.includes(level);
});
};
// 创建文件日志写入器
const createFileLogger = (
logFilePath: string,
logger: Omit<LoggerMethods, 'close'>,
enabledLevels: string
): LoggerMethods => {
const writeStream = fs.createWriteStream(logFilePath, WRITE_STREAM_OPTIONS);
const logToFile = (...args: any[]): void => {
writeStream.write(`${util.format(...args)}${os.EOL}`);
};
const logToConsoleAndFile = (...args: any[]): void => {
const message = util.format(...args);
console.error(message);
writeStream.write(`${message}${os.EOL}`);
};
// 配置日志输出方式
Object.entries(logger).forEach(([level, logFn]) => {
logFn.log = enabledLevels.includes(level) ? logToConsoleAndFile : logToFile;
});
// 返回完整logger对象
return {
...logger,
close: (): void => {
writeStream.end();
// 切换回仅控制台日志
Object.values(logger).forEach((logFn) => {
logFn.log = console.error;
});
}
};
};
// 主导出函数
export const createLogger = (
options: LoggerOptions | string
): LoggerMethods => {
// 处理参数重载
const normalizedOptions = typeof options === 'string'
? { namespace: options }
: 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;
\ No newline at end of file \ No newline at end of file
// import debug from 'debug';
// import fs from 'fs';
// import os from 'os';
// import util from 'util';
// // 类型定义
// type LogLevel = 'error' | 'info' | 'warn' | 'debug' | 'trace';
// type LoggerMethods = {
// [key in LogLevel]: debug.Debugger;
// } & {
// close: () => void;
// };
// interface LoggerOptions {
// namespace: string;
// logFilePath?: string;
// enabledLevels?: string;
// debugEnabled?: boolean;
// }
// // 配置解析
// const parseEnvBool = (envVar: string): boolean => {
// const value = process.env[envVar] || '';
// return /^(yes|on|true|enable|enabled|1)$/i.test(value);
// };
// const getEnvValue = (envVar: string, defaultValue: string): string => {
// return process.env[envVar] !== undefined ? process.env[envVar] : defaultValue;
// };
// // 默认配置
// const DEFAULT_LOG_LEVELS = 'info:*,warn:*,error:*,debug:*,trace:*';
// const WRITE_STREAM_OPTIONS: fs.WriteStreamOptions = {
// flags: 'a',
// encoding: 'utf8',
// autoClose: true,
// emitClose: true
// };
// // 空日志函数
// const noop = (..._args: any[]): void => {};
// const noopLogger: LoggerMethods = {
// error: noop,
// info: noop,
// warn: noop,
// debug: noop,
// trace: noop,
// close: noop
// };
// // 创建基础日志函数
// const createBaseLoggers = (namespace: string): Omit<LoggerMethods, 'close'> => {
// return {
// error: debug('error').extend(namespace),
// info: debug('info').extend(namespace),
// warn: debug('warn').extend(namespace),
// debug: debug('debug').extend(namespace),
// trace: debug('trace').extend(namespace)
// };
// };
// // 配置日志级别
// const configureLogLevels = (
// logger: Omit<LoggerMethods, 'close'>,
// enabledLevels: string
// ): void => {
// Object.entries(logger).forEach(([level]) => {
// logger[level as LogLevel].enabled = enabledLevels.includes(level);
// });
// };
// // 创建文件日志写入器
// const createFileLogger = (
// logFilePath: string,
// logger: Omit<LoggerMethods, 'close'>,
// enabledLevels: string
// ): LoggerMethods => {
// const writeStream = fs.createWriteStream(logFilePath, WRITE_STREAM_OPTIONS);
// const logToFile = (...args: any[]): void => {
// writeStream.write(`${util.format(...args)}${os.EOL}`);
// };
// const logToConsoleAndFile = (...args: any[]): void => {
// const message = util.format(...args);
// console.error(message);
// writeStream.write(`${message}${os.EOL}`);
// };
// // 配置日志输出方式
// Object.entries(logger).forEach(([level, logFn]) => {
// logFn.log = enabledLevels.includes(level) ? logToConsoleAndFile : logToFile;
// });
// // 返回完整logger对象
// return {
// ...logger,
// close: (): void => {
// writeStream.end();
// // 切换回仅控制台日志
// Object.values(logger).forEach((logFn) => {
// logFn.log = console.error;
// });
// }
// };
// };
// // 主导出函数
// export const createLogger = (
// options: LoggerOptions | string
// ): LoggerMethods => {
// // 处理参数重载
// const normalizedOptions = typeof options === 'string'
// ? { namespace: options }
// : 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;
\ No newline at end of file \ No newline at end of file
支持 Markdown 格式
你添加了 0 到此讨论。请谨慎行事。
Finish editing this message first!