@Override
  public void filteredExceptionOccured(
      Spy spy, String methodCall, Exception e, String sql, long execTime) {
    String classType = spy.getClassType();
    Integer spyNo = spy.getConnectionNumber();
    String header = spyNo + ". " + classType + "." + methodCall;
    if (sql == null) {
      jdbcLogger.error(header, e);
      sqlOnlyLogger.error(header, e);
      sqlTimingLogger.error(header, e);
    } else {
      sql = processSql(sql);
      jdbcLogger.error(header + " " + sql, e);

      // if at debug level, display debug info to error log
      if (sqlOnlyLogger.isDebugEnabled()) {
        sqlOnlyLogger.error(getDebugInfo() + nl + spyNo + ". " + sql, e);
      } else {
        sqlOnlyLogger.error(header + " " + sql, e);
      }

      // if at debug level, display debug info to error log
      if (sqlTimingLogger.isDebugEnabled()) {
        sqlTimingLogger.error(
            getDebugInfo() + nl + spyNo + ". " + sql + " {FAILED after " + execTime + " msec}", e);
      } else {
        sqlTimingLogger.error(
            header + " FAILED! " + sql + " {FAILED after " + execTime + " msec}", e);
      }
    }
  }
 /**
  * Called whenever a connection spy is aborted.
  *
  * @param spy ConnectionSpy that was aborted.
  */
 private void connectionAborted(Spy spy) {
   if (connectionLogger.isDebugEnabled()) {
     connectionLogger.info(spy.getConnectionNumber() + ". Connection aborted " + getDebugInfo());
     connectionLogger.debug(ConnectionSpy.getOpenConnectionsDump());
   } else {
     connectionLogger.info(spy.getConnectionNumber() + ". Connection aborted");
   }
 }
  /**
   * Helper method to quickly build a SQL timing dump output String for logging.
   *
   * @param spy the Spy wrapping the class where the SQL occurred.
   * @param execTime how long it took the SQL to run, in milliseconds.
   * @param methodCall a description of the name and call parameters of the method that generated
   *     the SQL.
   * @param sql SQL that occurred.
   * @param debugInfo if true, include debug info at the front of the output.
   * @return a SQL timing dump String for logging.
   */
  private String buildSqlTimingDump(
      Spy spy, long execTime, String methodCall, String sql, boolean debugInfo) {
    StringBuffer out = new StringBuffer();

    if (debugInfo) {
      out.append(getDebugInfo());
      out.append(nl);
      out.append(spy.getConnectionNumber());
      out.append(". ");
    }

    // NOTE: if both sql dump and sql timing dump are on, the processSql
    // algorithm will run TWICE once at the beginning and once at the end
    // this is not very efficient but usually
    // only one or the other dump should be on and not both.

    sql = processSql(sql);

    out.append(sql);
    out.append(" {executed in ");
    out.append(execTime);
    out.append(" msec}");

    return out.toString();
  }
 public void sqlOccurred(Spy spy, String methodCall, String sql) {
   if (!Properties.isDumpSqlFilteringOn() || shouldSqlBeLogged(sql)) {
     if (sqlOnlyLogger.isDebugEnabled()) {
       sqlOnlyLogger.debug(
           getDebugInfo() + nl + spy.getConnectionNumber() + ". " + processSql(sql));
     } else if (sqlOnlyLogger.isInfoEnabled()) {
       sqlOnlyLogger.info(processSql(sql));
     }
   }
 }
 public void methodReturned(Spy spy, String methodCall, String returnMsg) {
   String classType = spy.getClassType();
   Logger logger =
       ResultSetSpy.classTypeDescription.equals(classType) ? resultSetLogger : jdbcLogger;
   if (logger.isInfoEnabled()) {
     String header =
         spy.getConnectionNumber()
             + ". "
             + classType
             + "."
             + methodCall
             + " returned "
             + returnMsg;
     if (logger.isDebugEnabled()) {
       logger.debug(header + " " + getDebugInfo());
     } else {
       logger.info(header);
     }
   }
 }