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

StructuredLoggingJsonMembersCustomizer implementations declared in spring.factories with a generic type more specific than Object are not called #43312

Closed
quaff opened this issue Nov 28, 2024 · 5 comments
Assignees
Labels
type: bug A general bug
Milestone

Comments

@quaff
Copy link
Contributor

quaff commented Nov 28, 2024

package com.example;

import org.springframework.boot.json.JsonWriter.Members;
import org.springframework.boot.logging.structured.StructuredLoggingJsonMembersCustomizer;

public class MyCustomizer implements StructuredLoggingJsonMembersCustomizer<String> {

	@Override
	public void customize(Members<String> members) {
		members.add("test", "value");

	}

}
package com.example;

import static org.assertj.core.api.Assertions.assertThat;

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.system.CapturedOutput;
import org.springframework.boot.test.system.OutputCaptureExtension;

@SpringBootTest
@ExtendWith(OutputCaptureExtension.class)
public class MyCustomizerTests {

	@Test
	void test(CapturedOutput output) {
		assertThat(output).contains("{\"@timestamp\""); // structured logging is working
		assertThat(output).contains("\"test\":\"value\""); // MyCustomizer is working
	}
}

test failed with:

java.lang.AssertionError: 
Expecting actual:
  {"@timestamp":"2024-11-28T08:42:45.558754Z","log.level":"INFO","process.pid":71176,"process.thread.name":"main","log.logger":"com.example.MyCustomizerTests","message":"Starting MyCustomizerTests using Java 17.0.13 with PID 71176","ecs.version":"8.11"}
{"@timestamp":"2024-11-28T08:42:45.562533Z","log.level":"INFO","process.pid":71176,"process.thread.name":"main","log.logger":"com.example.MyCustomizerTests","message":"No active profile set, falling back to 1 default profile: \"default\"","ecs.version":"8.11"}
{"@timestamp":"2024-11-28T08:42:46.289631Z","log.level":"INFO","process.pid":71176,"process.thread.name":"main","log.logger":"com.example.MyCustomizerTests","message":"Started MyCustomizerTests in 0.939 seconds (process running for 1.622)","ecs.version":"8.11"}

to contain:
  ""test":"value"" 
	at com.example.MyCustomizerTests.test(MyCustomizerTests.java:18)
	at java.base/java.lang.reflect.Method.invoke(Method.java:569)
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)

Here is a reproducer project structured-logging.zip

@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged label Nov 28, 2024
@wilkinsona wilkinsona self-assigned this Nov 28, 2024
@wilkinsona
Copy link
Member

Thanks for the sample, @quaff. The problem's due to generics and the use of LambdaSafe to invoke the customizer. It will work if you change your customizer to implement StructuredLoggingJsonMembersCustomizer<Object>. The problem doesn't occur when using logging.structured.json.customizer to declare the customizer as StructuredLoggingJsonPropertiesJsonMembersCustomizer doesn't use LambdaSafe to invoke the customizer.

@wilkinsona wilkinsona changed the title StructuredLoggingJsonMembersCustomizer implementations in spring.factories are not used StructuredLoggingJsonMembersCustomizer implementations declared in spring.factories with a generic type more specific than Object are not called Nov 28, 2024
@wilkinsona wilkinsona added type: bug A general bug and removed status: waiting-for-triage An issue we've not yet triaged labels Nov 28, 2024
@wilkinsona wilkinsona modified the milestones: 3.4.x, 3.4.1 Nov 28, 2024
@quaff
Copy link
Contributor Author

quaff commented Nov 29, 2024

Is it by design that logging.structured.json.customizer doesn't accept multiple Customizers like spring.factories? @wilkinsona

@wilkinsona
Copy link
Member

Sorry, I don't remember. Do you, @philwebb or @mhalbritter?

@mhalbritter
Copy link
Contributor

No, sorry, I don't know.

@philwebb
Copy link
Member

It's not really by design as such. The StructuredLoggingJsonMembersCustomizer was quite a last minute addition and to save development time I just added support for a single customizer. I think the injection into StructuredLogFormatter constructors gets a bit more complex if we directly support a list.

I do think we could create a ComposteStructuredLoggingJsonMembersCustomizer pretty easily if we want to support lists.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: bug A general bug
Projects
None yet
Development

No branches or pull requests

5 participants