Добавление настраиваемого поля в log4j json макет разбивает структуру регистрации весны - PullRequest
0 голосов
/ 04 мая 2020

У меня есть приложение Spring Boot (2.2.6), которое использует Log4j2 (с Slf4j). Log4j настроен на использование макета json, и в конце я хочу загрузить журналы в Datadog. Для этого 'serviceName' важно как поле в json.

. Теперь согласно документу log4j (https://logging.apache.org/log4j/2.x/manual/layouts.html#JSONLayout) можно добавить настраиваемое поле с помощью KeyValuePair. Теги и это работает. К сожалению, это нарушает нормальную структуру журналов пружин.

Log4j2. xml config:

<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
    <Appenders>
        <!-- Write logs to stdout, JSON, one line per log event -->
        <Console name="Console" target="SYSTEM_OUT">
            <JSONLayout compact="true" eventEol="true" includeStacktrace="true" locationInfo="true"
                        stacktraceAsString="true" properties="true">
      <KeyValuePair key="serviceName" value="$${env:APPLICATION_NAME:-local}-sidecar"/> <!-- fine w/o this line -->
</JSONLayout>
        </Console>
    </Appenders>
    <Loggers>
        <Logger name="my.service" level="debug" additivity="false">
            <AppenderRef ref="Console"/>
        </Logger>
        <Logger name="org.springframework" level="info" additivity="false">
            <AppenderRef ref="Console"/>
        </Logger>
        <Logger name="org.apache" level="info" additivity="false">
            <AppenderRef ref="Console"/>
        </Logger>
        <Root level="info">
            <AppenderRef ref="Console"/>
        </Root>
    </Loggers>
</Configuration>

Журнал без настраиваемого поля:

{
  "thread": "main",
  "level": "INFO",
  "loggerName": "com.nginxtrafficsidecar.ApplicationKt",
  "message": "Starting ApplicationKt on xxx with PID 17300 (C:\\Users\\Felix\\Documents\\code\\nginx-traffic-sidecar\\build\\classes\\kotlin\\main started by Felix in C:\\Users\\Felix\\Documents\\code\\nginx-traffic-sidecar)",
  "endOfBatch": false,
  "loggerFqcn": "org.apache.commons.logging.LogAdapter$Log4jLog",
  "threadId": 1,
  "instant": {
    "epochSecond": 1587975181,
    "nanoOfSecond": 331370300
  },
  "source": {
    "class": "org.springframework.boot.StartupInfoLogger",
    "method": "logStarting",
    "file": "StartupInfoLogger.java",
    "line": 55,
    "classLoaderName": "app"
  },
  "contextMap": {},
  "threadPriority": 5
}

log с настраиваемым полем:

{
  "logEvent": "Starting ApplicationKt on xxx with PID 9732 (C:\\Users\\Felix\\Documents\\code\\nginx-traffic-sidecar\\build\\classes\\kotlin\\main started by Felix in C:\\Users\\Felix\\Documents\\code\\nginx-traffic-sidecar)",
  "serviceName": "local-sidecar"
}

В документе Spring указано, как это может работать с logback, но не с log4j (https://docs.spring.io/spring-boot/docs/current/reference/html/spring-boot-features.html#boot -features-custom-log-configuration , конец главы)

Я искал, но не смог найти ничего полезного. Любые идеи, как я могу добавить пользовательское поле в журнал json, сохраняя при этом все поля, поступающие из Spring?

Спасибо, Феликс

1 Ответ

0 голосов
/ 04 мая 2020
  1. скачайте Аннотации Джексона и импортируйте его, потому что JsonLayout использует Jackson Annotations внутренний код.
    • в моем случае скачайте и импортируйте эти
jackson-annotations-2.10.3.jar
jackson-core-2.10.3.jar
jackson-databind-2.10.3.jar
добавьте <JsonLayout>...</JsonLayout> в вашу конфигурацию (в моем случае log4j2. xml), как показано ниже
<JsonLayout>
  <KeyValuePair key="testKey" value="testValue"/>
</JsonLayout>

Замените key и value на то, что вы хотите использовать. В моем случае key это "testKey" и value это "testValue"

Запустите и проверьте свой журнал!

Это мой полный пример кода и xml информация о конфигурации. код

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.ThreadContext;

public class LogTest{
    private static final Logger logger = LogManager.getLogger(LogTest.class.getName());


    public static void main(String[] args) {
        ThreadContext.put("logFileName", "testFile1" );
        logger.info("log printed! - testFile1");

        ThreadContext.put("logFileName", "testFile2" );
        logger.info("log printed! - testFile2");

        ThreadContext.remove("logFileName");
    }

}

log4j2. xml

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
    <Appenders>
        <Routing name="RoutingAppender">
            <Routes pattern="${ctx:logFileName}">
                <Route>
                    <RollingFile name="Rolling-${ctx:logFileName}"
                                 fileName="./logs/${ctx:logFileName}.log"
                                 filePattern="./logs/${ctx:logFileName}.%i.log.gz">
                        <JsonLayout>
                            <KeyValuePair key="testKey" value="testValue"/>
                        </JsonLayout>
                        <SizeBasedTriggeringPolicy size="512" />
                    </RollingFile>
                </Route>
            </Routes>
        </Routing>
    </Appenders>

    <Loggers>
        <Root level="all">
            <AppenderRef ref="RoutingAppender" />
        </Root>
    </Loggers>
</Configuration>

выход

{
  "instant" : {
    "epochSecond" : 1588590944,
    "nanoOfSecond" : 469000000
  },
  "thread" : "main",
  "level" : "INFO",
  "loggerName" : "com.test.LogTest",
  "message" : "log printed! - testFile2",
  "endOfBatch" : false,
  "loggerFqcn" : "org.apache.logging.log4j.spi.AbstractLogger",
  "threadId" : 1,
  "threadPriority" : 5,
  "testKey" : "testValue"
}

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...