Мы переходим с log4j на log4j2 для нашей инфраструктуры непрерывной интеграции. Поскольку нашей кодовой базой является Java, мы используем testNg, у которого нет собственного бегуна в TeamCity, поэтому, чтобы иметь возможность аккуратно сложить установочный код, тесты и их шаги, мы добавили TeamCityLogger
. Этот регистратор отвечает за добавление сообщений службы TeamCity , где это необходимо. Эти сообщения требуют другого форматирования, чем в обычных строках журнала. Мы также не хотим видеть их при локальном запуске наших тестов. Для этого у нас был следующий log4j.xml:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE log4j:configuration SYSTEM "http://logging.apache.org/log4j/1.2/apidocs/org.apache.logging.log4j/xml/doc-files/log4j.dtd">
<log4j:configuration>
<appender name="console" class="org.apache.logging.log4j.ConsoleAppender">
<layout class="org.apache.logging.log4j.PatternLayout">
<param name="ConversionPattern" value="[%d{ABSOLUTE}][%t] %-5p %c{1}(%L) - %m%n"/>
</layout>
<filter class="org.apache.logging.log4j.varia.LevelRangeFilter">
<param name="levelMin" value="INFO" />
<param name="levelMax" value="ERROR" />
</filter>
</appender>
<appender name="teamcity" class="org.apache.logging.log4j.ConsoleAppender">
<layout class="org.apache.logging.log4j.PatternLayout">
<param name="ConversionPattern" value="%m%n%n"/>
</layout>
<filter class="org.apache.logging.log4j.varia.LevelRangeFilter">
<param name="levelMin" value="DEBUG" />
<param name="levelMax" value="DEBUG" />
</filter>
<filter class="org.apache.logging.log4j.varia.StringMatchFilter">
<param name="StringToMatch" value="##teamcity" />
<param name="AcceptOnMatch" value="true" />
</filter>
<filter class="org.apache.logging.log4j.varia.DenyAllFilter"/>
</appender>
<appender name="file" class="org.apache.logging.log4j.FileAppender">
<param name="File" value="log4j.log"/>
<param name="Append" value="false"/>
<param name="ImmediateFlush" value="true"/>
<layout class="org.apache.logging.log4j.PatternLayout">
<param name="ConversionPattern" value="[%d{ABSOLUTE}] %m%n"/>
</layout>
</appender>
<root>
<priority value ="debug" />
<appender-ref ref="console" />
<appender-ref ref="teamcity" />
<appender-ref ref="file" />
</root>
</log4j:configuration>
Наш TeamCityLogger
довольно прост:
public class TeamcityLogger {
public static Logger _logger = LogManager.getLogger("TeamcityLogger");
public static void tc_openBlock(String blockLabel){
String escapedLabel = tc_escaped(blockLabel);
_logger.debug(String.format("##teamcity[blockOpened name='<%s>']", escapedLabel));
}
public static void tc_closeBlock(String blockLabel){
String escapedLabel = tc_escaped(blockLabel);
_logger.debug(String.format("##teamcity[blockClosed name='<%s>']", escapedLabel));
}
}
где tc_escaped
выполняет простое экранирование предоставленной строки в соответствии с рекомендациями JetBrains.
Вокруг кода, который мы хотели бы сложить, мы добавляем сообщения blockOpen
и blockClose
TeamCity, очень похожие на:
public class SomeClass {
private static Logger _logger = LogManager.getLogger(SomeClass.class.getSimpleName());
public void MethodToFold(){
TeamcityLogger.tc_openBlock("FoldMe");
_logger.info("I'm doing something");
_logger.info("I'm doing something else");
TeamcityLogger.tc_closeBlock("FoldMe");
}
}
Это создаст хороший консольный журнал
[12:56:55,977][main] INFO SomeClass(17) - I'm doing something
[12:56:55,995][main] INFO SomeClass(18) - I'm doing something else
При запуске в TeamCity журнал сборки будет выглядеть так:
[19:51:04] : [Step 3/3] <FoldMe>
[19:51:04] : [<FoldMe>]
[19:51:04] : [<FoldMe>] [12:56:55,977][main] INFO SomeClass(17) - I'm doing something
[19:51:04] : [<FoldMe>] [12:56:55,995][main] INFO SomeClass(18) - I'm doing something else
[19:51:05] : [Step 3/3]
Наш новый log4j2.xml выглядит так:
<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
<Appenders>
<Console name="console">
<PatternLayout pattern="[%d{ABSOLUTE}][%t] %-5level %c{1}(%L) - %highlight{%m%n}"/>
</Console>
<Console name="teamcity">
<PatternLayout pattern="%m%n%n"/>
<Filters>
<RegexFilter regex="##teamcity" onMatch="ACCEPT" onMismatch="DENY"/>
<ThresholdFilter level="debug" onMatch="ACCEPT" onMismatch="DENY" />
</Filters>
</Console>
<File name="file" immediateFlush="true" fileName="log4j.log" append="false">
<PatternLayout pattern="[%d{ABSOLUTE}] %m%n"/>
</File>
</Appenders>
<Loggers>
<Root level="info">
<AppenderRef ref="console"/>
<AppenderRef ref="teamcity"/>
<AppenderRef ref="file"/>
</Root>
</Loggers>
</Configuration>
Что хорошо выглядит на консоли, но в TeamCity загруженный журнал сборки выглядит как
[13:06:04] : [Step 3/3] [13:06:04,089][main] INFO SomeClass(17) - [32mI'm doing something
[13:06:04] : [Step 3/3] [m[13:06:04,178][main] INFO SomeClass(18) - [32mI'm doing something else
Это означает, что у нас больше нет складывания.
Изменение конфигурации с дополнительной ссылкой на регистратор как
<Loggers>
<Logger name="TeamcityLogger">
<AppenderRef ref="teamcity"/>
</Logger>
<Root level="info">
<AppenderRef ref="console"/>
<AppenderRef ref="teamcity"/>
<AppenderRef ref="file"/>
</Root>
</Loggers>
Добавляет дополнительную строку журнала:
[13:19:12,281][main] DEBUG TeamcityLogger(17) -
В журнал TeamCity.
Я также попытался настроить уровень корневого журнала для отладки и добавить <ThresholdFilter level="info" onMatch="ACCEPT" onMismatch="DENY" />
в консоль appender, но это снова удалило мое сворачивание.
Любые предложения о том, как должен выглядеть xml, чтобы это работало?