# 日志输出器

说明

本章中使用的宏变量如果没有特殊描述,则存储在Core.Macros中。

# 输出模型

输出模型

# 输出器配置

通常,我们实例化日志输出器时需要指定由运行环境、最小输出等级和功能参数构成的配置对象,即:{ env, level, params }。

  • env:日志输出器的运行环境,默认值为BASE_LOGGER_DEVELOPMENT_ENVIRONMENT。

    说明

    通常,运行环境将影响日志输出器的输出行为:

    • 当运行环境为BASE_LOGGER_DEVELOPMENT_ENVIRONMENT时,日志输出器将日志统一输出至控制台。

    • 当运行环境非BASE_LOGGER_DEVELOPMENT_ENVIRONMENT时,日志输出器将日志输出至由其本身功能实现而指向的目标位置。

    我们在自定义输出器时同样应该遵守在运行环境为BASE_LOGGER_DEVELOPMENT_ENVIRONMENT时输出日志到控制台的准则。

  • level:最小输出等级(支持使用输出等级的全称或别名),日志输出器仅输出权重大于等于此输出等级的日志。

    最小输出等级的默认值依赖于日志输出器的运行环境:

    • 当运行环境为BASE_LOGGER_DEVELOPMENT_ENVIRONMENT时,默认值为'all'。

    • 当运行环境非BASE_LOGGER_DEVELOPMENT_ENVIRONMENT时,默认值为'error'。

    说明

    当最小输出等级不在日志输出器的输出等级支持列表中时,日志输出器将使用等级选举产生的默认日志等级。

    我们可以在输出等级一节中了解日志输出器原生支持的输出等级。

  • params:控制日志输出器的输出行为的功能参数,不同类型的日志输出器通常拥有不同的功能参数。

    提示

    功能参数将在日志输出器实例化时被缓存在实例属性params中。

    因此,我们在自定义输出器时可以使用功能参数的缓存机制存储一些自定义参数,以使其在整个输出器生命周期的任意阶段中共享。

    需要注意的是,为了避免对日志输出器的行为产生影响,我们在使用自定义参数时不要使用与已有功能参数相同的键名。

# 输出等级

我们可以使用输出等级名称和输出等级别名指定输出等级。

日志输出器默认支持6个输出等级:

日志类型 名称 别名 权重
追踪日志 'trace' 't' 10000
调试日志 'debug' 't' 20000
信息日志 'infos' 'i'、'info' 30000
警告日志 'warns' 'w'、'warn' 40000
错误日志 'error' 'e'、'err' 50000
灾难日志 'fatal' 'f' 60000

另外,日志输出器使用2个内部输出等级用于等级限定:

限定规则 等级名称 等级别名 等级权重
保留所有日志 'all' 'a' 0
禁止所有日志 'off' 'o' 100000

日志输出器内部使用4个基准输出等级:

  • 最小输出等级(通过配置对象指定)

  • 默认日志等级(通过配置对象中的功能参数指定)

  • 默认警告日志等级(通过配置对象中的功能参数指定)

  • 默认错误日志等级(通过配置对象中的功能参数指定)

当基准输出等级未指定,或指定的值不在输出等级支持列表中时,将使用等级选举的结果。

# 等级选举

日志输出器将自动进行等级选举以在输出等级支持列表中选出基准输出等级的默认值。一旦某个基准输出等级无效,则应用选举结果。

注意

等级选举将产生绝对有效的默认日志等级、默认警告日志等级和默认错误日志等级,但是日志输出器不会应用全部的选举结果。

比如,当我们指定的默认日志等级无效,但默认警告日志等级和默认错误日志等级有效时,日志输出器仅使用选举结果中的默认日志等级。

另外,当最小输出等级无效时将使用选举结果中的默认日志等级。


输出等级选举规则为:

  1. 迭代输出等级支持列表,尝试在配置了default为true的输出等级中选择权重最高项作为默认日志等级。

  2. 若上述步骤未能产生默认日志等级(比如:输出等级支持列表中不存在default为true的输出等级),则使用输出等级支持列表中权重居中项作为默认日志等级。

  3. 若上述步骤产生了两个权重居中的输出等级,则使用权重较小项(两者中前者)作为默认日志等级。

  4. 选举比默认日志等级权重大一个梯度的输出等级(即输出等级支持列表按权重升序排列后位于默认日志等级后一个位置的输出等级)作为默认警告日志等级。

  5. 若上述步骤未能产生默认警告日志等级(比如:默认日志等级位于输出等级支持列表的最末位),则使用默认日志等级作为默认警告日志等级。

  6. 选举比默认日志等级权重大二个梯度的输出等级(即输出等级支持列表按权重升序排列后位于默认日志等级后二个位置的输出等级)作为默认错误日志等级。

  7. 若上述步骤未能产生默认错误日志等级(比如:默认日志等级位于输出等级支持列表的最末位或倒数第二位),则使用默认警告日志等级作为默认错误日志等级。

# 基础输出器

基础输出器抽象了日志输出器基本的生命周期管理和输出链路控制,是日志输出器的基类。

通过基础输出器输出的日志最终将打印至控制台。因此,基础输出器通常不用于生产环境的日志收集。

注意

我们实现的自定义输出器必须继承自基础输出器,否则在使用时将无法通过类型校验。

# 功能说明

  1. 输出的日志将被打印至控制台。

  2. 支持自启动。即:基础输出器实例化后自动启动,无需显式执行实例方法start即可执行输出动作。

  3. 执行实例方法start、close和log时自动进行状态检测。

    • 执行实例方法log时:检测当前是否处于启动状态,若实例未启动则放弃此次日志输出。

    • 执行实例方法start时:检测当前是否处于启动状态,若实例已启动则不再执行启动逻辑。

    • 执行实例方法close时:检测当前是否处于关闭状态,若实例已关闭则不再执行关闭逻辑。

    说明

    通常,日志输出器仅提供实例方法start、close和log以被业务层调用。

    在业务层执行日志输出器提供的实例方法时默认进行状态检测,未通过状态检测或执行链路中产生异常时将抛出异常信息。

    我们可以通过实例化日志输出器时指定功能参数以控制是否进行状态检测和捕获异常信息。

  4. 实例方法log支持多种调用方式以快捷输出日志。

    调用方式 说明
    log(message) 根据日志内容智能选择输出等级,且根据实际调用栈获取调用方法名
    log(level, message) 使用指定的输出等级输出日志,且根据实际调用栈获取调用方法名
    log(level, funcName, message) 使用指定的输出等级和方法名输出日志

    说明

    使用log(message)方式输出日志时,日志输出器将根据日志内容message自动选择输出等级:

    • 当message非Error类型:使用默认日志等级输出日志。
    • 当message为Error类型:使用默认错误日志等级输出日志。

    在日志输出器执行输出动作时,如果实际应用的输出等级权重高于或等于默认错误日志等级时,将在日志内容中附加调用栈:

    • 当message非Error类型时:使用执行实例方法log时的实际调用栈。
    • 当message为Error类型时:使用Error实例携带的调用栈。

    我们可以通过在日志输出器实例化时配置callStackOffset以调整自动构建调用栈时的偏移基准。

# 功能参数

  • # template

    设置此配置将指定日志输出器的输出模板,默认值为:BASE_LOGGER_MESSAGE_DEFAULT_TEMPLATE,即:'[${timestamp}] [${env} LOG] [${level}] - <${funcName}><${content}>\n'。

    说明

    宏变量BASE_LOGGER_MESSAGE_DEFAULT_TEMPLATE存储在Core.Messages中。

    我们在指定输出模板时,可以使用${}引用日志的内容元素,默认支持:

    内容元素 说明
    ${env} 当前运行环境
    ${level} 日志输出等级
    ${content} 日志内容(可能由日志消息和调用栈组成)
    ${funcName} 调用方法名
    ${timestamp} 时间戳字符串
  • # defaultLevel

    设置此配置将指定日志输出器的默认日志等级,默认值为:null。我们可以使用输出等级的名称或别名作为默认日志等级。

    当指定此配置为null或指定了不在输出等级支持列表中的值时,将使用等级选举产生的默认日志等级。

    应用场景

    在以下场景中,日志输出器将自动应用默认日志等级:

    • 日志输出器配置的最小输出等级不在输出等级支持列表中时,将使用默认日志等级作为最小输出等级。

    • 日志输出器使用log(message)方式输出日志,且日志内容message不为Error类型时,将使用默认日志等级输出日志。

    • 日志输出器使用log(level[, funcName], message)方式输出日志,且指定的输出等级不在输出等级支持列表中时,将使用默认日志等级输出日志。

    让我们来看一个有关默认日志等级的🌰:

    const Core = require('node-corejs');
    
    // 创建基础输出器
    const logger = new Core.BaseLogger({
      level: 'x', // 此时最小输出等级无效,将应用默认日志等级error
      params: { defaultLevel: 'error' },
    });
    
    logger.log('i', '此条日志不会被输出');             // infos日志权重小于当前的最小输出等级error
    logger.log('这是一条红色的错误日志');               // 不指定输出等级时将使用默认等级error
    logger.log('x', '这是一条红色的错误日志');          // 输出等级无效时将使用默认等级error
    logger.log('x', '方法名', '这是一条红色的错误日志'); // 输出等级无效时将使用默认等级error
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
  • # defaultWarnsLevel

    设置此配置将指定日志输出器的默认警告日志等级,默认值为:null。我们可以使用输出等级的名称或别名作为默认警告日志等级。

    当指定此配置为null或指定了不在输出等级支持列表中的值时,将使用等级选举产生的默认警告日志等级。

    说明

    默认警告日志等级是日志输出器的预留属性,并没有在实际业务中使用。

    我们可以在自定义输出器时,将内部产生的异常使用默认警告日志等级输出。

  • # defaultErrorLevel

    设置此配置将指定日志输出器的默认错误日志等级,默认值为:null。我们可以使用输出等级的名称或别名作为默认错误日志等级。

    当指定此配置为null或指定了不在输出等级支持列表中的值时,将使用等级选举产生的默认错误日志等级。

    应用场景

    在以下场景中,日志输出器将自动应用默认错误日志等级:

    • 日志输出器使用log(message)方式输出日志,且日志内容message为Error类型时,将使用默认错误日志等级输出日志。

    • 日志输出器使用log(level[, funcName], message)方式输出日志,且指定的输出等级的权重高于或等于默认错误日志等级的权重时,将在日志内容中附加调用栈。

    让我们来看一个有关默认错误日志等级的🌰:

    const Core = require('node-corejs');
    
    // 创建基础输出器
    const logger = new Core.BaseLogger({
      params: { defaultErrorLevel: 'i' } // 指定infos为默认错误等级
    });
    
    logger.log(new Error('这是一条绿色且包含调用栈的错误日志'));        // Error类型的日志内容将以infos等级输出
    logger.log('i', new Error('这是一条绿色且包含调用栈的错误日志'));   // 指定infos及以上的输出等级时将在日志内容中添加调用栈
    logger.log('d', new Error('这是一条蓝色且不包含调用栈的错误日志')); // debug等级的权重小于infos因此不在日志内容中添加调用栈
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
  • # callStackOffset

    设置此配置将指定日志输出器构建实际调用栈时使用的偏移基准,默认值为:BASE_LOGGER_DEFAULT_CALLSTACK_OFFSET,即:0,此时将取得实例方法log之前的调用栈记录。

    说明

    偏移基准仅作用于日志输出器自动构建实际调用栈的场景,不会影响Error类型日志内容的调用栈提取。


    我们可以根据实际场景调整偏移基准以控制调用栈提取内容:

    • 使用Function类型的偏移基准:日志输出器自动构建调用栈时将仅提取在偏移基准之上的调用栈记录。

      注意

      日志输出器使用Error.captureStackTrace提取调用栈,如果偏移基准指定的Function不在调用链路中则将取得空调用栈。

    • 使用Number类型的偏移基准:日志输出器首先提取实例方法log之前的调用栈记录,接下来通过slice应用偏移基准中指定的偏移量以取得调用栈。

      注意

      因nodejs默认限制,日志输出器使用Error.captureStackTrace最大仅能提取实例方法log之前的Error.stackTraceLimit条调用栈记录。偏移基准将以此为基础进行偏移,使调用栈信息量降低。

    我们可以使用日志输出器的某个原型方法作为偏移基准:

    const Core = require('node-corejs');
    
    // 创建基础输出器
    const logger = new Core.BaseLogger({
      params: {
        // 使用原型方法作为偏移基准
        callStackOffset: Core.BaseLogger.prototype.buildCallSnapshot
      }
    });
    
    logger.log('e', '非Error类型日志内容将应用偏移基准');
    logger.log(new Error('Error类型日志内容不受偏移基准影响'));
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
  • # _checkStateInLog

    设置此配置将指定日志输出器在执行实例方法log时是否检查输出器状态,默认值为:true。

    通常,日志输出器的状态(开启/关闭)应与输出动作所需资源的创建与否具有相关性,因此引入了此配置以在执行输出动作时检查输出器状态。

    提示

    启用此配置后,如果日志输出器在执行输出动作时处于关闭状态,则抛出类型为BASE_LOGGER_ERROR_TYPE_CANT_LOG的异常信息且不再执行后续的实际输出链路。

    我们可以设置异常处理器_errorHandler以捕获和处理状态检查失败时抛出的异常。

    注意

    我们在自定义输出器时需要注意:

    对于输出链路中存在异步操作的日志输出器,仅在执行实例方法log时检查输出器状态无法保证输出动作所需资源的有效性,应在操作资源时进行有效性校验或进行异常捕获。

  • # _checkStateInStart

    设置此配置将指定日志输出器在执行实例方法start时是否检查输出器状态,默认值为:true。

    警告

    日志输出器默认开启此配置用于避免资源创建逻辑多次执行,请谨慎调整此配置。

    提示

    启用此配置后,如果日志输出器在执行启动动作时已处于启动状态,则抛出类型为BASE_LOGGER_ERROR_TYPE_CANT_START的异常信息且不再执行后续的实际启动逻辑。

    我们可以设置异常处理器_errorHandler以捕获和处理状态检查失败时抛出的异常。

  • # _checkStateInClose

    设置此配置将指定日志输出器在执行实例方法close时是否检查输出器状态,默认值为:true。

    警告

    日志输出器默认开启此配置用于避免资源释放逻辑多次执行,请谨慎调整此配置。

    提示

    启用此配置后,如果日志输出器在执行关闭动作时已处于关闭状态,则抛出类型为BASE_LOGGER_ERROR_TYPE_CANT_CLOSE的异常信息且不再执行后续的实际关闭逻辑。

    我们可以设置异常处理器_errorHandler以捕获和处理状态检查失败时抛出的异常。

  • # _errorHandler

    设置此配置将指定日志输出器的异常处理器。

    说明

    日志输出器将自动捕获关键动作中产生的异常并调用实例方法onError,默认将直接触发异常处理器。

    通常,我们在自定义输出器时应根据关键动作实际逻辑的同步或异步指定对应的实例方法为Function或AsyncFunction,在其中使用throw即可直接触发异常处理,日志输出器将自动根据产生异常的关键动作计算其类型。

    对于需要自定义类型或无法通过throw抛出的异常,我们可以直接调用实例方法onError。

    异常处理器接收一个参数列表为(errType, errDetail)的Function:

    • errType:异常的类型,为String。

      日志输出器将根据产生异常的关键动作计算其类型:

      异常类型 描述 产生原因
      BASE_LOGGER_ERROR_TYPE_CANT_LOG 日志输出器无法执行输出动作 日志输出链路中产生了异常
      BASE_LOGGER_ERROR_TYPE_CANT_INIT 日志输出器无法构建和实例化 输出器初始化时产生了异常
      BASE_LOGGER_ERROR_TYPE_CANT_START 日志输出器无法启动 输出器启动时产生了异常
      BASE_LOGGER_ERROR_TYPE_CANT_CLOSE 日志输出器无法关闭 输出器关闭时产生了异常
    • errDetail:异常的细节信息,为Object。

      通常,细节信息的结构中至少包含{ error }以指示造成异常的Error对象。

      在日志输出器执行实例方法start、close和log未通过状态校验时将产生以下Error:

      提示

      Error描述文案的相关宏变量存储在Core.Messages中,我们可以在Error产生前修改对应宏变量的值以实现对Error描述文案的变更。

      Error描述文案 描述 产生原因
      BASE_LOGGER_MESSAGE_CANT_LOG 日志输出器无法输出日志 执行日志输出时无法通过状态检验
      BASE_LOGGER_MESSAGE_CANT_START 日志输出器无法启动 执行启动动作时无法通过状态校验
      BASE_LOGGER_MESSAGE_CANT_CLOSE 日志输出器无法关闭 执行关闭动作时无法通过状态校验

# 日期输出器

日期输出器提供了按时间周期归档日志的能力。

我们可以使用日期输出器将同一时间周期内产生的日志输出至单个日志文件或是按照体积自动拆分为日志文件组。

同时,我们还可以指定归档周期保留数量,日期输出器将滚动清理过期的日志文件。

提示

日期输出器继承自基础输出器,支持其全部功能参数。

另外,日期输出器在运行环境为BASE_LOGGER_DEVELOPMENT_ENVIRONMENT时,将保持与基础输出器一致的输出行为,即:将日志打印至控制台。

此时,当输出器执行启动和关闭动作时,仅进行基本状态判断,不再触发对资源的计算和操作。

# 功能说明

  1. 将日志按照指定的归档周期归档至文件中。

  2. 支持日志文件按体积自动分割。

  3. 支持设置归档周期保留数量,以自动清理过时的日志文件。

  4. 支持设置日志文件的输出目录和输出文件名的构成规则。

    提示

    • 输出目录可能由归档源目录和归档前缀构成。

    • 输出文件名结构为:<%归档前缀%>.<%归档日期%>.<%归档偏移%>.<%文件后缀%>。

    构成元素 规则
    归档前缀 实例化日期输出器时配置filePrefix和filePrefixAsFileName附加至输出文件名中
    归档日期 一定出现在归档文件名中;日期格式将使用实例化日期输出器时指定的dateFormat
    归档偏移 实例化日期输出器时配置maxSize启动日志文件自动分割时会附加至输出文件名中
    文件后缀 实例化日期输出器时配置keepFileExt启用日志文件后缀时会附加至输出文件名中
  5. 输出环境异常时自动降级以保证日志完整性。

    说明

    当日期输出器无法创建日志输出目录或输出文件时,运行环境自动降级至BASE_LOGGER_DEVELOPMENT_ENVIRONMENT将日志打印至控制台。

# 异常捕获

在日期输出器的异常处理器中可能接收到拓展的自定义异常类型(即:errType):

异常类型 描述 产生原因
BASE_LOGGER_ERROR_TYPE_CANT_CREATE_FILE 无法创建日志文件 应用权限不足或操作系统异常(磁盘不足等)
BASE_LOGGER_ERROR_TYPE_CANT_CREATE_FOLDER 无法创建输出目录 应用权限不足或操作系统异常(磁盘不足等)

同时,日期输出器拓展的自定义异常类型附带的细节信息(即:errDetail)将更加详细,其结构为{ error, errorPath, errorDescription }。

  • error:导致异常的Error实例。
  • errorPath:导致异常的日志输出目录/文件路径。
  • errorDescription:异常描述。

提示

异常描述文案的相关宏变量存储在Core.Messages中, 我们同样可以通过修改对应宏变量的值以实现对异常描述文案的变更。

异常描述文案 产生时机 异常类型归属
BASE_LOGGER_MESSAGE_CANT_CREATE_FILE 日期输出器无法创建日志文件时 BASE_LOGGER_ERROR_TYPE_CANT_CREATE_FILE
BASE_LOGGER_MESSAGE_CANT_CREATE_FOLDER 日期输出器无法创建输出目录时 BASE_LOGGER_ERROR_TYPE_CANT_CREATE_FOLDER

# 功能参数

提示

日期输出器支持基础输出器的全部功能参数。

  • # sourcePath

    设置此配置将指定日期输出器的归档源目录,默认值为path.resolve(process.cwd(), `./logs/${process.pid}`)。

    归档源目录是进行日志文件分割和清理的工作区,我们将在日志分割和日志清理中进行详细讨论。

    提示

    • 由于文件系统限制,我们在指定归档源目录时使用的<:?*"|>这7个非法字符将被自动替换为'_'。

    • 在使用了Cluster架构的应用程序中,多进程抢夺相同的文件资源将导致日志归档异常。因此,我们应尽量使用进程标识符(比如:process.pid)作为归档源目录的构成元素。

    • 当由归档源目录和归档前缀构成的日志输出目录在文件系统中不存在时,日期输出器将在实例化过程中尝试创建,创建失败将导致运行环境降级。


    通常,应用程序中的日志输出器应使用相同的归档源目录以实现日志的集中存储:

    const Core = require('node-corejs');
    
    // 公用的日志归档源目录
    const sourcePath = './testlogs';
    
    // 创建第一个日期输出器
    const logger1 = new Core.DateLogger({
      env: 'prod',
      params: { filePrefix: 'DateLogger1', sourcePath }
    });
    
    // 创建第二个日期输出器
    const logger2 = new Core.DateLogger({
      env: 'prod',
      params: { filePrefix: 'DateLogger2', sourcePath }
    });
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
  • # filePrefix

    设置此配置将指定日期输出器的归档前缀,默认值为''。

    归档前缀可以作为日志输出目录和输出文件名的组成部分。因此,由于文件系统限制,我们在指定归档前缀时使用的<\.:?*"|/>这10个非法字符将被自动替换为'_'。

    注意

    归档前缀是一个非常关键的功能参数,将极大影响日期输出器的行为。

    此配置将影响以下功能参数:

    对于联动关系的注意事项,我们将在配置联动一节中进行详细讨论。

  • # filePrefixAsSourcePath

    设置此配置将指定日期输出器是否在归档源目录中创建以归档前缀命名的目录用于存放日志文件,即在文件系统中使用归档前缀分类日志文件,默认值为true。

    注意

    此配置将被以下功能参数影响:

    此配置将影响以下功能参数:

    因此,当我们指定的值违反了联动关系时将被日期输出器强制校正。

    对于联动关系的注意事项,我们将在配置联动一节中进行详细讨论。

  • # filePrefixAsFileName

    设置此配置将指定日期输出器是否在输出文件名中展示归档前缀,默认值为true。

    注意

    此配置将被以下功能参数影响:

    此配置将影响以下功能参数:

    因此,当我们指定的值违反了联动关系时将被日期输出器强制校正。

    对于联动关系的注意事项,我们将在配置联动一节中进行详细讨论。


让我们来看一个使用归档前缀构建输出目录和输出文件名的🌰:

const Core = require('node-corejs');

const env = 'prod';
const level = 'infos';
const sourcePath = './testlogs';

// 日志输出目录:./testlogs/DateLogger1
// 日志输出文件:[归档日期].log
const logger1 = new Core.DateLogger({
  env,
  level,
  params: {
    sourcePath,
    filePrefix: 'DateLogger1',
    filePrefixAsFileName: false,
    filePrefixAsSourcePath: true,
  }
});

// 日志输出目录:./testlogs/DateLogger2
// 日志输出文件:DateLogger2.[归档日期].log
const logger2 = new Core.DateLogger({
  env,
  level,
  params: {
    sourcePath,
    filePrefix: 'DateLogger2',
    filePrefixAsFileName: true,
    filePrefixAsSourcePath: true,
  }
});

// 日志输出目录:./testlogs
// 日志输出文件:DateLogger3.[归档日期].log
const logger3 = new Core.DateLogger({
  env,
  level,
  params: {
    sourcePath,
    filePrefix: 'DateLogger3',
    filePrefixAsFileName: true,
    filePrefixAsSourcePath: false,
  }
});

// 执行日志输出
logger1.log('一条🌰日志');
logger2.log('一条🌰日志');
logger3.log('一条🌰日志');
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
  • # dateFormat

    设置此配置将指定日期输出器的归档周期和归档日期格式,默认值为YYYY-MM-DD。

    归档日期将根据此配置中指定的归档日期格式附加至输出文件名。因此,由于文件系统限制,我们在指定此配置时使用的<\.:?*"|/>这10个非法字符将被自动替换为'_'。

    说明

    日期输出器支持以月、日、时、分、秒(因年周期过长,故不支持)作为归档周期。

    我们在指定归档日期格式时需要使用递进方式组合日期元素,即归档日期格式必须包含归档周期前置的所有日期元素。比如:

    • 选择月作为归档周期

      归档日期格式需要包含月及其前置的所有日期元素,即:年('YYYY')和月('MM')。

      此时,我们可以指定归档日期格式为:'YYYY-MM'。

    • 当选择分作为归档周期

      归档日期格式需要包含分及其前置的所有日期元素,即:年('YYYY')、月('MM')、日('DD')、时('HH')和分('mm')。

      此时,我们可以指定归档日期格式为:'YYYY-MM-DD_HH_mm'。


    日期元素及其表示方式从前至后依次为:

    • 年:'YYYY'
    • 月:'MM'
    • 日:'DD'
    • 时:'HH'
    • 分:'mm'
    • 秒:'ss'

    接下来,我们尝试构建一个以秒为归档周期的日期输出器:









     






    const Core = require('node-corejs');
    
    // 创建输出器
    const logger = new Core.DateLogger({
      env: 'prod',
      level: 'infos',
      params: {
        sourcePath: './testlogs',
        dateFormat: 'YYYY-MM-DD_HH_mm_ss' // 指定日期格式和归档周期
      }
    });
    
    // 每150ms执行一次日志输出
    setInterval(() => { logger.log('一条🌰日志') }, 150);
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
  • # keepDateNum

    设置此配置将指定日期输出器的归档周期保留数量,当指定了<=0的值时将关闭自动清理,默认值为0。

    提示

    日期输出器将保留包含当前归档周期在内的最近keepDateNum个周期内生成的日志文件。比如:

    1. 指定归档周期保留数量为2。

    2. 指定归档日期格式为'YYYY-MM'。

    3. 当前日期为2011年10月,且日志输出目录中有五个日志文件:

      • 2011-01.log
      • 2011-02.log
      • 2011-05.log
      • 2011-08.log
      • 2011-10.log

    清理动作完成后,将只保留2011-10.log、2011-08.log两个日志文件。

  • # maxSize

    设置此配置将指定日期输出器触发日志文件分割的最大体积,单位为Byte,当指定了<=0的值时将关闭自动分割,默认值为0。

    提示

    启动自动分割后,输出文件名中将附加归档偏移。

  • # keepFileExt

    设置此配置将指定日期输出器是否在输出文件名中附加文件后缀.log,默认值为true。


接下来,我们将在一个复杂的场景下使用日期输出器进行日志收集:

  • 保留最近5个归档日期内的日志。

  • 将每秒内产生的日志归档至同一日志文件,超出1KB时自动分割。

  • 日志文件按照归档前缀存储,且输出文件名中不展示归档前缀。

const Core = require('node-corejs');

// 构建输出器
const logger = new Core.DateLogger({
  env: 'prod',
  params: {
    maxSize: 1024,                      // 最大日志文件体积为1K
    keepDateNum: 5,                     // 保留最近5个周期
    sourcePath: './testlogs',           // 归档源目录
    filePrefix: 'ComplexLogger',        // 归档前缀
    filePrefixAsFileName: false,        // 输出文件名不附加归档前缀
    filePrefixAsSourcePath: true,       // 在归档源目录中创建归档前缀目录
    dateFormat: 'YYYY-MM-DD_HH_mm_ss',  // 以秒作为归档周期
  },
});

// 每100ms执行一次日志输出
setInterval(() => logger.log(new Error(`一个🌰日志`)), 100);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

# 配置联动

在日期输出器的功能参数中,其中三个功能参数具有联动关系:

首先,我们先分析其联动逻辑关系:

  1. 当归档前缀无效时,则归档前缀无法参与输出目录和输出文件名的构建。
  2. 当归档前缀有效时,则归档前缀至少参与输出目录和输出文件名其中一项的构建,否则设置归档前缀没有意义。

说明

当归档前缀没有指定或是指定为''时,认为无效。


因此,日期输出器将自动进行功能参数校正以满足联动关系:

  • 当filePrefix无效时,将锁定filePrefixAsSourcePath和filePrefixAsFileName为false。

  • 当filePrefix有效时,则filePrefixAsSourcePath和filePrefixAsFileName中必须至少有一项指定为true。

    如果两项都指定为false,则锁定filePrefixAsSourcePath为true。

提示

日期输出器将在功能功能参数违反联动关系时,优先保证使用归档前缀构建输出目录而不是用于构建输出文件名。

# 日志分割

在自动分割日志文件的模式下,日期输出器将在执行日志输出动作时根据日志文件的体积情况自动定向目标输出文件。

提示

自动分割功能不会对已产生的日志文件进行分割。


接下来,我们将讨论日志分割的实现方案:

  • 日期输出器执行启动动作时

    在其归档源目录中提取相同归档前缀且相同归档周期内全部日志文件以进行日志分割的首次仲裁计算,将取得初始归档偏移和日志文件的体积。

    提示

    当日期输出器启用使用归档前缀构建日志输出目录时,将提升日志文件检索效率。

  • 日志输出器执行输出动作时

    计算输出动作造成的体积增量,并与分割阈值maxSize进行比较,以仲裁后续归档偏移。

注意

当多个启用了日志分割的日期输出器将日志输出至相同的日志输出目录,且拥有相同的归档前缀和归档周期时,将可能导致日志分割紊乱。

即:多个日期输出器的sourcePath、filePrefix、filePrefixAsSourcePath和dateFormat指定了相同的值。

因此,我们在使用日期输出器时通常:

  • 在单进程维度,每个日期输出器指定唯一的归档前缀。

  • 在Cluter架构下,使用进程标识参与构建归档源目录,以隔离不同进程内日期输出器对应的日志输出目录。

# 日志清理

Corejs内置了用于定时进行文件清理的清理引擎,将统一管理挂载了清理规则的文件系统目录。

清理引擎将在单个文件系统目录挂载多个清理规则时自动仲裁触发周期,以避免过于频繁的磁盘读写。


日志清理同样使用分治设计,清理引擎将周期性选择日志输出目录中符合以下全部条件的日志文件按照归档周期保留数量进行删除:

  • 归档日期早于当前日期
  • 与当前日期输出器拥有相同的归档前缀
  • 与当前日期输出器拥有相同的归档日期格式

提示

日期输出器将在执行启动动作时向清理引擎中添加清理规则:

  • 未使用归档前缀构建日志输出目录时,日期输出器向归档源目录的规则池中添加清理规则。

  • 使用了归档前缀构建日志输出目录时,日期输出器向归档源目录下归档前缀目录的规则池中添加清理规则。

因此,我们通常使用归档前缀构建日志输出目录,以提高清理仲裁逻辑的执行效率。

# 文件输出器

文件输出器提供了将日志输出至单一文件的能力。

通常,我们使用文件输出器对频次型业务产生的日志进行收集,将每次业务执行链路中的日志输出至同一文件。

提示

文件输出器继承自基础输出器,支持其全部功能参数。

另外,文件输出器在运行环境为BASE_LOGGER_DEVELOPMENT_ENVIRONMENT时,将保持与基础输出器一致的输出行为,即:将日志打印至控制台。

此时,当输出器执行启动和关闭动作时,仅进行基本状态判断,不再触发对资源的计算和操作。

# 功能说明

  1. 文件输出器将其产生的所有日志输出至同一的文件。

  2. 支持自动/手动管理文件输出器的状态和资源。

  3. 支持设置日志文件的输出目录和输出文件名的构成规则。

    提示

    日志文件的输出目录和输出文件名由多个功能参数(归档源目录、归档前缀、归档周期等)共同决定。

    通常,我们将相同业务产生的日志归档至相同的输出目录中,并使用不同的输出文件名以区分业务调用的次序。

  4. 支持设置归档周期和周期保留数量,以自动清理过时的输出文件。

  5. 输出环境异常时自动降级以保证日志完整性。

    说明

    当文件输出器无法创建日志输出目录或输出文件时,运行环境自动降级至BASE_LOGGER_DEVELOPMENT_ENVIRONMENT将日志打印至控制台。

# 异常捕获

在文件输出器的异常处理器中可能接收到拓展的自定义异常类型(即:errType):

异常类型 描述 产生原因
BASE_LOGGER_ERROR_TYPE_CANT_CREATE_FILE 无法创建日志文件 应用权限不足或操作系统异常(磁盘不足等)
BASE_LOGGER_ERROR_TYPE_CANT_CREATE_FOLDER 无法创建输出目录 应用权限不足或操作系统异常(磁盘不足等)

同时,文件输出器拓展的自定义异常类型附带的细节信息(即:errDetail)将更加详细,其结构为{ error, errorPath, errorDescription }。

  • error:导致异常的Error实例。
  • errorPath:导致异常的日志输出目录/文件路径。
  • errorDescription:异常描述。

提示

异常描述文案的相关宏变量存储在Core.Messages中, 我们同样可以通过修改对应宏变量的值以实现对异常描述文案的变更。

异常描述文案 产生时机 异常类型归属
BASE_LOGGER_MESSAGE_CANT_CREATE_FILE 文件输出器无法创建日志文件时 BASE_LOGGER_ERROR_TYPE_CANT_CREATE_FILE
BASE_LOGGER_MESSAGE_CANT_CREATE_FOLDER 文件输出器无法创建输出目录时 BASE_LOGGER_ERROR_TYPE_CANT_CREATE_FOLDER

此外,文件输出器在输出器启动和关闭动作时可能产生新的Error。

提示

Error信息文案的相关宏变量存储在Core.Messages中, 我们同样可以通过修改对应宏变量的值以实现对Error信息文案的变更。

Error信息文案 产生时机 Error类型归属
FILE_LOGGER_MESSAGE_CANT_START_IN_AUTO 自动模式下的文件输出器执行了start() BASE_LOGGER_ERROR_TYPE_CANT_START
FILE_LOGGER_MESSAGE_CANT_CLOSE_IN_AUTO 自动模式下的文件输出器执行了close() BASE_LOGGER_ERROR_TYPE_CANT_CLOSE

# 运行模式

文件输出器支持使用两种管理状态和资源的模式:

  • 自动模式

    文件输出器的默认运行模式。

    此模式下,文件输出器将自动进行状态和资源管理:

    • 执行日志输出动作前,如果文件输出器处于关闭状态,将自动执行启动动作,再执行日志输出。
    • 执行日志输出动作后,如果文件输出器在等待阈值timeout内无日志输出动作,将自动执行关闭动作。

    注意

    在自动模式下,手动执行文件输出器的启动和关闭将产生异常,我们可以在异常处理器中对其进行捕获和处理。

    因此,我们无需在业务层中显式调用使用了自动模式的文件输出器的实例方法start()和close(),直接使用实例方法log()输出日志即可。

  • 手动模式

    此模式下,我们需要手动对文件输出器进行状态和资源管理:

    • 执行实例方法start():启动文件输出器,并创建文件句柄等必要资源。
    • 执行实例方法close():关闭文件输出器,并释放文件句柄等必要资源。

    注意

    在文件输出器处于关闭状态时执行输出动作,或重复启动/关闭时将产生异常,我们可以在异常处理器中对其进行捕获和处理。

# 使用规则

每次业务执行时实例化文件输出器,调整相关功能参数以指定日志的输出目录和输出文件名:

  • 对于同类型业务,实例化文件输出器时使用相同的归档源目录、归档前缀和归档周期及其附属配置,以将同类型业务产生的日志归档至相同的输出目录。
  • 在输出文件名中附带次序标识或内置随机文件名,以在输出目录中区分每次业务执行链路。

# 输出目录


我们无法直接指定日志最终的输出目录,而是通过调整归档源目录、归档前缀和归档日期及其附属配置间接指定。

因此,日志的输出目录将由归档源目录、归档前缀和归档日期中的一项或几项组合而成。

注意

仅在文件输出器使用归档前缀预分类日志文件时,才能通过归档日期进行二次分类。

即:输出目录构成规则为path.resolve(<%归档源目录%>[, <%归档前缀%>[, <%归档日期%>]])。

我们将在配置联动一节中详细讨论功能参数间的依赖关系。

# 输出文件名


我们也无法直接指定日志最终的输出文件名,同样是通过调整归档前缀、归档日期和归档文件名及其附属配置间接指定。

输出文件名的结构为:<%归档前缀%>.<%归档文件名%>.<%归档日期%>.<%归档类型%>.<%文件后缀%>。

构成元素 规则
归档前缀 实例化文件输出器时,指定功能参数filePrefix和filePrefixAsFileName附加至输出文件名中
归档文件名 一定出现在输出文件名中;首先应用实例化文件输出器时的功能参数fileName,当此配置无效时则使用长度为16的随机字符串
归档日期 实例化文件输出器时,指定功能参数dateFormat和dateAsFileName附加至输出文件名中
归档类型 文件输出器将根据输出文件名构成元素的排列方式自动生成
文件后缀 实例化文件输出器时,指定功能参数keepFileExt附加至输出文件名中

说明

归档类型由归档前缀、归档日期和归档文件名的排列方式决定:

  • 当输出文件名由归档文件名和归档日期构成时,归档类型为[FN]。

  • 当输出文件名由归档前缀和归档文件名构成时,归档类型为[FP]。

  • 其他场景不附加归档类型至输出文件名。

需要注意的是,归档类型记录了输出文件名的元信息,对输出目录中已生成的日志文件进行重命名操作将导致元信息损坏。

# 功能参数

提示

日期输出器支持基础输出器的全部功能参数。

  • # sourcePath

    设置此配置将指定文件输出器的归档源目录,默认值为path.resolve(process.cwd(), `./logs/${process.pid}`)。

    归档源目录是进行日志文件清理的工作区,我们将在日志清理中进行详细讨论。

    提示

    • 由于文件系统限制,我们在指定归档源目录时使用的<:?*"|>这7个非法字符将被自动替换为'_'。

    • 在使用了Cluster架构的应用程序中,多进程抢夺相同的文件资源将导致日志归档异常。因此,我们应尽量使用进程标识符(比如:process.pid)作为归档源目录的构成元素。

    • 当由归档源目录、归档前缀和归档日期中的一项或几项构成的输出目录在文件系统中不存在时,文件输出器将在实例化过程中尝试创建,创建失败将导致运行环境降级。


    通常,日志输出器应使用相同的归档源目录以实现日志的集中存储。

    当然,文件输出器可以与日期输出器使用相同的归档源目录:

    const Core = require('node-corejs');
    
    // 日志归档源目录
    const sourcePath = './testlogs';
    
    // 创建日期输出器
    const dateLogger = new Core.DateLogger({
      env: 'prod',
      level: 'infos',
      params: { filePrefix: 'DateLogger', sourcePath }
    });
    
    // 创建文件输出器
    const fileLogger = new Core.FileLogger({
      env: 'prod',
      level: 'infos',
      params: { filePrefix: 'FileLogger', sourcePath }
    });
    
    // 执行日志输出
    dateLogger.log('一条🌰日志');
    fileLogger.log('一条🌰日志');
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
  • # auto

    设置此配置将指定文件输出器是否使用自动模式作为运行模式,默认值为true。

  • # timeout

    设置此配置将指定文件输出器在自动模式中自动释放资源的等待时间,单位为毫秒,默认值为10000。

    提示

    在手动模式下,此配置将被锁定为0。

    在自动模式下指定了<=0的值时,将使用默认值10000。


使用自动模式时,我们无需显式调用start()和close()即可执行日志输出动作。

在自动模式强行调用文件输出器的实例方法start()或close()将抛出异常,我们可以通过在实例化时配置异常处理器_errorHandler进行捕获和处理:

const Core = require('node-corejs');

// 创建使用自动模式的文件输出器
const logger = new Core.FileLogger({
  env: 'prod',
  params: {
    // 指定使用自动模式
    auto: true,
    timeout: 10000,
    // 将捕获到的异常输出到控制台
    _errorHandler(errType, errDetail) { console.log(errType, errDetail) }
  }
});

// 强行调用start()和close()
logger.start();
logger.close();
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

使用手动模式时,如果在执行日志输出动作前没有调用start()启动文件输出器,同样会抛出异常:

const Core = require('node-corejs');

// 创建使用手动模式的文件输出器
const logger = new Core.FileLogger({
  env: 'prod',
  params: {
    // 指定使用手动模式
    auto: false,
    // 将捕获到的异常输出到控制台
    _errorHandler(errType, errDetail) { console.log(errType, errDetail) }
  }
});

// 强行发起log()
logger.log('一条🌰日志');
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
  • # fileName

    设置此配置将指定文件输出器的归档文件名,默认根据进程标识、当前时间戳和8位随机小写字母和数字生成16长度的字符串作为归档文件名。

    归档文件名将作为输出文件名的组成部分。因此,由于文件系统限制,我们在指定此配置时使用的<\.:?*"|/>这10个非法字符将被自动替换为'_'。

    提示

    我们需求注意的是,归档文件名不是最终输出至文件系统的输出文件名,而是作为输出文件名的构成元素。

    对于输出文件名的构成规则请参考输出文件名。


    通常,归档文件名由业务自定义部分和随机字符串部分共同组成。

    此场景下,我们可以在指定归档文件名时使用宏字符串[%RANDOM_FILE_NAME%]以引用文件输出器内置的随机字符串:

    const Core = require('node-corejs');
    
    setInterval(() => {
      const logger = new Core.FileLogger({
        env: 'prod',
        level: 'infos',
        params: {
          sourcePath: './testlogs',
          // 在fileName中使用宏字符串
          fileName: 'LogFile_[%RANDOM_FILE_NAME%]'
        }
      });
    
      // 日志输出文件名为LogFile_[%随机字符串%].log
      logger.log('一个🌰日志');
    }, 500);
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
  • # filePrefix

    设置此配置将指定文件输出器的归档前缀,默认值为空字符串''。

    归档前缀可以作为输出目录和输出文件名的组成部分。因此,由于文件系统限制,我们在指定归档前缀时使用的<\.:?*"|/>这10个非法字符将被自动替换为'_'。

    注意

    归档前缀是一个非常关键的功能参数,将极大影响文件输出器的行为。

    此配置将影响以下功能参数:

    对于联动关系的注意事项,我们将在配置联动一节中进行详细讨论。

  • # filePrefixAsSourcePath

    设置此配置将指定文件输出器是否在归档源目录中创建以归档前缀命名的目录用于存放日志文件,即在文件系统中使用归档前缀分类日志文件,默认值为true。

    注意

    此配置将被以下功能参数影响:

    此配置将影响以下功能参数:

    因此,当我们指定的值违反了联动关系时将被文件输出器强制校正。

    对于联动关系的注意事项,我们将在配置联动一节中进行详细讨论。

  • # filePrefixAsFileName

    设置此配置将指定文件输出器是否在输出文件名中展示归档前缀,默认值为true。

    注意

    此配置将被以下功能参数影响:

    此配置将影响以下功能参数:

    因此,当我们指定的值违反了联动关系时将被文件输出器强制校正。

    对于联动关系的注意事项,我们将在配置联动一节中进行详细讨论。

  • # dateFormat

    设置此配置将指定文件输出器的归档周期和归档日期格式,默认值为YYYY-MM-DD。

    归档日期将根据此配置中指定的归档日期格式附加至输出文件名。因此,由于文件系统限制,我们在指定此配置时使用的<\.:?*"|/>这10个非法字符将被自动替换为'_'。

    说明

    文件输出器支持以月、日、时、分、秒(因年周期过长,故不支持)作为归档周期。

    我们在指定归档日期格式时需要使用递进方式组合日期元素,即归档日期格式必须包含归档周期前置的所有日期元素。比如:

    • 选择月作为归档周期

      归档日期格式需要包含月及其前置的所有日期元素,即:年('YYYY')和月('MM')。

      此时,我们可以指定归档日期格式为:'YYYY-MM'。

    • 当选择分作为归档周期

      归档日期格式需要包含分及其前置的所有日期元素,即:年('YYYY')、月('MM')、日('DD')、时('HH')和分('mm')。

      此时,我们可以指定归档日期格式为:'YYYY-MM-DD_HH_mm'。


    日期元素及其表示方式从前至后依次为:

    • 年:'YYYY'
    • 月:'MM'
    • 日:'DD'
    • 时:'HH'
    • 分:'mm'
    • 秒:'ss'

    注意

    归档日期格式也是一个非常关键的功能参数,将极大影响文件输出器的行为。

    此配置将影响以下功能参数:

    对于联动关系的注意事项,我们将在配置联动一节中进行详细讨论。

  • # dateAsSourcePath

    设置此配置将指定文件输出器是否在归档源目录中以归档前缀命名的目录下创建以归档日期命名的目录用于存放日志文件,即在文件系统中使用归档前缀和归档日期分类日志文件,默认值在filePrefix或dateFormat无效时为false,其他情况时为true。

    注意

    此配置将被以下功能参数影响:

    此配置将影响以下功能参数:

    因此,当我们指定的值违反了联动关系时将被文件输出器强制校正。

    对于联动关系的注意事项,我们将在配置联动一节中进行详细讨论。

  • # dateAsFileName

    设置此配置将指定文件输出器是否在输出文件名中展示归档日期,默认值在dateFormat无效时为false,其他情况时为true。

    注意

    此配置将被以下功能参数影响:

    此配置将影响以下功能参数:

    因此,当我们指定的值违反了联动关系时将被文件输出器强制校正。

    对于联动关系的注意事项,我们将在配置联动一节中进行详细讨论。

  • # keepDateNum

    设置此配置将指定文件输出器的归档周期保留数量,当指定的归档日期格式无效或指定了<=0的值时将关闭自动清理,默认值为0。

    提示

    文件输出器将保留包含当前归档周期在内的最近keepDateNum个周期内生成的日志文件。比如:

    1. 指定归档周期保留数量为2。

    2. 指定归档日期格式为'YYYY-MM'。

    3. 当前日期为2011年10月,且输出目录中有五个日志文件:

      • 2011-01.log
      • 2011-02.log
      • 2011-05.log
      • 2011-08.log
      • 2011-10.log

    清理动作完成后,将只保留2011-10.log、2011-08.log两个日志文件。

  • # keepFileExt

    设置此配置将指定文件输出器是否在输出文件名中附加文件后缀.log,默认值为true。


假设我们有一个间隔150ms执行的频次型业务需要使用文件输出器进行日志收集:

  • 仅保留最近5秒内的日志

  • 将此业务每秒产生的日志存储至相同目录

  • 输出文件名中展示业务执行次序和归档时间

const Core = require('node-corejs');

let count = 0;

// 每150ms创建文件输出器并输出日志以模拟每次业务执行
setInterval(() => {
  count += 1;
  const logger = new Core.FileLogger({
    env: 'prod',
    level: 'infos',
    params: {
      fileName: count,                    // 归档文件名
      sourcePath: './testlogs',           // 归档源目录
      filePrefix: 'ComplexLogger',        // 归档前缀
      filePrefixAsSourcePath: true,       // 使用归档前缀预分类日志
      filePrefixAsFileName: false,        // 输出文件名不附加归档前缀
      dateFormat: 'YYYY-MM-DD_HH_mm_ss',  // 归档日期格式
      dateAsSourcePath: true,             // 使用归档日期分类日志
      dateAsFileName: true,               // 输出文件名不附加归档日期
      keepDateNum: 5                      // 保留最近5个归档日期
    }
  });

  // 每个文件输出器执行4次日志输出以模拟业务链路内产生日志
  logger.log('i', `infos级别的🌰日志 -> ${count}`);
  logger.log('w', `warns级别的🌰日志 -> ${count}`);
  logger.log('e', `error级别的🌰日志 -> ${count}`);
  logger.log('f', `fatal级别的🌰日志 -> ${count}`);
}, 150);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

# 配置联动

在文件输出器的功能参数中,有两组联动关系:

# 归档前缀联动

# 归档日期联动


首先,我们分析归档前缀的联动逻辑关系:

  1. 当归档前缀无效时,则归档前缀无法参与输出目录和输出文件名的构建。
  2. 当归档前缀有效时,则归档前缀至少参与输出目录和输出文件名其中一项的构建,否则设置归档前缀没有意义。

接下来,我们分析归档日期的联动逻辑关系。归档日期与归档前缀的联动关系类似:

  1. 如果归档日期格式无效,则归档前缀无法参与输出目录和输出文件名的构建。
  2. 如果归档日期格式有效,则归档日期至少参与输出目录和输出文件名其中一项的构建,否则设置归档日期格式没有意义。

说明

当归档前缀、归档日期格式没有指定或指定为''时,认为其无效。

另外,我们已经知道,使用归档前缀预分类日志文件时,才能通过归档日期对日志文件进行二次分类。即:只有在使用归档前缀构建输出目录时才允许使用归档日期构建输出目录。

因此:如果归档前缀不参与构建输出目录,则归档日期也无法参与构建输出目录。


文件输出器将自动进行功能参数校正以满足联动关系。

对于归档前缀的联动关系,文件输出器将确保:

  • 当filePrefix无效时,将锁定filePrefixAsSourcePath和filePrefixAsFileName为false。

  • 当filePrefix有效时,则filePrefixAsSourcePath和filePrefixAsFileName中必须至少有一项指定为true。

    如果两项都指定为false,则锁定filePrefixAsSourcePath为true。

对于归档日期的联动关系,文件输出器将确保:

  • 当dateFormat无效时,将锁定dateAsSourcePath和dateAsFileName为false。

  • 当dateFormat有效时,则dateAsSourcePath和dateAsFileName中必须至少有一项指定为true。

    如果两项都指定为false,则锁定dateAsSourcePath为true。

提示

文件输出器将在功能功能参数违反联动关系时,优先保证使用归档前缀或归档日期构建输出目录而不是用于构建输出文件名。


对于归档前缀和归档日期维度的高阶联动,文件输出器将确保:

  • 当filePrefix无效时,将锁定dateAsSourcePath为false。

  • 当filePrefix有效,且filePrefixAsSourcePath为false时,将锁定dateAsSourcePath为false。

  • 当dateFormat有效,且dateAsSourcePath因①或②而被锁定为false时,则锁定dateAsFileName为true。

此策略将使文件输出器在保证归档前缀和归档日期的高阶联动性的基础上,使指定的归档日期格式发挥作用。

# 日志清理

提示

文件输出器的分治清理规则非常抽象,仅做了解即可。

文件输出器同样使用在实例化时向清理引擎注册清理策略的分治方式实现日志清理。

不同的是,文件输出器的实例化通常为高频行为,需要引入防止清理规则重复挂载的反制策略:

  • 输出目录为归档源目录时:

    将向归档源目录的规则池中挂载清理规则。

    对于相同归档源目录的规则池,将拒绝归档前缀、归档日期格式、归档周期保留数量完全一致的文件输出器进行二次规则挂载。

    此时,清理引擎将周期性选择归档源目录下与当前文件输出器拥有相同归档前缀且相同归档日期格式的日志文件按照归档周期保留数量进行清理仲裁。

  • 输出目录非归档源目录时:

    将向归档源目录下的归档前缀子目录的规则池中挂载清理规则。

    对于相同的归档源目录下的归档前缀目录的规则池,将拒绝使用归档日期构建输出目录、归档日期格式、归档周期保留数量完全一致的文件输出器进行二次规则挂载。

    此时,清理引擎将周期性选择归档源目录下的归档前缀子目录下与当前文件输出器拥有相同归档日期格式的日志文件按照归档周期保留数量进行清理仲裁。