gavlyukovskiy / spring-boot-data-source-decorator

Spring Boot integration with p6spy, datasource-proxy, flexy-pool and spring-cloud-sleuth
Apache License 2.0
870 stars 83 forks source link

Allow specifying timeunit for datasource-proxy #88

Open anton-tkachenko opened 1 year ago

anton-tkachenko commented 1 year ago

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()));
        }
    }
}
gavlyukovskiy commented 1 year ago

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?