summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--MANIFEST.in1
-rw-r--r--README.rst2
-rw-r--r--glances/outputs/bottle/plugin_table.tpl22
-rw-r--r--glances/outputs/bottle/plugin_text.tpl11
-rw-r--r--glances/outputs/glances_bottle.py106
-rw-r--r--glances/outputs/static/css/style.css130
-rw-r--r--glances/outputs/static/html/components/monitor_process.html4
-rw-r--r--glances/outputs/static/html/help.html63
-rw-r--r--glances/outputs/static/html/index.html28
-rw-r--r--glances/outputs/static/html/plugins/alert.html7
-rw-r--r--glances/outputs/static/html/plugins/alerts.html2
-rw-r--r--glances/outputs/static/html/plugins/cpu.html44
-rw-r--r--glances/outputs/static/html/plugins/cpu_more.html26
-rw-r--r--glances/outputs/static/html/plugins/diskio.html10
-rw-r--r--glances/outputs/static/html/plugins/docker.html20
-rw-r--r--glances/outputs/static/html/plugins/fs.html12
-rw-r--r--glances/outputs/static/html/plugins/ip.html1
-rw-r--r--glances/outputs/static/html/plugins/load.html24
-rw-r--r--glances/outputs/static/html/plugins/mem.html20
-rw-r--r--glances/outputs/static/html/plugins/mem_more.html18
-rw-r--r--glances/outputs/static/html/plugins/memswap.html20
-rw-r--r--glances/outputs/static/html/plugins/monitor.html3
-rw-r--r--glances/outputs/static/html/plugins/network.html12
-rw-r--r--glances/outputs/static/html/plugins/processcount.html6
-rw-r--r--glances/outputs/static/html/plugins/processlist.html31
-rw-r--r--glances/outputs/static/html/plugins/sensors.html8
-rw-r--r--glances/outputs/static/html/plugins/system.html6
-rw-r--r--glances/outputs/static/html/plugins/uptime.html1
-rw-r--r--glances/outputs/static/html/stats.html64
-rw-r--r--glances/outputs/static/images/glances.pngbin0 -> 43588 bytes
-rw-r--r--glances/outputs/static/js/app.js13
-rw-r--r--glances/outputs/static/js/directives.js78
-rw-r--r--glances/outputs/static/js/filters.js44
-rwxr-xr-xglances/outputs/static/js/modernizr.custom.js4
-rw-r--r--glances/outputs/static/js/stats_controller.js271
-rw-r--r--glances/outputs/static/js/variables.js30
-rw-r--r--glances/outputs/static/js/vendors/angular-route.min.js15
-rw-r--r--glances/outputs/static/js/vendors/angular-route.min.js.map8
-rw-r--r--glances/outputs/static/js/vendors/angular.min.js218
-rw-r--r--glances/outputs/static/js/vendors/angular.min.js.map8
-rw-r--r--glances/outputs/static/js/vendors/lodash.min.js137
-rw-r--r--glances/plugins/glances_docker.py2
-rw-r--r--glances/plugins/glances_help.py160
43 files changed, 1506 insertions, 184 deletions
diff --git a/MANIFEST.in b/MANIFEST.in
index 74ab5f46..859466ca 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -7,6 +7,7 @@ include glances/outputs/bottle/*.tpl
include glances/outputs/static/*.ico
include glances/outputs/static/css/*.css
include glances/outputs/static/js/*.js
+include glances/outputs/static/js/*.js.map
include man/glances.1
recursive-include docs images/*.png glances-doc.html
recursive-include glances *.py
diff --git a/README.rst b/README.rst
index 41669e1c..75d316d0 100644
--- a/README.rst
+++ b/README.rst
@@ -13,7 +13,7 @@ Glances - An eye on your system
.. image:: https://pypip.in/d/Glances/badge.png
:target: https://pypi.python.org/pypi/Glances/
:alt: Downloads
-
+
Follow Glances on Twitter: `@nicolargo`_ or `@glances_system`_
diff --git a/glances/outputs/bottle/plugin_table.tpl b/glances/outputs/bottle/plugin_table.tpl
deleted file mode 100644
index f98e5497..00000000
--- a/glances/outputs/bottle/plugin_table.tpl
+++ /dev/null
@@ -1,22 +0,0 @@
-% if stats['msgdict'] != []:
-<section id="{{ plugin_name }}" class="plugin">
- <table class="table">
- <tbody>
- <tr>
- % for msg in stats['msgdict']:
- % if msg['msg'].startswith('\n'):
- </tr>
- <tr>
- % else:
- % if stats['display']:
- <td class="{{ msg['decoration'].lower() }} {{ 'hidden-xs hidden-sm' if msg['optional'] else '' }}">
- {{ msg['msg'] }}
- </td>
- % end
- % end
- % end
- </tr>
- </tbody>
- </table>
-</section>
-% end \ No newline at end of file
diff --git a/glances/outputs/bottle/plugin_text.tpl b/glances/outputs/bottle/plugin_text.tpl
deleted file mode 100644
index 990e7478..00000000
--- a/glances/outputs/bottle/plugin_text.tpl
+++ /dev/null
@@ -1,11 +0,0 @@
-% if stats['msgdict'] != []:
-<section id="{{ plugin_name }}" class="plugin">
-% for msg in stats['msgdict']:
- % if stats['display']:
- <span class="{{ msg['decoration'].lower() }} {{ 'hidden-xs hidden-sm' if msg['optional'] else '' }}">
- {{ msg['msg'] }}
- </span>
- % end
-% end
-</section>
-% end \ No newline at end of file
diff --git a/glances/outputs/glances_bottle.py b/glances/outputs/glances_bottle.py
index a64272d8..c5529685 100644
--- a/glances/outputs/glances_bottle.py
+++ b/glances/outputs/glances_bottle.py
@@ -16,19 +16,20 @@
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
-
"""Web interface class."""
+# Import Glances libs
+# Import mandatory Bottle lib
import json
import os
import sys
-# Import Glances libs
+from glances.core.glances_globals import is_windows
from glances.core.glances_logging import logger
-# Import mandatory Bottle lib
+
try:
- from bottle import Bottle, template, static_file, TEMPLATE_PATH, abort, response, request
+ from bottle import Bottle, static_file, abort, response, request
except ImportError:
logger.critical('Bottle module not found. Glances cannot start in web server mode.')
sys.exit(2)
@@ -53,9 +54,6 @@ class GlancesBottle(object):
# Define routes
self._route()
- # Update the template path (glances/outputs/bottle)
- TEMPLATE_PATH.append(os.path.join(os.path.dirname(os.path.realpath(__file__)), 'bottle'))
-
# Path where the statics files are stored
self.STATIC_PATH = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'static')
@@ -63,10 +61,17 @@ class GlancesBottle(object):
"""Define route."""
self._app.route('/', method="GET", callback=self._index)
self._app.route('/<refresh_time:int>', method=["GET", "POST"], callback=self._index)
+
self._app.route('/<filename:re:.*\.css>', method="GET", callback=self._css)
self._app.route('/<filename:re:.*\.js>', method="GET", callback=self._js)
+ self._app.route('/<filename:re:.*\.js.map>', method="GET", callback=self._js_map)
+ self._app.route('/<filename:re:.*\.html>', method="GET", callback=self._html)
+
+ self._app.route('/<filename:re:.*\.png>', method="GET", callback=self._images)
self._app.route('/favicon.ico', method="GET", callback=self._favicon)
+
# REST API
+ self._app.route('/api/2/help', method="GET", callback=self._api_help)
self._app.route('/api/2/pluginslist', method="GET", callback=self._api_plugins)
self._app.route('/api/2/all', method="GET", callback=self._api_all)
self._app.route('/api/2/all/limits', method="GET", callback=self._api_all_limits)
@@ -105,8 +110,13 @@ class GlancesBottle(object):
self.stats.update()
# Display
- return self.display(self.stats, refresh_time=refresh_time)
+ return static_file("index.html", root=os.path.join(self.STATIC_PATH, 'html'))
+ def _html(self, filename):
+ """Bottle callback for *.html files."""
+ # Return the static file
+ return static_file(filename, root=os.path.join(self.STATIC_PATH, 'html'))
+
def _css(self, filename):
"""Bottle callback for *.css files."""
# Return the static file
@@ -117,11 +127,37 @@ class GlancesBottle(object):
# Return the static file
return static_file(filename, root=os.path.join(self.STATIC_PATH, 'js'))
+ def _js_map(self, filename):
+ """Bottle callback for *.js.map files."""
+ # Return the static file
+ return static_file(filename, root=os.path.join(self.STATIC_PATH, 'js'))
+
+ def _images(self, filename):
+ """Bottle callback for *.png files."""
+ # Return the static file
+ return static_file(filename, root=os.path.join(self.STATIC_PATH, 'images'))
+
def _favicon(self):
"""Bottle callback for favicon."""
# Return the static file
return static_file('favicon.ico', root=self.STATIC_PATH)
+ def _api_help(self):
+ """
+ Glances API RESTFul implementation
+ Return the help data
+ or 404 error
+ """
+ response.content_type = 'application/json'
+
+ # Update the stat
+ view_data = self.stats.get_plugin("help").get_view_data()
+ try:
+ plist = json.dumps(view_data, sort_keys=True)
+ except Exception as e:
+ abort(404, "Cannot get help view data (%s)" % str(e))
+ return plist
+
def _api_plugins(self):
"""
@api {get} /api/2/pluginslist Get plugins list
@@ -168,15 +204,24 @@ class GlancesBottle(object):
"""
response.content_type = 'application/json'
- # Update the stat
- self.stats.update()
-
- try:
- # Get the JSON value of the stat value
- statval = json.dumps(self.stats.getAllAsDict())
- except Exception as e:
- abort(404, "Cannot get stats (%s)" % str(e))
- return statval
+ if not self.args.debug:
+ # Update the stat
+ self.stats.update()
+
+ try:
+ # Get the JSON value of the stat ID
+ statval = json.dumps(self.stats.getAllAsDict())
+ except Exception as e:
+ abort(404, "Cannot get stats (%s)" % str(e))
+ return statval
+ else:
+ path = "~/glances/"
+ if is_windows:
+ path = "D:\\glances\\"
+ filepath = path + "debug.json"
+
+ f = open(filepath)
+ return f.read()
def _api_all_limits(self):
"""
@@ -328,33 +373,6 @@ class GlancesBottle(object):
else:
return pdict
- def display(self, stats, refresh_time=None):
- """Display stats on the web page.
-
- stats: Stats database to display
- """
-
- stats = {
- 'system': self.stats.get_plugin('system').get_stats_display(args=self.args),
- 'uptime': self.stats.get_plugin('uptime').get_stats_display(args=self.args),
- 'cpu': self.stats.get_plugin('cpu').get_stats_display(args=self.args),
- 'load': self.stats.get_plugin('load').get_stats_display(args=self.args),
- 'mem': self.stats.get_plugin('mem').get_stats_display(args=self.args),
- 'memswap': self.stats.get_plugin('memswap').get_stats_display(args=self.args),
- 'network': self.stats.get_plugin('network').get_stats_display(args=self.args),
- 'diskio': self.stats.get_plugin('diskio').get_stats_display(args=self.args),
- 'fs': self.stats.get_plugin('fs').get_stats_display(args=self.args),
- 'raid': self.stats.get_plugin('raid').get_stats_display(args=self.args),
- 'sensors': self.stats.get_plugin('sensors').get_stats_display(args=self.args),
- 'alert': self.stats.get_plugin('alert').get_stats_display(args=self.args),
- 'processcount': self.stats.get_plugin('processcount').get_stats_display(args=self.args),
- 'monitor': self.stats.get_plugin('monitor').get_stats_display(args=self.args),
- 'processlist': self.stats.get_plugin('processlist').get_stats_display(args=self.args),
- 'docker': self.stats.get_plugin('docker').get_stats_display(args=self.args)
- }
-
- return template('base', refresh_time=refresh_time, stats=stats)
-
class EnableCors(object):
name = 'enable_cors'
diff --git a/glances/outputs/static/css/style.css b/glances/outputs/static/css/style.css
index 3ac50123..4bb9e6f8 100644
--- a/glances/outputs/static/css/style.css
+++ b/glances/outputs/static/css/style.css
@@ -3,31 +3,45 @@ body {
color: #BBB;
font-family: "Lucida Sans Typewriter", "Lucida Console", Monaco, "Bitstream Vera Sans Mono", monospace;
}
-.plugin {
- margin-bottom: 20px;
-}
-.plugin table {
+
+.table {
+ display: table;
width: 100%;
}
-.plugin table tr td:not(:first-child) {
+.table-row-group {
+ display: table-row-group
+}
+.table-row {
+ display: table-row;
+}
+.table-cell {
+ display: table-cell;
text-align: right;
}
-.underline{
+.plugin {
+ margin-bottom: 20px;
+}
+.plugin.table-row-group .table-row:last-child .table-cell {
+ padding-bottom: 20px;
+}
+
+.underline {
text-decoration: underline
}
-.bold{
+.bold {
font-weight: bold;
}
-.sort{
+.sort {
font-weight: bold;
-}
-.sort:after{
- content: '\25BC'
+ color: white;
}
.text-right {
text-align: right;
}
+.text-left {
+ text-align: left;
+}
/* Theme */
@@ -77,25 +91,85 @@ body {
}
/* Plugins */
-#cpu table tr td:nth-child(3),
-#mem table tr td:nth-child(3),
-#monitor table tr td:nth-child(3) {
- text-align: left;
- padding-left: 20px;
-}
-#processlist table tr td {
- text-align: right;
-}
-#processlist table tr td,
-#docker table tr td {
+#processlist .table-cell, #containers .table-cell {
padding: 0px 5px 0px 5px;
white-space: nowrap;
}
-#processlist table tr td:nth-child(6),
-#processlist table tr td:nth-child(12) {
- text-align: left;
+gl-monitor-list {
+ display: block;
}
-#docker table tr td:nth-child(2),
-#docker table tr td:nth-child(6) {
+gl-monitor-list .table-cell {
text-align: left;
-} \ No newline at end of file
+}
+/* Loading page */
+
+#loading-page .glances-logo {
+ background: url('glances.png') no-repeat center center;
+ background-size: contain;
+}
+
+@media (max-width: 750px) {
+ #loading-page .glances-logo {
+ height: 400px;
+ }
+}
+@media (min-width: 750px) {
+ #loading-page .glances-logo {
+ height: 500px;
+ }
+}
+
+
+/*
+Loading animation
+source : https://github.com/lukehaas/css-loaders
+*/
+#loading-page .loader:before,
+#loading-page .loader:after,
+#loading-page .loader {
+ border-radius: 50%;
+ width: 1em;
+ height: 1em;
+ -webkit-animation-fill-mode: both;
+ animation-fill-mode: both;
+ -webkit-animation: loader 1.8s infinite ease-in-out;
+ animation: loader 1.8s infinite ease-in-out;
+}
+#loading-page .loader {
+ margin: auto;
+ font-size: 10px;
+ position: relative;
+ text-indent: -9999em;
+ -webkit-animation-delay: 0.16s;
+ animation-delay: 0.16s;
+}
+#loading-page .loader:before {
+ left: -3.5em;
+}
+#loading-page .loader:after {
+ left: 3.5em;
+ -webkit-animation-delay: 0.32s;
+ animation-delay: 0.32s;
+}
+#loading-page .loader:before,
+#loading-page .loader:after {
+ content: '';
+ position: absolute;
+ top: 0;
+}
+@-webkit-keyframes loader {
+ 0%, 80%, 100% {
+ box-shadow: 0 2.5em 0 -1.3em #56CA69;
+ }
+ 40% {
+ box-shadow: 0 2.5em 0 0 #56CA69;
+ }
+}
+@keyframes loader {
+ 0%, 80%, 100% {
+ box-shadow: 0 2.5em 0 -1.3em #56CA69;
+ }
+ 40% {
+ box-shadow: 0 2.5em 0 0 #56CA69;
+ }
+}
diff --git a/glances/outputs/static/html/components/monitor_process.html b/glances/outputs/static/html/components/monitor_process.html
new file mode 100644
index 00000000..ec883040
--- /dev/null
+++ b/glances/outputs/static/html/components/monitor_process.html
@@ -0,0 +1,4 @@
+<div class="table-cell {{ descriptionClass }}">{{ process.description }}</div>
+<div class="table-cell">{{ process.count > 1 ? process.count : '' }}</div>
+<div class="table-cell">{{ process.count > 0 ? 'RUNNING' : 'NOT RUNNING' }}</div>
+<div class="table-cell">{{ process.result }}</div>
diff --git a/glances/outputs/static/html/help.html b/glances/outputs/static/html/help.html
new file mode 100644
index 00000000..b193d08e
--- /dev/null
+++ b/glances/outputs/static/html/help.html
@@ -0,0 +1,63 @@
+<div class="row">
+ <div class="col-sm-2 col-lg-10">{{help.version}} {{help.psutil_version}}</div>
+</div>
+<div class="row">&nbsp;</div>
+<div class="row">
+ <div class="col-sm-2 col-lg-10">{{help.configuration_file}}</div>
+</div>
+<div class="row">&nbsp;</div>
+<div class="row">
+ <div class="col-sm-2 col-lg-3">{{help.sort_auto}}</div>
+ <div class="col-sm-2 col-lg-3">{{help.sort_network}}</div>
+</div>
+<div class="row">
+ <div class="col-sm-2 col-lg-3">{{help.sort_cpu}}</div>
+ <div class="col-sm-2 col-lg-3">{{help.show_hide_alert}}</div>
+</div>
+<div class="row">
+ <div class="col-sm-2 col-lg-3">{{help.show_mem}}</div>
+ <div class="col-sm-2 col-lg-3">{{help.delete_warning_alerts}}</div>
+</div>
+<div class="row">
+ <div class="col-sm-2 col-lg-3">{{help.sort_proc}}</div>
+ <div class="col-sm-2 col-lg-3">{{help.delete_warning_critical_alerts}}</div>
+</div>
+<div class="row">
+ <div class="col-sm-2 col-lg-3">{{help.sort_io}}</div>
+ <div class="col-sm-2 col-lg-3">{{help.percpu}}</div>
+</div>
+<div class="row">
+ <div class="col-sm-2 col-lg-3">{{help.show_hide_help}}</div>
+ <div class="col-sm-2 col-lg-3">{{help.show_hide_diskio}}</div>
+</div>
+<div class="row">
+ <div class="col-sm-2 col-lg-3">{{help.view_network_io_combination}}</div>
+ <div class="col-sm-2 col-lg-3">{{help.view_cumulative_network}}</div>
+</div>
+<div class="row">
+ <div class="col-sm-2 col-lg-3">{{help.show_hide_network}}</div>
+ <div class="col-sm-2 col-lg-3">{{help.show_hide_filesytem_freespace}}</div>
+</div>
+<div class="row">
+ <div class="col-sm-2 col-lg-3">{{help.show_hide_sensors}}</div>
+ <div class="col-sm-2 col-lg-3">{{help.generate_graphs}}</div>
+</div>
+<div class="row">
+ <div class="col-sm-2 col-lg-3">{{help.show_hide_left_sidebar}}</div>
+ <div class="col-sm-2 col-lg-3">{{help.reset_history}}</div>
+</div>
+<div class="row">
+ <div class="col-sm-2 col-lg-3">{{help.enable_disable_process_stats}}</div>
+ <div class="col-sm-2 col-lg-3">{{help.quit}}</div>
+</div>
+<div class="row">
+ <div class="col-sm-2 col-lg-3">{{help.enable_disable_top_extends_stats}}</div>
+ <div class="col-sm-2 col-lg-3">{{help.enable_disable_short_processname}}</div>
+</div>
+<div class="row">
+ <div class="col-sm-2 col-lg-3">{{help.enable_disable_docker}}</div>
+</div>
+<div class="row">&nbsp;</div>
+<div class="row">
+ <div class="col-sm-2 col-lg-3">{{help.edit_pattern_filter}}</div>
+</div>
diff --git a/glances/outputs/static/html/index.html b/glances/outputs/static/html/index.html
new file mode 100644
index 00000000..f9b20a70
--- /dev/null
+++ b/glances/outputs/static/html/index.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<html ng-app="glancesApp">
+
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+ <title>Glances</title>
+
+ <link rel="icon" type="image/x-icon" href="favicon.ico" />
+ <link rel="stylesheet" type="text/css" href="normalize.css" />
+ <link rel="stylesheet" type="text/css" href="bootstrap.min.css" />
+ <link rel="stylesheet" type="text/css" href="style.css" />
+
+ <script type="text/javascript" src="vendors/angular.min.js"></script>
+ <script type="text/javascript" src="vendors/angular-route.min.js"></script>
+ <script type="text/javascript" src="vendors/lodash.min.js"></script>
+ <script type="text/javascript" src="app.js"></script>
+ <script type="text/javascript" src="filters.js"></script>
+ <script type="text/javascript" src="variables.js"></script>
+ <script type="text/javascript" src="directives.js"></script>
+
+ <script type="text/javascript" src="stats_controller.js"></script>
+</head>
+
+<body ng-view="" ng-keydown="onKeyDown($event)">
+
+</body>
+</html>
diff --git a/glances/outputs/static/html/plugins/alert.html b/glances/outputs/static/html/plugins/alert.html
new file mode 100644
index 00000000..e8011851
--- /dev/null
+++ b/glances/outputs/static/html/plugins/alert.html
@@ -0,0 +1,7 @@
+<div class="table">
+ <div class="table-row" ng-repeat="alert in result['alert']">
+ <div class="table-cell text-left">
+{{alert.begin}} ({{(alert[1]-alert[0]) | date : 'h:mm:ss'}}) - {{alert[2]}} on {{alert[3]}} ({{alert[4]}})
+ </div>
+ </div>
+</div>
diff --git a/glances/outputs/static/html/plugins/alerts.html b/glances/outputs/static/html/plugins/alerts.html
new file mode 100644
index 00000000..a03db0fc
--- /dev/null
+++ b/glances/outputs/static/html/plugins/alerts.html
@@ -0,0 +1,2 @@
+<span class="title" ng-show="!result['alert'].length">No warning or critical alert detected</span>
+<span class="title" ng-show="result['alert'].length">Warning or critical alerts (lasts {{result['alert'].length}} entries)</span>
diff --git a/glances/outputs/static/html/plugins/cpu.html b/glances/outputs/static/html/plugins/cpu.html
new file mode 100644
index 00000000..3e78b419
--- /dev/null
+++ b/glances/outputs/static/html/plugins/cpu.html
@@ -0,0 +1,44 @@
+<div class="table" ng-show="!show.per_cpu">
+ <div class="table-row">
+ <div class="table-cell text-left title">CPU</div>
+ <div class="table-cell">{{result["cpu"].total}}%</div>
+ </div>
+ <div class="table-row">
+ <div class="table-cell text-left">user:</div>
+ <div class="table-cell" ng-class="getClass('cpu', 'cpu_user_', result['cpu'].user, 1)">
+ {{result["cpu"].user}}%