spring-boot-data-source-decorator icon indicating copy to clipboard operation
spring-boot-data-source-decorator copied to clipboard

Allow specifying timeunit for datasource-proxy

Open anton-tkachenko opened this issue 2 years ago • 1 comments

Current implementation of decoratpr hard-codes timeunit as seconds (in ProxyDataSourceBuilderConfigurer)

I want time-unit to be milliseconds (so that to log queries slower than 500 ms, for instance)

The only way I can do it now - is by subclassing/overriding ProxyDataSourceBuilderConfigurer bean in context, and I don't like it

I'd love to have one more property -

decorator.datasource.datasource-proxy.slow-query.timeunit=milliseconds // default seconds for compatibility

and then to specify threshold in ms

decorator.datasource.datasource-proxy.slow-query.threshold=500

And here is my hacky hack for overriding ->

@Configuration
public class ProxyDataSourceBuilderConfigurerOverrideConfig {

    // not mandatory, but it's better to unregister default bean
    @Autowired
    void unregisterLibraryBean(ConfigurableBeanFactory beanFactory) {
        ((BeanDefinitionRegistry) beanFactory).removeBeanDefinition("proxyDataSourceBuilderConfigurer");
    }

    @Bean
    @Primary
    public ProxyDataSourceBuilderConfigurer milliProxyDataSourceBuilderConfigurer() {
        return new ProxyDataSourceBuilderConfigurerMillisOverride();
    }

    /**
     * Whole purpose of this class is to replace SECONDS with MILLISECONDS
     *
     * everything else is copy-paste from {@link ProxyDataSourceBuilderConfigurer}
     */
    private static class ProxyDataSourceBuilderConfigurerMillisOverride extends ProxyDataSourceBuilderConfigurer {

        @Override
        public void configure(ProxyDataSourceBuilder proxyDataSourceBuilder, DataSourceProxyProperties datasourceProxy) {
            super.configure(proxyDataSourceBuilder, datasourceProxy);
            if (datasourceProxy.getLogging() == SLF4J && datasourceProxy.getSlowQuery().isEnableLogging()) {
                proxyDataSourceBuilder.logSlowQueryBySlf4j(
                        datasourceProxy.getSlowQuery().getThreshold(),
                        // this is actual change for parent class
                        TimeUnit.MILLISECONDS,
                        toSlf4JLogLevel(datasourceProxy.getSlowQuery().getLogLevel()),
                        datasourceProxy.getSlowQuery().getLoggerName());
            }
        }

        private SLF4JLogLevel toSlf4JLogLevel(String logLevel) {
            if (logLevel == null) {
                return null;
            }
            for (SLF4JLogLevel slf4JLogLevel : SLF4JLogLevel.values()) {
                if (slf4JLogLevel.name().equalsIgnoreCase(logLevel)) {
                    return slf4JLogLevel;
                }
            }
            throw new IllegalArgumentException("Unresolved log level " + logLevel + " for slf4j logger, "
                    + "known levels: " + Arrays.toString(SLF4JLogLevel.values()));
        }
    }
}

anton-tkachenko avatar Jul 13 '23 13:07 anton-tkachenko

Thanks for filing the issue, I definitely should have used milliseconds from the start :) I wonder if that's possible to switch it to Duration under the hood, but still leave setter for int values and treating this as seconds for compatibility?

gavlyukovskiy avatar Jul 25 '23 09:07 gavlyukovskiy