20.4. 高级配置
20.4.1. SIFT 日志
fuse-Karaf 提供了示例(默认情况下为 out)Log4j2 sift appender 配置,并使用 $FUSE_HOME/etc/org.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 附加器的模式属性是可用于区分用于记录的目标位置。
可用的查找有多种,如下所述 :http://logging.apache.org/log4j/2.x/manual/lookups.html
最重要的查找是 ctx,它会在 ThreadContext 映射(a.k.a)中查找值(键)。MDC)。
Fuse Karaf 提供的默认配置使用 ctx:bundle.name 作为模式,这意味着:
lookup bundle.name key in MDC
bundle. 前缀的密钥由 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()
但是,如果 Camel 上下文是使用 MDC 支持的 Camel 上下文(蓝色打印 XML DSL):
<camelContext id="my-context" xmlns="http://camel.apache.org/schema/blueprint" useMDCLogging="true">
在 MDC/ThreadContext 中,我还有更多可用的密钥,然后在 SIFT appender 配置中可用作模式:
- camel.exchangeId - Exchange 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 上下文 id。
请参阅 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 配置中的 log4j2.appender.mdc.name 的值匹配。
在这里,org.apache.camel 是一个日志记录器名称(或类别名称)。这与 Camel log: 端点中使用的值完全相同。因此,如果您在 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. 过滤器
您可以将过滤器应用到附加程序。过滤器评估每个日志事件,并确定是否将其发送到日志。
Log4j2 提供可供使用过滤器使用。
有关这些内容的综合视图,请参阅 Log4J 站点的 过滤器。
20.4.3. 嵌套附加器
嵌套的附加程序是一个特殊的附加程序,您可以使用"inside"另一个附加程序。它允许您在附加器链之间创建某种类型的"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 (映射诊断上下文)属性分割日志事件。
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
是捆绑包名称 -
version
是捆绑包版本
诊断问题来源非常有帮助。
例如,在以下 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 捆绑包前在列表中定义捆绑包。
您必须通过干净运行(提升 数据
文件夹)来重新启动 Apache Karaf,才能重新加载系统捆绑包。现在,您可以在 etc/org.ops4j.pax.logging.cfg
配置文件中直接使用您的 appender。