From cbc78b1894f1fa89e9633e7629181e6a0a04afc9 Mon Sep 17 00:00:00 2001 From: Harsh Gupta <42064744+Harshg999@users.noreply.github.com> Date: Thu, 23 Jan 2025 20:43:33 +0530 Subject: [PATCH] [logs] Add reverse order option for retrieving Hue logs --- desktop/core/src/desktop/log/api.py | 9 ++++++-- desktop/core/src/desktop/log/api_test.py | 28 +++++++++++++++++++----- 2 files changed, 29 insertions(+), 8 deletions(-) diff --git a/desktop/core/src/desktop/log/api.py b/desktop/core/src/desktop/log/api.py index 88683f60d98..c9348e67af5 100644 --- a/desktop/core/src/desktop/log/api.py +++ b/desktop/core/src/desktop/log/api.py @@ -26,6 +26,7 @@ from django.http import HttpResponse from desktop.auth.backend import is_admin +from desktop.lib.conf import coerce_bool from desktop.lib.django_util import JsonResponse from desktop.lib.i18n import smart_str from desktop.log import DEFAULT_LOG_DIR @@ -53,6 +54,7 @@ def decorator(*args, **kwargs): def get_hue_logs(request): """ Retrieves the last X characters of log messages from the log file. + Optionally, the log messages can be returned in reverse order. Args: request: The HTTP request object. @@ -68,11 +70,14 @@ def get_hue_logs(request): Notes: This endpoint retrieves the last X characters of log messages from the log file. The log file is read up to the buffer size, and if it's smaller than the buffer size, - the previous log file is read to complete the buffer. + the previous log file is read to complete the buffer. If the 'reverse' query parameter + is set to True, the log messages are returned in reverse order. """ if not is_admin(request.user): return HttpResponse("You must be a Hue admin to access this endpoint.", status=403) + reverse_logs = coerce_bool(request.GET.get('reverse', False)) + # Buffer size for reading log files LOG_BUFFER_SIZE = 32 * 1024 @@ -98,7 +103,7 @@ def get_hue_logs(request): # Read the previous log file contents buffer = _read_previous_log_file(LOG_BUFFER_SIZE, previous_log_file, prev_log_file_size, log_file_size) + buffer - response = {'hue_hostname': socket.gethostname(), 'logs': ''.join(buffer)} + response = {'hue_hostname': socket.gethostname(), 'logs': buffer[::-1] if reverse_logs else buffer} return JsonResponse(response) diff --git a/desktop/core/src/desktop/log/api_test.py b/desktop/core/src/desktop/log/api_test.py index 4dd4a3c7d67..8c87b3516d6 100644 --- a/desktop/core/src/desktop/log/api_test.py +++ b/desktop/core/src/desktop/log/api_test.py @@ -36,7 +36,7 @@ def setup_method(self): self.user_not_admin = User.objects.get(username="test_not_admin") def test_get_hue_logs_unauthorized(self): - request = Mock(method='GET', user=self.user_not_admin) + request = Mock(method='GET', GET={}, user=self.user_not_admin) response = get_hue_logs(request) res_content = response.content.decode('utf-8') @@ -46,7 +46,7 @@ def test_get_hue_logs_unauthorized(self): def test_log_directory_not_set(self): with patch('desktop.log.api.os.getenv') as os_getenv: - request = Mock(method='GET', user=self.user_admin) + request = Mock(method='GET', GET={}, user=self.user_admin) os_getenv.return_value = None response = get_hue_logs(request) @@ -58,7 +58,7 @@ def test_log_directory_not_set(self): def test_log_file_not_found(self): with patch('desktop.log.api.os.getenv') as os_getenv: with patch('desktop.log.api.os.path.exists') as os_path_exist: - request = Mock(method='GET', user=self.user_admin) + request = Mock(method='GET', GET={}, user=self.user_admin) os_getenv.return_value = '/var/log/hue/' os_path_exist.return_value = False @@ -71,8 +71,8 @@ def test_log_file_not_found(self): def test_get_hue_logs_success(self): with patch('desktop.log.api.os') as mock_os: with patch('desktop.log.api._read_log_file') as _read_log_file: - request = Mock(method='GET', user=self.user_admin) - _read_log_file.return_value = 'test log content' + request = Mock(method='GET', GET={}, user=self.user_admin) + _read_log_file.return_value = ['Line 1: test log content', 'Line 2: more log lines'] mock_os.os_getenv.return_value = '/var/log/hue/' mock_os.path.exists.return_value = True @@ -82,4 +82,20 @@ def test_get_hue_logs_success(self): response_data = json.loads(response.content) assert response.status_code == 200 - assert response_data == {'hue_hostname': socket.gethostname(), 'logs': 'test log content'} + assert response_data == {'hue_hostname': socket.gethostname(), 'logs': ['Line 1: test log content', 'Line 2: more log lines']} + + def test_get_hue_logs_reverse_success(self): + with patch('desktop.log.api.os') as mock_os: + with patch('desktop.log.api._read_log_file') as _read_log_file: + request = Mock(method='GET', GET={'reverse': 'true'}, user=self.user_admin) + _read_log_file.return_value = ['Line 1: test log content', 'Line 2: more log lines'] + + mock_os.os_getenv.return_value = '/var/log/hue/' + mock_os.path.exists.return_value = True + mock_os.path.getsize.return_value = 32 * 1024 * 2 # Greater than log buffer size + + response = get_hue_logs(request) + response_data = json.loads(response.content) + + assert response.status_code == 200 + assert response_data == {'hue_hostname': socket.gethostname(), 'logs': ['Line 2: more log lines', 'Line 1: test log content']}