Skip to content

Commit 2dbe3f4

Browse files
authored
Add query metrics (#1035)
1 parent d449d57 commit 2dbe3f4

File tree

2 files changed

+93
-1
lines changed

2 files changed

+93
-1
lines changed

pom.xml

+1-1
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@
6565
<fmt.maven.plugin.version>2.3.0</fmt.maven.plugin.version>
6666

6767
<!--Backend properties-->
68-
<ddf.version>2.29.14</ddf.version>
68+
<ddf.version>2.29.15</ddf.version>
6969
<ddf-jsonrpc.version>0.9</ddf-jsonrpc.version>
7070
<ddf.support.version>2.3.16</ddf.support.version>
7171
<antlr.version>4.3</antlr.version>

ui-backend/catalog-ui-search/src/main/java/org/codice/ddf/catalog/ui/util/CqlQueriesImpl.java

+92
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,15 @@
1313
*/
1414
package org.codice.ddf.catalog.ui.util;
1515

16+
import static ddf.catalog.Constants.QUERY_LOGGER_NAME;
17+
import static ddf.catalog.impl.operations.QueryOperations.QM_DO_QUERY;
18+
import static ddf.catalog.impl.operations.QueryOperations.QM_POST_QUERY;
19+
import static ddf.catalog.impl.operations.QueryOperations.QM_PRE_QUERY;
20+
import static ddf.catalog.impl.operations.QueryOperations.QM_TIMED_SOURCE;
21+
import static ddf.catalog.impl.operations.QueryOperations.QM_TOTAL_ELAPSED;
22+
import static java.time.ZoneOffset.UTC;
23+
import static java.time.format.DateTimeFormatter.ISO_DATE_TIME;
24+
1625
import com.google.common.base.Stopwatch;
1726
import com.google.gson.Gson;
1827
import com.google.gson.GsonBuilder;
@@ -54,9 +63,13 @@
5463
import org.codice.ddf.catalog.ui.query.utility.Status;
5564
import org.codice.ddf.catalog.ui.transformer.TransformerDescriptors;
5665
import org.codice.gsonsupport.GsonTypeAdapters;
66+
import org.slf4j.Logger;
67+
import org.slf4j.LoggerFactory;
5768

5869
public class CqlQueriesImpl implements CqlQueries {
5970

71+
private static final Logger QUERY_LOGGER = LoggerFactory.getLogger(QUERY_LOGGER_NAME);
72+
6073
private final CatalogFramework catalogFramework;
6174

6275
private final FilterBuilder filterBuilder;
@@ -69,6 +82,8 @@ public class CqlQueriesImpl implements CqlQueries {
6982

7083
private static final String METRICS_SOURCE_ELAPSED_PREFIX = "metrics.source.elapsed.";
7184

85+
private static final String CACHE_SOURCES_KEY = "cache-sources";
86+
7287
private static final Gson GSON =
7388
new GsonBuilder()
7489
.disableHtmlEscaping()
@@ -92,6 +107,8 @@ public CqlQueriesImpl(
92107
public CqlQueryResponse executeCqlQuery(CqlRequest cqlRequest)
93108
throws UnsupportedQueryException, SourceUnavailableException, FederationException,
94109
CqlParseException {
110+
long start = System.nanoTime();
111+
String startTime = (new Date()).toInstant().atOffset(UTC).format(ISO_DATE_TIME);
95112
QueryRequest request = cqlRequest.createQueryRequest(catalogFramework.getId(), filterBuilder);
96113
Stopwatch stopwatch = Stopwatch.createStarted();
97114

@@ -194,6 +211,12 @@ public CqlQueryResponse executeCqlQuery(CqlRequest cqlRequest)
194211
properties,
195212
processingDetails);
196213

214+
if (!responses.isEmpty()) {
215+
responses.get(0).getProperties().put("start-time", startTime);
216+
responses.get(0).getProperties().put(QM_TOTAL_ELAPSED, System.nanoTime() - start);
217+
QUERY_LOGGER.info("QueryMetrics: {}", getQueryMetricsLog(responses));
218+
}
219+
197220
return new CqlQueryResponseImpl(
198221
cqlRequest.getId(),
199222
request,
@@ -205,6 +228,75 @@ public CqlQueryResponse executeCqlQuery(CqlRequest cqlRequest)
205228
descriptors);
206229
}
207230

231+
private Map<String, Serializable> collectQueryProperties(
232+
Map<String, Serializable> requestProps, Map<String, Serializable> responseProps) {
233+
Map<String, Serializable> allProperties = new HashMap<>();
234+
if (requestProps != null) {
235+
allProperties.putAll(requestProps);
236+
}
237+
if (responseProps != null) {
238+
allProperties.putAll(responseProps);
239+
}
240+
return allProperties;
241+
}
242+
243+
private String getQueryMetricsLog(List<QueryResponse> queryResponses) {
244+
Map<String, Serializable> metricsMap = new HashMap<>();
245+
metricsMap.put("start-time", queryResponses.get(0).getProperties().get("start-time"));
246+
for (QueryResponse queryResponse : queryResponses) {
247+
Map<String, Serializable> requestProperties =
248+
queryResponse.getRequest() == null ? null : queryResponse.getRequest().getProperties();
249+
Map<String, Serializable> properties =
250+
collectQueryProperties(requestProperties, queryResponse.getProperties());
251+
// Combine the request and response metrics to log
252+
253+
addMetric(metricsMap, "total-duration", properties.get(QM_TOTAL_ELAPSED));
254+
addMetric(metricsMap, "prequery-duration", properties.get(QM_PRE_QUERY));
255+
addMetric(metricsMap, "query-duration", properties.get(QM_DO_QUERY));
256+
addMetric(metricsMap, "postquery-duration", properties.get(QM_POST_QUERY));
257+
HashMap<String, Serializable> sourceDurationMap = new HashMap<>();
258+
properties
259+
.entrySet()
260+
.stream()
261+
.filter(e -> e.getKey() != null && e.getKey().startsWith(QM_TIMED_SOURCE))
262+
.forEach(e -> sourceDurationMap.put(e.getKey().split(QM_TIMED_SOURCE)[1], e.getValue()));
263+
Serializable cacheSourceValue = sourceDurationMap.remove("cache");
264+
if (cacheSourceValue != null) {
265+
String sourceName = properties.get(CACHE_SOURCES_KEY).toString();
266+
sourceDurationMap.put(sourceName == null ? "Unknown Source" : sourceName, cacheSourceValue);
267+
}
268+
Map<String, Serializable> oldSourceDurationMap =
269+
(Map<String, Serializable>) metricsMap.remove("source-duration");
270+
if (oldSourceDurationMap != null) {
271+
oldSourceDurationMap.forEach((key, value) -> addMetric(sourceDurationMap, key, value));
272+
}
273+
metricsMap.put("source-duration", sourceDurationMap);
274+
}
275+
276+
HashMap<String, Serializable> additionalQueryMetrics =
277+
(HashMap<String, Serializable>)
278+
queryResponses.get(0).getProperties().get("additional-query-metrics");
279+
if (additionalQueryMetrics != null) {
280+
metricsMap.putAll(additionalQueryMetrics);
281+
}
282+
283+
Gson gson = new GsonBuilder().disableHtmlEscaping().create();
284+
return gson.toJson(metricsMap);
285+
}
286+
287+
private void addMetric(
288+
Map<String, Serializable> metricsMap, String metricName, Serializable metricValue) {
289+
if (metricValue == null) {
290+
return;
291+
}
292+
Serializable oldMetricValue = metricsMap.remove(metricName);
293+
if (oldMetricValue != null) {
294+
metricsMap.put(metricName, (long) metricValue + (long) oldMetricValue);
295+
}
296+
297+
metricsMap.put(metricName, metricValue);
298+
}
299+
208300
private List<Result> retrieveHitCount(QueryRequest request, List<QueryResponse> responses)
209301
throws UnsupportedQueryException, SourceUnavailableException, FederationException {
210302
QueryResponse queryResponse = catalogFramework.query(request);

0 commit comments

Comments
 (0)