Debugging package
The Core module comes equipped with several classes to troubleshoot and debug your Magnolia instance. This page covers each of these classes and explains how you can use them.
Servlet filters intercept and process requests or responses. They can do this either before the requests are sent to servlets or before the servlets send the responses back to clients. The Servlets filter chain defines the order in which filters are applied.
Always use caution when placing a filter in the chain manually and keep in mind that position in the chain matters. Depending on what you are trying to debug you may need to use a filter many times or even move it to different positions within the chain.
Never place a filter before the ContextFilter. Doing so will break your filter chain, generating a system failure in the Magnolia instance. |
In recent Java versions, you can enable the Java Flight Recorder (JFR), a light recording feature (consuming about 1% of CPU processing) to record all your system’s events into a file, which you can download and analyze later.
|
Enabling filters
The general procedure for enabling filters is as follows.
-
Download the filter.
-
Call tracking filter download link: config.server.filters.callTrackingFilter.xml
-
Dump headers filter download link: config.server.filters.dumpHeaders.xml
-
Performance test filter download link: config.server.filters.performanceTestFilter.xml
-
Session debugger filter download link: config.server.filters.sessionDebugger.xml
-
-
To enable a filter follow the steps below.
-
Open the Configuration app and click the node:
/server/filters
. -
From the Action bar, click
Import
.The filter appears at the bottom of the chain.
-
Drag (or move) the filter into position.
-
Enable the filter by changing the
enabled
property totrue
.
-
Disabling filters
To disable a filter:
-
Open the Configuration app and click the node:
/server/filters
. -
Select the filter you want to disable
-
Change the
enabled
property tofalse
. -
(Optional) Move the filter back down to the bottom of the chain.
Filters
Call tracking
class: info.magnolia.debug.CallTrackingFilter
This filter logs everything from the TrackingStatus
.
Usage
Sometimes, when debugging code, you might need to track the number of calls made to method executed deep down in the hierarchy on a per-request basis. Analyzing this with profiler can be cumbersome. While it’s straightforward to see the total time required for complete operations, you might need to see what each request thread was executing and how long that took. To get that data, this filter analyzes the stacktrace and provides aggregated information about the call hierarchy.
Like the other filters in this package, you need to enable the CallTrackingFilter
in the filter chain.
You also need to call the track()
method at the place where you want to see aggregated info from all the invocations.
Finally, here is an example output that shows the aggregated stacktrace from all invocations including counts of each execution path. With this information in hand, you can find (and hopefully fix) excessive calls.
Click to show the stacktrace
...
INFO info.magnolia.debug:
/magnoliaAuthor/demo-project.html:inits: 54, total calls: 14714, total time: 191947000
14714;info.magnolia.debug.TrackingStatus.track(TrackingStatus.java:82)
14714;info.magnolia.cms.util.SimpleUrlPattern.match(SimpleUrlPattern.java:212)
4;info.magnolia.voting.voters.URIPatternVoter.boolVote(URIPatternVoter.java:60)
...
4;info.magnolia.cms.beans.config.DefaultVirtualURIMapping.mapURI(DefaultVirtualURIMapping.java:56)
14706;info.magnolia.cms.security.PermissionImpl.match(PermissionImpl.java:89)
4;info.magnolia.voting.voters.AbstractBoolVoter.vote(AbstractBoolVoter.java:62)
4;info.magnolia.cms.beans.config.VirtualURIManager.getURIMapping(VirtualURIManager.java:107)
14706;info.magnolia.cms.security.AccessManagerImpl.getPermissions(AccessManagerImpl.java:87)
4;info.magnolia.cms.filters.VirtualUriFilter.getURIMapping(VirtualUriFilter.java:100)
14706;info.magnolia.cms.security.AccessManagerImpl.isGranted(AccessManagerImpl.java:64)
4;info.magnolia.voting.DefaultVoting.vote(DefaultVoting.java:56)
14706;info.magnolia.cms.core.Access.isGranted(Access.java:63)
4;info.magnolia.cms.filters.AbstractMgnlFilter.bypasses(AbstractMgnlFilter.java:121)
4;info.magnolia.cms.filters.VirtualUriFilter.doFilter(VirtualUriFilter.java:66)
...
3742;info.magnolia.cms.core.DefaultHierarchyManager.isGranted(DefaultHierarchyManager.java:422)
4;info.magnolia.cms.filters.AbstractMgnlFilter.doFilter(AbstractMgnlFilter.java:88)
47;info.magnolia.cms.core.DefaultHierarchyManager.isExist(DefaultHierarchyManager.java:396)
4;info.magnolia.cms.filters.AbstractMgnlFilter.matches(AbstractMgnlFilter.java:94)
10915;info.magnolia.cms.core.DefaultContent.newNodeDataInstance(DefaultContent.java:229)
2;info.magnolia.cms.security.URISecurityFilter.isAuthorized(URISecurityFilter.java:98)
2;info.magnolia.cms.security.URISecurityFilter.isAllowed(URISecurityFilter.java:82)
4;info.magnolia.cms.filters.MgnlFilterChain.doFilter(MgnlFilterChain.java:81)
246;info.magnolia.cms.core.DefaultContent.(DefaultContent.java:126)
4;info.magnolia.cms.filters.MgnlFilterChain.doFilter(MgnlFilterChain.java:82)
...
Removal
If the filter is no longer needed, it’s a good idea to remove it or at least turn it off so that it stops logging.
Since every request produces an output, the log can grow quickly. |
The best thing to do is to disable the filter. This way if you need it again in the future, you can turn it back on.
Derby test persistence manager
class: info.magnolia.debug.DerbyTestPersistenceManager
The persistence manager implementation measures the time spent saving data.
You must also enable the PerformanceTestFilter
.
While this specific implementation is intended for the Derby database, it should be quite straightforward to create an implementation for any other database. |
Deployment
To deploy this class:
-
Create a new repository configuration which uses the test persistence manager. Here is an example:
jackrabbit-bundle-derby-test-search.xml<PersistenceManager class="info.magnolia.debug.DerbyTestPersistenceManager"> <param name="url" value="jdbc:derby:${wsp.home}/db;create=true" /> <param name="schemaObjectPrefix" value="${wsp.name}_" /> </PersistenceManager>
-
In your properties file, update the JR configuration to point to the test configuration.
magnolia.repositories.home=${magnolia.home}/repositories-test magnolia.repositories.jackrabbit.config=WEB-INF/config/repo-conf/jackrabbit-bundle-derby-test-search.xml
-
Start up the instance and let it create a new test repository.
-
Configure the
PerformanceTestFilter
behind the context filter (see the instructions below).You need the
PerformanceTestFilter
because this is the filter that prints the time data to the standard log. The time data is stored in aPerformanceTestStatus
object.
Usage
The point of this class is to examine how long it takes to persist (store) data.
It’s not a good idea to use an embedded database in a production environment. The embedded database has to share memory with the application. |
Let’s look at an example where you upload a large file (100M+) into the DAM to measure the time it takes to persist it.
Create a new asset in the DAM and upload the new file in the detail subapp.
Once you click Save, you should see some information printed to the standard log through the PerformanceTestFilter
.
The times are in milliseconds.
INFO info.magnolia.debug : /magnoliaAuthor/.magnolia/admincentral/UIDL/ : performanceTestFilter: 2092, pm-store: 680, pm-blob: 670
Removal
Once the test is complete, revert to your repository.
-
In your properties file, update the JR configuration to point to the original configuration.
magnolia.repositories.home=${magnolia.home}/repositories magnolia.repositories.jackrabbit.config=WEB-INF/config/repo-conf/jackrabbit-bundle-derby-search.xml
Dump headers
class: info.magnolia.debug.DumpHeadersFilter
This filter dumps the headers for the request and the response.
Usage
The point of the DumpHeadersFilter
is to print header information for each request and response to the standard log.
This can be helpful for examining requests and their origin, especially when the request passes through other servers before arriving in Magnolia.
On the response side of things, double check that a specific header is being set before leaving Magnolia.
Let’s look at a specific example of deploying to filter at the top of the chain. This is probably the most common use case of the filter.
You must place the filter near the top of the chain right behind the context filter. Never place the filter above context because this would break the system.
Once the filter is deployed, you can begin examining the requests. The request doesn’t need to be for a website.
Remember that all requests, even those for the Admincentral, go through the filter chain. This means any request could be examined and (with this filter deployed) all requests will produce output in the log.
An example of requesting the Travel Home page.
Click to show the example
Each request has a number associated with it.
This way you can match the request to the response.
In the example below, that number is 8 .
|
# Request
INFO info.magnolia.debug : 8 uri: /magnoliaPublic/travel.html
INFO info.magnolia.debug : 8 session: true
INFO info.magnolia.debug : 8 parameters:
INFO info.magnolia.debug : 8 method: GET
INFO info.magnolia.debug : 8 header: host=localhost:8080
INFO info.magnolia.debug : 8 header: connection=keep-alive
INFO info.magnolia.debug : 8 header: cache-control=max-age=0
INFO info.magnolia.debug : 8 header: upgrade-insecure-requests=1
INFO info.magnolia.debug : 8 header: user-agent=Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36 OPR/60.0.3255.160
INFO info.magnolia.debug : 8 header: accept=text/html,application/xhtml-xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
INFO info.magnolia.debug : 8 header: accept-encoding=gzip, deflate, br
INFO info.magnolia.debug : 8 header: accept-language=en-US,en;q=0.9
INFO info.magnolia.debug : 8 header: cookie=JSESSIONID=214520A11DA4335D81735380B0BA06F8; _first_pageview=1; _jsuid=4186500974; no_tracky_100843699=1
# Response
INFO info.magnolia.debug : 8 response status: 200
INFO info.magnolia.debug : 8 response length: 5483
INFO info.magnolia.debug : 8 response mime type: text/html;charset=UTF-8
INFO info.magnolia.debug : /magnoliaPublic/travel.html response: X-Magnolia-Registration = Registered
Removal
After using the filter, it’s a good idea to remove it or at least turn it off so that it stops logging. Every request produces an output and the log could grow quickly.
Probably the best thing to do is disable the filter. This way if you need it again in the future, you can turn it back on. |
Logging response
class: info.magnolia.debug.LoggingResponse
This class wraps a response and records the set headers and http status for debugging purposes.
Performance test
class: info.magnolia.debug.PerformanceTestFilter
The point of this filter is to log the round-trip time it takes to fulfill the requests.
The filter logs the data recorded by the PerformanceTestStatus
class to the standard output, providing more details about the system’s performance in milliseconds.
Usage
To use the filter, you need to decide where to place it in the filter chain.
In the standard output below, the filter was the second filter in the chain (after the context
filter).
Everything below the filter is included in the time measurement, and so, in this case, it is about the total time to fulfill the request.
INFO info.magnolia.debug : /magnoliaPublic/travel.html : performanceTestFilter: 154
Sometimes, you should move this filter down the chain.
For example, putting it just before the cms
subchain tells you how long it takes to render a specific request.
Again, the time is printed to the standard output in milliseconds.
Removal
When not using the filter, it’s a good idea to remove it or at least turn it off so that it stops logging. Every request produces some output and the log can therefore grow fast.
The best thing to do is to disable the filter. This way if you need it again in the future, you can turn it back on. |
Session debugger
class: info.magnolia.debug.SessionDebugger
This is a filter and listener that can help to debug session issues.
Usage
The point of this filter is to log session information.
Configure it behind the context
filter to see all session data in the log.
Click to see an example output
WARN info.magnolia.debug : -- Session found
-- Session attributes :
com.vaadin.server.VaadinSession.AdminCentral = com.vaadin.server.VaadinSession@1ea60cc1
Key[type=info.magnolia.personalization.trait.storage.StorageAwareTraitCollector$SessionScopedTraitStorage, annotation=[none]] = info.magnolia.personalization.trait.storage.StorageAwareTraitCollector$SessionScopedTraitStorage@1d4950db
AdminCentral.lock = java.util.concurrent.locks.ReentrantLock@2f872e69[Unlocked]
javax.security.auth.Subject = Subject:
Principal: MgnlUser - superuser [51ae3379-67cf-4994-9e05-f97cb8bc3e4a]
Principal: info.magnolia.cms.security.Realm$RealmImpl@179a1
Principal: RoleListImpl[name=roles,list=[workflow-base, rest-admin, publisher, superuser]]
Principal: GroupListImpl[name=groups,list=[publishers]]
Principal: PrincipalCollectionImpl[name=PrincipalCollection]
-- Session is new : false
----------