Commit 52d23ac224f43323e60e4cd2a87cf74597e5e3ba

Authored by Igor Kulikov
2 parents c1b53afd cc5b2cc4

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

... ... @@ -273,7 +273,8 @@ sql:
273 273 # Specify whether to remove null characters from strValue of attributes and timeseries before insert
274 274 remove_null_chars: "${SQL_REMOVE_NULL_CHARS:true}"
275 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 278 postgres:
278 279 # Specify partitioning size for timestamp key-value storage. Example: DAYS, MONTHS, YEARS, INDEFINITE.
279 280 ts_key_value_partitioning: "${SQL_POSTGRES_TS_KV_PARTITIONING:MONTHS}"
... ...
... ... @@ -43,6 +43,7 @@ import org.thingsboard.server.dao.model.ModelConstants;
43 43 import java.util.ArrayList;
44 44 import java.util.Arrays;
45 45 import java.util.Collection;
  46 +import java.util.Collections;
46 47 import java.util.HashMap;
47 48 import java.util.HashSet;
48 49 import java.util.List;
... ... @@ -114,12 +115,12 @@ public class DefaultAlarmQueryRepository implements AlarmQueryRepository {
114 115 protected final NamedParameterJdbcTemplate jdbcTemplate;
115 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 121 this.jdbcTemplate = jdbcTemplate;
122 122 this.transactionTemplate = transactionTemplate;
  123 + this.queryLog = queryLog;
123 124 }
124 125
125 126 @Override
... ... @@ -230,8 +231,17 @@ public class DefaultAlarmQueryRepository implements AlarmQueryRepository {
230 231 if (!textSearchQuery.isEmpty()) {
231 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 246 String dataQuery = mainQuery + sortPart;
237 247
... ... @@ -239,10 +249,12 @@ public class DefaultAlarmQueryRepository implements AlarmQueryRepository {
239 249 if (pageLink.getPageSize() > 0) {
240 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 259 return AlarmDataAdapter.createAlarmData(pageLink, rows, totalElements, orderedEntityIds);
248 260 });
... ...
... ... @@ -17,12 +17,8 @@ package org.thingsboard.server.dao.sql.query;
17 17
18 18 import lombok.extern.slf4j.Slf4j;
19 19 import org.apache.commons.lang3.StringUtils;
20   -import org.springframework.beans.factory.annotation.Autowired;
21   -import org.springframework.beans.factory.annotation.Value;
22 20 import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
23 21 import org.springframework.stereotype.Repository;
24   -import org.springframework.transaction.TransactionStatus;
25   -import org.springframework.transaction.support.TransactionCallback;
26 22 import org.springframework.transaction.support.TransactionTemplate;
27 23 import org.thingsboard.server.common.data.EntityType;
28 24 import org.thingsboard.server.common.data.id.CustomerId;
... ... @@ -237,13 +233,12 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository {
237 233
238 234 private final NamedParameterJdbcTemplate jdbcTemplate;
239 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 239 this.jdbcTemplate = jdbcTemplate;
246 240 this.transactionTemplate = transactionTemplate;
  241 + this.queryLog = queryLog;
247 242 }
248 243
249 244 @Override
... ... @@ -254,11 +249,14 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository {
254 249 ctx.append(addEntityTableQuery(ctx, query.getEntityFilter()));
255 250 ctx.append(" e where ");
256 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 262 @Override
... ... @@ -329,7 +327,14 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository {
329 327 fromClauseCount = fromClauseData;
330 328 }
331 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 339 if (totalElements == 0) {
335 340 return new PageData<>();
... ... @@ -354,11 +359,13 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository {
354 359 if (pageLink.getPageSize() > 0) {
355 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 369 return EntityDataAdapter.createEntityData(pageLink, selectionMapping, rows, totalElements);
363 370 });
364 371 }
... ... @@ -486,7 +493,7 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository {
486 493 + SELECT_TYPE + ", " + SELECT_NAME + ", " + SELECT_LABEL + ", " +
487 494 SELECT_FIRST_NAME + ", " + SELECT_LAST_NAME + ", " + SELECT_EMAIL + ", " + SELECT_REGION + ", " +
488 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 497 ", entity.entity_type as entity_type";
491 498 String from = getQueryTemplate(entityFilter.getDirection());
492 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 +}
... ...