4 Ways to Diagnose the Bloomreach Delivery Tier
Saimir Muço
2020-02-17
Working with the HST delivery tier can be a lot of fun and you can leverage its full potential to build a highly reusable, flexible and extensible page model over your content. You can make use of sitemap, page and component configurations, workspace and inheritance configuration model but also more advanced configurations like multiple page mappings or enabling the page cache on specific URLs.
When all is in place, you’ll be dealing with the complexity of the configuration blocks coming together. Often after deploying, is not easy to keep under control the performance of the delivery tier.
Fortunately, the HST delivery comes with HST page diagnostics tooling to help you on the way. Here are some ways to diagnose your HST model.
Use HST diagnostics locally
The question - Which components contribute to the page I’m rendering - can quickly be answered by enabling the attribute hst:diagnosticsenabled. On the next request, the full page execution stack will be printed on the log file. Let's review a few interesting information details from it:
-
Sitemap information. It should look something like this:
|- Sitemap Matching (1ms): { sitemapitem=HstSiteMapItemService{ canonicalPath='/hst:myproject/hst:configurations/myproject/hst:sitemap/root', site=HstSiteService{ name='myproject', configurationPath='/hst:myproject/hst:configurations/myproject' } } }
-
The name of the pipeline executed for this request. For a standard page, it will be DefaultSitePipeline, for a plain REST resource will be JaxrsRestPlainPipeline, a resource will use ContainerResourcePipeline and so on. You can find all details in the Request processing and pipelines documentation page.
-
Targeting information if the module is configured to be used in your application
-
Page cache information. If the page cache is enabled (read more here) and the cached variant is served, PageCachingValve will be the last valve to get invoked.
-
List of calls to doPrepareBeforeRender methods on all the contributing components
-
List of calls to doBeforeRender methods. Here you’ll find the class names, window names and component id-s. If HST queries are executed or external CRISP resources are retrieved , you will find the details for the calls as well
|- HstComponentInvokerProfiler (9ms): {method=doBeforeRender, window=contentlist, component=org.onehippo.cms7.essentials.components.EssentialsListComponent, ref=r5_r1_r1, HippoBeanIterationCount=2}
| `- query (6ms): {statement=//*[(@hippo:paths='6142584f-3a68-465c-9cd7-6408957ac033') and (@hippo:availability='live') and not(@jcr:primaryType='nt:frozenNode') and ((@jcr:primaryType=myproject:contentdocument'))] order by @jcr:score descending }
|- HstComponentInvokerProfiler (1004ms): {method=doBeforeRender, window=Cart, component=com.bloomreach.commercedxp.starterstore.components.GenericCommandChainComponent, ref=r63_r1_r1_r6}
| |- com.bloomreach.commercedxp.starterstore.commands.cart.CartProductListCommand (105ms): {}
| | `- crispResResolver (44ms): {space=commercetools, op=resolve, verb=GET, sc=200, path=/carts/{cartId}, params={cartId=123}}
-
List of templates used to render each component. If there are HST queries executed during this phase, they will be printed as well
|- HstComponentInvokerProfiler (1011ms): {method=doRender, window=footer, component=org.onehippo.cms7.essentials.components.EssentialsMenuComponent, ref=r63_r3} | `- Dispatcher (1005ms): {dispatch=/freemarker/myproject/base-footer.ftl} | |- login (8ms): {} | |- login (14ms): {} | |- query (2ms): {statement=//element(*, resourcebundle:resourcebundle)[@resourcebundle:id='essentials.global' and hippo:availability='live'] order by @resourcebundle:id}
There is a lot more you can explore and figure out from a simple page execution with HST diagnostics. And it will save you a lot of time from navigating with the console or using the debugger.
Use HST diagnostics in a deployed environment
After successfully deploying the application, you probably want to test the page (rendering) performance.
HST diagnostics can be used herein two ways.
-
Enable diagnostics in the acceptance environment, execute load tests and produce logs for statistics. Then use analyzer tools like ELK, Humio or Splunk to aggregate statistics and create graphs.
-
Use HST diagnostics for slow pages. By setting a hst:diagnosticsthresholdmillisec value, you’ll get the details of the pages that take more than the threshold time to produce the response. Should you need to enable diagnostics in a live environment, make sure you use hst:diagnosticsforips to generate the logs only for requests coming from specific clients
Combine it with partial page rendering
Sometimes you might need to investigate the execution of a single component without creating a separate page configuration for it. The HST model provides support for partial page rendering. You can narrow down the subtree of the components that you want in the result and can bring it to the single component that you really want to focus on. The following example gets the execution details of the component /top/search:
14.11.2019 17:04:51 INFO http-nio-8080-exec-9 [DiagnosticReportingValve.logDiagnosticSummary:44] Diagnostic Summary:
- HstDelegateeFilterBean (63ms): {request=Request{ method='GET', scheme='http', host='localhost:8080', requestURI='/site/search./top/search', queryString='query=lorem'}}
|- Sitemap Matching (0ms): {}
`- Pipeline processing (63ms): {pipeline=DefaultSitePipeline}
|- Invoke Valve org.hippoecm.hst.core.container.InitializationValve (0ms): {}
|- Invoke Valve org.hippoecm.hst.core.container.CmsSecurityValve (0ms): {}
|- Invoke Valve org.hippoecm.hst.core.container.SecurityValve (0ms): {}
|- Invoke Valve org.hippoecm.hst.core.container.SubjectBasedSessionValve (0ms): {}
|- Invoke Valve org.hippoecm.hst.core.container.JCRSessionStatefulConcurrencyValve (0ms): {}
|- Invoke Valve org.hippoecm.hst.core.container.ContextResolvingValve (0ms): {}
|- Invoke Valve org.hippoecm.hst.core.container.LocalizationValve (49ms): {}
|- Invoke Valve org.hippoecm.hst.core.container.ActionValve (0ms): {}
|- Invoke Valve org.hippoecm.hst.core.container.ResourceServingValve (0ms): {}
|- Invoke Valve org.hippoecm.hst.core.container.PageInfoRenderingValve (0ms): {}
|- Invoke Valve org.hippoecm.hst.core.container.ESIPageInfoScanningValve (0ms): {}
|- Invoke Valve org.hippoecm.hst.core.container.PageCachingValve (0ms): {}
|- Invoke Valve org.hippoecm.hst.core.container.ComponentRenderingValve (0ms): {}
`- Invoke Valve org.hippoecm.hst.core.container.AggregationValve (14ms): {}
|- HstComponentInvokerProfiler (0ms): {method=doPrepareBeforeRender, window=search, component=org.onehippo.cms7.essentials.components.EssentialsSearchComponent, ref=r3_r3_r1}
|- HstComponentInvokerProfiler (3ms): {method=doBeforeRender, window=search, component=org.onehippo.cms7.essentials.components.EssentialsSearchComponent, ref=r3_r3_r1, HippoBeanIterationCount=2}
| `- query (1ms): {statement=//*[(@hippo:paths='6142584f-3a68-465c-9cd7-6408957ac033') and (@hippo:availability='live') and not(@jcr:primaryType='nt:frozenNode') and (jcr:contains(., 'lorem'))] order by @jcr:score descending }
`- HstComponentInvokerProfiler (1ms): {method=doRender, window=search, component=org.onehippo.cms7.essentials.components.EssentialsSearchComponent, ref=r3_r3_r1}
`- Dispatcher (1ms): {dispatch=/freemarker/hstdefault/search-box.ftl}
Get more with page model API
Partial page rendering can be very convenient to isolate a group of components or a single component and test the performance. However, it can be challenging to identify the path of the components hierarchy in order to reach the component. Think for example of the workspace components that are configured using the template composer.
In this case, you can enable and use the Page Model API. With only a few configuration changes, you can generate JSON responses with both configuration and content. The configuration part shows clearly the components hierarchy and will help to quickly build the navigation path to the desired component.
Combining the Page Model API with partial page rendering is naturally possible and can be used for example when you need to load-test only the component “before rendering” phase and exclude the “rendering” phase.
To conclude, please make sure to get the best from the out-of-the-box HST tools but in case this is not sufficient, you can still add your own diagnostics to the stack; refer to the documentation page on how to implement it. Ultimately, if you know of other ways of using the hst page diagnostics, I'd love to hear about it from you.