HHH-14217 Add syntax highlighting to the logged SQL
Using ANSI escape codes Must be explicitly enabled using hibernate.highlight_sql
This commit is contained in:
parent
9ac29ab4dc
commit
cf995a1571
|
@ -621,6 +621,9 @@ Write all SQL statements to the console. This is an alternative to setting the l
|
|||
`*hibernate.format_sql*` (e.g. `true` or `false` (default value))::
|
||||
Pretty-print the SQL in the log and console.
|
||||
|
||||
`*hibernate.highlight_sql*` (e.g. `true` or `false` (default value))::
|
||||
Colorize the SQL in the console using ANSI escape codes.
|
||||
|
||||
`*hibernate.use_sql_comments*` (e.g. `true` or `false` (default value))::
|
||||
If true, Hibernate generates comments inside the SQL, for easier debugging.
|
||||
|
||||
|
|
|
@ -742,6 +742,11 @@ public interface AvailableSettings extends org.hibernate.jpa.AvailableSettings {
|
|||
*/
|
||||
String FORMAT_SQL ="hibernate.format_sql";
|
||||
|
||||
/**
|
||||
* Enable highlighting of SQL logged to the console using ANSI escape codes
|
||||
*/
|
||||
String HIGHLIGHT_SQL ="hibernate.highlight_sql";
|
||||
|
||||
/**
|
||||
* Add comments to the generated SQL
|
||||
*/
|
||||
|
|
|
@ -20,6 +20,10 @@ public enum FormatStyle {
|
|||
* Formatting for DDL (CREATE, ALTER, DROP, etc) statements
|
||||
*/
|
||||
DDL( "ddl", DDLFormatterImpl.INSTANCE ),
|
||||
/**
|
||||
* Syntax highlighting via ANSI escape codes
|
||||
*/
|
||||
HIGHLIGHT( "highlight", HighlightingFormatter.INSTANCE ),
|
||||
/**
|
||||
* No formatting
|
||||
*/
|
||||
|
|
|
@ -0,0 +1,105 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.engine.jdbc.internal;
|
||||
|
||||
import org.hibernate.engine.jdbc.env.spi.AnsiSqlKeywords;
|
||||
import org.hibernate.internal.util.StringHelper;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
/**
|
||||
* Performs basic syntax highlighting for SQL using ANSI escape codes.
|
||||
*
|
||||
* @author Gavin King
|
||||
*/
|
||||
public class HighlightingFormatter implements Formatter {
|
||||
|
||||
private static final Set<String> KEYWORDS = new HashSet<>( AnsiSqlKeywords.INSTANCE.sql2003() );
|
||||
static {
|
||||
// additional keywords not reserved by ANSI SQL 2003
|
||||
KEYWORDS.addAll( Arrays.asList( "KEY", "SEQUENCE", "CASCADE", "INCREMENT" ) );
|
||||
}
|
||||
|
||||
public static final Formatter INSTANCE =
|
||||
new HighlightingFormatter(
|
||||
"34", // blue
|
||||
"36", // cyan
|
||||
"32"
|
||||
);
|
||||
|
||||
private static String escape(String code) {
|
||||
return "\u001b[" + code + "m";
|
||||
};
|
||||
|
||||
private final String keywordEscape;
|
||||
private final String stringEscape;
|
||||
private final String quotedEscape;
|
||||
private final String normalEscape;
|
||||
|
||||
/**
|
||||
* @param keywordCode the ANSI escape code to use for highlighting SQL keywords
|
||||
* @param stringCode the ANSI escape code to use for highlighting SQL strings
|
||||
*/
|
||||
public HighlightingFormatter(String keywordCode, String stringCode, String quotedCode) {
|
||||
keywordEscape =escape(keywordCode);
|
||||
stringEscape = escape(stringCode);
|
||||
quotedEscape = escape(quotedCode);
|
||||
normalEscape = escape("0");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String format(String sql) {
|
||||
String symbolsAndWs = "=><!+-*/()',.|&`\"?" + StringHelper.WHITESPACE;
|
||||
StringBuilder result = new StringBuilder();
|
||||
boolean inString = false;
|
||||
boolean inQuoted = false;
|
||||
for (StringTokenizer tokenizer = new StringTokenizer( sql, symbolsAndWs, true );
|
||||
tokenizer.hasMoreTokens(); ) {
|
||||
String token = tokenizer.nextToken();
|
||||
switch (token) {
|
||||
case "\"":
|
||||
case "`": // for MySQL
|
||||
if (inString) {
|
||||
result.append(token);
|
||||
}
|
||||
else if (inQuoted) {
|
||||
inQuoted = false;
|
||||
result.append(token).append(normalEscape);
|
||||
}
|
||||
else {
|
||||
inQuoted = true;
|
||||
result.append(quotedEscape).append(token);
|
||||
}
|
||||
break;
|
||||
case "'":
|
||||
if (inQuoted) {
|
||||
result.append("'");
|
||||
}
|
||||
else if (inString) {
|
||||
inString = false;
|
||||
result.append("'").append(normalEscape);
|
||||
}
|
||||
else {
|
||||
inString = true;
|
||||
result.append(stringEscape).append("'");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if ( KEYWORDS.contains( token.toUpperCase() ) ) {
|
||||
result.append(keywordEscape).append(token).append(normalEscape);
|
||||
}
|
||||
else {
|
||||
result.append(token);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result.toString();
|
||||
}
|
||||
}
|
|
@ -55,9 +55,10 @@ public class JdbcServicesImpl implements JdbcServices, ServiceRegistryAwareServi
|
|||
|
||||
final boolean showSQL = ConfigurationHelper.getBoolean( Environment.SHOW_SQL, configValues, false );
|
||||
final boolean formatSQL = ConfigurationHelper.getBoolean( Environment.FORMAT_SQL, configValues, false );
|
||||
final boolean highlightSQL = ConfigurationHelper.getBoolean( Environment.HIGHLIGHT_SQL, configValues, false );
|
||||
final long logSlowQuery = ConfigurationHelper.getLong( Environment.LOG_SLOW_QUERY, configValues, 0 );
|
||||
|
||||
this.sqlStatementLogger = new SqlStatementLogger( showSQL, formatSQL, logSlowQuery );
|
||||
this.sqlStatementLogger = new SqlStatementLogger( showSQL, formatSQL, highlightSQL, logSlowQuery );
|
||||
|
||||
resultSetWrapper = new ResultSetWrapperImpl( serviceRegistry );
|
||||
}
|
||||
|
|
|
@ -6,16 +6,15 @@
|
|||
*/
|
||||
package org.hibernate.engine.jdbc.spi;
|
||||
|
||||
import java.sql.Statement;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.hibernate.engine.jdbc.internal.FormatStyle;
|
||||
import org.hibernate.engine.jdbc.internal.Formatter;
|
||||
import org.hibernate.internal.CoreLogging;
|
||||
import org.hibernate.internal.build.AllowSysOut;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
import java.sql.Statement;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* Centralize logging for SQL statements.
|
||||
*
|
||||
|
@ -27,6 +26,7 @@ public class SqlStatementLogger {
|
|||
|
||||
private boolean logToStdout;
|
||||
private boolean format;
|
||||
private final boolean highlight;
|
||||
|
||||
/**
|
||||
* Configuration value that indicates slow query. (In milliseconds) 0 - disabled.
|
||||
|
@ -37,29 +37,42 @@ public class SqlStatementLogger {
|
|||
* Constructs a new SqlStatementLogger instance.
|
||||
*/
|
||||
public SqlStatementLogger() {
|
||||
this( false, false );
|
||||
this( false, false, false );
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new SqlStatementLogger instance.
|
||||
*
|
||||
* @param logToStdout Should we log to STDOUT in addition to our internal logger.
|
||||
* @param format Should we format the statements prior to logging
|
||||
* @param format Should we format the statements in the console and log
|
||||
*/
|
||||
public SqlStatementLogger(boolean logToStdout, boolean format) {
|
||||
this( logToStdout, format, 0 );
|
||||
this( logToStdout, format, false );
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new SqlStatementLogger instance.
|
||||
*
|
||||
* @param logToStdout Should we log to STDOUT in addition to our internal logger.
|
||||
* @param format Should we format the statements prior to logging
|
||||
* @param format Should we format the statements in the console and log
|
||||
* @param highlight Should we highlight the statements in the console
|
||||
*/
|
||||
public SqlStatementLogger(boolean logToStdout, boolean format, boolean highlight) {
|
||||
this( logToStdout, format, highlight, 0 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new SqlStatementLogger instance.
|
||||
*
|
||||
* @param logToStdout Should we log to STDOUT in addition to our internal logger.
|
||||
* @param format Should we format the statements in the console and log
|
||||
* @param highlight Should we highlight the statements in the console
|
||||
* @param logSlowQuery Should we logs query which executed slower than specified milliseconds. 0 - disabled.
|
||||
*/
|
||||
public SqlStatementLogger(boolean logToStdout, boolean format, long logSlowQuery) {
|
||||
public SqlStatementLogger(boolean logToStdout, boolean format, boolean highlight, long logSlowQuery) {
|
||||
this.logToStdout = logToStdout;
|
||||
this.format = format;
|
||||
this.highlight = highlight;
|
||||
this.logSlowQuery = logSlowQuery;
|
||||
}
|
||||
|
||||
|
@ -120,14 +133,18 @@ public class SqlStatementLogger {
|
|||
*/
|
||||
@AllowSysOut
|
||||
public void logStatement(String statement, Formatter formatter) {
|
||||
if ( format ) {
|
||||
if ( logToStdout || LOG.isDebugEnabled() ) {
|
||||
if ( logToStdout || LOG.isDebugEnabled() ) {
|
||||
if ( format ) {
|
||||
statement = formatter.format( statement );
|
||||
}
|
||||
if ( highlight ) {
|
||||
statement = FormatStyle.HIGHLIGHT.getFormatter().format( statement );
|
||||
}
|
||||
}
|
||||
LOG.debug( statement );
|
||||
if ( logToStdout ) {
|
||||
System.out.println( "Hibernate: " + statement );
|
||||
String prefix = highlight ? "\u001b[35m[Hibernate]\u001b[0m " : "Hibernate: ";
|
||||
System.out.println( prefix + statement );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -57,7 +57,7 @@ public class BasicTestingJdbcServiceImpl implements JdbcServices, ServiceRegistr
|
|||
public void prepare(boolean allowAggressiveRelease) throws SQLException {
|
||||
dialect = ConnectionProviderBuilder.getCorrespondingDialect();
|
||||
connectionProvider = ConnectionProviderBuilder.buildConnectionProvider( allowAggressiveRelease );
|
||||
sqlStatementLogger = new SqlStatementLogger( true, false );
|
||||
sqlStatementLogger = new SqlStatementLogger( true, false, false );
|
||||
|
||||
Connection jdbcConnection = connectionProvider.getConnection();
|
||||
try {
|
||||
|
|
Loading…
Reference in New Issue