查找
查找提供了一种在任意位置向 Log4j 配置添加值的方法。它们是实现 StrLookup 接口的特定类型插件。有关如何在配置文件中使用查找的信息,请参阅 配置 页面中 属性替换 部分。
上下文映射查找
ContextMapLookup 允许应用程序将数据存储在 Log4j ThreadContext 映射中,然后在 Log4j 配置中检索这些值。在下面的示例中,应用程序将在 ThreadContext 映射中使用键“loginId”存储当前用户的登录 ID。在初始配置处理期间,第一个“$”将被删除。PatternLayout 支持使用查找进行插值,然后将为每个事件解析变量。请注意,模式“%X{loginId}”将实现相同的结果。
<File name="Application" fileName="application.log">
<PatternLayout>
<pattern>%d %p %c{1.} [%t] $${ctx:loginId} %m%n</pattern>
</PatternLayout>
</File>日期查找
DateLookup 有点不同于其他查找,因为它不使用键来定位项目。相反,键可用于指定对 SimpleDateFormat 有效的日期格式字符串。当前日期或与当前日志事件关联的日期将按指定格式进行格式化。
<RollingFile name="Rolling-${map:type}" fileName="${filename}" filePattern="target/rolling1/test1-$${date:MM-dd-yyyy}.%i.log.gz">
<PatternLayout>
<pattern>%d %p %c{1.} [%t] %m%n</pattern>
</PatternLayout>
<SizeBasedTriggeringPolicy size="500" />
</RollingFile>Docker 查找
DockerLookup 可用于从应用程序正在运行的 Docker 容器中查找属性。
Log4j Docker 提供对以下容器属性的访问权限| containerId | 分配给容器的完整 ID。 |
| containerName | 分配给容器的名称。 |
| imageId | 分配给映像的 ID。 |
| imageName | 分配给映像的名称。 |
| shortContainerId | 容器 ID 的前 12 个字符。 |
| shortImageId | 映像 ID 的前 12 个字符。 |
<JsonLayout properties="true" compact="true" eventEol="true">
<KeyValuePair key="containerId" value="${docker:containerId}"/>
<KeyValuePair key="containerName" value="${docker:containerName}"/>
<KeyValuePair key="imageName" value="${docker:imageName}"/>
</JsonLayout>此查找受 Log4j Docker 支持 中列出的要求约束。
环境查找
EnvironmentLookup 允许系统配置环境变量(在全局文件(如 /etc/profile)或应用程序的启动脚本中),然后从日志记录配置中检索这些变量。下面的示例在应用程序日志中包含当前登录用户的名称。
<File name="Application" fileName="application.log">
<PatternLayout>
<pattern>%d %p %c{1.} [%t] $${env:USER} %m%n</pattern>
</PatternLayout>
</File>此查找还支持默认值语法。在下面的示例中,当 USER 环境变量未定义时,将使用默认值 jdoe
<File name="Application" fileName="application.log">
<PatternLayout>
<pattern>%d %p %c{1.} [%t] $${env:USER:-jdoe} %m%n</pattern>
</PatternLayout>
</File>EventLookup
EventLookup 提供对配置中日志事件中字段的访问权限。
| 键 | 描述 |
|---|---|
| Exception | 如果事件中包含异常,则返回异常的简单类名。 |
| Level | 返回事件的日志记录级别。 |
| Logger | 返回记录器的名称。 |
| Marker | 返回与日志事件关联的标记的名称(如果存在)。 |
| Message | 返回格式化的消息字符串。 |
| ThreadId | 返回与日志事件关联的线程 ID。 |
| ThreadName | 返回与日志事件关联的线程的名称。 |
| Timestamp | 返回事件发生时的毫秒时间。 |
在此示例中,RoutingAppender 根据日志事件中是否存在名为“AUDIT”的标记来选择路由。
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN" name="RoutingTest">
<Appenders>
<Console name="STDOUT" target="SYSTEM_OUT" />
<Flume name="AuditLogger" compress="true">
<Agent host="192.168.10.101" port="8800"/>
<Agent host="192.168.10.102" port="8800"/>
<RFC5424Layout enterpriseNumber="18060" includeMDC="true" appName="MyApp"/>
</Flume>
<Routing name="Routing">
<Routes>
<Route pattern="$${event:Marker}">
<RollingFile
name="Rolling-${mdc:UserId}"
fileName="${mdc:UserId}.log"
filePattern="${mdc:UserId}.%i.log.gz">
<PatternLayout>
<pattern>%d %p %c{1.} [%t] %m%n</pattern>
</PatternLayout>
<SizeBasedTriggeringPolicy size="500" />
</RollingFile>
</Route>
<Route ref="AuditLogger" key="AUDIT"/>
<Route ref="STDOUT" key="STDOUT"/>
</Routes>
<IdlePurgePolicy timeToLive="15" timeUnit="minutes"/>
</Routing>
</Appenders>
<Loggers>
<Root level="error">
<AppenderRef ref="Routing" />
</Root>
</Loggers>
</Configuration>Java 查找
JavaLookup 允许使用 java: 前缀以方便的预格式化字符串检索 Java 环境信息。
| 键 | 描述 |
|---|---|
| version |
简短的 Java 版本,例如
|
| runtime |
Java 运行时版本,例如
|
| vm |
Java VM 版本,例如
|
| os |
操作系统版本,例如
|
| locale |
系统区域设置和文件编码信息,例如
|
| hw |
硬件信息,例如
|
例如
<File name="Application" fileName="application.log">
<PatternLayout header="${java:runtime} - ${java:vm} - ${java:os}">
<Pattern>%d %m%n</Pattern>
</PatternLayout>
</File>JNDI 查找
从 Log4j 2.17.0 开始,JNDI 操作要求将 log4j2.enableJndiLookup=true 设置为系统属性或相应的环境变量,才能使此查找正常工作。请参阅 enableJndiLookup 系统属性。
JndiLookup 允许通过 JNDI 检索变量。默认情况下,键将以 java:comp/env/ 为前缀,但是如果键包含“:”,则不会添加任何前缀。
JNDI 查找仅支持 java 协议或无协议(如以下示例所示)。
<File name="Application" fileName="application.log">
<PatternLayout>
<pattern>%d %p %c{1.} [%t] $${jndi:logging/context-name} %m%n</pattern>
</PatternLayout>
</File>Java 的 JNDI 模块在 Android 上不可用。
JVM 输入参数查找(JMX)
使用 JMX 映射 JVM 输入参数(但不是 main 参数)以获取 JVM 参数。
使用前缀 jvmrunargs 访问 JVM 参数。
请参阅 java.lang.management.RuntimeMXBean.getInputArguments() 的 Javadoc。
Java 的 JMX 模块在 Android 或 Google App Engine 上不可用。
Kubernetes 查找
KubernetesLookup 可用于从应用程序正在运行的容器的 Kubernetes 环境中查找属性。
Log4j Kubernetes 提供对以下容器属性的访问权限| accountName | 服务帐户名称 |
| clusterName | 应用程序部署到的集群的名称 |
| containerId | 分配给容器的完整 ID |
| containerName | 分配给容器的名称 |
| host | 分配给主机操作系统的名称 |
| hostIp | 主机的 IP 地址 |
| imageId | 分配给容器映像的 ID |
| imageName | 分配给容器映像的名称 |
| labels | 所有标签,以列表格式 |
| labels.app | 应用程序名称 |
| labels.podTemplateHash | Pod 的模板哈希值 |
| masterUrl | 用于访问 API 服务器的 URL |
| namespaceId | 各种 Kubernetes 组件所在的命名空间的 ID |
| namespaceName | 各种 Kubernetes 组件所在的命名空间 |
| podId | Pod 的 IP 号码 |
| podIp | Pod 的 IP 地址 |
| podName | Pod 的名称 |
<GelfLayout includeStackTrace="true" host="${hostName}" includeThreadContext="true" includeNullDelimiter="true"
compressionType="OFF">
<ThreadContextIncludes>requestId,sessionId,loginId,userId,ipAddress,callingHost</ThreadContextIncludes>
<MessagePattern>%d [%t] %-5p %X{requestId, sessionId, loginId, userId, ipAddress} %C{1.}.%M:%L - %m%n</MessagePattern>
<KeyValuePair key="docker.containerId" value="${docker:containerId:-}"/>
<KeyValuePair key="application" value="$${lower:${spring:spring.application.name}}"/>
<KeyValuePair key="kubernetes.serviceAccountName" value="${k8s:accountName:-}"/>
<KeyValuePair key="kubernetes.clusterName" value="${k8s:clusterName:-}/>
<KeyValuePair key="kubernetes.containerId" value="${k8s:containerId:-}"/>
<KeyValuePair key="kubernetes.containerName" value="${k8s:containerName:-}"/>
<KeyValuePair key="kubernetes.host" value="${k8s:host:-}"/>
<KeyValuePair key="kubernetes.labels.app" value="${k8s:labels.app:-}"/>
<KeyValuePair key="kubernetes.labels.pod-template-hash" value="${k8s:labels.podTemplateHash:-}"/>
<KeyValuePair key="kubernetes.master_url" value="${k8s:masterUrl:-}"/>
<KeyValuePair key="kubernetes.namespaceId" value="${k8s:namespaceId:-}"/>
<KeyValuePair key="kubernetes.namespaceName" value="${k8s:namespaceName:-}"/>
<KeyValuePair key="kubernetes.podID" value="${k8s:podId:-}"/>
<KeyValuePair key="kubernetes.podIP" value="${k8s:podIp:-}"/>
<KeyValuePair key="kubernetes.podName" value="${k8s:podName:-}"/>
<KeyValuePair key="kubernetes.imageId" value="${k8s:imageId:-}"/>
<KeyValuePair key="kubernetes.imageName" value="${k8s:imageName:-}"/>
</GelfLayout>此查找受 Log4j Kubernetes 支持 中列出的配置要求约束。
Log4j 配置位置查找
Log4j 配置属性。表达式 ${log4j:configLocation} 和 ${log4j:configParentLocation} 分别提供 Log4j 配置文件的绝对路径及其父文件夹。
下面的示例使用此查找将日志文件放置在相对于 Log4j 配置文件的目录中。
<File name="Application" fileName="${log4j:configParentLocation}/logs/application.log">
<PatternLayout>
<pattern>%d %p %c{1.} [%t] %m%n</pattern>
</PatternLayout>
</File>小写查找
LowerLookup 将传入的参数转换为小写。可以假设该值将是嵌套查找的结果。
<File name="Application" fileName="application.log">
<PatternLayout>
<pattern>%d %p %c{1.} [%t] $${lower:{${spring:spring.application.name}} %m%n</pattern>
</PatternLayout>
</File>主参数查找(应用程序)
此查找要求您手动将应用程序的主参数提供给 Log4j
import org.apache.logging.log4j.core.lookup.MainMapLookup;
public static void main(String args[]) {
MainMapLookup.setMainArguments(args);
...
}如果已设置主要参数,则此查找允许应用程序从日志记录配置中检索这些主要参数值。 main: 前缀后的键可以是参数列表中的基于 0 的索引,也可以是字符串,其中 ${main:myString} 将替换为主要参数列表中 myString 之后的值。
${main:--file} 将导致查找失败,因为它将查找名为“main”且默认值为“-file”的变量。 为了避免这种情况,分隔查找名称和键的冒号后面必须跟一个反斜杠作为转义字符,如 ${main:\--file}例如,假设 static void main String[] 参数为
--file foo.txt --verbose -x bar
那么以下替换是可能的
| 表达式 | 结果 |
|---|---|
| ${main:0} |
|
| ${main:1} |
|
| ${main:2} |
|
| ${main:3} |
|
| ${main:4} |
|
| ${main:\--file} |
|
| ${main:\-x} |
|
| ${main:bar} |
|
| ${main:\--quiet:-true} |
|
示例用法
<File name="Application" fileName="application.log">
<PatternLayout header="File: ${main:--file}">
<Pattern>%d %m%n</Pattern>
</PatternLayout>
</File>Map 查找
MapLookup 具有多种用途。
- 为配置文件中声明的属性提供基础。
- 从 LogEvents 中的 MapMessages 检索值。
第一项仅仅意味着 MapLookup 用于替换在配置文件中定义的属性。 这些变量在没有前缀的情况下指定 - 例如 ${name}。 第二种用法允许从当前 MapMessage 中替换值,如果当前日志事件包含 MapMessage。 在下面的示例中,RoutingAppender 将为 MapMessage 中名为“type”的键的每个唯一值使用不同的 RollingFileAppender。 请注意,以这种方式使用时,应在属性声明中声明“type”的值,以在消息不是 MapMessage 或 MapMessage 不包含键的情况下提供默认值。 有关如何设置默认值的详细信息,请参阅 属性替换 部分的 配置 页面。
<Routing name="Routing">
<Routes pattern="$${map:type}">
<Route>
<RollingFile name="Rolling-${map:type}" fileName="target/rolling1/test1-${map:type}.log"
filePattern="target/rolling1/test1-${map:type}.%i.log.gz">
<PatternLayout>
<pattern>%d %p %c{1.} [%t] %m%n</pattern>
</PatternLayout>
<SizeBasedTriggeringPolicy size="500" />
</RollingFile>
</Route>
</Routes>
</Routing>标记查找
标记查找允许您在有趣的配置中使用标记,例如路由追加器。 考虑以下 YAML 配置和根据标记记录到不同文件的代码
Configuration:
status: debug
Appenders:
Console:
RandomAccessFile:
- name: SQL_APPENDER
fileName: logs/sql.log
PatternLayout:
Pattern: "%d{ISO8601_BASIC} %-5level %logger{1} %X %msg%n"
- name: PAYLOAD_APPENDER
fileName: logs/payload.log
PatternLayout:
Pattern: "%d{ISO8601_BASIC} %-5level %logger{1} %X %msg%n"
- name: PERFORMANCE_APPENDER
fileName: logs/performance.log
PatternLayout:
Pattern: "%d{ISO8601_BASIC} %-5level %logger{1} %X %msg%n"
Routing:
name: ROUTING_APPENDER
Routes:
pattern: "$${marker:}"
Route:
- key: PERFORMANCE
ref: PERFORMANCE_APPENDER
- key: PAYLOAD
ref: PAYLOAD_APPENDER
- key: SQL
ref: SQL_APPENDER
Loggers:
Root:
level: trace
AppenderRef:
- ref: ROUTING_APPENDERpublic static final Marker SQL = MarkerFactory.getMarker("SQL");
public static final Marker PAYLOAD = MarkerFactory.getMarker("PAYLOAD");
public static final Marker PERFORMANCE = MarkerFactory.getMarker("PERFORMANCE");
final Logger logger = LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME);
logger.info(SQL, "Message in Sql.log");
logger.info(PAYLOAD, "Message in Payload.log");
logger.info(PERFORMANCE, "Message in Performance.log");请注意配置的关键部分是 pattern: "$${marker:}"。 这将生成三个日志文件,每个文件都包含特定标记的日志事件。 Log4j 将将带有 SQL 标记的日志事件路由到 sql.log,将带有 PAYLOAD 标记的日志事件路由到 payload.log,依此类推。
您可以使用 "${marker:name}" 和 "$${marker:name}" 符号来检查标记是否存在,其中 name 是标记名称。 如果标记存在,则表达式返回名称,否则返回 null。
资源包查找
资源包查找从资源包中检索值(请参阅 Java 文档)。 格式为 ${dollar}{bundle:BundleName:BundleKey}。 包名称遵循包命名约定,例如:${dollar}{bundle:com.domain.Messages:MyKey}。
<File name="Application" fileName="application-${spring:profiles.active[0]}.log">
<PatternLayout>
<pattern>%d %p %c{1.} [%t] $${bundle:MyBundle:MyKey} %m%n</pattern>
</PatternLayout>
</File>Spring Boot 查找
Spring Boot 查找从 Spring 配置中检索 Spring 属性的值,以及活动和默认配置文件的值。 指定“profiles.active”键将返回活动配置文件,而指定“profiles.default”键将返回默认配置文件。 默认和活动配置文件可以是数组。 如果存在多个配置文件,则将以逗号分隔列表的形式返回。 要从数组中检索单个项目,请将“[{index}]”附加到键。 例如,要返回列表中的第一个活动配置文件,请指定“profiles.active[0]”。
此查找将在 Spring Boot 初始化应用程序日志记录之前返回 null 值。 Spring Boot 查找需要将 log4j-spring-boot jar 包含为依赖项。
<File name="Application" fileName="application-${spring:profiles.active[0]}.log">
<PatternLayout>
<pattern>%d %p %c{1.} [%t] $${spring:spring.application.name} %m%n</pattern>
</PatternLayout>
</File>此查找需要在应用程序中包含 log4j-spring-cloud-config-client。
结构化数据查找
StructuredDataLookup 与 MapLookup 非常相似,因为它将从 StructuredDataMessages 中检索值。 除了 Map 值之外,它还将返回 id 的名称部分(不包括企业编号)和类型字段。 下面的示例与 MapMessage 示例之间的主要区别在于“type”是 StructuredDataMessage 的属性,而“type”必须是 MapMessage 中 Map 的一个项目。
<Routing name="Routing">
<Routes pattern="$${sd:type}">
<Route>
<RollingFile name="Rolling-${sd:type}" fileName="${filename}"
filePattern="target/rolling1/test1-${sd:type}.%i.log.gz">
<PatternLayout>
<pattern>%d %p %c{1.} [%t] %m%n</pattern>
</PatternLayout>
<SizeBasedTriggeringPolicy size="500" />
</RollingFile>
</Route>
</Routes>
</Routing>系统属性查找
由于在应用程序内部和外部使用系统属性定义值非常普遍,因此它们可以通过查找访问是自然而然的。 由于系统属性通常在应用程序外部定义,因此通常会看到类似以下内容
<Appenders>
<File name="ApplicationLog" fileName="${sys:logPath}/app.log"/>
</Appenders>此查找还支持默认值语法。 在下面的示例中,当 logPath 系统属性未定义时,将使用默认值 /var/logs
<Appenders>
<File name="ApplicationLog" fileName="${sys:logPath:-/var/logs}/app.log"/>
</Appenders>大写查找
UpperLookup 将传入的参数转换为大写。 可以推测该值将是嵌套查找的结果。
<File name="Application" fileName="application.log">
<PatternLayout>
<pattern>%d %p %c{1.} [%t] $$upper{${spring:spring.application.name}} %m%n</pattern>
</PatternLayout>
</File>Web 查找
WebLookup 允许应用程序检索与 ServletContext 关联的变量。 除了能够检索 ServletContext 中的各种字段之外,WebLookup 还支持查找存储为属性或配置为初始化参数的值。 下表列出了可以检索的各种键
| 键 | 描述 |
|---|---|
| attr.name | 返回具有指定名称的 ServletContext 属性 |
| contextPath | Web 应用程序的上下文路径 |
| contextPathName | Web 应用程序上下文路径中第一个以“/”字符分隔的标记。 |
| effectiveMajorVersion | 获取此 ServletContext 代表的应用程序所基于的 Servlet 规范的主要版本。 |
| effectiveMinorVersion | 获取此 ServletContext 代表的应用程序所基于的 Servlet 规范的次要版本。 |
| initParam.name | 返回具有指定名称的 ServletContext 初始化参数 |
| majorVersion | 返回此 servlet 容器支持的 Servlet API 的主要版本。 |
| minorVersion | 返回此 servlet 容器支持的 Servlet API 的次要版本。 |
| rootDir | 返回使用“/”的值调用 getRealPath 的结果。 |
| serverInfo | 返回 servlet 正在运行的 servlet 容器的名称和版本。 |
| servletContextName | 返回 Web 应用程序的名称,如部署描述符的 display-name 元素中定义的那样 |
任何其他指定的键名将首先检查是否存在具有该名称的 ServletContext 属性,然后检查是否存在具有该名称的初始化参数。 如果找到键,则将返回相应的值。
<Appenders>
<File name="ApplicationLog" fileName="${web:rootDir}/app.log"/>
</Appenders>

