logging-log4j2
logging-log4j2 copied to clipboard
New Feature: Add stacktrace package-name filtering for JsonTemplateLayout like it exists for PatternLayout
Hi, in PatternLayout, we are able to filter out certain package names from stacktraces by providing a list of package-names to filter, as documented in the patterns table for pattern layout:
%ex{filters("org.apache", "org.spring")}
In JsonTemplateLayout, there are a number of configuration options available for printing stacktraces, but I can't find a filtering option that allows me to filter out packages from stacktraces the same way that we're able to in PatternLayout. I am aware of the "truncation" configuration defined under the "exception"
section of the JsonTemplateLayout documentation, but this wouldn't work for my use case because I have interceptors defined in my code that are interspered in the stacktrace with the boilerplate "org.apache" stuff that I don't need to see. If I were to truncate the stacktrace after something like "org.apache", I would lose the knowledge of what interceptors were involved in a particular request before the exception occurred.
Below is an example of one such stacktrace where my own "com.mycompany" stacktrace lines are spread among other package names I would like to filter out:
Click me to expand stacktrace
2023-10-29 17:33:14.904 ERROR 86240 [nio-8080-exec-2][][] c.m.m.c.ExceptionHelper : Request: http://localhost:8080/myapi/doc/save raised exception: com.fasterxml.jackson.core.JsonParseException: Unexpected character ('[' (code 91)): was expecting a colon to separate field name and value
at [Source: (String)"{"items" "<rest of my json payload>"[truncated 12434 chars]; line: 1, column: 13]
at com.fasterxml.jackson.core.JsonParser._constructError(JsonParser.java:2391) ~[jackson-core-2.13.5.jar:2.13.5]
at com.fasterxml.jackson.core.base.ParserMinimalBase._reportError(ParserMinimalBase.java:735) ~[jackson-core-2.13.5.jar:2.13.5]
at com.fasterxml.jackson.core.base.ParserMinimalBase._reportUnexpectedChar(ParserMinimalBase.java:659) ~[jackson-core-2.13.5.jar:2.13.5]
at com.fasterxml.jackson.core.json.ReaderBasedJsonParser._skipColon2(ReaderBasedJsonParser.java:2309) ~[jackson-core-2.13.5.jar:2.13.5]
at com.fasterxml.jackson.core.json.ReaderBasedJsonParser._skipColon(ReaderBasedJsonParser.java:2288) ~[jackson-core-2.13.5.jar:2.13.5]
at com.fasterxml.jackson.core.json.ReaderBasedJsonParser.nextToken(ReaderBasedJsonParser.java:737) ~[jackson-core-2.13.5.jar:2.13.5]
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:177) ~[jackson-databind-2.13.5.jar:2.13.5]
at com.fasterxml.jackson.databind.deser.DefaultDeserializationContext.readRootValue(DefaultDeserializationContext.java:323) ~[jackson-databind-2.13.5.jar:2.13.5]
at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4674) ~[jackson-databind-2.13.5.jar:2.13.5]
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3629) ~[jackson-databind-2.13.5.jar:2.13.5]
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3597) ~[jackson-databind-2.13.5.jar:2.13.5]
at com.mycompany.myapi.controller.MyController.saveDoc(MyController.java:159) ~[classes/:?]
at com.mycompany.myapi.controller.MyController$$FastClassBySpringCGLIB$$d73ec01b.invoke(<generated>) ~[classes/:?]
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218) ~[spring-core-5.3.28.jar:5.3.28]
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:793) ~[spring-aop-5.3.28.jar:5.3.28]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) ~[spring-aop-5.3.28.jar:5.3.28]
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:763) ~[spring-aop-5.3.28.jar:5.3.28]
at org.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor.invoke(MethodBeforeAdviceInterceptor.java:58) ~[spring-aop-5.3.28.jar:5.3.28]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.28.jar:5.3.28]
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:763) ~[spring-aop-5.3.28.jar:5.3.28]
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97) ~[spring-aop-5.3.28.jar:5.3.28]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.28.jar:5.3.28]
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:763) ~[spring-aop-5.3.28.jar:5.3.28]
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:708) ~[spring-aop-5.3.28.jar:5.3.28]
at com.mycompany.myapi.controller.MyController$$EnhancerBySpringCGLIB$$5aa9ebd4.saveDoc(<generated>) ~[classes/:?]
at jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:?]
at jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:?]
at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:?]
at java.lang.reflect.Method.invoke(Method.java:566) ~[?:?]
at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205) ~[spring-web-5.3.28.jar:5.3.28]
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:150) ~[spring-web-5.3.28.jar:5.3.28]
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:117) ~[spring-webmvc-5.3.28.jar:5.3.28]
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:895) ~[spring-webmvc-5.3.28.jar:5.3.28]
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:808) ~[spring-webmvc-5.3.28.jar:5.3.28]
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) ~[spring-webmvc-5.3.28.jar:5.3.28]
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1072) ~[spring-webmvc-5.3.28.jar:5.3.28]
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:965) ~[spring-webmvc-5.3.28.jar:5.3.28]
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006) ~[spring-webmvc-5.3.28.jar:5.3.28]
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909) ~[spring-webmvc-5.3.28.jar:5.3.28]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:555) ~[tomcat-embed-core-9.0.76.jar:4.0.FR]
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883) ~[spring-webmvc-5.3.28.jar:5.3.28]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:623) ~[tomcat-embed-core-9.0.76.jar:4.0.FR]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:209) ~[tomcat-embed-core-9.0.76.jar:9.0.76]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:153) ~[tomcat-embed-core-9.0.76.jar:9.0.76]
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:51) ~[tomcat-embed-websocket-9.0.76.jar:9.0.76]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:178) ~[tomcat-embed-core-9.0.76.jar:9.0.76]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:153) ~[tomcat-embed-core-9.0.76.jar:9.0.76]
at com.mycompany.myapi.config.HttpRequestLoggingFilter.doFilterInternal(HttpRequestLoggingFilter.java:28) ~[classes/:?]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) ~[spring-web-5.3.28.jar:5.3.28]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:178) ~[tomcat-embed-core-9.0.76.jar:9.0.76]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:153) ~[tomcat-embed-core-9.0.76.jar:9.0.76]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:337) ~[spring-security-web-5.7.9.jar:5.7.9]
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:115) ~[spring-security-web-5.7.9.jar:5.7.9]
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:81) ~[spring-security-web-5.7.9.jar:5.7.9]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346) ~[spring-security-web-5.7.9.jar:5.7.9]
at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:122) ~[spring-security-web-5.7.9.jar:5.7.9]
at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:116) ~[spring-security-web-5.7.9.jar:5.7.9]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346) ~[spring-security-web-5.7.9.jar:5.7.9]
at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:126) ~[spring-security-web-5.7.9.jar:5.7.9]
at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:81) ~[spring-security-web-5.7.9.jar:5.7.9]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346) ~[spring-security-web-5.7.9.jar:5.7.9]
at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:109) ~[spring-security-web-5.7.9.jar:5.7.9]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346) ~[spring-security-web-5.7.9.jar:5.7.9]
at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:149) ~[spring-security-web-5.7.9.jar:5.7.9]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346) ~[spring-security-web-5.7.9.jar:5.7.9]
at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:63) ~[spring-security-web-5.7.9.jar:5.7.9]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346) ~[spring-security-web-5.7.9.jar:5.7.9]
at org.springframework.security.web.authentication.www.BasicAuthenticationFilter.doFilterInternal(BasicAuthenticationFilter.java:164) ~[spring-security-web-5.7.9.jar:5.7.9]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) ~[spring-web-5.3.28.jar:5.3.28]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346) ~[spring-security-web-5.7.9.jar:5.7.9]
at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:103) ~[spring-security-web-5.7.9.jar:5.7.9]
at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:89) ~[spring-security-web-5.7.9.jar:5.7.9]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346) ~[spring-security-web-5.7.9.jar:5.7.9]
at org.springframework.security.web.header.HeaderWriterFilter.doHeadersAfter(HeaderWriterFilter.java:90) ~[spring-security-web-5.7.9.jar:5.7.9]
at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:75) ~[spring-security-web-5.7.9.jar:5.7.9]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) ~[spring-web-5.3.28.jar:5.3.28]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346) ~[spring-security-web-5.7.9.jar:5.7.9]
at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:112) ~[spring-security-web-5.7.9.jar:5.7.9]
at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:82) ~[spring-security-web-5.7.9.jar:5.7.9]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346) ~[spring-security-web-5.7.9.jar:5.7.9]
at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:55) ~[spring-security-web-5.7.9.jar:5.7.9]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) ~[spring-web-5.3.28.jar:5.3.28]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346) ~[spring-security-web-5.7.9.jar:5.7.9]
at org.springframework.security.web.session.DisableEncodeUrlFilter.doFilterInternal(DisableEncodeUrlFilter.java:42) ~[spring-security-web-5.7.9.jar:5.7.9]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) ~[spring-web-5.3.28.jar:5.3.28]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:346) ~[spring-security-web-5.7.9.jar:5.7.9]
at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:221) ~[spring-security-web-5.7.9.jar:5.7.9]
at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:186) ~[spring-security-web-5.7.9.jar:5.7.9]
at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:354) ~[spring-web-5.3.28.jar:5.3.28]
at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:267) ~[spring-web-5.3.28.jar:5.3.28]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:178) ~[tomcat-embed-core-9.0.76.jar:9.0.76]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:153) ~[tomcat-embed-core-9.0.76.jar:9.0.76]
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) ~[spring-web-5.3.28.jar:5.3.28]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) ~[spring-web-5.3.28.jar:5.3.28]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:178) ~[tomcat-embed-core-9.0.76.jar:9.0.76]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:153) ~[tomcat-embed-core-9.0.76.jar:9.0.76]
at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) ~[spring-web-5.3.28.jar:5.3.28]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) ~[spring-web-5.3.28.jar:5.3.28]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:178) ~[tomcat-embed-core-9.0.76.jar:9.0.76]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:153) ~[tomcat-embed-core-9.0.76.jar:9.0.76]
at org.springframework.boot.actuate.metrics.web.servlet.WebMvcMetricsFilter.doFilterInternal(WebMvcMetricsFilter.java:96) ~[spring-boot-actuator-2.7.13.jar:2.7.13]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) ~[spring-web-5.3.28.jar:5.3.28]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:178) ~[tomcat-embed-core-9.0.76.jar:9.0.76]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:153) ~[tomcat-embed-core-9.0.76.jar:9.0.76]
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) ~[spring-web-5.3.28.jar:5.3.28]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) ~[spring-web-5.3.28.jar:5.3.28]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:178) ~[tomcat-embed-core-9.0.76.jar:9.0.76]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:153) ~[tomcat-embed-core-9.0.76.jar:9.0.76]
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:167) ~[tomcat-embed-core-9.0.76.jar:9.0.76]
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:90) ~[tomcat-embed-core-9.0.76.jar:9.0.76]
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:481) ~[tomcat-embed-core-9.0.76.jar:9.0.76]
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:130) ~[tomcat-embed-core-9.0.76.jar:9.0.76]
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:93) ~[tomcat-embed-core-9.0.76.jar:9.0.76]
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74) ~[tomcat-embed-core-9.0.76.jar:9.0.76]
at com.mycompany.myapi.config.StatusInterceptorValve.invoke(StatusInterceptorValve.java:32) ~[classes/:?]
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343) ~[tomcat-embed-core-9.0.76.jar:9.0.76]
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:390) ~[tomcat-embed-core-9.0.76.jar:9.0.76]
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:63) ~[tomcat-embed-core-9.0.76.jar:9.0.76]
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:926) ~[tomcat-embed-core-9.0.76.jar:9.0.76]
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1791) ~[tomcat-embed-core-9.0.76.jar:9.0.76]
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52) ~[tomcat-embed-core-9.0.76.jar:9.0.76]
at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191) ~[tomcat-embed-core-9.0.76.jar:9.0.76]
at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659) ~[tomcat-embed-core-9.0.76.jar:9.0.76]
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) ~[tomcat-embed-core-9.0.76.jar:9.0.76]
at java.lang.Thread.run(Thread.java:829) ~[?:?]
Assuming my understanding is correct that there is no stacktrace-package-filtering option available in JsonTemplateLayout like there is in PatternLayout, then I would like to add such a feature that could look like this:
Currently, to specify truncation, I would specify the following in my template-json file:
"stackTrace": {
"stringified": {
"truncation": {
"suffix": "... [truncated]",
"pointMatcherStrings": ["at javax.servlet.http.HttpServlet.service"]
}
}
}
To add stacktrace filtering to this configuration, I was thinking the easiest would be to have a separate block like this:
"stackTrace": {
"stringified": {
"filtered": {
"packagesToExclude": [
"org.apache",
"org.spring",
"jdk."
]
}
}
}
If someone specified both truncation and filtering, we can throw an error so the developer picks one to use for processing their stacktraces. Then we can add in the logic for the "filtered" Resolver to a new Java file like we have for the stacktrace truncation stuff in StackTraceStringResolver.java.
I hope that makes sense. Assuming this could be approved, I can work on making a PR for this in the near future. 👍
@takanuva15, sounds reasonable to me. I think both package exclusions and point matchers can coexist, there is no need to throw an exception when they do. Please take the following implementation notes into account:
- You need to update
StackTraceStringResolver
. - You need to refactor the current
STSR#truncate(TruncatingBufferedPrintWriter,TruncatingBufferedPrintWriter,CharSequencePointer)
into two methods: one for point matchers, one for package exclusions. - Since point matchers and package exclusions will coexist, you need an order. Please do the truncation using point matchers first.
- Introduce
packageExclusionPrefixes
(containing an array of package name prefixes that will be matched against) andpackageExclusionRegexes
directives - Note that stringified stack traces and their truncation operate in totally different ways between
PatternLayout
andJsonTemplateLayout
. JTL first renders the stack trace usingThrowable#printStackTrace(PrintWriter)
into a mutableCharSequence
and then truncates it. This is of crucial importance, since it enables cheap (almost garbage-free?) stack trace rendering. Hence, no allocations, please. - Please try to adopt the existing coding style.
- Don't forget to add
final
modifiers wherever possible. - Don't forget to add a
src/changelog/add-package-exclusion-to-jtl.xml
. - Don't forget to update
json-template-layout.adoc
- Don't forget to update the
ExceptionResolver
javadoc (this one and AsciiDoc one should match) - Add your tests to
StackTraceStringResolverTest
. (Please adhere to the grouping implemented by comment blocks there.)
You can find me on Slack if you need help. Thanks in advance and good luck! :muscle:
@vy I tried accessing the Slack link but it says I don't have an account. Is there an account request-form somewhere that I need to submit?
Question:
- Is using
String.format(...)
considered an allocation? - I keep getting
java: plug-in not found: ErrorProne
when running the junit test even though I'm using the latest IntelliJ?
@vy I tried accessing the Slack link but it says I don't have an account. Is there an account request-form somewhere that I need to submit?
@takanuva15, I think you're right. I guess that is exclusive to ASF members. :disappointed: Let me know if you any suggestions on a particular medium for chat.
- Is using
String.format(...)
considered an allocation?
Yes.
- I keep getting
java: plug-in not found: ErrorProne
when running the junit test even though I'm using the latest IntelliJ?
Try removing all "Override compiler parameters per-module" entries in "Settings > Build, Execution, Deployment > Compiler > Java Compiler". Sadly I am the one and only one in the entire Log4j crew who thinks tests should be able to run in an IDE. The rest thinks this is not necessary and they are fine with attaching their IDE to ./mvnw -Dmaven.surefire.debug
process. :face_exhaling: If the aforementioned IntelliJ trick doesn't work for you, try the following:
- Make sure you installed everything in the
2.x
branch:./mvnw install -DskipTests
- After making a change to the JTL code, install your changes:
./mvnw install -pl :log4j-layout-template-json -DskipTests
- Run all tests:
./mvnw test -pl :log4j-layout-template-json-test
- Run a particular test
./mvnw test -pl :log4j-layout-template-json-test -Dtest=FooBarTest
You can connect your IDE to a ./mvnw test
run by
- Add
-Dmaven.surefire.debug
to the./mvnw test
command - Use "Run > Attach to process" in IntelliJ
@takanuva15, I think you're right. I guess that is exclusive to ASF members. 😞 Let me know if you any suggestions on a particular medium for chat.
I worked on a different open-source project a few years ago and the guy I was working with pointed to me a cool open-source chat protocol called matrix. Not sure if you've heard of it before, but it's basically like iMessage, WhatsApp, etc. with 1-1 and group chats, but the chat protocol is open so anyone can develop a client for it as long as it understands the Matrix protocol. I already have an existing account on there as @takanuva15:matrix.org
, so if you're inclined to give it a shot, you should be able to download any of the compatible clients available and message my username.
Try removing all "Override compiler parameters per-module" entries in "Settings > Build, Execution, Deployment > Compiler > Java Compiler".
This fix worked in my IntelliJ! Whoooo I can debug my code now!!! Would it be fine to update the BUILDING.md file in my future PR with this tidbit you just shared?
I worked on a different open-source project a few years ago and the guy I was working with pointed to me a cool open-source chat protocol called matrix. Not sure if you've heard of it before, but it's basically like iMessage, WhatsApp, etc. with 1-1 and group chats, but the chat protocol is open so anyone can develop a client for it as long as it understands the Matrix protocol. I already have an existing account on there as
@takanuva15:matrix.org
, so if you're inclined to give it a shot, you should be able to download any of the compatible clients available and message my username.
Sent you a message from @yazicivo:matrix.org
.
This fix worked in my IntelliJ! Whoooo I can debug my code now!!! Would it be fine to update the BUILDING.md file in my future PR with this tidbit you just shared?
Updated build instructions in a31ea22a75ec4c57ed55249cb13fa4629454f12b.
Hi, a few additional questions:
- You mentioned that I should "refactor the current
STSR#truncate
" method into two methods, where I do truncation first and then package exclusions. In terms of implementation, what I currently have working is:- run package truncation on
srcWriter
intodstWriter
- copy the truncation output from
dstWriter
back tosrcWriter
- run package exclusion on
srcWriter
intodstWriter
- run package truncation on
Does this sound like the correct sequence of events for the implementation?
- For the
StackTraceStringResolverTest
, can I define test json-templates in json files undersrc/test/resources
instead of repeating the deeply-nestedasMap(...)
calls? - For the
StackTraceStringResolverTest
, can we split the@Nested
test classes into separate files and group them all in a subpackage (eglayout.template.json.resolver.stacktracestring
)? The current test class is getting close to 1000 lines with my new tests and the class is starting to look like spaghetti code 😸
You mentioned that I should "refactor the current
STSR#truncate
" method into two methods, where I do truncation first and then package exclusions. In terms of implementation, what I currently have working is:
- run package truncation on
srcWriter
intodstWriter
- copy the truncation output from
dstWriter
back tosrcWriter
- run package exclusion on
srcWriter
intodstWriter
Does this sound like the correct sequence of events for the implementation?
Yes. Please add necessary branching to avoid the buffer copying if there are no package exclusions.
- For the
StackTraceStringResolverTest
, can I define test json-templates in json files undersrc/test/resources
instead of repeating the deeply-nestedasMap(...)
calls?
I would not stop your from doing it, but I like self-contained tests. As can be seen in log4j-core-test
, placing test resources to src/test/resources
is a slippery slope that eventually leads to a waste land of files where it is not possible to trace back who uses what for which purpose. Not to mention, it adds to the cognitive load while troubleshooting too.
If you insist on using src/test/resources
, please only place your JSON templates there. That is, don't place a Log4j configuration and use that to bootstrap a fully-fledged LoggerContext
. They are expensive, they pollute the JVM and obstruct test parallelization. Please only create a JsonTemplateLayout
instance and test its rendering.
- For the
StackTraceStringResolverTest
, can we split the@Nested
test classes into separate files and group them all in a subpackage (eglayout.template.json.resolver.stacktracestring
)? The current test class is getting close to 1000 lines with my new tests and the class is starting to look like spaghetti code 😸
Okay. Use stacktrace.string
please, we will need a stacktrace.object
in the future.
Hello, Any ETA on this enhancement? Would really love to have this released
@abhijit911turbo It's still under development on my fork; been distracted with other things that life has thrown on me lol. No definite ETA I can give you at this point
@abhijit911turbo, @takanuva15, sorry to break it to you, but if you need this feature from Log4j, which I presume is deployed at an organization helping you to pay your bills at the end of the month, you can always contract one of the maintainers. I can understand the motivation behind "waiting until someone magically makes it happen", but, honestly, paying a couple of bucks instead if waiting is a win-win from many perspectives.