Multi-tenancy, Spring boot & Javamelody

121 views
Skip to first unread message

Mamon Masod

unread,
Mar 24, 2021, 6:47:37 PM3/24/21
to javamelody
Hi,
I'm having an issue while integrating javamelody with multi-tenancy architecture.
I found that javamelody sets the http request name as same as the dispatcher-servlet & Mapping-handler best-match-pattern.
but I need to distinguish the http request from one Tenant to another,
I couldn't find a way to amend the request name without having side effects, like changing the Http Servlet Request Attribute ("org.springframework.web.servlet.HandlerMapping.bestMatchingPattern"). but of course it's not a good idea.
so I need a way to add the tenant Id to the request name, or any other way to distinguish http requests.

Thanks in advance 

Mamon Masod

unread,
Mar 28, 2021, 7:31:45 PM3/28/21
to javamelody
Hello all,
in case my description above isn't clear,
I have a multi-tenant architecture (SaaS), which means that my app could be used by multiple tenants and I must know each request is made by which tenant,   
so I need to get Javamelody's reports by tenant-level.
I tried many solutions to change Javamelody's request name to include a unique text for each tenant, like "tenant-{tenantId}"), then I would be able to get all http request made by a specific tenant. 
for example I tried to create many mappings for the dispatcher servlet, one mapping for each tenant, but that didn't help because Javamelody is getting the http request name after the dispatcher servlet does it's work and specifies the best matched controller & method.
if I can force Javamelody to consider the dispatcher servlet name in the http request name that would be great, or any other way I can control the Javamelody's http request name through it.
thanks a lot.

evernat

unread,
Mar 28, 2021, 8:01:35 PM3/28/21
to javamelody
Hi Mamon,

You can override the "protected String getRequestName(HttpServletRequest request)" method of the javamelody MonitoringFilter.
For example:
public class MultiTenantMonitoringFilter extends MonitoringFilter {
   @Override
   protected String getRequestName(HttpServletRequest request){
      return "tenant-" + getCurrentTenantId() + ' ' + super.getRequestName(request);
   }
}

If you use the javamelody spring boot starter, you can use your MultiTenantMonitoringFilter instead of the MonitoringFilter by adding a method like the following in your application configuration:

    @Bean(name = JavaMelodyAutoConfiguration.REGISTRATION_BEAN_NAME)
    public FilterRegistrationBean<MonitoringFilter> monitoringFilter(
            JavaMelodyConfigurationProperties properties, ServletContext servletContext) {
        final FilterRegistrationBean<MonitoringFilter> registrationBean = new FilterRegistrationBean<>();

        // Create the monitoring filter and set its configuration parameters.
        final MonitoringFilter filter;
        if (properties.isManagementEndpointMonitoringEnabled()) {
            // if the management endpoint is enabled, disable the /monitoring reports on the application port
            filter = new MultiTenantMonitoringFilter() {
                @Override
                protected boolean isAllowed(HttpServletRequest request,
                        HttpServletResponse response) throws IOException {
                    response.sendError(HttpServletResponse.SC_FORBIDDEN, "Forbidden access");
                    return false;
                }
            };
        } else {
// use your multi-tenant MonitoringFilter
            filter = new MultiTenantMonitoringFilter();
        }
        filter.setApplicationType("Spring Boot");

        // Wrap the monitoring filter in the registration bean.
        registrationBean.setFilter(filter);
        registrationBean.setAsyncSupported(true);
        registrationBean.setName("javamelody");
        registrationBean.setDispatcherTypes(DispatcherType.REQUEST, DispatcherType.ASYNC);

        // Set the initialization parameter for the monitoring filter.
        for (final Entry<String, String> parameter : properties.getInitParameters().entrySet()) {
            registrationBean.addInitParameter(parameter.getKey(), parameter.getValue());
        }

        // Set the URL patterns to activate the monitoring filter for.
        registrationBean.addUrlPatterns("/*");

        final FilterRegistration filterRegistration = servletContext
                .getFilterRegistration("javamelody");
        if (filterRegistration != null) {
            // if webapp deployed as war in a container with MonitoringFilter already added by web-fragment.xml,
            // do not try to add it again
            registrationBean.setEnabled(false);
            for (final Map.Entry<String, String> entry : registrationBean.getInitParameters()
                    .entrySet()) {
                filterRegistration.setInitParameter(entry.getKey(), entry.getValue());
            }
        }
        return registrationBean;
    }

bye,
Emeric

Mamon Masod

unread,
Mar 29, 2021, 7:48:08 AM3/29/21
to javamelody
Hi  Emeric ,
Actually I tried that before, but it didn't work, but now I could make it works because of ' ', I found that the trick is in the space character ' ',
so thank you so much.
please I need to a couple of things also,
1. in case of war deployment, the Javamelody configuration is being taken from the Javamelody core dependency, how can I override it to take my new  MultiTenantMonitoringFilter in consideration .
2. can I aggregate some stats based on Http Request Name Like('%some text%') when generating reports?

Thanks again
Reply all
Reply to author
Forward
0 new messages