Add real time log view in GUI 53/38953/3
authorchenjiankun <chenjiankun1@huawei.com>
Wed, 9 Aug 2017 03:23:58 +0000 (03:23 +0000)
committerchenjiankun <chenjiankun1@huawei.com>
Fri, 11 Aug 2017 09:29:58 +0000 (09:29 +0000)
JIRA: YARDSTICK-775

We have GUI now, but we can't see real time log in GUI view.
So I add real time log view in GUI.

Change-Id: Ie83f327ef0a94302afa6b3def764fec6ef5818d1
Signed-off-by: chenjiankun <chenjiankun1@huawei.com>
13 files changed:
api/__init__.py
api/resources/v2/tasks.py
api/urls.py
gui/app/index.html
gui/app/scripts/controllers/projectDetail.controller.js
gui/app/scripts/controllers/taskLog.controller.js [new file with mode: 0644]
gui/app/scripts/factory/main.factory.js
gui/app/scripts/router.config.js
gui/app/views/projectdetail.html
gui/app/views/taskLog.html [new file with mode: 0644]
tests/unit/benchmark/core/test_task.py
yardstick/benchmark/core/task.py
yardstick/common/constants.py

index c5aefff..3235022 100644 (file)
@@ -35,13 +35,11 @@ class ApiResource(Resource):
             pass
 
         args.update({k: v for k, v in request.form.items()})
-        LOG.debug('Input args is: action: %s, args: %s', action, args)
 
         return action, args
 
     def _get_args(self):
         args = common_utils.translate_to_str(request.args)
-        LOG.debug('Input args is: args: %s', args)
 
         return args
 
index 885a190..25a9cf1 100644 (file)
@@ -8,6 +8,8 @@
 ##############################################################################
 import uuid
 import logging
+import os
+import errno
 from datetime import datetime
 
 from oslo_serialization import jsonutils
@@ -252,3 +254,37 @@ class V2Task(ApiResource):
         task_thread.start()
 
         return result_handler(consts.API_SUCCESS, {'uuid': task_id})
+
+
+class V2TaskLog(ApiResource):
+
+    def get(self, task_id):
+        try:
+            uuid.UUID(task_id)
+        except ValueError:
+            return result_handler(consts.API_ERROR, 'invalid task id')
+
+        task_handler = V2TaskHandler()
+        try:
+            task = task_handler.get_by_uuid(task_id)
+        except ValueError:
+            return result_handler(consts.API_ERROR, 'no such task id')
+
+        index = int(self._get_args().get('index', 0))
+
+        try:
+            with open(os.path.join(consts.TASK_LOG_DIR, '{}.log'.format(task_id))) as f:
+                f.seek(index)
+                data = f.readlines()
+                index = f.tell()
+        except OSError as e:
+            if e.errno == errno.ENOENT:
+                return result_handler(consts.API_ERROR, 'log file does not exist')
+            return result_handler(consts.API_ERROR, 'error with log file')
+
+        return_data = {
+            'index': index,
+            'data': data
+        }
+
+        return result_handler(task.status, return_data)
index 3fef91a..83cf4da 100644 (file)
@@ -48,6 +48,7 @@ urlpatterns = [
     Url('/api/v2/yardstick/tasks', 'v2_tasks'),
     Url('/api/v2/yardstick/tasks/action', 'v2_tasks'),
     Url('/api/v2/yardstick/tasks/<task_id>', 'v2_task'),
+    Url('/api/v2/yardstick/tasks/<task_id>/log', 'v2_task_log'),
 
     Url('/api/v2/yardstick/testcases', 'v2_testcases'),
     Url('/api/v2/yardstick/testcases/action', 'v2_testcases'),
index 5592656..d959b14 100644 (file)
     <script src="scripts/controllers/suitedetail.controller.js"></script>
     <script src="scripts/controllers/suitecreate.controller.js"></script>
     <script src="scripts/controllers/task.controller.js"></script>
+    <script src="scripts/controllers/taskLog.controller.js"></script>
     <script src="scripts/controllers/report.controller.js"></script>
     <script src="scripts/controllers/project.controller.js"></script>
     <script src="scripts/controllers/projectDetail.controller.js"></script>
index 4ab4a05..a616f3e 100644 (file)
@@ -671,20 +671,8 @@ angular.module('yardStickGui2App')
                 })
             }
 
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+            $scope.gotoLog = function gotoLog(task_id) {
+                $state.go('app2.taskLog', { taskId: task_id });
+            }
         }
-    ]);
\ No newline at end of file
+    ]);
diff --git a/gui/app/scripts/controllers/taskLog.controller.js b/gui/app/scripts/controllers/taskLog.controller.js
new file mode 100644 (file)
index 0000000..17722b7
--- /dev/null
@@ -0,0 +1,34 @@
+'use strict';
+
+angular.module('yardStickGui2App').controller('TaskLogController', ['$scope', '$stateParams', '$http', '$interval', 'mainFactory', function ($scope, $stateParams, $http, $interval, mainFactory) {
+        $scope.logLines = [];
+        $scope.getLog = getLog;
+        $scope.taskId = $stateParams.taskId;
+        $scope.taskStatus = 0;
+        $scope.index = 0;
+
+        $scope.goBack = function goBack() {
+            window.history.back();
+        }
+
+        function getLog(){
+
+            function get_data(){
+                mainFactory.getTaskLog().get({'taskId': $scope.taskId, 'index': $scope.index}).$promise.then(function(data){
+                    angular.forEach(data.result.data, function(ele){
+                        $scope.logLines.push(ele);
+                        $scope.index = data.result.index;
+                    });
+
+                    if(data.status == 1){
+                        $interval.cancel($scope.intervalTask);
+                        $scope.taskStatus = 1;
+                    }
+                });
+            }
+
+            $scope.intervalTask = $interval(get_data, 2000);
+        }
+
+        getLog();
+}]);
index f8e9df9..44fbeb3 100644 (file)
@@ -178,6 +178,14 @@ angular.module('yardStickGui2App')
                 })
             },
 
+            getTaskLog: function(){
+                return $resource(Base_URL + '/api/v2/yardstick/tasks/:taskId/log?index=:index', { taskId: "@taskId", index: "@index" }, {
+                    'get': {
+                        method: 'GET'
+                    }
+                })
+            },
+
             taskAddEnv: function() {
                 return $resource(Base_URL + '/api/v2/yardstick/tasks/:taskId', { taskId: "@taskId" }, {
                     'put': {
index b429542..9d3c045 100644 (file)
@@ -142,6 +142,16 @@ angular.module('yardStickGui2App')
                         label: 'Task'
                     }
 
+                })
+                .state('app2.taskLog', {
+                    url: '/task/:taskId/log',
+                    templateUrl: 'views/taskLog.html',
+                    controller: 'TaskLogController',
+                    params: { taskId: null },
+                    ncyBreadcrumb: {
+                        label: 'TaskLog'
+                    }
+
                 })
                 .state('app2.report', {
                     url: '/report/:taskId',
index 357a26a..405ff5a 100644 (file)
@@ -47,6 +47,7 @@
                             <li role="menuitem" ng-show="task.status!=0"><a ng-click="runAtaskForTable(task.uuid)">run</a></li>
 
                             <li role="menuitem" ng-show="task.status!=0"><a ng-click="gotoModify(task.uuid)">modify</a></li>
+                            <li role="menuitem" ng-show="task.status!=-1"><a ng-click="gotoLog(task.uuid)">log</a></li>
                             <li role="menuitem" ng-show="task.status!=-1 && task.status!=0"><a ng-click="gotoReport(task.uuid)" style="color:#2ecc71">reporting</a></li>
                             <li role="menuitem"><a ng-click="openDeleteEnv(task.uuid,'task')">delete</a></li>
 
diff --git a/gui/app/views/taskLog.html b/gui/app/views/taskLog.html
new file mode 100644 (file)
index 0000000..f90eb22
--- /dev/null
@@ -0,0 +1,39 @@
+<div class="content">
+    <i class="fa fa-arrow-left fa-1x" aria-hidden="true" style="color: #999;cursor:pointer" ng-click="goBack()">Back</i>
+    <h3>Log</h3>
+    <hr/>
+    <div style="display:flex;flex-direction:row">
+        <div>
+            <div style="margin-top:5px;">Task: {{ taskId }}</div>
+        </div>
+        <div class="progree-parent"  style="margin-top:10px;margin-left:20px">
+            <div class="progree-child" ng-show="taskStatus==0" style="width:50%"></div>
+            <div class="progree-child" ng-show="taskStatus==1" style="width:100%"></div>
+        </div>
+        <i class="fa fa-check" aria-hidden="true" style="margin-top:10px;margin-left:5px;color: #2ecc71;" ng-show="taskStatus==1">finish</i>
+        <i class="fa fa-spinner" aria-hidden="true" style="margin-top:10px;margin-left:5px;color: #2ecc71;" ng-show="taskStatus==0">runing</i>
+    </div>
+    <div class="box">
+        <div class="line-block" ng-repeat="line in logLines track by $index">
+            <span>{{ line }}</span>
+        </div>
+    </div>
+</div>
+
+<style>
+    .box {
+        width: 90%%;
+        border-radius: 5px;
+        border: 1px solid #e8e8e8;
+        line-height: 180%;
+        margin-top: 20px;
+    }
+
+    .line-block {
+        margin-left: 10px;
+    }
+
+    .content {
+        height: 90%;
+    }
+</style>
index 7f61753..25688bf 100644 (file)
@@ -118,7 +118,8 @@ class TaskTestCase(unittest.TestCase):
             },
         ])
 
-        expected_get_network_calls = 4 # once for each vld_id in the nodes dict
+        # once for each vld_id in the nodes dict
+        expected_get_network_calls = 4
         expected = {
             'a': {'name': 'a', 'network_type': 'private'},
             'b': {'name': 'b', 'vld_id': 'y', 'subnet_cidr': '10.20.0.0/16'},
@@ -289,6 +290,13 @@ class TaskTestCase(unittest.TestCase):
         task.change_server_name(scenario, suffix)
         self.assertTrue(scenario['target']['name'], 'demo-8')
 
+    @mock.patch('yardstick.benchmark.core.task.logging')
+    def test_set_log(self, mock_logging):
+        task_obj = task.Task()
+        task_obj.task_id = 'task_id'
+        task_obj._set_log()
+        self.assertTrue(mock_logging.root.addHandler.called)
+
     def _get_file_abspath(self, filename):
         curr_path = os.path.dirname(os.path.abspath(__file__))
         file_path = os.path.join(curr_path, filename)
index 395f3b8..dd35bd4 100644 (file)
@@ -65,6 +65,8 @@ class Task(object):     # pragma: no cover
         task_id = getattr(args, 'task_id')
         self.task_id = task_id if task_id else str(uuid.uuid4())
 
+        self._set_log()
+
         check_environment()
 
         try:
@@ -156,6 +158,17 @@ class Task(object):     # pragma: no cover
         print("Done, exiting")
         return result
 
+    def _set_log(self):
+        log_format = '%(asctime)s %(name)s %(filename)s:%(lineno)d %(levelname)s %(message)s'
+        log_formatter = logging.Formatter(log_format)
+
+        log_path = os.path.join(constants.TASK_LOG_DIR, '{}.log'.format(self.task_id))
+        log_handler = logging.FileHandler(log_path)
+        log_handler.setFormatter(log_formatter)
+        log_handler.setLevel(logging.DEBUG)
+
+        logging.root.addHandler(log_handler)
+
     def _init_output_config(self, output_config):
         output_config.setdefault('DEFAULT', {})
         output_config.setdefault('dispatcher_http', {})
@@ -414,7 +427,7 @@ class TaskParser(object):       # pragma: no cover
 
         try:
             with open(self.path) as stream:
-                cfg = yaml.safe_load(stream)
+                cfg = yaml.load(stream)
         except IOError as ioerror:
             sys.exit(ioerror)
 
@@ -478,7 +491,7 @@ class TaskParser(object):       # pragma: no cover
                     raise e
                 print("Input task is:\n%s\n" % rendered_task)
 
-                cfg = yaml.safe_load(rendered_task)
+                cfg = yaml.load(rendered_task)
         except IOError as ioerror:
             sys.exit(ioerror)
 
index 822d3b4..f80e104 100644 (file)
@@ -64,6 +64,7 @@ RELENG_DIR = get_param('dir.releng', '/home/opnfv/repos/releng')
 LOG_DIR = get_param('dir.log', '/tmp/yardstick/')
 YARDSTICK_ROOT_PATH = dirname(
     dirname(abspath(pkg_resources.resource_filename(__name__, "")))) + sep
+TASK_LOG_DIR = get_param('dir.tasklog', '/var/log/yardstick/')
 CONF_SAMPLE_DIR = join(REPOS_DIR, 'etc/yardstick/')
 ANSIBLE_DIR = join(REPOS_DIR, 'ansible')
 SAMPLE_CASE_DIR = join(REPOS_DIR, 'samples')