Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

(Closeable)ThreadContext putAll removes entire context #2946

Closed
nielsm5 opened this issue Sep 12, 2024 · 36 comments · Fixed by #3050
Closed

(Closeable)ThreadContext putAll removes entire context #2946

nielsm5 opened this issue Sep 12, 2024 · 36 comments · Fixed by #3050
Assignees
Labels
api Affects the public API bug Incorrect, unexpected, or unintended behavior of existing code
Milestone

Comments

@nielsm5
Copy link

nielsm5 commented Sep 12, 2024

Description

The ThreadContext no longer works as intended. The new version closes/removes items from the stack when it shouldn't.

CloseableThreadContext calls ThreadContext.putAll.

if (!valuesToReplace.isEmpty()) {
    ThreadContext.putAll(valuesToReplace);
}

Once putAll has been called, the stack is gone, and only the newly inserted values are present.
Since it's used by CloseableThreadContext#close() it's quite destructive...

Configuration

Version: 2.24.0

Operating system: All

JDK: All

Reproduction

	@Test
	public void testAutoCloseableThreadContext() {
		try (final CloseableThreadContext.Instance ctc1 = CloseableThreadContext.put("outer", "one")) {
			try (final CloseableThreadContext.Instance ctc2 = CloseableThreadContext.put("outer", "two")) {
				assertEquals("two", ThreadContext.get("outer"));

				try (final CloseableThreadContext.Instance ctc3 = CloseableThreadContext.put("inner", "one")) {
					assertEquals("one", ThreadContext.get("inner"));

					ThreadContext.put("not-in-closeable", "true");
					assertEquals("two", ThreadContext.get("outer"));
				}

				assertEquals("two", ThreadContext.get("outer"));
				assertNull(ThreadContext.get("inner"));
			}

			assertEquals("one", ThreadContext.get("outer"));
			assertNull(ThreadContext.get("inner"));
		}
		assertEquals("true", ThreadContext.get("not-in-closeable"));

		assertNull(ThreadContext.get("inner"));
		assertNull(ThreadContext.get("outer"));
	}

and

	@Test
	public void testAutoCloseableThreadContextPutAll() {
		try (final CloseableThreadContext.Instance ctc1 = CloseableThreadContext.put("outer", "one")) {
			try (final CloseableThreadContext.Instance ctc2 = CloseableThreadContext.put("outer", "two")) {
				assertEquals("two", ThreadContext.get("outer"));

				try (final CloseableThreadContext.Instance ctc3 = CloseableThreadContext.put("inner", "one")) {
					assertEquals("one", ThreadContext.get("inner"));

					ThreadContext.put("not-in-closeable", "true");
					ThreadContext.putAll(Collections.singletonMap("inner", "two"));
					assertEquals("two", ThreadContext.get("inner"));
					assertEquals("two", ThreadContext.get("outer"));
				}

				assertEquals("two", ThreadContext.get("outer"));
				assertNull(ThreadContext.get("inner"));
			}

			assertEquals("one", ThreadContext.get("outer"));
			assertNull(ThreadContext.get("inner"));
		}
		assertEquals("true", ThreadContext.get("not-in-closeable"));

		assertNull(ThreadContext.get("inner"));
		assertNull(ThreadContext.get("outer"));
	}
@tnleeuw
Copy link

tnleeuw commented Sep 12, 2024

Another test that shows the same failure is this test, which does not use ThreadContext.put / ThreadContext.putAll() in the test code but just nesting of CloseableThreadContext.Instance, with nested values that need to be restored on closing an inner context. This test fails because CloseableThreadContext.Instance.closeMap() calls ThreadContext.putAll(valuesToReplace).

	@Test
	public void testCloseableThreadContextWithMultipleNestingLevels() {
		ThreadContext.clearMap();

		try (CloseableThreadContext.Instance k1Outer = CloseableThreadContext.put("k1", "outer")) {
			assertEquals("outer", ThreadContext.get("k1"));
			try (CloseableThreadContext.Instance k1Inner = CloseableThreadContext.put("k1", "inner")) {
				assertEquals("inner", ThreadContext.get("k1"));

				try (CloseableThreadContext.Instance k2Outer = CloseableThreadContext.put("k2", "outer")) {
					assertEquals("inner", ThreadContext.get("k1"));
					assertEquals("outer", ThreadContext.get("k2"));
					try (CloseableThreadContext.Instance k2Inner = CloseableThreadContext.put("k2", "inner")) {
						assertEquals("inner", ThreadContext.get("k1"));
						assertEquals("inner", ThreadContext.get("k2"));

					}
					assertEquals("inner", ThreadContext.get("k1")); // Expect k1 to still exist but it has disappeared here
					assertEquals("outer", ThreadContext.get("k2"));
				}
				assertEquals("inner", ThreadContext.get("k1"));
				assertNull(ThreadContext.get("k2"));

			}
			assertEquals("outer", ThreadContext.get("k1"));
			assertNull(ThreadContext.get("k2"));
		}
		assertNull(ThreadContext.get("k1"));
	}

And another test, simpler, that fails because now CloseableThreadContext.putAll() calls ThreadContext.putAll().

	@Test
	public void testCloseableThreadContext2() {
		ThreadContext.clearMap();

		try (CloseableThreadContext.Instance outer = CloseableThreadContext.put("k1", "outer")) {
			assertEquals("outer", ThreadContext.get("k1"));
			try (CloseableThreadContext.Instance inner = CloseableThreadContext.putAll(Collections.singletonMap("k2", "inner"))) {
				assertEquals("inner", ThreadContext.get("k2"));
				assertEquals("outer", ThreadContext.get("k1")); // Cannot find key "k1" anymore, but it should
			}
			assertNull(ThreadContext.get("k2"));
			assertEquals("outer", ThreadContext.get("k1"));
		}
		assertNull(ThreadContext.get("k1"));
	}

@ppkarwasz
Copy link
Contributor

@nielsm5,

Thank you for the report. I believe this is the same problem that was fixed in #2942.

@tnleeuw
Copy link

tnleeuw commented Sep 12, 2024

@nielsm5,

Thank you for the report. I believe this is the same problem that was fixed in #2942.

That would be great; does it fix the tests we added? (Just short on time to verify that myself right now but if you don't have time either then perhaps tomorrow I can find the time to verify this).

@ppkarwasz
Copy link
Contributor

@nielsm5,

Can you check the latest 2.24.1-SNAPSHOT snapshot, if it solves the problem (see Logging Services Download for details about our snapshot repository).

@ppkarwasz
Copy link
Contributor

That would be great; does it fix the tests we added? (Just short on time to verify that myself right now but if you don't have time either then perhaps tomorrow I can find the time to verify this).

I believe so, the problem with putAll was that it overwrote the previous entries instead of appending to them.

@tnleeuw
Copy link

tnleeuw commented Sep 12, 2024

That would be great; does it fix the tests we added? (Just short on time to verify that myself right now but if you don't have time either then perhaps tomorrow I can find the time to verify this).

I believe so, the problem with putAll was that it overwrote the previous entries instead of appending to them.

Sounds like it should fix this issue. I will test with a snapshot-build tomorrow.

@tnleeuw
Copy link

tnleeuw commented Sep 13, 2024

I can confirm that the latest snapshot build fixes our tests.

@ppkarwasz
Copy link
Contributor

Thanks for the confirmation, I am closing it and adding it to the 2.24.1 milestone due in about 10 days.

@nielsm5
Copy link
Author

nielsm5 commented Sep 30, 2024

This has NOT been fixed (yet). Not all closeables are closed properly...

@vy
Copy link
Member

vy commented Sep 30, 2024

@nielsm5, that is embarrassing sad, to say the least. 😞 Apologies for the inconvenience. Thanks for the report. I will take care of this issue in a day or two.

@vy vy reopened this Sep 30, 2024
@vy vy added bug Incorrect, unexpected, or unintended behavior of existing code api Affects the public API and removed waiting-for-maintainer labels Sep 30, 2024
@vy vy self-assigned this Sep 30, 2024
@nielsm5
Copy link
Author

nielsm5 commented Sep 30, 2024

Thanks, and no worries, mistakes happen. Luckily we've got tests.

@tnleeuw
Copy link

tnleeuw commented Sep 30, 2024

I see now that perhaps 2 weeks ago there was a case that I did not verify when testing the snapshot.

Here are 2 unit tests that show the issue. These unit tests only use JDK apis, JUnit, and Log4J2 api.

While in the scope of the inner nested CloseableThreadContext, ctc3, a value is put directly into the ThreadContext with a key (not-in-closeable) that is not part of any of the CloseableThreadContexts. (This case was not in my earlier scenarios).

After the context ctc3 is closed, the key inner that was added by ctc3 should be removed but the assert shows that it isn't.

When I comment out the line ThreadContext.put("not-in-closeable", "true"); from the tests, then the assertNull(ThreadContext.get("inner")); does succeed in both tests.

With this line in the tests, the assertNull(ThreadContext.get("inner")); fails.

In Log4J2 2.23.1 both tests pass.


	@Test
	public void testAutoCloseableThreadContext() {
		ThreadContext.clearMap();
		try (final CloseableThreadContext.Instance ctc1 = CloseableThreadContext.put("outer", "one")) {
			try (final CloseableThreadContext.Instance ctc2 = CloseableThreadContext.put("outer", "two")) {
				assertEquals("two", ThreadContext.get("outer"));

				try (final CloseableThreadContext.Instance ctc3 = CloseableThreadContext.put("inner", "one")) {
					assertEquals("one", ThreadContext.get("inner"));

					ThreadContext.put("not-in-closeable", "true"); // Remove this line, and closing context behaves as expected
					assertEquals("two", ThreadContext.get("outer"));
				}

				assertEquals("two", ThreadContext.get("outer"));
				assertNull(ThreadContext.get("inner")); // Test fails here
			}

			assertEquals("one", ThreadContext.get("outer"));
			assertNull(ThreadContext.get("inner"));
		}
		assertEquals("true", ThreadContext.get("not-in-closeable"));

		assertNull(ThreadContext.get("inner"));
		assertNull(ThreadContext.get("outer"));
	}

	@Test
	public void testAutoCloseableThreadContextPutAll() {
		ThreadContext.clearMap();
		try (final CloseableThreadContext.Instance ctc1 = CloseableThreadContext.put("outer", "one")) {
			try (final CloseableThreadContext.Instance ctc2 = CloseableThreadContext.put("outer", "two")) {
				assertEquals("two", ThreadContext.get("outer"));

				try (final CloseableThreadContext.Instance ctc3 = CloseableThreadContext.put("inner", "one")) {
					assertEquals("one", ThreadContext.get("inner"));

					ThreadContext.put("not-in-closeable", "true"); // Remove this line, and closing context behaves as expected
					ThreadContext.putAll(Collections.singletonMap("inner", "two")); // But this is not a problem
					System.err.println(ThreadContext.getContext());
					assertEquals("two", ThreadContext.get("inner"));
					assertEquals("two", ThreadContext.get("outer"));
				}

				assertEquals("two", ThreadContext.get("outer"));
				assertNull(ThreadContext.get("inner")); // This is where the test fails
			}

			assertEquals("one", ThreadContext.get("outer"));
			assertNull(ThreadContext.get("inner"));
		}
		assertEquals("true", ThreadContext.get("not-in-closeable"));

		assertNull(ThreadContext.get("inner"));
		assertNull(ThreadContext.get("outer"));
	}

@vy
Copy link
Member

vy commented Oct 3, 2024

@tnleeuw, @nielsm5, would you mind reviewing #3050, please?

@tnleeuw
Copy link

tnleeuw commented Oct 3, 2024

@tnleeuw, @nielsm5, would you mind reviewing #3050, please?

I am not sure about the actual changes to the map-updating as I don't know the code well enough but I see you included both test-cases provided above, so if they pass the changes should be good to go!

@vy
Copy link
Member

vy commented Oct 3, 2024

I am not sure about the actual changes to the map-updating as I don't know the code well enough but I see you included both test-cases provided above, so if they pass the changes should be good to go!

@tnleeuw, could you locally compile that branch (see BUILDING.adoc) and use the produced artifacts to see if they pass your tests?

@tnleeuw
Copy link

tnleeuw commented Oct 3, 2024

I am not sure about the actual changes to the map-updating as I don't know the code well enough but I see you included both test-cases provided above, so if they pass the changes should be good to go!

@tnleeuw, could you locally compile that branch (see BUILDING.adoc) and use the produced artifacts to see if they pass your tests?

I'm trying but I get weird errors in my project about classes not found, when I change my log4j2 dependency to 2.25.0-SNAPSHOT.
I do see that version in my local Maven repository.

I'm not quite sure what's going on, Maven doesn't give me a very sensible error message but IntelliJ complains about not being able to load the annotation class NullMarked from jspecify.

java: cannot access org.jspecify.annotations.NullMarked
  class file for org.jspecify.annotations.NullMarked not found

And from the Maven output:

[ERROR] COMPILATION ERROR : 
[INFO] -------------------------------------------------------------
[ERROR] cannot access org.jspecify.annotations.NullMarked
  class file for org.jspecify.annotations.NullMarked not found

This goes away again as soon as I switch back to any release version of Log4J2.

I'm a bit puzzled because git blame seems to indicate that jspecify has been part of the project for a long time already, and is not a transitive dependency of release versions of Log4J2 either.

@vy
Copy link
Member

vy commented Oct 3, 2024

@tnleeuw, if I understand it right, you are able to successfully compile Log4j, though using it in your project is failing due to the error you cited. I will further investigate the JSpecify issue. In the meantime, could you add JSpecify dependency in the provided scope (for the time being) and see if MDC behaves as expected, please?

@ppkarwasz
Copy link
Contributor

I'm a bit puzzled because git blame seems to indicate that jspecify has been part of the project for a long time already, and is not a transitive dependency of release versions of Log4J2 either.

I am a bit puzzled too, since annotations were conceived from the start as optional and compilation should not fail if they are missing. Which JDK are you using to compile your project? There is a known bug in JDK 8 (JDK-8152174) that causes problem if optional annotations are missing.

@tnleeuw
Copy link

tnleeuw commented Oct 3, 2024

Adding jspecify to my own dependencies, tests that previously failed do now succeed. Still running the entire test suite.

@tnleeuw
Copy link

tnleeuw commented Oct 3, 2024

I'm a bit puzzled because git blame seems to indicate that jspecify has been part of the project for a long time already, and is not a transitive dependency of release versions of Log4J2 either.

I am a bit puzzled too, since annotations were conceived from the start as optional and compilation should not fail if they are missing. Which JDK are you using to compile your project? There is a known bug in JDK 8 (JDK-8152174) that causes problem if optional annotations are missing.

I currently use JDK17.0.12, built by Amazon.
There's no problem with other builds, which also use jspecify annotations, so that puzzles me. The only difference might be that I built this version locally from IntelliJ, letting IntelliJ build the commandline:

C:\Users\Tim\.jdks\corretto-17.0.12\bin\java.exe -Dmaven.multiModuleProjectDirectory=C:\Users\Tim\IdeaProjects\logging-log4j2 [lots of paths and OPENS added by IntelliJ] org.codehaus.classworlds.Launcher -Didea.version=2024.2.3 -DskipTests=true install

Using Maven 3.9.8 from the Maven wrapper

@vy
Copy link
Member

vy commented Oct 3, 2024

I built this version locally from IntelliJ

@tnleeuw, just to get the most obvious probability out of our way, could you try the following instead, please?

./mvnw clean install -DskipTests

@tnleeuw
Copy link

tnleeuw commented Oct 3, 2024

I built this version locally from IntelliJ

@tnleeuw, just to get the most obvious probability out of our way, could you try the following instead, please?

./mvnw clean install -DskipTests

Done but that doesn't make any difference.

Again using Amazon Coretto JDK 17.0.12 to build Log4J2, and also for my project.

@tnleeuw
Copy link

tnleeuw commented Oct 3, 2024

When I add jspecify as dependency to my project, all LogContext / ThreadContext related tests pass.

There is 1 failing test, which is an unexpected newline at the end of a logline. That doesn't look related to anything to do with the ThreadContext but it's something for ourselves to keep in mind after the release of 2.25.0.

@vy
Copy link
Member

vy commented Oct 3, 2024

@tnleeuw, thank you so much for taking to time the evaluate the fix! 😍 Much appreciated! 🙇

When I add jspecify as dependency to my project, all LogContext / ThreadContext related tests pass.

There is 1 failing test, which is an unexpected newline at the end of a logline. That doesn't look related to anything to do with the ThreadContext but it's something for ourselves to keep in mind after the release of 2.25.0.

2.25.0 will ship a written-from-scratch exception rendering logic for Pattern Layout – #2691. (We will ofcourse document this in release notes.) Could you check if the discrepancy is due to a usage of %ex, %xEx, or %xEx, please?

@tnleeuw
Copy link

tnleeuw commented Oct 3, 2024

@tnleeuw, thank you so much for taking to time the evaluate the fix! 😍 Much appreciated! 🙇

You're welcome!

When I add jspecify as dependency to my project, all LogContext / ThreadContext related tests pass.
There is 1 failing test, which is an unexpected newline at the end of a logline. That doesn't look related to anything to do with the ThreadContext but it's something for ourselves to keep in mind after the release of 2.25.0.

2.25.0 will ship a written-from-scratch exception rendering logic for Pattern Layout – #2691. (We will ofcourse document this in release notes.) Could you check if the discrepancy is due to a usage of %ex, %xEx, or %xEx, please?

The code uses a custom TestAppender class and a custom Layout class that extends from AbstractStringLayout and has a PatternFormatter[] parsed from this pattern: "%level - %m - %throwable{1}"

So as far as I can determine from our custom log4j code, we do not use any of %ex, %xEx, or %xEx -- unless I miss something that happens underwater.

The relevant bit of initialisation code is:

	IbisPatternLayout(final Configuration config, final String pattern, final Charset charset, final boolean alwaysWriteExceptions, final boolean disableAnsi, final boolean noConsoleNoAnsi) {
		super(config, charset);

		try {
			final PatternParser parser = PatternLayout.createPatternParser(configuration);
			final List<PatternFormatter> list = parser.parse(pattern, alwaysWriteExceptions, disableAnsi, noConsoleNoAnsi);
			final PatternFormatter[] formatters = list.toArray(new PatternFormatter[0]);
			serializer = new PatternSerializer(formatters);
		} catch (final RuntimeException ex) {
			throw new IllegalArgumentException("Cannot parse pattern '" + pattern + "'", ex);
		}
	}

@ppkarwasz
Copy link
Contributor

@nielsm5,

Could you explain your use-case for the following assertion on the "not-in-closeable" key:

ThreadContext.clearMap();
try (final CloseableThreadContext.Instance c = CloseableThreadContext.put("inner", "one")) {
    ThreadContext.put("not-in-closeable", "true");
}
assertEquals("true", ThreadContext.get("not-in-closeable"));

The CloseableThreadContext contract does not specify how the original thread context must be restored, but only that it must be restored. So whether the "not-in-closeable" key is kept or restore to the original value is IMHO implementation specific.

@tnleeuw
Copy link

tnleeuw commented Oct 7, 2024

@ppkarwasz This is not a complete answer to your question but see my comment that I just added to the PR: #3050 (comment)

@vy
Copy link
Member

vy commented Oct 7, 2024

this pattern: "%level - %m - %throwable{1}"

@tnleeuw, %throwable, %ex, %exception are all synonyms referring to the same exception pattern converter. Starting with 2.25.0, exception handling will have some behavioral changes. In your particular case, %level - %m - %throwable{1} outputs

@tnleeuw
Copy link

tnleeuw commented Oct 7, 2024

this pattern: "%level - %m - %throwable{1}"

@tnleeuw, %throwable, %ex, %exception are all synonyms referring to the same exception pattern converter. Starting with 2.25.0, exception handling will have some behavioral changes. In your particular case, %level - %m - %throwable{1} outputs

I didn't even realize %ex was short for %exception and synonymous with %throwable -- makes sense of course, but I just didn't think of it when looking at it last week! 😳
Anyway this change is not consequential for us, we just need to be aware, and probably just add a .trim() to our test.

@nielsm5
Copy link
Author

nielsm5 commented Oct 7, 2024

@nielsm5,

Could you explain your use-case for the following assertion on the "not-in-closeable" key:

ThreadContext.clearMap();
try (final CloseableThreadContext.Instance c = CloseableThreadContext.put("inner", "one")) {
    ThreadContext.put("not-in-closeable", "true");
}
assertEquals("true", ThreadContext.get("not-in-closeable"));

The CloseableThreadContext contract does not specify how the original thread context must be restored, but only that it must be restored. So whether the "not-in-closeable" key is kept or restore to the original value is IMHO implementation specific.

I hear you, however this is how it's always worked up to version 24. I would expect this behavior to keep working as-is without Log4j2 suddenly introducing non-backwards-compatible/breaking changes.

@tnleeuw
Copy link

tnleeuw commented Oct 8, 2024

@sjoerdtalsma @Marcono1234 If you see this message, I am under the impression that your system also depends on Log4J2 ThreadContext behaviour as it was until Log4J2 2.23.1. Since the Log4J team is trying to understand if we genuinely have need / use-case for that behaviour, I would appreciate to hear what is your use-case and what breaks with the current Log4J 2.24.1 behaviour.

@ppkarwasz
Copy link
Contributor

ppkarwasz commented Oct 8, 2024

@sjoerdtalsma @Marcono1234 If you see this message, I am under the impression that your system also depends on Log4J2 ThreadContext behaviour as it was until Log4J2 2.23.1. Since the Log4J team is trying to understand if we genuinely have need / use-case for that behaviour, I would appreciate to hear what is your use-case and what breaks with the current Log4J 2.24.1 behaviour.

To be more precise the behavior in 2.24.0 and 2.24.1 is a bug in the ThreadContext.remove() and ThreadContext.removeAll() methods. We will address it regardless of this discussion.

What we are discussing here is the future of the Log4j API. @rgoers, plans to introduce a new tool called ScopedContext, which will work like this:

ScopedContext.where("foo", "bar").run(() -> some lambda);

This API will clear all the changes to the context data of the current thread once "some lambda" exits. You will be even allowed to add custom Objects to the context data or maps that will be converted to JSON, without the risk of memory leaks.

Once that is out, we don't exclude the possibility of deprecating ThreadContext. As far as I understand, this will break your use-case, right?

@tnleeuw
Copy link

tnleeuw commented Oct 8, 2024

If there is a way to get from current scope to outer scope, or root scope, then we can "walk that tree" and put things in the outer scope -- which will eventually be cleared, after the top-level process that runs on the thread exits.
That way there could be a structured way to propagate information up the log-context scope that we now wish to see in the log-context for the remainder of a process-execution.

I don't know what others in my team think about it.

@sjoerdtalsma
Copy link

sjoerdtalsma commented Oct 8, 2024

@sjoerdtalsma @Marcono1234 If you see this message, I am under the impression that your system also depends on Log4J2 ThreadContext behaviour as it was until Log4J2 2.23.1. Since the Log4J team is trying to understand if we genuinely have need / use-case for that behaviour, I would appreciate to hear what is your use-case and what breaks with the current Log4J 2.24.1 behaviour.

Hi, thanks for touching base.

Let me try to explain our use-case.

The purpose of our framework is propagating a snapshot consisting of one or more threadlocal states to a new thread.
For this we provide context-aware implementations of Runnable, Callable, CompletableFuture, ExecutorService, etc.
The framework is pluggable, meaning it will detect ContextManager implementations automatically to be included in the snapshot. One such ContextManager implementation for Log4J2 intends to propagate the logging context from the current thread to the snapshot.

The features our framework needs are:

  • capturing the state from the current thread
  • (temporarily) reactivating this state on another thread, ideally restoring the state to what it was before reactivating the snapshot by closing the reactivation.

I hope this makes some sense? Feel free to reach out if further questions exist.

@Marcono1234
Copy link

I hadn't investigated in depth why talsma-ict/context-propagation#484 respectively talsma-ict/context-propagation#491 failed; based on the Log4j 2 release notes I had assumed it is related to this issue here and suggested to wait for the fix.

But now after having looked a bit into this, it seems the failures might not be related to the issue here. Sorry for the confusion.

Instead #2374 seems to have caused a behavior change: In 2.23.1 and before it seems NoOpThreadContextMap was only used if the thread context map was explicitly disabled. Otherwise, even if no Log4j provider was found, a functional thread context map was used.
With the changes from #2374 if no provider is present, SimpleProvider is used and that uses NoOpThreadContextMap by default.

However, I am not sure if that has any noticeable effect on production applications because they most likely have a Log4j 2 provider on their classpath (probably log4j-core), or if not they are not using or don't care if ThreadContext is functional or not.

It was just the case that https://github.com/talsma-ict/context-propagation previously only had a log4j-api dependency, but was using ThreadContext in the unit tests and was expecting that it works (because talsma-ict/context-propagation is a library with integration for Log4j 2, but it does not actually use Log4j 2 for logging). The solution seems to be to simply add log4j-core as test scoped dependency, see talsma-ict/context-propagation#498.

@tnleeuw
Copy link

tnleeuw commented Oct 9, 2024

@sjoerdtalsma @Marcono1234 Thanks for getting back to us! We also do have some code that copies state from one thread to another including the Log4J2 ThreadContext, but at least as of 2.24.1 that part does not break.
For the rest it seems that our use-cases do not overlap.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
api Affects the public API bug Incorrect, unexpected, or unintended behavior of existing code
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants