查找

查找提供了一种在任意位置向 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 版本,例如

Java 版本 1.7.0_67

runtime

Java 运行时版本,例如

Java(TM) SE 运行时环境(版本 1.7.0_67-b01)来自 Oracle Corporation

vm

Java VM 版本,例如

Java HotSpot(TM) 64 位服务器 VM(版本 24.65-b04,混合模式)

os

操作系统版本,例如

Windows 7 6.1 Service Pack 1,体系结构:amd64-64

locale

系统区域设置和文件编码信息,例如

默认区域设置:en_US,平台编码:Cp1252

hw

硬件信息,例如

处理器:4,体系结构:amd64-64,指令集:amd64

例如

<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}

--file

${main:1}

foo.txt

${main:2}

--verbose

${main:3}

-x

${main:4}

bar

${main:\--file}

foo.txt

${main:\-x}

bar

${main:bar}

null

${main:\--quiet:-true}

true

示例用法

<File name="Application" fileName="application.log">
  <PatternLayout header="File: ${main:--file}">
    <Pattern>%d %m%n</Pattern>
  </PatternLayout>
</File>

Map 查找

MapLookup 具有多种用途。

  1. 为配置文件中声明的属性提供基础。
  2. 从 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_APPENDER
public 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>