diff --git a/AUTHORS b/AUTHORS index bb405e52..528226a5 100644 --- a/AUTHORS +++ b/AUTHORS @@ -21,6 +21,9 @@ https://github.com/jrenner Maxime Desbrus (aka) desbma https://github.com/desbma +Nicolas Hart (aka) NclsHart for the UI design +https://github.com/nclsHart + ========= Packagers ========= diff --git a/MANIFEST.in b/MANIFEST.in index 17120544..90e5bd3d 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -3,7 +3,8 @@ include COPYING include NEWS include README.rst include conf/glances.conf -include glances/outputs/static/html/*.html +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 diff --git a/NEWS b/NEWS index 8e32b1f4..90d1eddc 100644 --- a/NEWS +++ b/NEWS @@ -2,6 +2,11 @@ Glances Version 2.x ============================================================================== +Version 2.4 +=========== + + ... + Version 2.3 =========== @@ -23,6 +28,10 @@ Bugs corrected: * R/W error with the glances.log file (issue #474) +Other enhancement: + + * Alert < 3 seconds are no longer displayed + Version 2.2.1 ============= diff --git a/README.rst b/README.rst index 4db9f2c5..e7c28670 100644 --- a/README.rst +++ b/README.rst @@ -13,9 +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 -.. image:: https://badges.gitter.im/Join%20Chat.svg - :target: https://gitter.im/nicolargo/glances?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge - + Follow Glances on Twitter: `@nicolargo`_ or `@glances_system`_ @@ -233,6 +231,16 @@ Gateway to other services Glances can export stats to: ``CSV`` file, ``InfluxDB`` and ``StatsD`` server. +How to contribute ? +=================== + +If you want to contribute to the Glances project, read this `Wiki`_ page. + +There is also a chat dedicated to the Glances' developpers: + +.. image:: https://badges.gitter.im/Join%20Chat.svg + :target: https://gitter.im/nicolargo/glances?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge + Author ====== @@ -249,3 +257,4 @@ LGPL. See ``COPYING`` for more details. .. _@glances_system: https://twitter.com/glances_system .. _glances-doc: https://github.com/nicolargo/glances/blob/master/docs/glances-doc.rst .. _forum: https://groups.google.com/forum/?hl=en#!forum/glances-users +.. _Wiki: https://github.com/nicolargo/glances/wiki/How-to-contribute-to-Glances-%3F diff --git a/docs/glances-doc.html b/docs/glances-doc.html index 151fb1f3..35f786b0 100644 --- a/docs/glances-doc.html +++ b/docs/glances-doc.html @@ -123,9 +123,9 @@ td.option-group {

Glances

-

This manual describes Glances version 2.2.1.

-

Copyright © 2012-2014 Nicolas Hennion <nicolas@nicolargo.com>

-

December 2014

+

This manual describes Glances version 2.3.

+

Copyright © 2011-2015 Nicolas Hennion <nicolas@nicolargo.com>

+

January 2015

Table of Contents

-
  • Other Outputs
  • -
  • APIs Documentations
  • -
  • Support
  • +
  • Gateway to others services
  • +
  • APIs Documentations
  • +
  • Support
  • @@ -235,6 +237,7 @@ device with a web browser, just run the server with the @server is the IP address or hostname of the server.

    +

    To change the refresh rate of the page, just add the period in seconds between refreshes at the end of the URL, ie. to refresh every 10s, use http://@server:61208/10.

    The Glances web interface follows responsive web design principles.

    Screenshot from Chrome on Android

    images/screenshot-web2.png @@ -308,10 +311,18 @@ http://@server:61208  Set the export path for graph history ---output-csv OUTPUT_CSV +--export-csv CSV_FILE  export stats to a CSV file +--export-influxdb + + export stats to an InfluxDB server + +--export-statsd + + export stats to a Statsd server + -c CLIENT, --client CLIENT  connect to a Glances server by IPv4/IPv6 address or @@ -442,7 +453,7 @@ Filter is a regular expression pattern:

    F
    Switch between FS used and free space
    g
    -
    Generate hraphs for current history
    +
    Generate graphs for current history
    h
    Show/hide the help screen
    i
    @@ -532,6 +543,28 @@ cp /usr/share/doc/glances/glances.conf $XDG_CONFIG_HOME/glances/

    On OS X, you should copy the configuration file to ~/Library/Application Support/glances/.

    +

    Configuration file description

    +

    Each plugin and export module can have a section.

    +

    Example for the CPU plugin:

    +
    +[cpu]
    +user_careful=50
    +user_warning=70
    +user_critical=90
    +iowait_careful=50
    +iowait_warning=70
    +iowait_critical=90
    +system_careful=50
    +system_warning=70
    +system_critical=90
    +steal_careful=50
    +steal_warning=70
    +steal_critical=90
    +
    +

    By default Steal CPU time alerts aren't logged. If you want to enable log/alert, just add:

    +
    +steal_log=True
    +

    Logs and debug mode

    @@ -550,6 +583,7 @@ can ben logged using the -d option on the command line.

    +

    If glances.log is not writable, a new file will be created and returned to the user console.

    Anatomy Of The Application

    @@ -667,6 +701,8 @@ adapted dynamically.

    Note: limit values can be overwritten in the configuration file under the [filesystem] section.

    +

    If a RAID controller is detected on you system, its status will be displayed:

    +images/raid.png

    Sensors

    @@ -833,30 +869,86 @@ progress processes list alerts
    +
    +

    Docker

    +

    If you use Docker, Glances can help you to monitor your container. Glances uses the Docker API through the Docker-Py library.

    +images/docker.png
    -
    -

    Other Outputs

    +
    +

    Actions

    +

    Glances can trigger actions on events.

    +

    By action, we mean all shell command line. For example, if you want to execute the foo.py script if the last 5 minutes load are critical then add the action line to the Glances configuration file:

    +
    +[load]
    +critical=5.0
    +critical_action=python /path/to/foo.py
    +
    +

    All the stats are available in the command line through the use of the {{mustache}} syntax. Another example to create a log file containing used vs total disk space if a space trigger warning is reached:

    +
    +[fs]
    +warning=70
    +warning_action=echo {{mnt_point}} {{used}}/{{size}} > /tmp/fs.alert
    +
    +

    Note: You can use all the stats for the current plugin (see https://github.com/nicolargo/glances/wiki/The-Glances-2.x-API-How-to for the stats list)

    +
    +
    +
    +

    Gateway to others services

    +

    CSV

    It is possible to export statistics to CSV file.

    -$ glances --output-csv /tmp/glances.csv
    +$ glances --export-csv /tmp/glances.csv
    +
    +

    CSV file description: +- Stats description (first line) +- Stats (others lines)

    +

    InfluxDB

    +

    You can export statistics to an InfluxDB server (time series server). The connection should be defined in the Glances configuration file as following:

    +
    +[influxdb]
    +host=localhost
    +port=8086
    +user=root
    +password=root
    +db=glances
    +
    +

    and run Glances with:

    +
    +$ glances --export-influxdb
    +
    +

    Statsd

    +

    You can export statistics to a Statsd server (welcome to Graphite !). The connection should be defined in the Glances configuration file as following:

    +
    +[statsd]
    +host=localhost
    +port=8125
    +prefix=glances
    +
    +

    Note: the prefix option is optionnal ('glances by default')

    +

    and run Glances with:

    +
    +$ glances --export-statsd
    +
    +

    Glances will generate stats as:

    +
    +'glances.cpu.user': 12.5,
    +'glances.cpu.total': 14.9,
    +'glances.load.cpucore': 4,
    +'glances.load.min1': 0.19,
    +...
     
    -

    CSV files have two lines per stats:

    -
    -

    APIs Documentations

    -

    Glances includes a XML-RPC server and a RESTFULL-JSON API which and can be used by another client software.

    +

    APIs Documentations

    +

    Glances includes a XML-RPC server and a RESTFUL-JSON API which and can be used by another client software.

    APIs documentations are available at:

    -

    Support

    +

    Support

    To post a question about Glances use case, please post it to the offical Q&A forum.

    To report a bug or a feature request use the bug tracking system at https://github.com/nicolargo/glances/issues.

    diff --git a/docs/glances-doc.rst b/docs/glances-doc.rst index 60d7fe40..65377b34 100644 --- a/docs/glances-doc.rst +++ b/docs/glances-doc.rst @@ -514,6 +514,10 @@ Alerts are set for used disk space. *Note*: limit values can be overwritten in the configuration file under the ``[filesystem]`` section. +If a RAID controller is detected on you system, its status will be displayed: + +.. image:: images/raid.png + Sensors ------- @@ -715,15 +719,19 @@ Glances can trigger actions on events. By action, we mean all shell command line. For example, if you want to execute the foo.py script if the last 5 minutes load are critical then add the action line to the Glances configuration file: - [load] - critical=5.0 - critical_action=python /path/to/foo.py +.. code-block:: + + [load] + critical=5.0 + critical_action=python /path/to/foo.py All the stats are available in the command line through the use of the {{mustache}} syntax. Another example to create a log file containing used vs total disk space if a space trigger warning is reached: - [fs] - warning=70 - warning_action=echo {{mnt_point}} {{used}}/{{size}} > /tmp/fs.alert +.. code-block:: + + [fs] + warning=70 + warning_action=echo {{mnt_point}} {{used}}/{{size}} > /tmp/fs.alert *Note*: You can use all the stats for the current plugin (see https://github.com/nicolargo/glances/wiki/The-Glances-2.x-API-How-to for the stats list) diff --git a/docs/images/docker.png b/docs/images/docker.png index e8115359..4e64168e 100644 Binary files a/docs/images/docker.png and b/docs/images/docker.png differ diff --git a/docs/images/raid.png b/docs/images/raid.png new file mode 100644 index 00000000..fc9bd12b Binary files /dev/null and b/docs/images/raid.png differ diff --git a/glances/__init__.py b/glances/__init__.py index 0d29033a..e6374f29 100644 --- a/glances/__init__.py +++ b/glances/__init__.py @@ -20,7 +20,7 @@ """Init the Glances software.""" __appname__ = 'glances' -__version__ = '2.3_RC1' +__version__ = '2.4beta' __author__ = 'Nicolas Hennion ' __license__ = 'LGPL' diff --git a/glances/core/glances_actions.py b/glances/core/glances_actions.py index ee29fd61..1a762b70 100644 --- a/glances/core/glances_actions.py +++ b/glances/core/glances_actions.py @@ -70,6 +70,11 @@ class GlancesActions(object): # Action already executed => Exit return False + logger.debug("Run action {0} for {1} ({2}) with stats {3}".format(commands, + stat_name, + criticity, + mustache_dict)) + # Ran all actions in background for cmd in commands: # Replace {{arg}} by the dict one (Thk to {Mustache}) diff --git a/glances/core/glances_logs.py b/glances/core/glances_logs.py index 7d6a10b6..f2f9a3d4 100644 --- a/glances/core/glances_logs.py +++ b/glances/core/glances_logs.py @@ -100,12 +100,15 @@ class GlancesLogs(object): return process_auto_by - def add(self, item_state, item_type, item_value, proc_list=[], proc_desc=""): + def add(self, item_state, item_type, item_value, + proc_list=[], proc_desc="", + peak_time=3): """Add a new item to the logs list. If 'item' is a 'new one', add the new item at the beginning of the logs list. If 'item' is not a 'new one', update the existing item. + If event < peak_time the the alert is not setoff """ # Add or update the log item_index = self.__itemexist__(item_type) @@ -147,9 +150,13 @@ class GlancesLogs(object): # Reset the automatic process sort key self.reset_process_sort() - # Close the item - self.logs_list[item_index][1] = time.mktime( - datetime.now().timetuple()) + endtime = time.mktime(datetime.now().timetuple()) + if endtime - self.logs_list[item_index][0] > peak_time: + # If event is > peak_time seconds + self.logs_list[item_index][1] = endtime + else: + # If event <= peak_time seconds, ignore + self.logs_list.remove(self.logs_list[item_index]) else: # Update the item # State diff --git a/glances/core/glances_main.py b/glances/core/glances_main.py index d8627380..fbc17417 100644 --- a/glances/core/glances_main.py +++ b/glances/core/glances_main.py @@ -66,7 +66,7 @@ Monitor local machine and export stats to a CSV file (standalone mode):\n\ $ glances --export-csv\n\ \n\ Monitor local machine and export stats to a InfluxDB server with 5s refresh time (standalone mode):\n\ - $ glances -t 5 --export-influxdb -t 5\n\ + $ glances -t 5 --export-influxdb\n\ \n\ Start a Glances server (server mode):\n\ $ glances -s\n\ diff --git a/glances/outputs/bottle/base.tpl b/glances/outputs/bottle/base.tpl new file mode 100644 index 00000000..30d69690 --- /dev/null +++ b/glances/outputs/bottle/base.tpl @@ -0,0 +1,61 @@ + + + + + + + Glances + + + + + + + +
    +
    +
    +
    + % include('plugin_text', plugin_name="system", stats=stats['system']) +
    +
    + % include('plugin_text', plugin_name="uptime", stats=stats['uptime']) +
    +
    +
    +
    +
    + % include('plugin_table', plugin_name="cpu", stats=stats['cpu']) +
    +
    + % include('plugin_table', plugin_name="load", stats=stats['load']) +
    +
    + % include('plugin_table', plugin_name="mem", stats=stats['mem']) +
    +
    + % include('plugin_table', plugin_name="memswap", stats=stats['memswap']) +
    +
    +
    +
    + % include('plugin_table', plugin_name="network", stats=stats['network']) + % include('plugin_table', plugin_name="diskio", stats=stats['diskio']) + % include('plugin_table', plugin_name="fs", stats=stats['fs']) + % include('plugin_table', plugin_name="sensors", stats=stats['sensors']) +
    +
    + % include('plugin_table', plugin_name="alert", stats=stats['alert']) + % include('plugin_text', plugin_name="processcount", stats=stats['processcount']) + % include('plugin_table', plugin_name="docker", stats=stats['docker']) +
    +
    + % include('plugin_table', plugin_name="monitor", stats=stats['monitor']) +
    +
    + % include('plugin_table', plugin_name="processlist", stats=stats['processlist']) +
    +
    +
    + + \ No newline at end of file diff --git a/glances/outputs/glances_bottle.py b/glances/outputs/glances_bottle.py index d757ae6e..0c20c306 100644 --- a/glances/outputs/glances_bottle.py +++ b/glances/outputs/glances_bottle.py @@ -362,16 +362,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 - # """ - - # path = os.path.join(os.path.dirname(os.path.realpath(__file__)), "bottle", "index.html") - # f = open(path) - # return f.read() - class EnableCors(object): name = 'enable_cors' diff --git a/glances/outputs/static/css/style.css b/glances/outputs/static/css/style.css index 2d852eb8..13c3ab2c 100644 --- a/glances/outputs/static/css/style.css +++ b/glances/outputs/static/css/style.css @@ -167,3 +167,26 @@ source : https://github.com/lukehaas/css-loaders box-shadow: 0 2.5em 0 0 #56CA69; } } + +#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 { + 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; +} +#docker table tr td:nth-child(2), +#docker table tr td:nth-child(6) { + text-align: left; +} diff --git a/glances/plugins/glances_docker.py b/glances/plugins/glances_docker.py index da96235e..0aba990a 100644 --- a/glances/plugins/glances_docker.py +++ b/glances/plugins/glances_docker.py @@ -76,17 +76,20 @@ class Plugin(GlancesPlugin): # Connexion error (Docker not detected) # Let this message in debug mode logger.debug("Can't connect to the Docker server (%s)" % e) - ret = None + return None except docker.errors.APIError as e: if version is None: # API error (Version mismatch ?) logger.debug("Docker API error (%s)" % e) # Try the connection with the server version import re - version = re.search('server\:\ (.*)\)\"\)', str(e)) + version = re.search('server\:\ (.*)\)\".*\)', str(e)) if version: logger.debug("Try connection with Docker API version %s" % version.group(1)) ret = self.connect(version=version.group(1)) + else: + logger.debug("Can not retreive Docker server version") + ret = None else: # API error logger.error("Docker API error (%s)" % e) @@ -97,6 +100,10 @@ class Plugin(GlancesPlugin): logger.error("Can't connect to the Docker server (%s)" % e) ret = None + # Log an info if Docker plugin is disabled + if ret is None: + logger.debug("Docker plugin is disable because an error has been detected") + return ret def reset(self): @@ -163,13 +170,17 @@ class Plugin(GlancesPlugin): Output: a dict {'total': 1.49, 'user': 0.65, 'system': 0.84}""" ret = {} # Read the stats - with open('/sys/fs/cgroup/cpuacct/docker/' + id + '/cpuacct.stat', 'r') as f: - for line in f: - m = re.search(r"(system|user)\s+(\d+)", line) - if m: - ret[m.group(1)] = int(m.group(2)) + try: + with open('/sys/fs/cgroup/cpuacct/docker/' + id + '/cpuacct.stat', 'r') as f: + for line in f: + m = re.search(r"(system|user)\s+(\d+)", line) + if m: + ret[m.group(1)] = int(m.group(2)) + except IOError as e: + logger.error("Can not grab container CPU stat ({0})".format(e)) + return ret # Get the user ticks - ticks = self.get_user_ticks() + ticks = self.get_user_ticks() if isinstance(ret["system"], numbers.Number) and isinstance(ret["user"], numbers.Number): ret["total"] = ret["system"] + ret["user"] for k in ret.keys(): @@ -183,11 +194,15 @@ class Plugin(GlancesPlugin): Output: a dict {'rss': 1015808, 'cache': 356352}""" ret = {} # Read the stats - with open('/sys/fs/cgroup/memory/docker/' + id + '/memory.stat', 'r') as f: - for line in f: - m = re.search(r"(rss|cache)\s+(\d+)", line) - if m: - ret[m.group(1)] = int(m.group(2)) + try: + with open('/sys/fs/cgroup/memory/docker/' + id + '/memory.stat', 'r') as f: + for line in f: + m = re.search(r"(rss|cache)\s+(\d+)", line) + if m: + ret[m.group(1)] = int(m.group(2)) + except IOError as e: + logger.error("Can not grab container MEM stat ({0})".format(e)) + return ret # Return the stats return ret diff --git a/glances/plugins/glances_fs.py b/glances/plugins/glances_fs.py index e4dfbcff..57719ced 100644 --- a/glances/plugins/glances_fs.py +++ b/glances/plugins/glances_fs.py @@ -24,6 +24,7 @@ import operator import psutil from glances.plugins.glances_plugin import GlancesPlugin +from glances.core.glances_logging import logger # SNMP OID # The snmpd.conf needs to be edited. diff --git a/glances/plugins/glances_plugin.py b/glances/plugins/glances_plugin.py index 9a69a50f..7ff575f6 100644 --- a/glances/plugins/glances_plugin.py +++ b/glances/plugins/glances_plugin.py @@ -413,14 +413,15 @@ class GlancesPlugin(object): if type(self.stats) is list: # If the stats are stored in a list of dict (fs plugin for exemple) # Return the dict for the current header - try: - mustache_dict = ( - item for item in self.stats if item[self.get_key()] == header).next() - except StopIteration: - mustache_dict = {} + mustache_dict = {} + for item in self.stats: + if item[self.get_key()] == header: + mustache_dict = item + break else: # Use the stats dict mustache_dict = self.stats + # Run the action self.actions.run( stat_name, ret.lower(), command, mustache_dict=mustache_dict) diff --git a/man/glances.1 b/man/glances.1 index 0b47497a..3a717659 100644 --- a/man/glances.1 +++ b/man/glances.1 @@ -1,4 +1,4 @@ -.TH glances 1 "December, 2014" "version 2.2.1" "USER COMMANDS" +.TH glances 1 "January, 2015" "version 2.3" "USER COMMANDS" .SH NAME glances \- A cross-platform curses-based system monitoring tool .SH SYNOPSIS diff --git a/requirements.txt b/requirements.txt index 52546a76..7a795604 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1 +1 @@ -psutil==2.1.3 +psutil==2.2.0 diff --git a/setup.py b/setup.py index e46c3484..f598e2bf 100755 --- a/setup.py +++ b/setup.py @@ -52,7 +52,7 @@ def get_requires(): setup( name='Glances', - version='2.3RC1', + version='2.4beta', description="A cross-platform curses-based monitoring tool", long_description=open('README.rst').read(), author='Nicolas Hennion',