20.4. 高级配置

20.4.1. SIFT 日志记录

Fuse-Karaf 提供 Log4j2 sift appender 的 Log4j2 sift appender 和一个日志记录器的示例(在 $FUSE_HOME/etc/org.ops4j.pax.ops4j.pax.logging.cfg 文件中:

# Sift appender
log4j2.appender.mdc.type = Routing
log4j2.appender.mdc.name = SiftAppender
log4j2.appender.mdc.routes.type = Routes
# see: http://logging.apache.org/log4j/2.x/manual/appenders.html#Routes
log4j2.appender.mdc.routes.pattern = $\\{ctx:bundle.name}
log4j2.appender.mdc.routes.sift.type = Route
log4j2.appender.mdc.routes.sift.appender.type = RollingRandomAccessFile
log4j2.appender.mdc.routes.sift.appender.name = RollingFile
log4j2.appender.mdc.routes.sift.appender.fileName = ${karaf.data}/log/sift-$\\{ctx:bundle.name}.log
log4j2.appender.mdc.routes.sift.appender.filePattern = ${karaf.data}/log/sift-$\\{ctx:bundle.name}-%i.log.gz
log4j2.appender.mdc.routes.sift.appender.append = true
log4j2.appender.mdc.routes.sift.appender.layout.type = PatternLayout
log4j2.appender.mdc.routes.sift.appender.layout.pattern = ${log4j2.pattern}
log4j2.appender.mdc.routes.sift.appender.policies.type = Policies
log4j2.appender.mdc.routes.sift.appender.policies.size.type = SizeBasedTriggeringPolicy
log4j2.appender.mdc.routes.sift.appender.policies.size.size = 16MB
log4j2.appender.mdc.routes.sift.appender.strategy.type = DefaultRolloverStrategy
log4j2.appender.mdc.routes.sift.appender.strategy.max = 20
...
# sample logger using Sift appender
#log4j2.logger.example.name = org.apache.camel
#log4j2.logger.example.level = INFO
#log4j2.logger.example.appenderRef.SiftAppender.ref = SiftAppender

配置在 http://logging.apache.org/log4j/2.x/manual/appenders.html#RoutingAppender中描述

SIFT/Routing appender 的 Pattern 属性是可用于区分日志的目标位置。

可用的查找有不同的查找,如下所述 :http://logging.apache.org/log4j/2.x/manual/lookups.html

最重要的查找是 ctx one,它会在 ThreadContext 映射(a.k.a)中查找值(键)。MDC).

Fuse Karaf 提供的默认配置使用 ctx:bundle.name 作为模式,即:

lookup bundle.name key in MDC

bundle. prefix 键由 pax-logging 本身提供,有 3 个不同的值可供选择:

  • bundle.name == org.osgi.framework.Bundle.getSymbolicName()
  • bundle.id == org.osgi.framework.Bundle.getBundleId()
  • bundle.version == org.osgi.framework.Bundle.getVersion().toString()

但是,如果使用 MDC 支持创建 Camel 上下文(蓝色打印 XML DSL):

<camelContext id="my-context" xmlns="http://camel.apache.org/schema/blueprint" useMDCLogging="true">

在 MDC/ThreadContext 中会有一个更多密钥,然后将其用作 SIFT appender 配置中的模式:

  • Camel.exchangeId - 交换 ID
  • Camel.messageId - 消息 ID
  • Camel.correlationId - 与交换的关联 ID。例如,来自 Splitter EIP 的子消息
  • Camel.transactionKey - 转换交换的事务 ID。请注意 id 不是唯一的,而是其事务模板的 id,用于标记给定事务的事务边界。因此,我们决定将密钥命名为 transactionKey,而不是 transactionID 表明这一事实。
  • Camel.routeId - 路由的 id,当前正在路由。
  • Camel.breadcrumbId - 用于跨传输跟踪消息的唯一 ID。
  • Camel.contextId - 用于跟踪来自不同 camel 上下文的消息的 camel 上下文。

请查看 https://people.apache.org/~dkulp/camel/mdc-logging.html

例如,若要通过 Camel 的路由 ID 来区分日志目标文件,请使用:

log4j2.appender.mdc.routes.pattern = $\\{ctx:camel.routeId}
...
log4j2.appender.mdc.routes.sift.appender.fileName = ${karaf.data}/log/sift-$\\{ctx:camel.routeId}.log
log4j2.appender.mdc.routes.sift.appender.filePattern = ${karaf.data}/log/sift-$\\{ctx:camel.routeId}-%i.log.gz

更多事情 - 仅附加器配置还不够 - 必须将其附加到某些日志记录器。同样,配置示例包含:

# sample logger using Sift appender
#log4j2.logger.example.name = org.apache.camel
#log4j2.logger.example.level = INFO
#log4j2.logger.example.appenderRef.SiftAppender.ref = SiftAppender

(注意,log4j2.logger.example.appenderRef.SiftAppender.ref 属性的值应与 appender configuration 中的 log4j2.appender.mdc.name 的值匹配。

在这里,org.apache.camel 是日志记录器名称(或类别名称)。这完全与 Camel 日志中使用的值完全相同:端点。因此,如果您已有(在 Camel 路由中):

<to uri="log:org.apache.camel" />

日志记录可以正常工作。

另一个工作配置是:

<to uri="log:my-special-logger" />

和:

log4j2.logger.example.name = my-special-logger
log4j2.logger.example.level = DEBUG
log4j2.logger.example.appenderRef.SiftAppender.ref = SiftAppender

20.4.2. 过滤器

您可以将过滤器应用到 appender。过滤器评估每个日志事件,并确定是否将其发送到日志。

Log4j2 提供可用的过滤器。

注意

请参阅 Log4J 站点上的 过滤器,以获得到其中的综合视图。

20.4.3. 嵌套的附加器

嵌套的附加器是特殊的附加器,您可以使用 "inside" another appender。它允许您在一个附加器链之间创建某种"routing"。

最常用的"嵌套合规"附加器为:

  • AsyncAppender(org.apache.log4j2.AsyncAppender)会异步记录事件。此附加程序收集事件并将其分配到附加的所有附加者。
  • RewriteAppender(org.apache.log4j2.rewrite.RewriteAppender)在可能重新编写日志事件后将日志消息转发到另一个附加程序。

这种附加器接受 appender 定义中的 appenders 属性:

log4j2.appender.[appender-name].appenders=[comma-separated-list-of-appender-names]

例如,您可以创建一个名为 async 的 AsyncAppender,异步将日志消息分配给 JMS 附加程序:

log4j2.appender.async=org.apache.log4j2.AsyncAppender
log4j2.appender.async.appenders=jms

log4j2.appender.jms=org.apache.log4j2.net.JMSAppender
...

20.4.4. 错误处理程序

有时,附加程序可能会失败。例如,RollingFileAppender 尝试写入文件系统,但文件系统已满,或者 JMS 附加程序尝试发送消息,但 JMS 代理不可用。

日志记录可能很重要,因此务必要知道日志附加程序是否失败。

每个日志附加程序可以将错误处理委托给错误处理程序,从而有机会响应附加程序错误。

  • FailoverAppender(org.apache.log4j2.varia.FailoverAppender)允许在主附加程序失败时接管辅助附加程序。错误消息打印在 System.err 上,并记录在辅助附加程序中。
注意

有关 FailoverAppender 的更多信息,请转至 Log4j2 的 Apppender Page

您可以使用 appender 定义本身上的 errorhandler 属性定义您要用于每个 appender 的错误处理器:

log4j2.appender.[appender-name].errorhandler=[error-handler-class]
log4j2.appender.[appender-name].errorhandler.root-ref=[true|false]
log4j2.appender.[appender-name].errorhandler.logger-ref=[logger-ref]
log4j2.appender.[appender-name].errorhandler.appender-ref=[appender-ref]

20.4.5. OSGi 特定 MDC 属性

路由 附加器是 OSGi 的附加程序,可让您根据 MDC(Mapped Diagnostic Context)属性分割日志事件。

MDC 允许您区分不同的日志事件来源。

路由 附加器默认提供面向 OSGi 的 MDC 属性:

  • bundle.id 是捆绑包 ID
  • bundle.name 是捆绑包符号名称
  • bundle.version 是捆绑包版本

您可以使用这些 MDC 属性为每个捆绑包创建日志文件:

log4j2.appender.routing.type = Routing
log4j2.appender.routing.name = Routing
log4j2.appender.routing.routes.type = Routes
log4j2.appender.routing.routes.pattern = $$\\{ctx:bundle.name\\}
log4j2.appender.routing.routes.bundle.type = Route
log4j2.appender.routing.routes.bundle.appender.type = RollingRandomAccessFile
log4j2.appender.routing.routes.bundle.appender.name = Bundle-$\\{ctx:bundle.name\}
log4j2.appender.routing.routes.bundle.appender.fileName = ${karaf.data}/log/bundle-$\\{ctx:bundle.name\\}.log
log4j2.appender.routing.routes.bundle.appender.filePattern = ${karaf.data}/log/bundle-$\\{ctx:bundle.name\\}.log.%d{yyyy-MM-dd}
log4j2.appender.routing.routes.bundle.appender.append = true
log4j2.appender.routing.routes.bundle.appender.layout.type = PatternLayout
log4j2.appender.routing.routes.bundle.appender.policies.type = Policies
log4j2.appender.routing.routes.bundle.appender.policies.time.type = TimeBasedTriggeringPolicy
log4j2.appender.routing.routes.bundle.appender.strategy.type = DefaultRolloverStrategy
log4j2.appender.routing.routes.bundle.appender.strategy.max = 31

log4j2.rootLogger.appenderRef.Routing.ref = Routing

20.4.6. 加强 OSGi 堆栈追踪器

默认情况下,Apache Karaf 提供特殊的堆栈跟踪器,可添加一些 OSGi 特定信息。

在堆栈跟踪中,除了引发异常的类外,您还可以在每个堆栈追踪行末尾找到模式 [id:name:version],其中:

  • id 是捆绑包 ID
  • name 是捆绑包名称
  • 版本是捆绑包版本

诊断问题源非常有用。

例如,在以下 IllegalArgumentException 堆栈追踪中,我们可以查看有关异常来源的 OSGi 详情:

java.lang.IllegalArgumentException: Command not found:  *:foo
	at org.apache.felix.gogo.runtime.shell.Closure.execute(Closure.java:225)[21:org.apache.karaf.shell.console:4.0.0]
	at org.apache.felix.gogo.runtime.shell.Closure.executeStatement(Closure.java:162)[21:org.apache.karaf.shell.console:4.0.0]
	at org.apache.felix.gogo.runtime.shell.Pipe.run(Pipe.java:101)[21:org.apache.karaf.shell.console:4.0.0]
	at org.apache.felix.gogo.runtime.shell.Closure.execute(Closure.java:79)[21:org.apache.karaf.shell.console:4.0.0]
	at org.apache.felix.gogo.runtime.shell.CommandSessionImpl.execute(CommandSessionImpl.java:71)[21:org.apache.karaf.shell.console:4.0.0]
	at org.apache.karaf.shell.console.jline.Console.run(Console.java:169)[21:org.apache.karaf.shell.console:4.0.0]
	at java.lang.Thread.run(Thread.java:637)[:1.7.0_21]

20.4.7. 自定义附加器

您可以在 Apache Karaf 中使用您自己的附加器。

最简单的方法是将您的附件程序打包为 OSGi 捆绑包,并将其作为 org.ops4j.pax.logging.pax-logging-service 捆绑包的片段附加。

例如,您要创建 MyAppender

public class MyAppender extends AppenderSkeleton {
...
}

您将编译并打包成包含 MANIFEST 的 OSGi 捆绑包:

Manifest:
Bundle-SymbolicName: org.mydomain.myappender
Fragment-Host: org.ops4j.pax.logging.pax-logging-service
...

将捆绑包复制到 Apache Karaf 系统 文件夹中。系统 文件夹使用标准的 Maven 目录布局:groupId/artifactId/version。

etc/startup.properties 配置文件中,您可以在 pax-logging-service 捆绑包前在列表中定义捆绑包。

要重新加载系统捆绑包,您必须通过清理一个干净运行(清除 data 文件夹)来重启 Apache Karaf。现在,您可以直接在 etc/org.ops4j.pax.logging.cfg 配置文件中使用附加程序。