diff --git a/corehq/apps/case_search/templates/case_search/profile_case_search.html b/corehq/apps/case_search/templates/case_search/profile_case_search.html index 8ef81047a72c..a79e9a6a366f 100644 --- a/corehq/apps/case_search/templates/case_search/profile_case_search.html +++ b/corehq/apps/case_search/templates/case_search/profile_case_search.html @@ -47,17 +47,17 @@

Profile Slow Case Searches

- seconds; + seconds
- % of total; + % of total
% of parent
+ class="list-group"> @@ -66,9 +66,14 @@

Profile Slow Case Searches

- Elasticsearch query: + Elasticsearch query #: + - + seconds
+ + Download Profile JSON +

         
diff --git a/corehq/apps/case_search/utils.py b/corehq/apps/case_search/utils.py index 07e19920f22d..2db2109c1d7d 100644 --- a/corehq/apps/case_search/utils.py +++ b/corehq/apps/case_search/utils.py @@ -3,6 +3,7 @@ from collections import defaultdict from dataclasses import dataclass, field from functools import wraps +from io import BytesIO from django.utils.functional import cached_property from django.utils.translation import gettext as _ @@ -40,11 +41,13 @@ reverse_index_case_query, wrap_case_search_hit, ) +from corehq.apps.hqadmin.utils import get_download_url from corehq.apps.registry.exceptions import ( RegistryAccessException, RegistryNotFound, ) from corehq.apps.registry.helper import DataRegistryHelper +from corehq.util.dates import get_timestamp_for_filename from corehq.util.quickcache import quickcache from corehq.util.timer import TimingContext @@ -57,24 +60,47 @@ class CaseSearchProfiler: timing_context: TimingContext = field( default_factory=lambda: TimingContext('Case Search')) queries: list = field(default_factory=list) - profile_results: list = field(default_factory=list) + _query_number: int = 0 def run_query(self, slug, es_query): + self._query_number += 1 if self.debug_mode: es_query = es_query.enable_profiling() - with self.timing_context('run query'): + tc = self.timing_context(f'run query #{self._query_number}: {slug}') + timer = tc.peek() + with tc: results = es_query.run() if self.debug_mode: - self.queries.append({'slug': slug, 'query': es_query.raw_query}) - self.profile_results.append({'slug': slug, 'results': results.raw.get('profile')}) - + self.queries.append({ + 'slug': slug, + 'query_number': self._query_number, + 'query': es_query.raw_query, + 'duration': timer.duration, + 'profile_url': self._get_profile_url(slug, self._query_number, results.raw.get('profile')), + }) return results def add_query(self, slug, es_query): + self._query_number += 1 if self.debug_mode: - self.queries.append({'slug': slug, 'query': es_query.raw_query}) + self.queries.append({ + 'slug': slug, + 'query_number': self._query_number, + 'query': es_query.raw_query, + 'duration': None, + 'profile_url': None, + }) + + @staticmethod + def _get_profile_url(slug, query_number, profile_json): + timestamp = get_timestamp_for_filename() + name = f'es_profile_{query_number}_{slug}_{timestamp}.json' + io = BytesIO() + io.write(json.dumps(profile_json).encode('utf-8')) + io.seek(0) + return get_download_url(io, name, content_type='application/json') def time_function(): diff --git a/corehq/apps/case_search/views.py b/corehq/apps/case_search/views.py index f38bb2fb456e..f27170d9aa12 100644 --- a/corehq/apps/case_search/views.py +++ b/corehq/apps/case_search/views.py @@ -116,5 +116,4 @@ def post(self, request, *args, **kwargs): 'related_count': profiler.related_count, 'timing_data': profiler.timing_context.to_dict(), 'queries': profiler.queries, - 'profile_results': profiler.profile_results, })