Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Log JDBC connection URL for embedded database when using H2 console #17063

Closed
sbrannen opened this issue Jun 5, 2019 · 3 comments
Closed

Log JDBC connection URL for embedded database when using H2 console #17063

sbrannen opened this issue Jun 5, 2019 · 3 comments
Assignees
Labels
type: enhancement A general enhancement
Milestone

Comments

@sbrannen
Copy link
Member

sbrannen commented Jun 5, 2019

When testing a web application with an embedded H2 database and the H2 console enabled (spring.h2.console.enabled=true), it would be useful if Spring Boot logged the JDBC connection URL so that users know how to connect to the database from the /h2/console endpoint.

As @wilkinsona mentioned elsewhere, it would be even better if the H2 console could be prepopulated with the right JDBC connection URL.

FWIW, the embedded database support in core Spring always logs the JDBC connection URL at INFO level (see org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseFactory.initDatabase()).

@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged label Jun 5, 2019
@wilkinsona
Copy link
Member

it would be even better if the H2 console could be prepopulated with the right JDBC connection URL.

This would require us to write out a properties file that's then read by H2's console to populate its UI. While technically possible, it's rather clunky.

it would be useful if Spring Boot logged the JDBC connection URL so that users know how to connect to the database from the /h2/console endpoint.

This is relatively straightforward change to H2ConsoleAutoConfiguration:

diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/h2/H2ConsoleAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/h2/H2ConsoleAutoConfiguration.java
index 89e03abd5a..c857d486fc 100644
--- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/h2/H2ConsoleAutoConfiguration.java
+++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/h2/H2ConsoleAutoConfiguration.java
@@ -16,13 +16,23 @@
 
 package org.springframework.boot.autoconfigure.h2;
 
+import java.sql.Connection;
+import java.sql.SQLException;
+
+import javax.sql.DataSource;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
 import org.h2.server.web.WebServlet;
 
+import org.springframework.beans.factory.ObjectProvider;
+import org.springframework.boot.autoconfigure.AutoConfigureAfter;
 import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
 import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
 import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
 import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
 import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;
+import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
 import org.springframework.boot.context.properties.EnableConfigurationProperties;
 import org.springframework.boot.web.servlet.ServletRegistrationBean;
 import org.springframework.context.annotation.Bean;
@@ -40,11 +50,15 @@ import org.springframework.context.annotation.Configuration;
 @ConditionalOnWebApplication(type = Type.SERVLET)
 @ConditionalOnClass(WebServlet.class)
 @ConditionalOnProperty(prefix = "spring.h2.console", name = "enabled", havingValue = "true", matchIfMissing = false)
+@AutoConfigureAfter(DataSourceAutoConfiguration.class)
 @EnableConfigurationProperties(H2ConsoleProperties.class)
 public class H2ConsoleAutoConfiguration {
 
+       private static final Log logger = LogFactory.getLog(H2ConsoleAutoConfiguration.class);
+
        @Bean
-       public ServletRegistrationBean<WebServlet> h2Console(H2ConsoleProperties properties) {
+       public ServletRegistrationBean<WebServlet> h2Console(H2ConsoleProperties properties,
+                       ObjectProvider<DataSource> dataSource) {
                String path = properties.getPath();
                String urlMapping = path + (path.endsWith("/") ? "*" : "/*");
                ServletRegistrationBean<WebServlet> registration = new ServletRegistrationBean<>(new WebServlet(), urlMapping);
@@ -55,6 +69,15 @@ public class H2ConsoleAutoConfiguration {
                if (settings.isWebAllowOthers()) {
                        registration.addInitParameter("webAllowOthers", "");
                }
+               dataSource.ifAvailable((available) -> {
+                       try (Connection connection = available.getConnection()) {
+                               logger.info("H2 console available at '" + path + "'. Database available at '"
+                                               + connection.getMetaData().getURL() + "'");
+                       }
+                       catch (SQLException ex) {
+                               // Continue
+                       }
+               });
                return registration;
        }

It produces a log message like this at startup:

2019-06-05 21:21:28.628  INFO 39116 --- [           main] o.s.b.a.h2.H2ConsoleAutoConfiguration    : H2 console available at '/h2-console'. Database available at 'jdbc:h2:mem:testdb'

While I still think it'd be nice to do this automatically, the latter feels like the more pragmatic option. Let's see what the rest of the team thinks.

@wilkinsona wilkinsona added for: team-attention An issue we'd like other members of the team to review type: enhancement A general enhancement and removed for: team-attention An issue we'd like other members of the team to review status: waiting-for-triage An issue we've not yet triaged labels Jun 5, 2019
@wilkinsona wilkinsona added this to the 2.2.x milestone Jun 7, 2019
@wilkinsona wilkinsona self-assigned this Jun 7, 2019
@wilkinsona wilkinsona modified the milestones: 2.2.x, 2.2.0.M4 Jun 14, 2019
@rozeuss
Copy link

rozeuss commented Oct 7, 2020

Hi,

Having two datasources defined as described in this it ends up with wiring only the first datasource. In my case, where MariaDB is the 1st datasource (marked with @Primary) and H2 is the 2nd, it logs following:

H2 console available at '/h2-console'. Database available at 'jdbc:mariadb://localhost:3306/product?useLegacyDatetimeCode=false&serverTimezone=UTC'

@wilkinsona
Copy link
Member

wilkinsona commented Oct 7, 2020

Thanks, @rozeuss. That's an interesting problem. I believe you can use the H2 console to connect to any database over JDBC, so arguably the log message isn't wrong. However, given your comment, I guess the database URL it contains isn't the one that you expected. I guess we could list the URLs of every DataSource rather than just the primary DataSource. If you'd like us to do something like this, please open a new issue and we can consider our options.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: enhancement A general enhancement
Projects
None yet
Development

No branches or pull requests

4 participants