From e413c170e9919d59347b3918dfe2192fbb987215 Mon Sep 17 00:00:00 2001 From: nicolargo Date: Tue, 1 May 2012 18:25:11 +0200 Subject: [PATCH] Add PID/UID to the processes informations --- NEWS | 1 + README.md | 257 +++++++++++++++++++++++++++++++++++++- glances/css/default.css | 11 +- glances/glances.py | 121 ++++++++++-------- glances/html/default.html | 4 + setup.py | 6 + 6 files changed, 345 insertions(+), 55 deletions(-) mode change 120000 => 100644 README.md diff --git a/NEWS b/NEWS index 72bf4139..7e6b87ca 100644 --- a/NEWS +++ b/NEWS @@ -7,6 +7,7 @@ Version 1.4 * No more autotools, use setup.py to install * Sort by Process name ('p' key) * Only major stats (CPU, Load and memory) use background colors + * Add optionnal (if space is available): PID, UID * Improve operating system name * Code is now checked with pep8 diff --git a/README.md b/README.md deleted file mode 120000 index 100b9382..00000000 --- a/README.md +++ /dev/null @@ -1 +0,0 @@ -README \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 00000000..15e9547b --- /dev/null +++ b/README.md @@ -0,0 +1,256 @@ +[![Flattr this git repo](http://api.flattr.com/button/flattr-badge-large.png)](https://flattr.com/submit/auto?user_id=nicolargo&url=https://github.com/nicolargo/glances&title=Glances&language=&tags=github&category=software) + +============================= +Glances -- Eye on your system +============================= + +## Description + +Glances is a CLI curses based monitoring tool for GNU/Linux and BSD OS. + +Glances uses the PsUtil library to get information from your system. + +It is developed in Python. + +![screenshot](https://github.com/nicolargo/glances/raw/master/screenshot.png) + +## Installation + +### From package manager (very easy way) + +Packages exist for Arch, Fedora, Redhat, FreeBSD... + +### From PPA (easy way for Ubuntu/Mint...) + +Arnaud Hartmann (thanks to him !) maintains a PPA with the latest Glances version: + +To install the PPA just enter: + + $ sudo add-apt-repository ppa:arnaud-hartmann/glances-dev + $ sudo apt-get update + +Then install Glances: + + $ sudo apt-get install glances + +### From PyPi (easy way) + +PyPi is an official Python package manager. + +You first need to install pypi on your system. For exemple on Debian/Ubuntu: + + $ sudo apt-get install python-pip + +Then install the latest Glances version: + + $ sudo pip install glances + +### From source + +Get the latest version: + + $ wget https://github.com/downloads/nicolargo/glances/glances-1.4.tar.gz + +Glances use a standard GNU style installer: + + $ tar zxvf glances-1.4.tar.gz + $ cd glances-1.4 + $ sudo python setup.py install + +Pre-requisites: + +* Python 2.6+ (not tested with Python 3+) + +## Running + +Easy way (that's all folks !): + + $ glances.py + +## User guide + +By default, stats are refreshed every second, to change this setting, you can +use the -t option. For exemple to set the refrech rate to 5 seconds: + + $ glances.py -t 5 + +Importants stats are colored: + +* GREEN: stat counter is "OK" +* BLUE: stat counter is "CAREFUL" +* MAGENTA: stat counter is "WARNING" +* RED: stat counter is "CRITICAL" + +When Glances is running, you can press: + +* 'h' to display an help message whith the keys you can press +* 'a' to set the automatic mode. The processes are sorted automatically + + If CPU > 70%, sort by process "CPU consumption" + + If MEM > 70%, sort by process "memory size" + +* 'c' to sort the processes list by CPU consumption +* 'd' Disable or enable the disk IO stats +* 'f' Disable or enable the file system stats +* 'l' Disable or enable the logs +* 'm' to sort the processes list by process size +* 'n' Disable or enable the network interfaces stats +* 'q' Exit + +### Header + +![screenshot](https://github.com/nicolargo/glances/raw/master/doc/header.png) + +The header shows the Glances version, the host name and the operating +system name, version and architecture. + +### CPU + +![screenshot](https://github.com/nicolargo/glances/raw/master/doc/cpu.png) + +The CPU states are shown as a percentage and for the configured refresh +time. + +If user|kernel|nice CPU is < 50%, then status is set to "OK". + +If user|kernel|nice CPU is > 50%, then status is set to "CAREFUL". + +If user|kernel|nice CPU is > 70%, then status is set to "WARNING". + +If user|kernel|nice CPU is > 90%, then status is set to "CRITICAL". + +### Load + +![screenshot](https://github.com/nicolargo/glances/raw/master/doc/load.png) + +On the Nosheep blog, Zach defines the average load: "In short it is the +average sum of the number of processes waiting in the run-queue plus the +number currently executing over 1, 5, and 15 minute time periods." + +Glances gets the number of CPU cores to adapt the alerts. With Glances, +alerts on average load are only set on 5 and 15 mins. + +If average load is < O.7*Core, then status is set to "OK". + +If average load is > O.7*Core, then status is set to "CAREFUL". + +If average load is > 1*Core, then status is set to "WARNING". + +If average load is > 5*Core, then status is set to "CRITICAL". + +### Memory + +![screenshot](https://github.com/nicolargo/glances/raw/master/doc/mem.png) + +Glances uses tree columns: memory (RAM), swap and "real". + +Real used memory is: used - cache. + +Real free memory is: free + cache. + +With Glances, alerts are only set for on used swap and real memory. + +If memory is < 50%, then status is set to "OK". + +If memory is > 50%, then status is set to "CAREFUL". + +If memory is > 70%, then status is set to "WARNING". + +If memory is > 90%, then status is set to "CRITICAL". + +### Network bit rate + +![screenshot](https://github.com/nicolargo/glances/raw/master/doc/network.png) + +Glances display the network interface bit rate. The unit is adapted +dynamicaly (bits per second, Kbits per second, Mbits per second...). + +Alerts are set only if the network interface maximum speed is available. + +If bitrate is < 50%, then status is set to "OK". + +If bitrate is > 50%, then status is set to "CAREFUL". + +If bitrate is > 70%, then status is set to "WARNING". + +If bitrate is > 90%, then status is set to "CRITICAL". + +For exemple, on a 100 Mbps Ethernet interface, the warning status is set +if the bit rate is higher than 70 Mbps. + +### Disk I/O + +![screenshot](https://github.com/nicolargo/glances/raw/master/doc/diskio.png) + +Glances display the disk I/O throughput. The unit is adapted dynamicaly +(bytes per second, Kbytes per second, Mbytes per second...). + +There is no alert on this information. + +### Filesystem + +![screenshot](https://github.com/nicolargo/glances/raw/master/doc/fs.png) + +Glances display the total and used filesytem disk space. The unit is +adapted dynamicaly (bytes per second, Kbytes per second, Mbytes per +second...). + +Alerts are set for used disk space: + +If disk used is < 50%, then status is set to "OK". + +If disk used is > 50%, then status is set to "CAREFUL". + +If disk used is > 70%, then status is set to "WARNING". + +If disk used is > 90%, then status is set to "CRITICAL". + +### Processes + +![screenshot](https://github.com/nicolargo/glances/raw/master/doc/processlist.png) + +Glances displays a summary and a list of processes. + +By default (or if you hit the 'a' key) the process list is automaticaly +sorted by CPU of memory consumption. + +The number of processes in the list is adapted to the screen size. + +### Logs + +![screenshot](https://github.com/nicolargo/glances/raw/master/doc/logs.png) + +A logs list is displayed in the bottom of the screen if (an only if): + +* at least one WARNING or CRITICAL alert was occured. +* space is available in the bottom of the console/terminal + +There is one line per alert with the following information: + +* start date +* end date +* alert name +* (min/avg/max) values + +### Footer + +![screenshot](https://github.com/nicolargo/glances/raw/master/doc/footer.png) + +Glances displays a caption and the current time/date. + +## Localisation + +To generate french locale execute as root or sudo : +i18n_francais_generate.sh + +To generate spanish locale execute as root or sudo : +i18n_espanol_generate.sh + +## Todo + +You are welcome to contribute to this software. + +* Packaging for Debian, Ubuntu, BSD... +* Check the needed Python library in the configure.ac +* Add file system stats when the python-statgrab is corrected diff --git a/glances/css/default.css b/glances/css/default.css index 01e219db..6e4811ba 100644 --- a/glances/css/default.css +++ b/glances/css/default.css @@ -175,5 +175,14 @@ header { margin-top: 50px; } - /* Footer */ + +footer { + clear: both; + margin: 20px 0px 10px 0px; + text-align: center; +} + +footer a { + color: white; +} diff --git a/glances/glances.py b/glances/glances.py index 8c2458dc..987139b6 100755 --- a/glances/glances.py +++ b/glances/glances.py @@ -22,7 +22,7 @@ from __future__ import generators __appname__ = 'glances' -__version__ = "1.4b17" +__version__ = "1.4b18" __author__ = "Nicolas Hennion " __licence__ = "LGPL" @@ -66,7 +66,11 @@ try: import psutil except ImportError: print _('PsUtil library initialization failed, Glances cannot start.') - print _('On Debian/Ubuntu, you can try (as root):') + print + print _('On Ubuntu 12.04+, you can try (as root):') + print _('# apt-get install python-psutil') + print + print _('On Debian/Ubuntu(< 12.04), you can try (as root):') print _('# apt-get install python-dev python-pip') print _('# pip install psutil') print @@ -606,6 +610,8 @@ class glancesStats: if (psutil_get_cpu_percent_tag): procstat['cpu_percent'] = \ proc.get_cpu_percent(interval=0) + procstat['pid'] = proc.pid + procstat['uid'] = proc.username self.process.append(procstat) except: pass @@ -708,24 +714,22 @@ class glancesScreen: # Init windows positions self.term_w = 80 self.term_h = 24 - self.host_x = 0 - self.host_y = 0 self.system_x = 0 - self.system_y = 1 + self.system_y = 0 self.cpu_x = 0 - self.cpu_y = 3 + self.cpu_y = 2 self.load_x = 20 - self.load_y = 3 + self.load_y = 2 self.mem_x = 41 - self.mem_y = 3 + self.mem_y = 2 self.network_x = 0 - self.network_y = 8 + self.network_y = 7 self.diskio_x = 0 self.diskio_y = -1 self.fs_x = 0 self.fs_y = -1 self.process_x = 30 - self.process_y = 8 + self.process_y = 7 self.log_x = 0 self.log_y = -1 self.help_x = 0 @@ -995,8 +999,7 @@ class glancesScreen: def display(self, stats): # Display stats - self.displayHost(stats.getHost()) - self.displaySystem(stats.getSystem()) + self.displaySystem(stats.getHost(), stats.getSystem()) self.displayCpu(stats.getCpu()) self.displayLoad(stats.getLoad(), stats.getCore()) self.displayMem(stats.getMem(), stats.getMemSwap()) @@ -1038,32 +1041,18 @@ class glancesScreen: # Wait 100ms... curses.napms(100) - def displayHost(self, host): - # Host information - if (not host): - return 0 - screen_x = self.screen.getmaxyx()[1] - screen_y = self.screen.getmaxyx()[0] - if ((screen_y > self.host_y) - and (screen_x > self.host_x + 79)): - host_msg = _("Glances v") + self.__version + _(" running on ") + \ - host['hostname'] - self.term_window.addnstr(self.host_y, \ - self.host_x + int(screen_x / 2) - \ - len(host_msg) / 2, host_msg, \ - 80, \ - self.title_color if self.hascolors else 0) - - def displaySystem(self, system): + def displaySystem(self, host, system): # System information - if (not system): + if (not host or not system): return 0 screen_x = self.screen.getmaxyx()[1] screen_y = self.screen.getmaxyx()[0] if ((screen_y > self.system_y) and (screen_x > self.system_x + 79)): - system_msg = system['os_name'] + " " + system['platform'] + " " + \ - system['os_version'] + system_msg = host['hostname'] + " (" + \ + system['os_name'] + " " + \ + system['platform'] + " " + \ + system['os_version'] + ")" self.term_window.addnstr(self.system_y, \ self.system_x + int(screen_x / 2) - \ len(system_msg) / 2, \ @@ -1393,7 +1382,12 @@ class glancesScreen: stats.getProcessCount()['sleeping']), \ 8) # Display the process detail - if ((screen_y > self.process_y + 7) + tag_pid = tag_uid = False + if (screen_x > process_x + 55): + tag_pid = True + if (screen_x > process_x + 64): + tag_uid = True + if ((screen_y > self.process_y + 8) and (screen_x > process_x + 49)): # Processes detail self.term_window.addnstr(self.process_y + 3, process_x, \ @@ -1406,7 +1400,20 @@ class glancesScreen: if (self.getProcessSortedBy() == 'proc_size') else 0) self.term_window.addnstr(self.process_y + 3, process_x + 18, \ _("Mem resi."), 9) - self.term_window.addnstr(self.process_y + 3, process_x + 30, \ + process_name_x = 30 + # If screen space (X) is available then: + # 1) Add PID + if (tag_pid): + self.term_window.addnstr(self.process_y + 3, process_x + process_name_x, \ + _("PID"), 6 ) + process_name_x = process_name_x + 8 + # 2) Add UID + if (tag_uid): + self.term_window.addnstr(self.process_y + 3, process_x + process_name_x, \ + _("UID"), 8 ) + process_name_x = process_name_x + 10 + # 3) Process name + self.term_window.addnstr(self.process_y + 3, process_x + process_name_x, \ _("Process name"), 12, \ curses.A_UNDERLINE \ if (self.getProcessSortedBy() == 'process_name') else 0) @@ -1418,7 +1425,7 @@ class glancesScreen: return 6 for processes in range(0, min(screen_y - self.term_h + \ - self.process_y - log_count + 2, len(processlist))): + self.process_y - log_count + 4, len(processlist))): if (psutil_get_cpu_percent_tag): self.term_window.addnstr(self.process_y + 4 + processes, \ process_x, \ @@ -1436,27 +1443,39 @@ class glancesScreen: process_x + 18, \ self.__autoUnit(\ processlist[processes]['proc_resident']), 9) - maxprocessname = screen_x - process_x - 30 - # If screen space is available then display long name + # If screen space (X) is available then: + # 1) Add PID + if (tag_pid): + self.term_window.addnstr(self.process_y + 4 + processes, \ + process_x + 30, \ + str(processlist[processes]['pid']), 6) + # 2) Add UID + if (tag_uid): + self.term_window.addnstr(self.process_y + 4 + processes, \ + process_x + 38, \ + str(processlist[processes]['uid']), 8) + # 3) Display long process command line + maxprocessname = screen_x - process_x - process_name_x if ((len(processlist[processes]['proctitle']) > maxprocessname) or (len(processlist[processes]['proctitle']) == 0)): processname = processlist[processes]['process_name'] else: processname = processlist[processes]['proctitle'] self.term_window.addnstr(self.process_y + 4 + processes, \ - process_x + 30, processname, maxprocessname) + process_x + process_name_x, processname, maxprocessname) def displayCaption(self): # Caption screen_x = self.screen.getmaxyx()[1] screen_y = self.screen.getmaxyx()[0] - if ((screen_x < 80) or (screen_y < 24)): + msg = _("Glances ") + __version__ + if ((screen_x > 79) and (screen_y > 23)): # Help can only be displayed on a 80x24 console - return 0 + msg = msg + " - " + _("Press 'h' for help") if ((screen_y > self.caption_y) and (screen_x > self.caption_x + 32)): self.term_window.addnstr(max(self.caption_y, screen_y - 1), \ - self.caption_x, _("Press 'h' for help"), self.default_color) + self.caption_x, msg, self.default_color) def displayHelp(self): """ @@ -1468,7 +1487,7 @@ class glancesScreen: screen_y = self.screen.getmaxyx()[0] if ((screen_y > self.help_y + 23) and (screen_x > self.help_x + 79)): - # Console 80x24 is mandatory to display teh help message + # Console 80x24 is mandatory to display the help message self.erase() self.term_window.addnstr(self.help_y, self.help_x, \ @@ -1547,15 +1566,15 @@ class glancesHtml: This class manages the HTML output """ - def __init__(self, htmlfolder="./", refresh_time=1): + def __init__(self, htmlfolder="/usr/share", refresh_time=1): # Global information to display # Init refresh time self.__refresh_time = refresh_time # Set the templates path - environment = jinja2.Environment(\ - loader=jinja2.FileSystemLoader('html'), \ + environment = jinja2.Environment( \ + loader=jinja2.FileSystemLoader(htmlfolder + '/html'), \ extensions=['jinja2.ext.loopcontrols']) # Open the template @@ -1668,12 +1687,6 @@ class glancesHtml: proccount=stats.getProcessCount(), \ proclist=stats.getProcessList()) - # Display stats - # Todo: - #~ self.displayCaption() - #~ self.displayNow(stats.getNow()) - #~ self.displayHelp() - # Write data into the file f.write(data) @@ -1738,7 +1751,7 @@ def printSyntax(): print "" print _("\t-f file\t\tSet the output folder (HTML) or file (CSV)") print _("\t-h\t\tDisplay the syntax and exit") - print _("\t-o output\tGenerate output (available: HTML, CSV)") + print _("\t-o output\tDefine additional output (available: HTML or CSV)") print _("\t-t sec\t\tSet the refresh time in second default is %d" \ % refresh_time) print _("\t-v\t\tDisplay the version and exit") @@ -1790,7 +1803,9 @@ def init(): if (jinja_tag): html_tag = True else: - print _("Error: Need Jinja library to export into HTML") + print _("Error: Need Jinja2 library to export into HTML") + print + print _("Try to install the python-jinja2 package") sys.exit(2) elif arg == "csv": if (csvlib_tag): diff --git a/glances/html/default.html b/glances/html/default.html index 06d3ef34..65dd52cf 100644 --- a/glances/html/default.html +++ b/glances/html/default.html @@ -225,3 +225,7 @@ {% endif %} {% endblock %} + +{% block footer %} +

Powered by Glances

+{% endblock %} diff --git a/setup.py b/setup.py index 2a875b23..4ac6e2f7 100755 --- a/setup.py +++ b/setup.py @@ -15,6 +15,9 @@ data_files = [ 'NEWS', 'screenshot.png']), ('share/doc/glances/doc', glob('doc/*.png')), + ('share/glances/html', glob('glances/html/*.html')), + ('share/glances/html/css', glob('glances/css/*.css')), + ('share/glances/html/img', glob('glances/img/*.png')), ] for mo in glob('i18n/*/LC_MESSAGES/*.mo'): data_files.append((dirname(mo).replace('i18n/', 'share/locale/'), [mo])) @@ -31,6 +34,9 @@ setup(name='Glances', long_description=open('README').read(), install_requires=['psutil>=0.4.1'], packages=['glances'], + extras_require = { + 'HTML': ['jinja2>=2.0'], + }, include_package_data=True, data_files=data_files, entry_points={"console_scripts": ["glances = glances.glances:main"]},