IGNITE-8999 Web Console: Added support for optional "trace" in error message.
Project: http://git-wip-us.apache.org/repos/asf/ignite/repo Commit: http://git-wip-us.apache.org/repos/asf/ignite/commit/c8b3ba49 Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/c8b3ba49 Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/c8b3ba49 Branch: refs/heads/ignite-6467-1 Commit: c8b3ba49676949db15f15f19a24ca0ec3e41da08 Parents: 3e44ba2 Author: Vasiliy Sisko <vsi...@gridgain.com> Authored: Mon Jul 30 17:42:32 2018 +0700 Committer: Alexey Kuznetsov <akuznet...@apache.org> Committed: Mon Jul 30 17:42:32 2018 +0700 ---------------------------------------------------------------------- modules/web-console/frontend/app/app.js | 2 + .../components/queries-notebook/controller.js | 18 ++-- .../app/services/ErrorParser.service.js | 89 ++++++++++++++++++++ .../frontend/app/services/Messages.service.js | 29 +------ 4 files changed, 101 insertions(+), 37 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ignite/blob/c8b3ba49/modules/web-console/frontend/app/app.js ---------------------------------------------------------------------- diff --git a/modules/web-console/frontend/app/app.js b/modules/web-console/frontend/app/app.js index 276eac8..b9d72ab 100644 --- a/modules/web-console/frontend/app/app.js +++ b/modules/web-console/frontend/app/app.js @@ -86,6 +86,7 @@ import SqlTypes from './services/SqlTypes.service'; import LegacyTable from './services/LegacyTable.service'; import LegacyUtils from './services/LegacyUtils.service'; import Messages from './services/Messages.service'; +import ErrorParser from './services/ErrorParser.service'; import ModelNormalizer from './services/ModelNormalizer.service.js'; import UnsavedChangesGuard from './services/UnsavedChangesGuard.service'; import Caches from './services/Caches'; @@ -285,6 +286,7 @@ export default angular.module('ignite-console', [ .service(...Focus) .service(...InetAddress) .service(...Messages) +.service('IgniteErrorParser', ErrorParser) .service(...ModelNormalizer) .service(...LegacyTable) .service(...FormUtils) http://git-wip-us.apache.org/repos/asf/ignite/blob/c8b3ba49/modules/web-console/frontend/app/components/page-queries/components/queries-notebook/controller.js ---------------------------------------------------------------------- diff --git a/modules/web-console/frontend/app/components/page-queries/components/queries-notebook/controller.js b/modules/web-console/frontend/app/components/page-queries/components/queries-notebook/controller.js index ad76df2..09c4184 100644 --- a/modules/web-console/frontend/app/components/page-queries/components/queries-notebook/controller.js +++ b/modules/web-console/frontend/app/components/page-queries/components/queries-notebook/controller.js @@ -66,7 +66,7 @@ const _fullColName = (col) => { let paragraphId = 0; class Paragraph { - constructor($animate, $timeout, JavaTypes, paragraph) { + constructor($animate, $timeout, JavaTypes, paragraph, errorParser) { const self = this; self.id = 'paragraph-' + paragraphId++; @@ -146,14 +146,14 @@ class Paragraph { this.setError = (err) => { this.error.root = err; - this.error.message = err.message; + this.error.message = errorParser.extractMessage(err); let cause = err; while (nonNil(cause)) { if (nonEmpty(cause.className) && _.includes(['SQLException', 'JdbcSQLException', 'QueryCancelledException'], JavaTypes.shortClassName(cause.className))) { - this.error.message = cause.message || cause.className; + this.error.message = errorParser.extractMessage(cause.message || cause.className); break; } @@ -251,16 +251,16 @@ class Paragraph { // Controller for SQL notebook screen. export class NotebookCtrl { - static $inject = ['$rootScope', '$scope', '$http', '$q', '$timeout', '$interval', '$animate', '$location', '$anchorScroll', '$state', '$filter', '$modal', '$popover', 'IgniteLoading', 'IgniteLegacyUtils', 'IgniteMessages', 'IgniteConfirm', 'AgentManager', 'IgniteChartColors', 'IgniteNotebook', 'IgniteNodes', 'uiGridExporterConstants', 'IgniteVersion', 'IgniteActivitiesData', 'JavaTypes', 'IgniteCopyToClipboard', CSV.name]; + static $inject = ['$rootScope', '$scope', '$http', '$q', '$timeout', '$interval', '$animate', '$location', '$anchorScroll', '$state', '$filter', '$modal', '$popover', 'IgniteLoading', 'IgniteLegacyUtils', 'IgniteMessages', 'IgniteConfirm', 'AgentManager', 'IgniteChartColors', 'IgniteNotebook', 'IgniteNodes', 'uiGridExporterConstants', 'IgniteVersion', 'IgniteActivitiesData', 'JavaTypes', 'IgniteCopyToClipboard', CSV.name, 'IgniteErrorParser']; /** * @param {CSV} CSV */ - constructor($root, $scope, $http, $q, $timeout, $interval, $animate, $location, $anchorScroll, $state, $filter, $modal, $popover, Loading, LegacyUtils, Messages, Confirm, agentMgr, IgniteChartColors, Notebook, Nodes, uiGridExporterConstants, Version, ActivitiesData, JavaTypes, IgniteCopyToClipboard, CSV) { + constructor($root, $scope, $http, $q, $timeout, $interval, $animate, $location, $anchorScroll, $state, $filter, $modal, $popover, Loading, LegacyUtils, Messages, Confirm, agentMgr, IgniteChartColors, Notebook, Nodes, uiGridExporterConstants, Version, ActivitiesData, JavaTypes, IgniteCopyToClipboard, CSV, errorParser) { const $ctrl = this; this.CSV = CSV; - Object.assign(this, { $root, $scope, $http, $q, $timeout, $interval, $animate, $location, $anchorScroll, $state, $filter, $modal, $popover, Loading, LegacyUtils, Messages, Confirm, agentMgr, IgniteChartColors, Notebook, Nodes, uiGridExporterConstants, Version, ActivitiesData, JavaTypes }); + Object.assign(this, { $root, $scope, $http, $q, $timeout, $interval, $animate, $location, $anchorScroll, $state, $filter, $modal, $popover, Loading, LegacyUtils, Messages, Confirm, agentMgr, IgniteChartColors, Notebook, Nodes, uiGridExporterConstants, Version, ActivitiesData, JavaTypes, errorParser }); // Define template urls. $ctrl.paragraphRateTemplateUrl = paragraphRateTemplateUrl; @@ -970,7 +970,7 @@ export class NotebookCtrl { $scope.notebook.paragraphs = []; $scope.notebook.paragraphs = _.map($scope.notebook.paragraphs, - (paragraph) => new Paragraph($animate, $timeout, JavaTypes, paragraph)); + (paragraph) => new Paragraph($animate, $timeout, JavaTypes, paragraph, this.errorParser)); if (_.isEmpty($scope.notebook.paragraphs)) $scope.addQuery(); @@ -1933,9 +1933,7 @@ export class NotebookCtrl { const addToTrace = (item) => { if (nonNil(item)) { - const clsName = _.isEmpty(item.className) ? '' : '[' + JavaTypes.shortClassName(item.className) + '] '; - - scope.content.push((scope.content.length > 0 ? tab : '') + clsName + (item.message || '')); + scope.content.push((scope.content.length > 0 ? tab : '') + errorParser.extractFullMessage(item)); addToTrace(item.cause); http://git-wip-us.apache.org/repos/asf/ignite/blob/c8b3ba49/modules/web-console/frontend/app/services/ErrorParser.service.js ---------------------------------------------------------------------- diff --git a/modules/web-console/frontend/app/services/ErrorParser.service.js b/modules/web-console/frontend/app/services/ErrorParser.service.js new file mode 100644 index 0000000..9cda8ed --- /dev/null +++ b/modules/web-console/frontend/app/services/ErrorParser.service.js @@ -0,0 +1,89 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import isEmpty from 'lodash/isEmpty'; +import {nonEmpty} from 'app/utils/lodashMixins'; + +export default class { + static $inject = ['JavaTypes']; + + /** + * @param JavaTypes service. + */ + constructor(JavaTypes) { + this.JavaTypes = JavaTypes; + } + + extractMessage(err, prefix) { + prefix = prefix || ''; + + if (err) { + if (err.hasOwnProperty('data')) + err = err.data; + + if (err.hasOwnProperty('message')) { + let msg = err.message; + + const traceIndex = msg.indexOf(', trace='); + + if (traceIndex > 0) + msg = msg.substring(0, traceIndex); + + const lastIdx = msg.lastIndexOf(' err='); + let msgEndIdx = msg.indexOf(']', lastIdx); + + if (lastIdx > 0 && msgEndIdx > 0) { + let startIdx = msg.indexOf('[', lastIdx); + + while (startIdx > 0) { + const tmpIdx = msg.indexOf(']', msgEndIdx + 1); + + if (tmpIdx > 0) + msgEndIdx = tmpIdx; + + startIdx = msg.indexOf('[', startIdx + 1); + } + } + + return prefix + (lastIdx >= 0 ? msg.substring(lastIdx + 5, msgEndIdx > 0 ? msgEndIdx : traceIndex) : msg); + } + + if (nonEmpty(err.className)) { + if (isEmpty(prefix)) + prefix = 'Internal cluster error: '; + + return prefix + err.className; + } + + return prefix + err; + } + + return prefix + 'Internal error.'; + } + + extractFullMessage(err) { + const clsName = _.isEmpty(err.className) ? '' : '[' + this.JavaTypes.shortClassName(err.className) + '] '; + + let msg = err.message || ''; + const traceIndex = msg.indexOf(', trace='); + + if (traceIndex > 0) + msg = msg.substring(0, traceIndex); + + return clsName + (msg); + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/c8b3ba49/modules/web-console/frontend/app/services/Messages.service.js ---------------------------------------------------------------------- diff --git a/modules/web-console/frontend/app/services/Messages.service.js b/modules/web-console/frontend/app/services/Messages.service.js index 170ff04..1337e24 100644 --- a/modules/web-console/frontend/app/services/Messages.service.js +++ b/modules/web-console/frontend/app/services/Messages.service.js @@ -16,39 +16,14 @@ */ import {CancellationError} from 'app/errors/CancellationError'; -import isEmpty from 'lodash/isEmpty'; -import {nonEmpty} from 'app/utils/lodashMixins'; // Service to show various information and error messages. -export default ['IgniteMessages', ['$alert', ($alert) => { +export default ['IgniteMessages', ['$alert', 'IgniteErrorParser', ($alert, errorParser) => { // Common instance of alert modal. let msgModal; const errorMessage = (prefix, err) => { - prefix = prefix || ''; - - if (err) { - if (err.hasOwnProperty('data')) - err = err.data; - - if (err.hasOwnProperty('message')) { - const msg = err.message; - const lastIdx = msg.lastIndexOf(' err='); - - return prefix + (lastIdx >= 0 ? msg.substring(lastIdx + 5, msg.indexOf(']', lastIdx)) : msg); - } - - if (nonEmpty(err.className)) { - if (isEmpty(prefix)) - prefix = 'Internal cluster error: '; - - return prefix + err.className; - } - - return prefix + err; - } - - return prefix + 'Internal error.'; + return errorParser.extractMessage(err, prefix); }; const hideAlert = () => {