org.mariadb.jdbc.internal.logging.ProtocolLoggingProxy Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of mariadb-java-client Show documentation
Show all versions of mariadb-java-client Show documentation
JDBC driver for MariaDB and MySQL
/*
*
* MariaDB Client for Java
*
* Copyright (c) 2012-2014 Monty Program Ab.
* Copyright (c) 2015-2020 MariaDB Corporation Ab.
*
* This library is free software; you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by the Free
* Software Foundation; either version 2.1 of the License, or (at your option)
* any later version.
*
* This library 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 Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License along
* with this library; if not, write to Monty Program Ab [email protected].
*
* This particular MariaDB Client for Java file is work
* derived from a Drizzle-JDBC. Drizzle-JDBC file which is covered by subject to
* the following copyright and notice provisions:
*
* Copyright (c) 2009-2011, Marcus Eriksson
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this list
* of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
*
* Neither the name of the driver nor the names of its contributors may not be
* used to endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
*/
package org.mariadb.jdbc.internal.logging;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.nio.charset.Charset;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.List;
import org.mariadb.jdbc.internal.com.send.parameters.ParameterHolder;
import org.mariadb.jdbc.internal.protocol.Protocol;
import org.mariadb.jdbc.internal.util.dao.ClientPrepareResult;
import org.mariadb.jdbc.internal.util.dao.PrepareResult;
import org.mariadb.jdbc.internal.util.dao.ServerPrepareResult;
import org.mariadb.jdbc.util.Options;
public class ProtocolLoggingProxy implements InvocationHandler {
private static final Logger logger = LoggerFactory.getLogger(ProtocolLoggingProxy.class);
private final NumberFormat numberFormat;
private final boolean profileSql;
private final Long slowQueryThresholdNanos;
private final int maxQuerySizeToLog;
private final Protocol protocol;
/**
* Constructor. Will create a proxy around protocol to log queries.
*
* @param protocol protocol to proxy
* @param options options
*/
public ProtocolLoggingProxy(Protocol protocol, Options options) {
this.protocol = protocol;
this.profileSql = options.profileSql;
this.slowQueryThresholdNanos = options.slowQueryThresholdNanos;
this.maxQuerySizeToLog = options.maxQuerySizeToLog;
this.numberFormat = DecimalFormat.getInstance();
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try {
switch (method.getName()) {
case "executeQuery":
case "executePreparedQuery":
case "executeBatchStmt":
case "executeBatchClient":
case "executeBatchServer":
final long startTime = System.nanoTime();
Object returnObj = method.invoke(protocol, args);
if (logger.isInfoEnabled()
&& (profileSql
|| (slowQueryThresholdNanos != null
&& System.nanoTime() - startTime > slowQueryThresholdNanos))) {
String sql = logQuery(method.getName(), args);
logger.info(
"conn={}({}) - {} ms - Query: {}",
protocol.getServerThreadId(),
protocol.isMasterConnection() ? "M" : "S",
numberFormat.format(((double) System.nanoTime() - startTime) / 1000000),
subQuery(sql));
}
return returnObj;
default:
return method.invoke(protocol, args);
}
} catch (InvocationTargetException e) {
throw e.getCause();
}
}
@SuppressWarnings("unchecked")
private String logQuery(String methodName, Object[] args) {
switch (methodName) {
case "executeQuery":
switch (args.length) {
case 1:
return (String) args[0];
case 3:
return (String) args[2];
case 4:
case 5:
if (args[3] instanceof Charset) {
return (String) args[2];
}
ClientPrepareResult clientPrepareResult = (ClientPrepareResult) args[2];
return getQueryFromPrepareParameters(
clientPrepareResult,
(ParameterHolder[]) args[3],
clientPrepareResult.getParamCount());
default:
// no default
}
break;
case "executeBatchClient":
ClientPrepareResult clientPrepareResult = (ClientPrepareResult) args[2];
return getQueryFromPrepareParameters(
clientPrepareResult.getSql(),
(List) args[3],
clientPrepareResult.getParamCount());
case "executeBatchStmt":
List multipleQueries = (List) args[2];
if (multipleQueries.size() == 1) {
return multipleQueries.get(0);
} else {
StringBuilder sb = new StringBuilder();
for (String multipleQuery : multipleQueries) {
if (maxQuerySizeToLog > 0
&& (sb.length() + multipleQuery.length() + 1) > maxQuerySizeToLog) {
sb.append(multipleQuery, 1, Math.max(1, maxQuerySizeToLog - sb.length()));
break;
}
sb.append(multipleQuery).append(";");
if (maxQuerySizeToLog > 0 && sb.length() >= maxQuerySizeToLog) {
break;
}
}
return sb.toString();
}
case "executeBatchServer":
List parameterList = (List) args[4];
ServerPrepareResult serverPrepareResult = (ServerPrepareResult) args[1];
return getQueryFromPrepareParameters(
serverPrepareResult.getSql(), parameterList, serverPrepareResult.getParamCount());
case "executePreparedQuery":
ServerPrepareResult prepareResult = (ServerPrepareResult) args[1];
if (args[3] instanceof ParameterHolder[]) {
return getQueryFromPrepareParameters(
prepareResult, (ParameterHolder[]) args[3], prepareResult.getParamCount());
} else {
return getQueryFromPrepareParameters(
prepareResult.getSql(),
(List) args[3],
prepareResult.getParameters().length);
}
default:
// no default
}
return "-unknown-";
}
/**
* Get query, truncated if to big.
*
* @param sql current query
* @return possibly truncated query if too big
*/
public String subQuery(String sql) {
if (maxQuerySizeToLog > 0 && sql.length() > maxQuerySizeToLog - 3) {
return sql.substring(0, maxQuerySizeToLog - 3) + "...";
}
return sql;
}
private String getQueryFromPrepareParameters(
String sql, List parameterList, int parameterLength) {
if (parameterLength == 0) {
return sql;
} else {
StringBuilder sb = new StringBuilder(sql).append(", parameters ");
for (int paramNo = 0; paramNo < parameterList.size(); paramNo++) {
ParameterHolder[] parameters = parameterList.get(paramNo);
if (paramNo != 0) {
sb.append(",");
}
sb.append("[");
for (int i = 0; i < parameterLength; i++) {
if (i != 0) {
sb.append(",");
}
sb.append(parameters[i].toString());
}
if (maxQuerySizeToLog > 0 && sb.length() > maxQuerySizeToLog) {
break;
} else {
sb.append("]");
}
}
return sb.toString();
}
}
private String getQueryFromPrepareParameters(
PrepareResult serverPrepareResult, ParameterHolder[] paramHolders, int parameterLength) {
StringBuilder sb = new StringBuilder(serverPrepareResult.getSql());
if (paramHolders.length > 0) {
sb.append(", parameters [");
for (int i = 0; i < parameterLength; i++) {
if (i != 0) {
sb.append(",");
}
sb.append(paramHolders[i].toString());
if (maxQuerySizeToLog > 0 && sb.length() > maxQuerySizeToLog) {
break;
}
}
return sb.append("]").toString();
}
return serverPrepareResult.getSql();
}
}