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
配置文件中使用附加程序。