
customplugins.ExecutionTimeConnectionPlugin Maven / Gradle / Ivy
/*
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License, version 2.0
* (GPLv2), as published by the Free Software Foundation, with the
* following additional permissions:
*
* This program is distributed with certain software that is licensed
* under separate terms, as designated in a particular file or component
* or in the license documentation. Without limiting your rights under
* the GPLv2, the authors of this program hereby grant you an additional
* permission to link the program and your derivative works with the
* separately licensed software that they have included with the program.
*
* Without limiting the foregoing grant of rights under the GPLv2 and
* additional permission as to separately licensed software, this
* program is also subject to the Universal FOSS Exception, version 1.0,
* a copy of which can be found along with its FAQ at
* http://oss.oracle.com/licenses/universal-foss-exception.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License, version 2.0, for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see
* http://www.gnu.org/licenses/gpl-2.0.html.
*/
package customplugins;
import software.aws.rds.jdbc.mysql.shading.com.mysql.cj.conf.ConnectionUrl;
import software.aws.rds.jdbc.mysql.shading.com.mysql.cj.jdbc.ha.plugins.IConnectionPlugin;
import software.aws.rds.jdbc.mysql.shading.com.mysql.cj.log.Log;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Callable;
/**
* This connection plugin tracks the execution time of all the given JDBC methods throughout
* the lifespan of the current connection.
*
* During the cleanup phase when {@link ExecutionTimeConnectionPlugin#releaseResources()}
* is called, the plugin logs all the methods executed and time spent on each execution
* in milliseconds.
*/
public class ExecutionTimeConnectionPlugin implements IConnectionPlugin {
final long initializeTime;
final IConnectionPlugin nextPlugin;
private final Log logger;
private final Map methodExecutionTimes = new HashMap<>();
public ExecutionTimeConnectionPlugin(
IConnectionPlugin nextPlugin,
Log logger) {
this.nextPlugin = nextPlugin;
this.logger = logger;
initializeTime = System.currentTimeMillis();
}
@Override
public Object execute(
Class> methodInvokeOn,
String methodName,
Callable> executeJdbcMethod, Object[] args)
throws Exception {
// This `execute` measures the time it takes for the remaining connection plugins to
// execute the given method call.
final long startTime = System.nanoTime();
final Object executeResult =
this.nextPlugin.execute(methodInvokeOn, methodName, executeJdbcMethod, args);
final long elapsedTime = System.nanoTime() - startTime;
methodExecutionTimes.merge(
methodName,
elapsedTime / 1000000,
Long::sum);
return executeResult;
}
@Override
public void transactionBegun() {
this.nextPlugin.transactionBegun();
}
@Override
public void transactionCompleted() {
this.nextPlugin.transactionCompleted();
}
@Override
public void openInitialConnection(ConnectionUrl connectionUrl) throws SQLException {
this.nextPlugin.openInitialConnection(connectionUrl);
}
@Override
public void releaseResources() {
// Output the aggregated information from all methods called throughout the lifespan
// of the current connection.
final long connectionUptime = System.nanoTime() - initializeTime;
final String leftAlignFormat = "| %-19s | %-10s |\n";
final StringBuilder logMessage = new StringBuilder();
logMessage.append("** ExecutionTimeConnectionPlugin Summary **\n");
logMessage.append(String.format(
"Connection Uptime: %ds\n",
connectionUptime / 1000000
));
logMessage
.append("** Method Execution Time **\n")
.append("+---------------------+------------+\n")
.append("| Method Executed | Total Time |\n")
.append("+---------------------+------------+\n");
methodExecutionTimes.forEach((key, val) -> logMessage.append(String.format(
leftAlignFormat,
key,
val + "ms")));
logMessage.append("+---------------------+------------+\n");
logger.logInfo(logMessage);
methodExecutionTimes.clear();
// Traverse the connection plugin chain by calling the next plugin. This step allows
// all connection plugins a chance to clean up any dangling resources or perform any
// last tasks before shutting down.
this.nextPlugin.releaseResources();
}
}