diff --git a/config-schema/package.json b/config-schema/package.json index cee1cfa70..0b0487255 100644 --- a/config-schema/package.json +++ b/config-schema/package.json @@ -24,6 +24,7 @@ "devDependencies": { "@biomejs/biome": "1.9.4", "@types/node": "^17.0.21", + "jest": "27.2.4", "typescript": "^4.9.5" }, "dependencies": { diff --git a/config-schema/src/commonSchema.ts b/config-schema/src/commonSchema.ts index 3f7b0a13e..bee046c7a 100644 --- a/config-schema/src/commonSchema.ts +++ b/config-schema/src/commonSchema.ts @@ -21,12 +21,6 @@ export const browserUrls = Joi.array() .required() .description('All URLs need to have same protocol to prevent mixed block errors') -export const DECAY_START_TIME = Joi.date() - .iso() // ISO 8601 format for date validation - .description('The start time for decay, expected in ISO 8601 format (e.g. 2021-05-13T17:46:31Z)') - .default(new Date('2021-05-13T17:46:31Z')) // default to the specified date if not provided - .required() - export const COMMUNITY_URL = Joi.string() .uri({ scheme: ['http', 'https'] }) .custom((value: string, helpers: Joi.CustomHelpers) => { @@ -131,6 +125,13 @@ export const LOG4JS_CONFIG = Joi.string() .default('log4js-config.json') .required() +export const LOG4JS_CONFIG_PLACEHOLDER = Joi.string() + .pattern(/^[a-zA-Z0-9-_]+(%v)?\.json$/) + .message('LOG4JS_CONFIG_PLACEHOLDER must be a valid filename ending with .json can contain %v as API Version placeholder before ending') + .description('config file name for log4js config file') + .default('log4js-config.json') + .required() + export const LOG_FILES_BASE_PATH = Joi.string() .pattern(/^[a-zA-Z0-9-_\/\.]+$/) .message('LOG_FILES_BASE_PATH must be a valid folder name, relative or absolute') diff --git a/config-schema/src/const.ts b/config-schema/src/const.ts new file mode 100644 index 000000000..87df0f804 --- /dev/null +++ b/config-schema/src/const.ts @@ -0,0 +1 @@ +export const DECAY_START_TIME = new Date('2021-05-13T17:46:31Z') \ No newline at end of file diff --git a/config-schema/src/index.ts b/config-schema/src/index.ts index c2ad9fc96..9c7c32653 100644 --- a/config-schema/src/index.ts +++ b/config-schema/src/index.ts @@ -2,4 +2,6 @@ import 'source-map-support/register' export * from './commonSchema' export { DatabaseConfigSchema } from './DatabaseConfigSchema' export { validate } from './validate' -export { createLog4jsConfig, type Category, initLogger, defaultCategory } from './log4js-config' +export type { LogLevel, Category } from './log4js-config' +export { createLog4jsConfig, initLogger, defaultCategory } from './log4js-config' +export { DECAY_START_TIME } from './const' diff --git a/config-schema/src/log4js-config/coloredContext.ts b/config-schema/src/log4js-config/coloredContext.ts index a221c7c9d..21a2d7b28 100644 --- a/config-schema/src/log4js-config/coloredContext.ts +++ b/config-schema/src/log4js-config/coloredContext.ts @@ -5,6 +5,7 @@ import { LogLevel } from './types' export type coloredContextLayoutConfig = { withStack?: LogLevel | boolean withFile?: LogLevel | boolean + withLine?: LogLevel | boolean } function colorize(str: string, level: Level): string { @@ -66,12 +67,35 @@ function isEnabledByLogLevel(eventLogLevel: Level, targetLogLevel?: LogLevel | b return eventLogLevel.isGreaterThanOrEqualTo(targetLogLevel) } +enum DetailKind { + Callstack = 'callstack', + File = 'file', + Line = 'line', +} +function resolveDetailKind(logEvent: LoggingEvent, config: coloredContextLayoutConfig): DetailKind | undefined { + if (logEvent.callStack && isEnabledByLogLevel(logEvent.level, config.withStack)) { + return DetailKind.Callstack + } + if (isEnabledByLogLevel(logEvent.level, config.withFile)) { + return DetailKind.File + } + if (isEnabledByLogLevel(logEvent.level, config.withLine)) { + return DetailKind.Line + } + return undefined +} + export function createColoredContextLayout(config: coloredContextLayoutConfig) { return (logEvent: LoggingEvent) => { const result: string[] = [] + const detailKind = resolveDetailKind(logEvent, config) + let categoryName = logEvent.categoryName + if (detailKind === DetailKind.Line) { + categoryName += `:${logEvent.lineNumber}` + } result.push( colorize( - `[${logEvent.startTime.toISOString()}] [${logEvent.level}] ${logEvent.categoryName} -`, + `[${logEvent.startTime.toISOString()}] [${logEvent.level}] ${categoryName} -`, logEvent.level, ), ) @@ -79,12 +103,11 @@ export function createColoredContextLayout(config: coloredContextLayoutConfig) { result.push(composeContextString(logEvent.context)) } result.push(composeDataString(logEvent.data)) - const showCallstack = - logEvent.callStack && isEnabledByLogLevel(logEvent.level, config.withStack) - if (!showCallstack && isEnabledByLogLevel(logEvent.level, config.withFile)) { + + if (detailKind === DetailKind.File) { result.push(`\n at ${logEvent.fileName}:${logEvent.lineNumber}`) } - if (showCallstack) { + if (detailKind === DetailKind.Callstack) { result.push(`\n${logEvent.callStack}`) } return result.join(' ') diff --git a/config-schema/src/log4js-config/index.ts b/config-schema/src/log4js-config/index.ts index 9652726ce..18699639f 100644 --- a/config-schema/src/log4js-config/index.ts +++ b/config-schema/src/log4js-config/index.ts @@ -33,7 +33,7 @@ export function createLog4jsConfig(categories: Category[], basePath?: string): C customFileAppenders.push({ name: category.name, filename: category.filename, - withFile: true, + withLine: true, withStack: 'error', }) // needed by log4js, show all error message accidentally without (proper) Category diff --git a/config-schema/src/log4js-config/types/CustomFileAppender.ts b/config-schema/src/log4js-config/types/CustomFileAppender.ts index f2281805e..46c292349 100644 --- a/config-schema/src/log4js-config/types/CustomFileAppender.ts +++ b/config-schema/src/log4js-config/types/CustomFileAppender.ts @@ -22,10 +22,14 @@ import { LogLevel } from './LogLevel' * { name: 'warn', filename: 'warn.log', withStack: 'debug' }, * ]) * ``` + * if stack is shown, no file and no line is shown, because it is already in the stack trace + * if file:line is shown, no extra line is shown + * line will be shown after category name:line */ export type CustomFileAppender = { name: string filename?: string withStack?: LogLevel | boolean // with stack if boolean or from log level on or above withFile?: LogLevel | boolean // with filename and line if boolean or from log level on or above + withLine?: LogLevel | boolean // with line if boolean or from log level on or above }