Skip to content

Commit

Permalink
enhance(controller): modify datasource param and add index for slowsql (
Browse files Browse the repository at this point in the history
  • Loading branch information
goldenxinxing authored Oct 25, 2023
1 parent 52368b4 commit ce807f3
Show file tree
Hide file tree
Showing 5 changed files with 279 additions and 1 deletion.
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
/*
* Copyright 2022 Starwhale, Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package ai.starwhale.mlops.configuration;

import java.sql.Statement;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.ParameterMapping;
import org.apache.ibatis.mapping.ParameterMode;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Signature;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.scripting.defaults.DefaultParameterHandler;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.type.TypeHandlerRegistry;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Component;
import org.springframework.util.ReflectionUtils;


@Slf4j
@Component
@Intercepts({
@Signature(type = StatementHandler.class, method = "query", args = {Statement.class, ResultHandler.class}),
@Signature(type = StatementHandler.class, method = "update", args = {Statement.class})
})
@ConditionalOnProperty(prefix = "sw.db.sql.log-slow-sql", name = "enable", havingValue = "true", matchIfMissing = true)
public class SlowSqlLogInterceptor implements Interceptor {

private Configuration configuration = null;
private static final ThreadLocal<SimpleDateFormat> DATE_FORMAT_THREAD_LOCAL =
ThreadLocal.withInitial(() -> new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS"));

private final int slowSqlMillis;

private final int maxSqlLength;

public SlowSqlLogInterceptor(
@Value("${sw.db.sql.slow-sql-millis:100}") int slowSqlMillis,
@Value("${sw.db.sql.max-print-length:200}") int maxSqlLength
) {
this.slowSqlMillis = slowSqlMillis;
this.maxSqlLength = maxSqlLength;
}


@Override
public Object intercept(Invocation invocation) throws Throwable {
Object target = invocation.getTarget();
long startTime = System.currentTimeMillis();
StatementHandler statementHandler = (StatementHandler) target;
try {
return invocation.proceed();
} finally {
long endTime = System.currentTimeMillis();
long cost = endTime - startTime;
if (cost >= slowSqlMillis) {
BoundSql boundSql = statementHandler.getBoundSql();

if (configuration == null) {
var parameterHandler = (DefaultParameterHandler) statementHandler.getParameterHandler();
var configurationField = ReflectionUtils.findField(parameterHandler.getClass(), "configuration");
if (configurationField != null) {
ReflectionUtils.makeAccessible(configurationField);
this.configuration = (Configuration) configurationField.get(parameterHandler);
}
}
if (configuration != null) {
var sql = formatSql(boundSql, configuration);
log.info("Execute SQL:[ {} ] cost[ {} ms]", sql, cost);
}
}
}
}

/**
* Get param list
*
* @param configuration the configuration
* @param boundSql the bound sql
*
* @return the param list
*/
public String formatSql(BoundSql boundSql, Configuration configuration) {
String sql = boundSql.getSql();
List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
Object parameterObject = boundSql.getParameterObject();

if (sql == null || sql.length() == 0) {
return "";
}
if (configuration == null) {
return "";
}
TypeHandlerRegistry typeHandlerRegistry = configuration.getTypeHandlerRegistry();
sql = sql.replaceAll("\\s+", " ");
// DefaultParameterHandler
if (parameterMappings != null) {
for (ParameterMapping parameterMapping : parameterMappings) {
if (parameterMapping.getMode() != ParameterMode.OUT) {
Object value;
String propertyName = parameterMapping.getProperty();
if (boundSql.hasAdditionalParameter(propertyName)) {
value = boundSql.getAdditionalParameter(propertyName);
} else if (parameterObject == null) {
value = null;
} else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {
value = parameterObject;
} else {
MetaObject metaObject = configuration.newMetaObject(parameterObject);
value = metaObject.getValue(propertyName);
}
String paramValueStr = "";
if (value instanceof String) {
paramValueStr = "'" + value + "'";
} else if (value instanceof Date) {
paramValueStr = "'" + DATE_FORMAT_THREAD_LOCAL.get().format(value) + "'";
} else {
paramValueStr = String.valueOf(value);
}
sql = sql.replaceFirst("\\?", paramValueStr);
}
}
}
if (sql.length() > maxSqlLength) {
return sql.substring(0, maxSqlLength);
} else {
return sql;
}
}
}
14 changes: 13 additions & 1 deletion server/controller/src/main/resources/application.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,12 @@ spring:
static-locations: file:/opt/starwhale.java/static/, classpath:/static/
sw:
version: ${SW_VERSION_CONTROLLER:0.1.0:8c82767b60686f3e2bfea9dafe8c8cce5dd34f52}
db:
sql:
log-slow-sql:
enable: ${SW_DB_SQL_LOG_SLOW_SQL_ENABLE:true}
slow-sql-millis: ${SW_DB_SQL_LOG_SLOW_SQL_MILLIS:100}
max-print-length: ${SW_DB_SQL_LOG_SLOW_SQL_MAX_PRINT_LENGTH:200}
features:
disabled: ${SW_DISABLED_FEATURES:}
public-api:
Expand Down Expand Up @@ -148,6 +154,10 @@ spring:
url: jdbc:mysql://${SW_METADATA_STORAGE_IP:127.0.0.1}:${SW_METADATA_STORAGE_PORT:3306}/${SW_METADATA_STORAGE_DB:starwhale}?useUnicode=true&characterEncoding=UTF-8&createDatabaseIfNotExist=true&allowMultiQueries=true&serverTimezone=UTC&useLegacyDatetimeCode=false&sessionVariables=time_zone='%2B00:00'
username: ${SW_METADATA_STORAGE_USER:starwhale}
password: ${SW_METADATA_STORAGE_PASSWORD:starwhale}
hikari:
max-pool-size: ${SW_METADATA_STORAGE_MAX_POOL_SIZE:100} # mysql server max_connections default is 151
connection-timeout: ${SW_METADATA_STORAGE_CONNECT_TIMEOUT:50000}
max-lifetime: ${SW_METADATA_STORAGE_MAX_LIFETIME:300000}
flyway:
locations: "classpath:db/migration"
ignore-missing-migrations: true
Expand All @@ -167,6 +177,8 @@ mybatis:

server:
tomcat:
mbeanregistry:
enabled: ${SW_CONTROLLER_TOMCAT_MBEANREGISTRY_ENABLED:true}
threads:
max: ${SW_CONTROLLER_TOMCAT_MAX_THREADS:500}
port: ${SW_CONTROLLER_PORT:8082}
Expand All @@ -188,7 +200,7 @@ management:
endpoints:
web:
exposure:
include: ${SW_BIZ_MANAGMENT_EXPOSURE_ENDPOINTS:httptrace,loggers,health,info,metrics}
include: ${SW_BIZ_MANAGMENT_EXPOSURE_ENDPOINTS:httptrace,loggers,health,info,metrics,prometheus}
server:
port: ${SW_MANAGEMENT_PORT:9082}
metrics:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/*
* Copyright 2022 Starwhale, Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/


CREATE INDEX dataset_read_log_session_id_IDX USING BTREE ON dataset_read_log (session_id,consumer_id,status);
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/*
* Copyright 2022 Starwhale, Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package ai.starwhale.mlops.configuration.sql;

import ai.starwhale.mlops.configuration.SlowSqlLogInterceptor;
import java.util.Map;
import org.apache.ibatis.session.Configuration;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;


public class SlowSqlTest {

@Test
public void sqlFormatTest() {
var interceptor = new SlowSqlLogInterceptor(100, 200);

var configuration = new Configuration();
configuration.addMapper(SqlMapper.class);

var statement = configuration.getMappedStatement("ai.starwhale.mlops.configuration.sql.SqlMapper.insert");
var boundSql = statement.getBoundSql("sw");
Assertions.assertEquals("INSERT INTO sw_user (name) VALUES ('sw')",
interceptor.formatSql(boundSql, configuration));

statement = configuration.getMappedStatement("ai.starwhale.mlops.configuration.sql.SqlMapper.selectById");
boundSql = statement.getBoundSql(Map.of("id", 1, "name", "sw"));
Assertions.assertEquals("SELECT name FROM sw_user where id = 1 and name = 'sw'",
interceptor.formatSql(boundSql, configuration));

statement = configuration.getMappedStatement(
"ai.starwhale.mlops.configuration.sql.SqlMapper.selectByIdAndName");
boundSql = statement.getBoundSql(Map.of("id", 2, "name", "sw2"));
Assertions.assertEquals("SELECT name FROM sw_user where id = 2 and name = 'sw2'",
interceptor.formatSql(boundSql, configuration));

statement = configuration.getMappedStatement("ai.starwhale.mlops.configuration.sql.SqlMapper.selectAll");
boundSql = statement.getBoundSql(null);
Assertions.assertEquals("SELECT name FROM sw_user", interceptor.formatSql(boundSql, configuration));
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/*
* Copyright 2022 Starwhale, Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package ai.starwhale.mlops.configuration.sql;

import java.util.List;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;


@Mapper
public interface SqlMapper {
@Insert("INSERT INTO sw_user (name) VALUES (#{name})")
int insert(String name);

@Select("SELECT name FROM sw_user")
List<String> selectAll();

@Select("SELECT name FROM sw_user where id = #{id} and name = #{name}")
String selectById(int id, String name);

@Select("SELECT name FROM sw_user \n"
+ " where id = #{id} and name = #{name}")
String selectByIdAndName(int id, String name);
}

0 comments on commit ce807f3

Please sign in to comment.