Comment déboguer / Log les connexions de Tomcat JDBC?

J'utilise Tomcat JDBC connection pool avec Spring boot, JDBC template et SQL Server. J'ai besoin de savoir ce qui se passe à l'intérieur de la piscine de connexion pendant que l'application attend la connexion à la base de données. Notamment....

  • nombre de connexions actives
  • nombre de connexions inactives
  • Pas de connexions bloquées, pour plus d'infos, pourquoi cette connexion est bloquée
  • nombre de connexions disponibles
  • et ...

Est y a-t-il un moyen d'obtenir ces informations en déboguant ou en utilisant des cadres de journalisation comme log4j?

toute idée sera appréciée.

17
demandé sur Sundararaj Govindasamy 2016-04-13 04:36:46

2 réponses

après beaucoup de recherches, je suis en mesure de trouver 3 façons de log & monitor database connection pool.

https://tomcat.apache.org/tomcat-8.0-doc/jdbc-pool.html

  1. Surveillance à l'aide de Botte De Printempspropriétés.

  2. Surveillance à l'aide de JMX ( Java Management Extensions ) (@nitin suggéré)

  3. Surveillance à l'aide de printemps Aspects.

1ère méthode: la Surveillance à l'aide de Printemps de Démarrage des propriétés.

j'ai trouvé ci-dessous des propriétés de démarrage qui seront très utiles pour enregistrer et surveiller le pool de connexion à la base de données.

ces propriétés (et quelques autres aussi) étaient ce n'est pas documenté. S'il vous plaît se référer ci-dessous GitHub question pour plus détail. https://github.com/spring-projects/spring-boot/issues/1829

#Maximum no.of active connections
spring.datasource.max-active=10

#Log the stack trace of abandoned connection
spring.datasource.log-abandoned=true

#Remove abandoned connection,So, new connection will be created and made available to threads which are waiting for DB connection
spring.datasource.remove-abandoned=true

#If any connection is not used for 10 seconds, consider that connection as "abandoned"
spring.datasource.remove-abandoned-timeout=10 

#Number of ms to wait before throwing an exception if no connection is available.
spring.datasource.max-wait=1000

cette liste contient plus de propriétés qui sont liées à source de données uniquement.(prises à partir du lien ci-dessus)

spring.datasource.abandon-when-percentage-full
spring.datasource.access-to-underlying-connection-allowed
spring.datasource.alternate-username-allowed
spring.datasource.auto-commit
spring.datasource.catalog
spring.datasource.commit-on-return
spring.datasource.connection-customizer
spring.datasource.connection-customizer-class-name
spring.datasource.connection-init-sql
spring.datasource.connection-init-sqls
spring.datasource.connection-properties
spring.datasource.connection-test-query
spring.datasource.connection-timeout
spring.datasource.data-source
spring.datasource.data-source-class-name
spring.datasource.data-source-j-n-d-i
spring.datasource.data-source-properties
spring.datasource.db-properties
spring.datasource.default-auto-commit
spring.datasource.default-catalog
spring.datasource.default-read-only
spring.datasource.default-transaction-isolation
spring.datasource.driver-class-loader
spring.datasource.fair-queue
spring.datasource.idle-timeout
spring.datasource.ignore-exception-on-pre-load
spring.datasource.init-s-q-l
spring.datasource.initialization-fail-fast
spring.datasource.isolate-internal-queries
spring.datasource.jdbc-interceptors
spring.datasource.jdbc-url
spring.datasource.jdbc4-connection-test
spring.datasource.leak-detection-threshold
spring.datasource.log-abandoned
spring.datasource.log-validation-errors
spring.datasource.log-writer
spring.datasource.login-timeout
spring.datasource.max-age
spring.datasource.max-lifetime
spring.datasource.max-open-prepared-statements
spring.datasource.maximum-pool-size
spring.datasource.metrics-tracker-class-name
spring.datasource.minimum-idle
spring.datasource.num-tests-per-eviction-run
spring.datasource.pool-name
spring.datasource.pool-prepared-statements
spring.datasource.pool-properties
spring.datasource.propagate-interrupt-state
spring.datasource.read-only
spring.datasource.record-metrics
spring.datasource.register-mbeans
spring.datasource.remove-abandoned
spring.datasource.remove-abandoned-timeout
spring.datasource.rollback-on-return
spring.datasource.suspect-timeout
spring.datasource.test-on-connect
spring.datasource.thread-factory
spring.datasource.transaction-isolation
spring.datasource.use-disposable-connection-facade
spring.datasource.use-equals
spring.datasource.use-lock
spring.datasource.validation-interval
spring.datasource.validation-query-timeout
spring.datasource.validator
spring.datasource.validator-class-name
spring.datasource.xa
spring.datasource.xa.data-source-class-name
spring.datasource.xa.properties

2ème méthode: la Surveillance à l'aide de JMX ( Java Management Extensions )

Tomcat JDBC pool fournit un MBean à savoir ConnectionPoolMBean.

https://tomcat.apache.org/tomcat-7.0-doc/api/org/apache/tomcat/jdbc/pool/jmx/ConnectionPoolMBean.html

la botte de printemps enregistre JMX MBeans automatiquement.Donc, pas besoin d'enregistrer/exporter ce MBean dans MBean server. Il suffit d'ouvrir le JConsole qui arrive avec JDK, pour l'ouvrir, dans Windows-> command prompt ->jconsole, thats it. Reportez-vous à la capture d'écran ci-dessous pour en savoir plus info.

enter image description here

enter image description here

ce MBean aussi notifie chaque fois qu'une connexion est abandonnée, la connexion échoue, lorsqu'une requête prend beaucoup de temps, etc. Consultez la capture d'écran ci-dessous.

enter image description here

3ème Voie: la Surveillance à l'aide de Printemps Aspects (seulement pour le développement de l'assurance de la qualité et de l'environnement).

j'utilise cet aspect de journal Piscine De Connexion TomcatJdbc.

j'ai créé un aspect Spring qui interceptera chaque appel de la base de données.Ce sera sûrement affecter la performance.

alors, utilisez cet aspect dans l'environnement de développement/QA,commenter cette méthode, elle n'est pas obligatoire (par exemple : pendant le déploiement de la production).

@Before("execution(* com.test.app.db.dao.*.*(..))")
    public void logBeforeConnection(JoinPoint jp) throws Throwable {
        String methodName = "";
        methodName += jp.getTarget().getClass().getName();
        methodName += ":";
        methodName += jp.getSignature().getName();
        logger.info("before method call : " + methodName +  " : number of connections in use by the application (active) : "+ tomcatJdbcPoolDataSource.getNumActive());
        logger.info("before method call : " + methodName +  " : the number of established but idle connections : "+ tomcatJdbcPoolDataSource.getNumIdle());
        logger.info("before method call : " + methodName +  " : number of threads waiting for a connection : "+ tomcatJdbcPoolDataSource.getWaitCount());
    }


@After("execution(* com.test.app.db.dao.*.*(..)) ")
public void logAfterConnection(JoinPoint jp) throws Throwable {
    String methodName = "";
    methodName += jp.getTarget().getClass().getName();
    methodName += ":";
    methodName += jp.getSignature().getName();
    logger.info("after method call : " + methodName +  " : number of connections in use by the application (active) : "+ tomcatJdbcPoolDataSource.getNumActive());
    logger.info("after method call : " + methodName +  " : the number of established but idle connections : "+ tomcatJdbcPoolDataSource.getNumIdle());
    logger.info("after method call : " + methodName +  " : number of threads waiting for a connection : "+ tomcatJdbcPoolDataSource.getWaitCount());
    //tomcatJdbcPoolDataSource.checkAbandoned();
}

Maintenant, vous pouvez facilement identifier l'appel de base de données particulier qui crée une fuite de connexion dans votre application.

23
répondu Sundararaj Govindasamy 2018-06-18 12:14:33

Merci @Sundararaj Govindasamy pour la bonne réponse. Basé sur cela, j'ai créé un composant dans mon application de démarrage de printemps pour déboguer les informations de ma base de données.

import org.apache.tomcat.jdbc.pool.DataSource;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class DataSourceAspectLogger {

    protected final Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    private DataSource ds;

    @Before("execution(* br.com.foo.core.repository.*.*(..))")
    public void logBeforeConnection(JoinPoint jp) throws Throwable {
        logDataSourceInfos("Before", jp);
    }

    @After("execution(* br.com.foo.core.repository.*.*(..)) ")
    public void logAfterConnection(JoinPoint jp) throws Throwable {
        logDataSourceInfos("After", jp);
    }

    public void logDataSourceInfos(final String time, final JoinPoint jp) {
        final String method = String.format("%s:%s", jp.getTarget().getClass().getName(), jp.getSignature().getName());
        logger.info(String.format("%s %s: number of connections in use by the application (active): %d.", time, method, ds.getNumActive()));
        logger.info(String.format("%s %s: the number of established but idle connections: %d.", time, method, ds.getNumIdle()));
        logger.info(String.format("%s %s: number of threads waiting for a connection: %d.", time, method, ds.getWaitCount()));
    }
}
2
répondu falvojr 2018-06-18 13:31:02