All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.mariadb.jdbc.internal.logging.ProtocolLoggingProxy Maven / Gradle / Ivy

The newest version!
/*
 *
 * MariaDB Client for Java
 *
 * Copyright (c) 2012-2014 Monty Program Ab.
 * Copyright (c) 2015-2017 MariaDB 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 org.mariadb.jdbc.internal.com.send.parameters.ParameterHolder;
import org.mariadb.jdbc.internal.protocol.Protocol;
import org.mariadb.jdbc.internal.util.Options;
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 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;

public class ProtocolLoggingProxy implements InvocationHandler {
    private static final NumberFormat numberFormat = DecimalFormat.getInstance();
    private static Logger logger = LoggerFactory.getLogger(ProtocolLoggingProxy.class);
    protected boolean profileSql;
    protected Long slowQueryThresholdNanos;
    protected int maxQuerySizeToLog;
    protected 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;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        long startTime = System.nanoTime();
        try {
            switch (method.getName()) {
                case "executeQuery":
                case "executePreparedQuery":
                case "executeBatch":
                case "executeBatchMulti":
                case "executeBatchRewrite":
                case "executeBatchMultiple":
                case "prepareAndExecutes":
                case "prepareAndExecute":
                    Object returnObj = method.invoke(protocol, args);
                    if (logger.isInfoEnabled() && (profileSql
                            || (slowQueryThresholdNanos != null && System.nanoTime() - startTime > slowQueryThresholdNanos.longValue()))) {
                        logger.info("Query - conn:" + protocol.getServerThreadId() + "(" + (protocol.isMasterConnection() ? "M" : "S") + ")"
                                + " - " + numberFormat.format(((double) System.nanoTime() - startTime) / 1000000) + " ms"
                                + logQuery(method.getName(), args, returnObj));
                    }
                    return returnObj;
                default:
                    return method.invoke(protocol, args);
            }
        } catch (InvocationTargetException e) {
            throw e.getCause();
        }
    }

    @SuppressWarnings("unchecked")
    private String logQuery(String methodName, Object[] args, Object returnObj) {
        String sql = "";
        switch (methodName) {
            case "executeQuery":
                switch (args.length) {
                    case 1:
                        sql = (String) args[0];
                        break;
                    case 3:
                        sql = (String) args[2];
                        break;
                    case 4:
                    case 5:
                        if (Charset.class.isInstance(args[3])) {
                            sql = (String) args[2];
                            break;
                        }
                        ClientPrepareResult clientPrepareResult = (ClientPrepareResult) args[2];
                        sql = getQueryFromPrepareParameters(clientPrepareResult, (ParameterHolder[]) args[3], clientPrepareResult.getParamCount());
                        break;
                    default:
                        //no default
                }
                break;

            case "executeBatchMulti":
                ClientPrepareResult clientPrepareResult = (ClientPrepareResult) args[2];
                sql = getQueryFromPrepareParameters(clientPrepareResult.getSql(), (List) args[3],
                        clientPrepareResult.getParamCount());
                break;

            case "executeBatch":
                List queries = (List) args[2];
                for (int counter = 0; counter < queries.size(); counter++) {
                    sql += queries.get(counter) + ";";
                    if (maxQuerySizeToLog > 0 && sql.length() > maxQuerySizeToLog) break;
                }
                break;

            case "executeBatchMultiple":
                List multipleQueries = (List) args[2];
                if (multipleQueries.size() == 1) {
                    sql = multipleQueries.get(0);
                } else {
                    for (int counter = 0; counter < multipleQueries.size(); counter++) {
                        if (maxQuerySizeToLog > 0 && (sql.length() + multipleQueries.get(counter).length() + 1) > maxQuerySizeToLog) {
                            sql += multipleQueries.get(counter).substring(1, Math.max(1, maxQuerySizeToLog - sql.length()));
                            break;
                        }
                        sql += multipleQueries.get(counter) + ";";
                        if (maxQuerySizeToLog > 0 && sql.length() >= maxQuerySizeToLog) break;
                    }
                }
                break;

            case "prepareAndExecute":
                ParameterHolder[] parameters = (ParameterHolder[]) args[4];
                ServerPrepareResult serverPrepareResult1 = (ServerPrepareResult) returnObj;
                sql = getQueryFromPrepareParameters(serverPrepareResult1, parameters, serverPrepareResult1.getParamCount());
                break;

            case "prepareAndExecutes":
                List parameterList = (List) args[4];
                ServerPrepareResult serverPrepareResult = (ServerPrepareResult) returnObj;
                sql = getQueryFromPrepareParameters(serverPrepareResult.getSql(), parameterList, serverPrepareResult.getParamCount());
                break;

            case "executeBatchRewrite":
                ClientPrepareResult prepareResultRewrite = (ClientPrepareResult) args[2];
                List parameterListRewrite = (List) args[3];
                sql = getQueryFromPrepareParameters(prepareResultRewrite.getSql(), parameterListRewrite, prepareResultRewrite.getParamCount());
                break;

            case "executePreparedQuery":
                ServerPrepareResult prepareResult = (ServerPrepareResult) args[1];
                if (args[3] instanceof ParameterHolder[]) {
                    sql = getQueryFromPrepareParameters(prepareResult, (ParameterHolder[]) args[3], prepareResult.getParamCount());
                } else {
                    sql = getQueryFromPrepareParameters(prepareResult.getSql(), (List) args[3],
                            prepareResult.getParameters().length);
                }
                break;

            default:
                //no default
        }
        if (maxQuerySizeToLog > 0) {
            return " - \"" + ((sql.length() < maxQuerySizeToLog) ? sql : sql.substring(0, maxQuerySizeToLog) + "...") + "\"";
        } else {
            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();
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy