Commit 52d23ac224f43323e60e4cd2a87cf74597e5e3ba

Authored by Igor Kulikov
2 parents c1b53afd cc5b2cc4

Merge branch 'master' of github.com:thingsboard/thingsboard

@@ -273,7 +273,8 @@ sql: @@ -273,7 +273,8 @@ sql:
273 # Specify whether to remove null characters from strValue of attributes and timeseries before insert 273 # Specify whether to remove null characters from strValue of attributes and timeseries before insert
274 remove_null_chars: "${SQL_REMOVE_NULL_CHARS:true}" 274 remove_null_chars: "${SQL_REMOVE_NULL_CHARS:true}"
275 # Specify whether to log database queries and their parameters generated by entity query repository 275 # Specify whether to log database queries and their parameters generated by entity query repository
276 - log_entity_queries: "${SQL_LOG_ENTITY_QUERIES:false}" 276 + log_queries: "${SQL_LOG_QUERIES:false}"
  277 + log_queries_threshold: "${SQL_LOG_QUERIES_THRESHOLD:5000}"
277 postgres: 278 postgres:
278 # Specify partitioning size for timestamp key-value storage. Example: DAYS, MONTHS, YEARS, INDEFINITE. 279 # Specify partitioning size for timestamp key-value storage. Example: DAYS, MONTHS, YEARS, INDEFINITE.
279 ts_key_value_partitioning: "${SQL_POSTGRES_TS_KV_PARTITIONING:MONTHS}" 280 ts_key_value_partitioning: "${SQL_POSTGRES_TS_KV_PARTITIONING:MONTHS}"
@@ -43,6 +43,7 @@ import org.thingsboard.server.dao.model.ModelConstants; @@ -43,6 +43,7 @@ import org.thingsboard.server.dao.model.ModelConstants;
43 import java.util.ArrayList; 43 import java.util.ArrayList;
44 import java.util.Arrays; 44 import java.util.Arrays;
45 import java.util.Collection; 45 import java.util.Collection;
  46 +import java.util.Collections;
46 import java.util.HashMap; 47 import java.util.HashMap;
47 import java.util.HashSet; 48 import java.util.HashSet;
48 import java.util.List; 49 import java.util.List;
@@ -114,12 +115,12 @@ public class DefaultAlarmQueryRepository implements AlarmQueryRepository { @@ -114,12 +115,12 @@ public class DefaultAlarmQueryRepository implements AlarmQueryRepository {
114 protected final NamedParameterJdbcTemplate jdbcTemplate; 115 protected final NamedParameterJdbcTemplate jdbcTemplate;
115 private final TransactionTemplate transactionTemplate; 116 private final TransactionTemplate transactionTemplate;
116 117
117 - @Value("${sql.log_entity_queries:false}")  
118 - private boolean logSqlQueries; 118 + private final DefaultQueryLogComponent queryLog;
119 119
120 - public DefaultAlarmQueryRepository(NamedParameterJdbcTemplate jdbcTemplate, TransactionTemplate transactionTemplate) { 120 + public DefaultAlarmQueryRepository(NamedParameterJdbcTemplate jdbcTemplate, TransactionTemplate transactionTemplate, DefaultQueryLogComponent queryLog) {
121 this.jdbcTemplate = jdbcTemplate; 121 this.jdbcTemplate = jdbcTemplate;
122 this.transactionTemplate = transactionTemplate; 122 this.transactionTemplate = transactionTemplate;
  123 + this.queryLog = queryLog;
123 } 124 }
124 125
125 @Override 126 @Override
@@ -230,8 +231,17 @@ public class DefaultAlarmQueryRepository implements AlarmQueryRepository { @@ -230,8 +231,17 @@ public class DefaultAlarmQueryRepository implements AlarmQueryRepository {
230 if (!textSearchQuery.isEmpty()) { 231 if (!textSearchQuery.isEmpty()) {
231 mainQuery = String.format("select * from (%s) a WHERE %s", mainQuery, textSearchQuery); 232 mainQuery = String.format("select * from (%s) a WHERE %s", mainQuery, textSearchQuery);
232 } 233 }
233 - String countQuery = mainQuery;  
234 - int totalElements = jdbcTemplate.queryForObject(String.format("select count(*) from (%s) result", countQuery), ctx, Integer.class); 234 + String countQuery = String.format("select count(*) from (%s) result", mainQuery);
  235 + long queryTs = System.currentTimeMillis();
  236 + int totalElements;
  237 + try {
  238 + totalElements = jdbcTemplate.queryForObject(countQuery, ctx, Integer.class);
  239 + } finally {
  240 + queryLog.logQuery(ctx, countQuery, System.currentTimeMillis() - queryTs);
  241 + }
  242 + if (totalElements == 0) {
  243 + return AlarmDataAdapter.createAlarmData(pageLink, Collections.emptyList(), totalElements, orderedEntityIds);
  244 + }
235 245
236 String dataQuery = mainQuery + sortPart; 246 String dataQuery = mainQuery + sortPart;
237 247
@@ -239,10 +249,12 @@ public class DefaultAlarmQueryRepository implements AlarmQueryRepository { @@ -239,10 +249,12 @@ public class DefaultAlarmQueryRepository implements AlarmQueryRepository {
239 if (pageLink.getPageSize() > 0) { 249 if (pageLink.getPageSize() > 0) {
240 dataQuery = String.format("%s limit %s offset %s", dataQuery, pageLink.getPageSize(), startIndex); 250 dataQuery = String.format("%s limit %s offset %s", dataQuery, pageLink.getPageSize(), startIndex);
241 } 251 }
242 - List<Map<String, Object>> rows = jdbcTemplate.queryForList(dataQuery, ctx);  
243 - if (logSqlQueries) {  
244 - log.info("QUERY: {}", dataQuery);  
245 - Arrays.asList(ctx.getParameterNames()).forEach(param -> log.info("QUERY PARAM: {}->{}", param, ctx.getValue(param))); 252 + queryTs = System.currentTimeMillis();
  253 + List<Map<String, Object>> rows;
  254 + try {
  255 + rows = jdbcTemplate.queryForList(dataQuery, ctx);
  256 + } finally {
  257 + queryLog.logQuery(ctx, dataQuery, System.currentTimeMillis() - queryTs);
246 } 258 }
247 return AlarmDataAdapter.createAlarmData(pageLink, rows, totalElements, orderedEntityIds); 259 return AlarmDataAdapter.createAlarmData(pageLink, rows, totalElements, orderedEntityIds);
248 }); 260 });
@@ -17,12 +17,8 @@ package org.thingsboard.server.dao.sql.query; @@ -17,12 +17,8 @@ package org.thingsboard.server.dao.sql.query;
17 17
18 import lombok.extern.slf4j.Slf4j; 18 import lombok.extern.slf4j.Slf4j;
19 import org.apache.commons.lang3.StringUtils; 19 import org.apache.commons.lang3.StringUtils;
20 -import org.springframework.beans.factory.annotation.Autowired;  
21 -import org.springframework.beans.factory.annotation.Value;  
22 import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; 20 import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
23 import org.springframework.stereotype.Repository; 21 import org.springframework.stereotype.Repository;
24 -import org.springframework.transaction.TransactionStatus;  
25 -import org.springframework.transaction.support.TransactionCallback;  
26 import org.springframework.transaction.support.TransactionTemplate; 22 import org.springframework.transaction.support.TransactionTemplate;
27 import org.thingsboard.server.common.data.EntityType; 23 import org.thingsboard.server.common.data.EntityType;
28 import org.thingsboard.server.common.data.id.CustomerId; 24 import org.thingsboard.server.common.data.id.CustomerId;
@@ -237,13 +233,12 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository { @@ -237,13 +233,12 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository {
237 233
238 private final NamedParameterJdbcTemplate jdbcTemplate; 234 private final NamedParameterJdbcTemplate jdbcTemplate;
239 private final TransactionTemplate transactionTemplate; 235 private final TransactionTemplate transactionTemplate;
  236 + private final DefaultQueryLogComponent queryLog;
240 237
241 - @Value("${sql.log_entity_queries:false}")  
242 - private boolean logSqlQueries;  
243 -  
244 - public DefaultEntityQueryRepository(NamedParameterJdbcTemplate jdbcTemplate, TransactionTemplate transactionTemplate) { 238 + public DefaultEntityQueryRepository(NamedParameterJdbcTemplate jdbcTemplate, TransactionTemplate transactionTemplate, DefaultQueryLogComponent queryLog) {
245 this.jdbcTemplate = jdbcTemplate; 239 this.jdbcTemplate = jdbcTemplate;
246 this.transactionTemplate = transactionTemplate; 240 this.transactionTemplate = transactionTemplate;
  241 + this.queryLog = queryLog;
247 } 242 }
248 243
249 @Override 244 @Override
@@ -254,11 +249,14 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository { @@ -254,11 +249,14 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository {
254 ctx.append(addEntityTableQuery(ctx, query.getEntityFilter())); 249 ctx.append(addEntityTableQuery(ctx, query.getEntityFilter()));
255 ctx.append(" e where "); 250 ctx.append(" e where ");
256 ctx.append(buildEntityWhere(ctx, query.getEntityFilter(), Collections.emptyList())); 251 ctx.append(buildEntityWhere(ctx, query.getEntityFilter(), Collections.emptyList()));
257 - if (logSqlQueries) {  
258 - log.info("QUERY: {}", ctx.getQuery());  
259 - Arrays.asList(ctx.getParameterNames()).forEach(param -> log.info("QUERY PARAM: {}->{}", param, ctx.getValue(param)));  
260 - }  
261 - return transactionTemplate.execute(status -> jdbcTemplate.queryForObject(ctx.getQuery(), ctx, Long.class)); 252 + return transactionTemplate.execute(status -> {
  253 + long startTs = System.currentTimeMillis();
  254 + try {
  255 + return jdbcTemplate.queryForObject(ctx.getQuery(), ctx, Long.class);
  256 + } finally {
  257 + queryLog.logQuery(ctx, ctx.getQuery(), System.currentTimeMillis() - startTs);
  258 + }
  259 + });
262 } 260 }
263 261
264 @Override 262 @Override
@@ -329,7 +327,14 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository { @@ -329,7 +327,14 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository {
329 fromClauseCount = fromClauseData; 327 fromClauseCount = fromClauseData;
330 } 328 }
331 String countQuery = String.format("select count(id) %s", fromClauseCount); 329 String countQuery = String.format("select count(id) %s", fromClauseCount);
332 - int totalElements = jdbcTemplate.queryForObject(countQuery, ctx, Integer.class); 330 +
  331 + long startTs = System.currentTimeMillis();
  332 + int totalElements;
  333 + try {
  334 + totalElements = jdbcTemplate.queryForObject(countQuery, ctx, Integer.class);
  335 + } finally {
  336 + queryLog.logQuery(ctx, countQuery, System.currentTimeMillis() - startTs);
  337 + }
333 338
334 if (totalElements == 0) { 339 if (totalElements == 0) {
335 return new PageData<>(); 340 return new PageData<>();
@@ -354,11 +359,13 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository { @@ -354,11 +359,13 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository {
354 if (pageLink.getPageSize() > 0) { 359 if (pageLink.getPageSize() > 0) {
355 dataQuery = String.format("%s limit %s offset %s", dataQuery, pageLink.getPageSize(), startIndex); 360 dataQuery = String.format("%s limit %s offset %s", dataQuery, pageLink.getPageSize(), startIndex);
356 } 361 }
357 - if (logSqlQueries) {  
358 - log.info("QUERY: {}", dataQuery);  
359 - Arrays.asList(ctx.getParameterNames()).forEach(param -> log.info("QUERY PARAM: {}->{}", param, ctx.getValue(param))); 362 + startTs = System.currentTimeMillis();
  363 + List<Map<String, Object>> rows;
  364 + try {
  365 + rows = jdbcTemplate.queryForList(dataQuery, ctx);
  366 + } finally {
  367 + queryLog.logQuery(ctx, countQuery, System.currentTimeMillis() - startTs);
360 } 368 }
361 - List<Map<String, Object>> rows = jdbcTemplate.queryForList(dataQuery, ctx);  
362 return EntityDataAdapter.createEntityData(pageLink, selectionMapping, rows, totalElements); 369 return EntityDataAdapter.createEntityData(pageLink, selectionMapping, rows, totalElements);
363 }); 370 });
364 } 371 }
@@ -486,7 +493,7 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository { @@ -486,7 +493,7 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository {
486 + SELECT_TYPE + ", " + SELECT_NAME + ", " + SELECT_LABEL + ", " + 493 + SELECT_TYPE + ", " + SELECT_NAME + ", " + SELECT_LABEL + ", " +
487 SELECT_FIRST_NAME + ", " + SELECT_LAST_NAME + ", " + SELECT_EMAIL + ", " + SELECT_REGION + ", " + 494 SELECT_FIRST_NAME + ", " + SELECT_LAST_NAME + ", " + SELECT_EMAIL + ", " + SELECT_REGION + ", " +
488 SELECT_TITLE + ", " + SELECT_COUNTRY + ", " + SELECT_STATE + ", " + SELECT_CITY + ", " + 495 SELECT_TITLE + ", " + SELECT_COUNTRY + ", " + SELECT_STATE + ", " + SELECT_CITY + ", " +
489 - SELECT_ADDRESS + ", " + SELECT_ADDRESS_2 + ", " + SELECT_ZIP + ", " + SELECT_PHONE + ", " + SELECT_ADDITIONAL_INFO + 496 + SELECT_ADDRESS + ", " + SELECT_ADDRESS_2 + ", " + SELECT_ZIP + ", " + SELECT_PHONE + ", " + SELECT_ADDITIONAL_INFO +
490 ", entity.entity_type as entity_type"; 497 ", entity.entity_type as entity_type";
491 String from = getQueryTemplate(entityFilter.getDirection()); 498 String from = getQueryTemplate(entityFilter.getDirection());
492 ctx.addUuidParameter("relation_root_id", rootId.getId()); 499 ctx.addUuidParameter("relation_root_id", rootId.getId());
  1 +/**
  2 + * Copyright © 2016-2020 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.dao.sql.query;
  17 +
  18 +import lombok.extern.slf4j.Slf4j;
  19 +import org.springframework.beans.factory.annotation.Value;
  20 +import org.springframework.stereotype.Component;
  21 +
  22 +import java.util.Arrays;
  23 +
  24 +@Component
  25 +@Slf4j
  26 +public class DefaultQueryLogComponent implements QueryLogComponent {
  27 +
  28 + @Value("${sql.log_queries:false}")
  29 + private boolean logSqlQueries;
  30 + @Value("${sql.log_queries_threshold:5000}")
  31 + private long logQueriesThreshold;
  32 +
  33 + @Override
  34 + public void logQuery(QueryContext ctx, String query, long duration) {
  35 + if (logSqlQueries && duration > logQueriesThreshold) {
  36 + log.info("QUERY: {} took {}ms", query, duration);
  37 + Arrays.asList(ctx.getParameterNames()).forEach(param -> log.info("QUERY PARAM: {} -> {}", param, ctx.getValue(param)));
  38 + }
  39 + }
  40 +}
  1 +/**
  2 + * Copyright © 2016-2020 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.dao.sql.query;
  17 +
  18 +public interface QueryLogComponent {
  19 +
  20 + void logQuery(QueryContext ctx, String query, long duration);
  21 +}