You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@logging.apache.org by "Volkan Yazici (Jira)" <ji...@apache.org> on 2022/09/18 19:53:00 UTC

[jira] [Closed] (LOG4J2-3188) Concurrent individual LoggerContext initializations cause severe LogEvent drop or incorrect delivery

     [ https://issues.apache.org/jira/browse/LOG4J2-3188?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ]

Volkan Yazici closed LOG4J2-3188.
---------------------------------
      Assignee: Volkan Yazici
    Resolution: Not A Problem

> Concurrent individual LoggerContext initializations cause severe LogEvent drop or incorrect delivery
> ----------------------------------------------------------------------------------------------------
>
>                 Key: LOG4J2-3188
>                 URL: https://issues.apache.org/jira/browse/LOG4J2-3188
>             Project: Log4j 2
>          Issue Type: Bug
>          Components: Core
>            Reporter: Volkan Yazici
>            Assignee: Volkan Yazici
>            Priority: Major
>
> When multiple {{LoggerContext}}'s get initialized concurrently, they affect each other causing severe {{LogEvent}} drop and incorrect delivery. Consider the following test:
> {code:java}
> @Execution(ExecutionMode.SAME_THREAD)
> class ParallelRunTest {
>     @ParameterizedTest
>     @ValueSource(chars = {'A', 'B', 'C', 'D'})
>     void test(final char letter) {
>         // Create the configuration builder.
>         final ConfigurationBuilder<?> configBuilder = ConfigurationBuilderFactory
>                 .newConfigurationBuilder()
>                 .setStatusLevel(Level.ERROR)
>                 .setConfigurationName("Letter-" + letter);
>         // Create the configuration.
>         final String appenderName = "File";
>         final String appenderFilepath = Paths
>                 .get(
>                         System.getProperty("java.io.tmpdir"),
>                         "ParallelRunTest-" + letter + ".log")
>                 .toAbsolutePath()
>                 .toString();
>         final Configuration config = configBuilder
>                 .add(configBuilder
>                         .newAppender(appenderName, "File")
>                         .addAttribute("fileName", appenderFilepath)
>                         .addAttribute("append", false)
>                         .addAttribute("immediateFlush", false)
>                         .addAttribute("ignoreExceptions", false)
>                         .add(configBuilder
>                                 .newLayout("PatternLayout")
>                                 .addAttribute("pattern", "%m\n")))
>                 .add(configBuilder
>                         .newRootLogger(Level.ALL)
>                         .add(configBuilder.newAppenderRef(appenderName)))
>                 .build(false);
>         // Initialize the configuration.
>         try (final LoggerContext loggerContext = Configurator.initialize(config)) {
>             final Logger logger = loggerContext.getLogger(ParallelRunTest.class);
>             // Write logs.
>             final String message = Strings.repeat(String.valueOf(letter), 999);
>             for (int i = 0; i < 1_000; i++) {
>                 logger.info(message);
>             }
>         }
>         // Verify the file content.
>         final long appenderFileLength = new File(appenderFilepath).length();
>         assertThat(appenderFileLength).isEqualTo(1_000_000L);
>     }
> }
> {code}
> Above test, given a {{letter}}, creates a {{ParallelRunTest-<letter>.log}} file, and writes 999 times that letter to each line (ending with a line-feed character) for 1,000 lines. The eventual file is expected to be of size {{lineLength * lineCount = 1,000 * 1,000 = 1e6}}. These assumptions indeed hold after a run:
> {code}
> wc -l /tmp/ParallelRunTest-*
>    1000 /tmp/ParallelRunTest-A.log
>    1000 /tmp/ParallelRunTest-B.log
>    1000 /tmp/ParallelRunTest-C.log
>    1000 /tmp/ParallelRunTest-D.log
>    4000 total
> for log_file in /tmp/ParallelRunTest-*; do
>     echo "file: $log_file"
>     echo "line lengths:"
>     awk "{print length}" $log_file | sort | uniq
>     echo "distinct lines:"
>     sort $log_file | uniq
>     echo
> done
> file: /tmp/ParallelRunTest-A.log
> line lengths:
> 999
> distinct lines:
> AAA...A
> file: /tmp/ParallelRunTest-B.log
> line lengths:
> 999
> distinct lines:
> BBB...B
> file: /tmp/ParallelRunTest-C.log
> line lengths:
> 999
> distinct lines:
> CCC...C
> file: /tmp/ParallelRunTest-D.log
> line lengths:
> 999
> distinct lines:
> DDD...D
> {code}
> Though when {{ExecutionMode.SAME_THREAD}} is replaced with {{ExecutionMode.CONCURRENT}} tests fail due to unexpected {{appenderFileLength}}:
> {code}
> wc -l /tmp/ParallelRunTest-*
>      96 /tmp/ParallelRunTest-A.log
>       1 /tmp/ParallelRunTest-B.log
>      96 /tmp/ParallelRunTest-C.log
>    3577 /tmp/ParallelRunTest-D.log
>    3770 total
> for log_file in /tmp/ParallelRunTest-*; do
>     echo "file: $log_file"
>     echo "line lengths:"
>     awk "{print length}" $log_file | sort | uniq
>     echo "distinct lines:"
>     sort $log_file | uniq
>     echo
> done
> file: /tmp/ParallelRunTest-A.log
> line lengths:
> 999
> distinct lines:
> AAA...A
> BBB...B
> CCC...C
> file: /tmp/ParallelRunTest-B.log
> line lengths:
> 999
> distinct lines:
> BBB...B
> file: /tmp/ParallelRunTest-C.log
> line lengths:
> 999
> distinct lines:
> BBB...B
> CCC...C
> file: /tmp/ParallelRunTest-D.log
> line lengths:
> 999
> distinct lines:
> AAA...A
> BBB...B
> CCC...C
> DDD...D
> {code}
> Note that {{AAA...A}}, {{BBB...B}}, etc. snippets shared above are truncated for display purposes, otherwise each line has 999 _unscrambled_ characters.
> Given 1) the total number of logged lines is less than 4000, 2) letters are scattered between files, and 3) lines are not scrambled, I have the feeling that produced {{LogEvent}}s either got lost or sent to wrong appenders.



--
This message was sent by Atlassian Jira
(v8.20.10#820010)