Prechádzať zdrojové kódy

[api][logs] Add reverse order option for retrieving Hue logs (#3968)

Harsh Gupta 10 mesiacov pred
rodič
commit
162e33a880

+ 7 - 2
desktop/core/src/desktop/log/api.py

@@ -26,6 +26,7 @@ from wsgiref.util import FileWrapper
 from django.http import HttpResponse
 from django.http import HttpResponse
 
 
 from desktop.auth.backend import is_admin
 from desktop.auth.backend import is_admin
+from desktop.lib.conf import coerce_bool
 from desktop.lib.django_util import JsonResponse
 from desktop.lib.django_util import JsonResponse
 from desktop.lib.i18n import smart_str
 from desktop.lib.i18n import smart_str
 from desktop.log import DEFAULT_LOG_DIR
 from desktop.log import DEFAULT_LOG_DIR
@@ -53,6 +54,7 @@ def api_error_handler(view_fn):
 def get_hue_logs(request):
 def get_hue_logs(request):
   """
   """
   Retrieves the last X characters of log messages from the log file.
   Retrieves the last X characters of log messages from the log file.
+  Optionally, the log messages can be returned in reverse order.
 
 
   Args:
   Args:
     request: The HTTP request object.
     request: The HTTP request object.
@@ -68,11 +70,14 @@ def get_hue_logs(request):
   Notes:
   Notes:
     This endpoint retrieves the last X characters of log messages from the log file.
     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 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):
   if not is_admin(request.user):
     return HttpResponse("You must be a Hue admin to access this endpoint.", status=403)
     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
   # Buffer size for reading log files
   LOG_BUFFER_SIZE = 32 * 1024
   LOG_BUFFER_SIZE = 32 * 1024
 
 
@@ -98,7 +103,7 @@ def get_hue_logs(request):
       # Read the previous log file contents
       # 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
       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)
   return JsonResponse(response)
 
 
 
 

+ 22 - 6
desktop/core/src/desktop/log/api_test.py

@@ -36,7 +36,7 @@ class TestHueLogs:
     self.user_not_admin = User.objects.get(username="test_not_admin")
     self.user_not_admin = User.objects.get(username="test_not_admin")
 
 
   def test_get_hue_logs_unauthorized(self):
   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)
     response = get_hue_logs(request)
     res_content = response.content.decode('utf-8')
     res_content = response.content.decode('utf-8')
@@ -46,7 +46,7 @@ class TestHueLogs:
 
 
   def test_log_directory_not_set(self):
   def test_log_directory_not_set(self):
     with patch('desktop.log.api.os.getenv') as os_getenv:
     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
       os_getenv.return_value = None
 
 
       response = get_hue_logs(request)
       response = get_hue_logs(request)
@@ -58,7 +58,7 @@ class TestHueLogs:
   def test_log_file_not_found(self):
   def test_log_file_not_found(self):
     with patch('desktop.log.api.os.getenv') as os_getenv:
     with patch('desktop.log.api.os.getenv') as os_getenv:
       with patch('desktop.log.api.os.path.exists') as os_path_exist:
       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_getenv.return_value = '/var/log/hue/'
         os_path_exist.return_value = False
         os_path_exist.return_value = False
 
 
@@ -71,8 +71,8 @@ class TestHueLogs:
   def test_get_hue_logs_success(self):
   def test_get_hue_logs_success(self):
     with patch('desktop.log.api.os') as mock_os:
     with patch('desktop.log.api.os') as mock_os:
       with patch('desktop.log.api._read_log_file') as _read_log_file:
       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.os_getenv.return_value = '/var/log/hue/'
         mock_os.path.exists.return_value = True
         mock_os.path.exists.return_value = True
@@ -82,4 +82,20 @@ class TestHueLogs:
         response_data = json.loads(response.content)
         response_data = json.loads(response.content)
 
 
         assert response.status_code == 200
         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']}