-
Notifications
You must be signed in to change notification settings - Fork 38.5k
Improve output from logging the map of request mappings [SPR-17450] #21982
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
Comments
Rossen Stoyanchev commented This has been given plenty of thought. The approach is documented on a wiki page but it's currently no linked to from the reference so it's not easy to find. The wiki mentions the case of request mappings. For further background, the request originated here, and the umbrella ticket for all changes is #21485. The full request mappings are logged at TRACE but as a map and not on individual lines. I suppose we could change the way the map is logged but that would also blow up the output, and unless you have wrapping on for the IDE console, which is off by default, it takes a lot of awkward scrolling left and right to get to a specific detail. The advantage of printing a map is that it doesn't overwhelm the output as a single line, and yet it's possible to search which is often needed anyway, and easy to copy the one line into an editor. I'm open to ideas for how to improve the debugging experience for request mappings, but simply dumping tens or potentially hundreds of lines with full method signatures and request mapping details at DEBUG, I'm afraid is not the best approach. It's worth pointing out the request mappings are available via
|
Gleb Tlaloc commented Thank you for the explanation. You're right. I can enable some logging by adding this to my DEV configuration. logging.level.org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping: "trace" But the quality of the result is still not the same as before. You already pointed it out. I have to scroll right now and need to search(!) for the information I want to know. Example: The log output changed from ... Mapped "{[/api/documents/{id}],methods=[GET],produces=[application/json]}" onto public myservice.document.DocumentDto myservice.document.read.ReadDocumentController.read(java.lang.String) ... to ... Mapped 1 handler method(s) for class myservice.document.read.ReadDocumentController: {public myservice.document.DocumentDto myservice.document.read.ReadDocumentController.read(java.lang.String)={[/api/documents/{id}],methods=[GET],produces=[application/json]}} The new log output is longer, as you mentioned. The only reason it is still understandable is because I prevent multiple mappings in controllers (whenever possible). If I would have multiple mappings within my controller it would be even more difficult to look for the information of interest. The previous log result puts the mapping almost at the beginning of the log message. I instantly can see that the endpoint The new logging puts information about the implementing component at the beginning of the log message. This results in the need to scroll right and is usually less interesting and only important if I need to take a deeper look into a specific mapping. The most typical questions (I usually face during development) that should be answered by this log output (as fast as possible):
Some ideas:
I think I understand the purpose of this change. You want to make the logs more clean. I totally support that, for production. But that doesn't have to mean that this rule must also apply for development. Maybe you can give the Liquibase team some tips, they just changed they logging to be more blathering, without the possibility to shut it down ;) As a result: Spring reduced their logging (unwanted for development) and Liquibase increased it (unwanted for production). Right now, this is what I don't like the most after upgrading to Spring Boot 2.1 and all the implied dependency upgrades. That is also a compliment, because (honestly) this is complaining on a high level ;) |
Gleb Tlaloc commented One more thing.The See yourself by enabling TRACE logging for these 2 components: logging.level.org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping: "trace"
logging.level.org.springframework.boot.actuate.endpoint.web.servlet.WebMvcEndpointHandlerMapping: "trace" This inconsistence could be cleaned up. Please have a look at this snipped. public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMapping implements InitializingBean {
[...]
public void registerMapping(T mapping, Object handler, Method method) {
if (logger.isTraceEnabled()) {
logger.trace("Register \"" + mapping + "\" to " + method.toGenericString());
}
this.mappingRegistry.register(mapping, handler, method);
}
[...]
protected void registerHandlerMethod(Object handler, Method method, T mapping) {
this.mappingRegistry.register(mapping, handler, method);
}
[...]
} These 2 methods do exactly the same, except one of them has no logging. Why can't For now I'm using a workaround. I've created a logger component to print a consistent log output by using But it still feels odd to create extra code because something is no longer done right (my opinion) by the framework. |
Rossen Stoyanchev commented
That's a Boot issue and there is a ticket already for it spring-projects/spring-boot#14292.
I can suggest reading the original request again but I'm sure you've done that. Development logging needs to be human friendly and not overwhelming. For example Spring Boot does a lot of tuning of log levels when devtools is present, and the levels varyi by project, in order to get a good out of the box dev experience. Consider that up until Spring Framework 5.1, Boot did not consider it feasible to set For the suggestions, we already log what you need at TRACE. I can however improve the output from the Map so that it looks like before with the mapping at the front. I don't think sending events makes much sense. All of this is readily available to applications to access at any time. |
Gleb Tlaloc commented
Exactly. As I see it, the way Spring MCV is doing it now, doesn't fulfill this requirements. To get some information during development (e.g the active request mappings for a single(!) moment after I startet the application), I have to change the log level to TRACE now, at least for specific components. Result:
Keep in mind that it is easier to clear the logs after the server has started to get rid of the "overwhelming" logs which was produced by the bootstrap procedure. But because of the initial log configuration I have more unnecessary log output during (dev) runtime. The funny thing is. You intended to reduce the noise. In reality (as least in my case): To get required information from the logs during dev, now I have to enable even more noise. So, what's the gain here? Conclusion: Now I have to enable a log level to see what I want in a way that is harder to understand as before. I'm also forced to see things I don't want or need because of that log level. I know this is all about opinions. It would be interesting how other developers see this new logging behavior. From my perspective: this change is not(!) helping. It make things worse. Before this change the request mapping was logged at INFO. Yes that was unnecessary. And to get rid of it, you don't just put it from the lobby to the basement. No, you put it deep underground. And to get to it I have to go through a lot more stuff now. |
Mark Jeffrey commented When I moved from JBoss to Spring Boot one of the many things I loved was that the mappings were output on startup! A minor thing but it saves a lot of frustration when developing a web app (and particularly when you go back to a project after some time). Today I had a 404 in a new Spring Boot 2.1 project. I checked the mappings and saw there were none! I assumed it was some new config parameter but after digging through the source code I found it was removed from AbstractHandlerMethodMapping on 18-June. Along with the listener port this is the most important startup output. The new output on trace is nowhere near as useful as the previous output (it is there but well hidden). For now I've reverted to Spring Boot 2.0 (at least during heavy development since we are targeting java 8). I would love to see this output restored (even as DEBUG it would be good). thanks, Mark |
Rossen Stoyanchev commented Mark Jeffrey, the key here is that mapping information becomes important when you are looking into a 404. I suspect that overall more time is spent developing the endpoints rather than changing mappings. And unlike the listener port, which is a simple int, mappings can easily overtake startup logging. Did you consider using the Boot Actuator endpoint for mappings? Most IDEs also support options for working with Spring MVC mappings. I'll consider improvements for the new output on trace soon. It's hidden compared to what you are used to seeing, but at the same time there are a lots of options for getting this information. |
Mark Jeffrey commented Rossen Stoyanchev Thanks for the reply. Indeed I checked in intellij and there is a possibility for seeing the endpoints in the Spring tab. Sorry to see the most useful logging in the SB startup go when some of the other logging is really useless (I realize that is a different project and I can turn it off). Examples of useless logging, for me most of this could go: 2018-11-08 16:16:11.151 INFO 14944 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2018-11-08 16:16:11.152 INFO 14944 --- [ main] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 2154 ms
2018-11-08 16:16:11.220 INFO 14944 --- [ main] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'characterEncodingFilter' to: [/*]
2018-11-08 16:16:11.222 INFO 14944 --- [ main] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'hiddenHttpMethodFilter' to: [/*]
2018-11-08 16:16:11.222 INFO 14944 --- [ main] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'formContentFilter' to: [/*]
2018-11-08 16:16:11.222 INFO 14944 --- [ main] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'requestContextFilter' to: [/*]
2018-11-08 16:16:11.223 INFO 14944 --- [ main] .s.DelegatingFilterProxyRegistrationBean : Mapping filter: 'springSecurityFilterChain' to: [/*]
2018-11-08 16:16:11.224 INFO 14944 --- [ main] o.s.b.w.servlet.ServletRegistrationBean : Servlet dispatcherServlet mapped to [/]
2018-11-08 16:16:11.389 INFO 14944 --- [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Starting...
2018-11-08 16:16:12.236 INFO 14944 --- [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Start completed.
2018-11-08 16:16:13.124 INFO 14944 --- [ main] liquibase.database.core.OracleDatabase : Could not set remarks reporting on OracleDatabase: com.zaxxer.hikari.pool.HikariProxyConnection.setRemarksReporting(boolean)
2018-11-08 16:16:13.196 INFO 14944 --- [ main] liquibase.database.core.OracleDatabase : Could not set check compatibility mode on OracleDatabase, assuming not running in any sort of compatibility mode: Cannot read from v$parameter: ORA-00942: table or view does not exist
2018-11-08 16:16:13.414 INFO 14944 --- [ main] liquibase.executor.jvm.JdbcExecutor : SELECT COUNT(*) FROM IBIS.DATABASECHANGELOGLOCK
2018-11-08 16:16:13.422 INFO 14944 --- [ main] liquibase.executor.jvm.JdbcExecutor : SELECT COUNT(*) FROM IBIS.DATABASECHANGELOGLOCK
2018-11-08 16:16:13.424 INFO 14944 --- [ main] liquibase.executor.jvm.JdbcExecutor : SELECT LOCKED FROM IBIS.DATABASECHANGELOGLOCK WHERE ID=1 FOR UPDATE
2018-11-08 16:16:13.440 INFO 14944 --- [ main] l.lockservice.StandardLockService : Successfully acquired change log lock
2018-11-08 16:16:14.134 INFO 14944 --- [ main] liquibase.executor.jvm.JdbcExecutor : SELECT MD5SUM FROM IBIS.DATABASECHANGELOG WHERE MD5SUM IS NOT NULL AND ROWNUM=1
2018-11-08 16:16:14.136 INFO 14944 --- [ main] liquibase.executor.jvm.JdbcExecutor : SELECT COUNT(*) FROM IBIS.DATABASECHANGELOG
2018-11-08 16:16:14.138 INFO 14944 --- [ main] l.c.StandardChangeLogHistoryService : Reading from IBIS.DATABASECHANGELOG
2018-11-08 16:16:14.138 INFO 14944 --- [ main] liquibase.executor.jvm.JdbcExecutor : SELECT * FROM IBIS.DATABASECHANGELOG ORDER BY DATEEXECUTED ASC, ORDEREXECUTED ASC
2018-11-08 16:16:14.158 INFO 14944 --- [ main] l.lockservice.StandardLockService : Successfully released change log lock
2018-11-08 16:16:14.302 INFO 14944 --- [ main] o.hibernate.jpa.internal.util.LogHelper : HHH000204: Processing PersistenceUnitInfo [
name: default
...]
2018-11-08 16:16:14.445 INFO 14944 --- [ main] org.hibernate.Version : HHH000412: Hibernate Core {5.3.7.Final}
2018-11-08 16:16:14.452 INFO 14944 --- [ main] org.hibernate.cfg.Environment : HHH000206: hibernate.properties not found
2018-11-08 16:16:14.662 INFO 14944 --- [ main] o.hibernate.annotations.common.Version : HCANN000001: Hibernate Commons Annotations {5.0.4.Final}
2018-11-08 16:16:14.849 INFO 14944 --- [ main] org.hibernate.dialect.Dialect : HHH000400: Using dialect: org.hibernate.dialect.Oracle12cDialect
2018-11-08 16:16:14.927 INFO 14944 --- [ main] o.h.e.j.e.i.LobCreatorBuilderImpl : HHH000421: Disabling contextual LOB creation as hibernate.jdbc.lob.non_contextual_creation is true
2018-11-08 16:16:14.934 INFO 14944 --- [ main] org.hibernate.type.BasicTypeRegistry : HHH000270: Type registration [byte[]] overrides previous : org.hibernate.type.BinaryType@38a38ed4
2018-11-08 16:16:14.935 INFO 14944 --- [ main] org.hibernate.type.BasicTypeRegistry : HHH000270: Type registration [[B] overrides previous : org.hibernate.type.BinaryType@38a38ed4
2018-11-08 16:16:14.936 INFO 14944 --- [ main] org.hibernate.type.BasicTypeRegistry : HHH000270: Type registration [Byte[]] overrides previous : org.hibernate.type.WrapperBinaryType@4bbf20d1
2018-11-08 16:16:14.936 INFO 14944 --- [ main] org.hibernate.type.BasicTypeRegistry : HHH000270: Type registration [[Ljava.lang.Byte;] overrides previous : org.hibernate.type.WrapperBinaryType@4bbf20d1
2018-11-08 16:16:15.936 INFO 14944 --- [ main] j.LocalContainerEntityManagerFactoryBean : Initialized JPA EntityManagerFactory for persistence unit 'default'
2018-11-08 16:16:17.244 INFO 14944 --- [ main] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor'
2018-11-08 16:16:17.629 INFO 14944 --- [ main] .i.w.c.BasicWebSecurityConfigurerAdapter : Content Security Policy: block-all-mixed-content; object-src 'none'; frame-src 'none'; default-src 'self'; img-src 'self' data:; style-src 'self'; connect-src 'self'
2018-11-08 16:16:17.686 INFO 14944 --- [ main] o.s.s.web.DefaultSecurityFilterChain : Creating filter chain: any request, [org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@411933, org.springframework.security.web.context.SecurityContextPersistenceFilter@5008559a, org.springframework.security.web.header.HeaderWriterFilter@f5f8de2, org.springframework.security.web.savedrequest.RequestCacheAwareFilter@490fbeaa, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@39c1e7b7, org.springframework.security.web.authentication.AnonymousAuthenticationFilter@393e7546, org.springframework.security.web.session.SessionManagementFilter@1002b06d, org.springframework.security.web.access.ExceptionTranslationFilter@68f264bf, org.springframework.security.web.access.intercept.FilterSecurityInterceptor@70ad0854] |
Rossen Stoyanchev commented Mark Jeffrey, indeed good logging takes extra thought, continuous feedback and multiple iterations. I'm afraid the quality of logging is often an afterthought. This is very much the spirit of the extensive improvements made to web logging in 5.1 to change that, and I welcome paying closer attention like the messages you've pointed out above. Most of the examples aren't in the Spring Framework. There is only the ContextLoader message with the startup time which I think is useful to know but debatable if the startup is already known. For the Boot servlet registrations, creating a ticket against Boot, for this and if you have others, would be the way to go (/cc Brian Clozel). I can see replacing the filter registration log statements with a single line that lists active filters and patterns, something like below, and the log level is also debatable:
For the others Boot does tweak logging for specific packages as far as I know, so they might be able to turn some of that noise down. |
Brian Clozel commented Thanks for the heads up rstoyanchev, I've created spring-boot#15166. |
Rossen Stoyanchev commented Below is sample output after the changes, based on these test controllers:
The output is tailored for request mapping purposes and aims to show only what's relevant for finding the method for a given request mapping. For example there is no need to show return type information in order to identify a method uniquely, and likewise there is no need to show full type information for method parameters. Indenting all logging information makes it easy to visually skip over it to subsequent log messages. Gleb Tlaloc this should meet one of your options, i.e.:
Let me know if you think anything is missing or could be added. |
Rossen Stoyanchev commented Resolving for now. |
Rossen Stoyanchev commented:
Which actuator endpoint lists all the service endpoints? I haven't found that info in documentation. |
Gleb Tlaloc opened SPR-17450 and commented
MVC mappings was automatically logged in previous releases of Spring MVC. This was removed in June 2018 for v5.1.0, see the commit. The change was titled as "Logging improvements for WebFlux". But frankly, I don't see any improvement in removing a valuable log command without any appropriate replacement.
This was removed from
o.s.w.s.h.AbstractHandlerMethodMapping.MappingRegistry.register(...)
:Even with log level TRACE, this information is no longer logged by any Spring component. During development this logs are a very good (and fast) information source to self-review the final configuration of HTTP mappings.
I couldn't find any documentation that explains this change.
Could you please do a review to assess if this change is intended? And if it is intended can you please publish some kind of documentation to explain what to do/use instead? Or, can you please consider to reenable this log again (at least on DEBUG level)?
Affects: 5.1.2
Reference URL: 28a5c30#diff-b91ebdcf6fba7c4886849e8144a7e687
Referenced from: commits c89e6c6
The text was updated successfully, but these errors were encountered: