Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature request: HDD S.M.A.R.T. reports #1288

Closed
btowntkd opened this issue Jul 12, 2018 · 14 comments
Closed

Feature request: HDD S.M.A.R.T. reports #1288

btowntkd opened this issue Jul 12, 2018 · 14 comments

Comments

@btowntkd
Copy link

btowntkd commented Jul 12, 2018

Description

It would be very useful to include S.M.A.R.T. data from attached drives, especially since this application is geared towards server environments.

Drive temperature data and general health status would be the most useful.

Smartmontools seem to be the lowest barrier to entry for this feature, and it is multi-platform.
https://www.smartmontools.org/

I am running Glances on Windows, so similar sensor-based solutions using hddtemp do not work (to my knowledge)

@nicolargo
Copy link
Owner

Hi, this proposal has already be discussed. The main issue is that the Glances running process has to be ran as root in order to grab the S.M.A.R.T stats.

A test has been done with the pySMART lib (https://pypi.org/project/py.SMART/) and confirms it:

$ ▶ python
Python 2.7.12 (default, Dec  4 2017, 14:50:18) 
[GCC 5.4.0 20160609] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> from pySMART import Device
/usr/local/lib/python2.7/dist-packages/pySMART/utils.py:154: UserWarning: _NOT_ADMIN_: smartctl is intended to be run as administrator/root and may not detect all device types, or may parse device information incorrectly, if run without these permissions.
>>> sda = Device('/dev/sda')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/local/lib/python2.7/dist-packages/pySMART/device.py", line 169, in __init__
    self.update()
  File "/usr/local/lib/python2.7/dist-packages/pySMART/device.py", line 478, in update
    smartctl_type[self.interface], self.name), shell=True,
KeyError: u'-d'

I do not want to implement a specific root function in Glances...

If you know another solution, let me know.

@btowntkd
Copy link
Author

btowntkd commented Jul 14, 2018

I think - for a system monitoring tool - it is reasonable for users to expect that certain features could require admin privileges.

Wouldn't it be fair to wrap the entire "S.M.A.R.T." info block into a try/except, and simply not display the info, with an error message in the log? Or mark "not available" for any fields which cannot be accessed? Those of us that are happy to run as root could see them; anyone without can just realize that's the price you pay for access to SMART data.

@nicolargo
Copy link
Owner

Ok will have a look on this issue.

@beat
Copy link

beat commented Aug 3, 2018

For display question: Suggestion: Any abnormal SMART state would making the reading of throughput indication red and add a line below with keyboard hint to display SMART info when abnormal.

@jjlawren
Copy link

You can configure smartd to write reports to CSV files: https://www.smartmontools.org/browser/trunk/smartmontools/smartd.8.in#lbAE. It would require more setup to use, but it could avoid requiring root permissions.

@tnibert
Copy link
Contributor

tnibert commented Aug 17, 2018

If you would like, I am happy to implement this. I have done something similar before. I can also look into configuration to give a regular user permission for this and add to documentation and/or create a script.

@tnibert
Copy link
Contributor

tnibert commented Aug 19, 2018

Ok, pySMART doesn't look like quite the silver bullet. The library that is in pip only works on python2. There are forks that are patched for python3, so I've just put in a check for python version to determine which library version to use.

With regards to using as non root, this is not looking very promising (see https://medium.com/opsops/why-smartctl-could-not-be-run-without-root-7ea0583b1323). Adding the user to the disk group on Linux seems to enable limited functionality of smartctl, but causes some havoc with pySMART. For now I have just added a check to see if the user is root/admin and disable the plugin if not. Having a web service running as root like that is terrible, but hey, let the user decide if they want to die in a fire.

At this point, I have the plugin in such a state that http://0.0.0.0:61208/api/3/all contains all of the SMART attribute data. I'm a bit stuck on how to present the data to the end user. For one thing, it is a lot of data and the curses GUI is very full. I see that there is a csv export in the code, so perhaps that would be the best output method. How do we want this data presented to the user?

@nicolargo
Copy link
Owner

Please test the feature from the DEVELOP branch (Glances 3.1_beta).

@tnibert
Copy link
Contributor

tnibert commented Sep 1, 2018

Manually tested and passed on current DEVELOP branch at commit cee0caf.

tim@komodo:~/code/glances$ python -m glances -V
Glances v3.0.1_beta with psutil v5.4.3
tim@komodo:~/code/glances$ sudo python3 -m glances --stdout smart
smart: [{'DeviceName': '<SAT device on /dev/sda mod:TOSHIBA MQ01ABD100 sn:27JKP9U6T>', '1': {'flags': '1', 'raw': '0', 'value': '100', 'worst': '100', 'threshold': '050', 'type': 'Pre-fail', 'updated': 'Always', 'when_failed': '-'}, '2': {'flags': '2', 'raw': '0', 'value': '100', 'worst': '100', 'threshold': '050', 'type': 'Pre-fail', 'updated': 'Offline', 'when_failed': '-'}, '3': {'flags': '3', 'raw': '1684', 'value': '100', 'worst': '100', 'threshold': '001', 'type': 'Pre-fail', 'updated': 'Always', 'when_failed': '-'}, '4': {'flags': '4', 'raw': '682', 'value': '100', 'worst': '100', 'threshold': '000', 'type': 'Old_age', 'updated': 'Always', 'when_failed': '-'}, '5': {'flags': '5', 'raw': '0', 'value': '100', 'worst': '100', 'threshold': '010', 'type': 'Pre-fail', 'updated': 'Always', 'when_failed': '-'}, '7': {'flags': '7', 'raw': '0', 'value': '100', 'worst': '100', 'threshold': '050', 'type': 'Pre-fail', 'updated': 'Always', 'when_failed': '-'}, '8': {'flags': '8', 'raw': '0', 'value': '100', 'worst': '100', 'threshold': '050', 'type': 'Pre-fail', 'updated': 'Offline', 'when_failed': '-'}, '9': {'flags': '9', 'raw': '2331', 'value': '095', 'worst': '095', 'threshold': '000', 'type': 'Old_age', 'updated': 'Always', 'when_failed': '-'}, '10': {'flags': '0', 'raw': '0', 'value': '113', 'worst': '100', 'threshold': '030', 'type': 'Pre-fail', 'updated': 'Always', 'when_failed': '-'}, '12': {'flags': '2', 'raw': '646', 'value': '100', 'worst': '100', 'threshold': '000', 'type': 'Old_age', 'updated': 'Always', 'when_failed': '-'}, '191': {'flags': '1', 'raw': '40', 'value': '100', 'worst': '100', 'threshold': '000', 'type': 'Old_age', 'updated': 'Always', 'when_failed': '-'}, '192': {'flags': '2', 'raw': '29', 'value': '100', 'worst': '100', 'threshold': '000', 'type': 'Old_age', 'updated': 'Always', 'when_failed': '-'}, '193': {'flags': '3', 'raw': '6819', 'value': '100', 'worst': '100', 'threshold': '000', 'type': 'Old_age', 'updated': 'Always', 'when_failed': '-'}, '194': {'flags': '4', 'raw': '33', 'value': '100', 'worst': '100', 'threshold': '000', 'type': 'Old_age', 'updated': 'Always', 'when_failed': '-'}, '196': {'flags': '6', 'raw': '0', 'value': '100', 'worst': '100', 'threshold': '000', 'type': 'Old_age', 'updated': 'Always', 'when_failed': '-'}, '197': {'flags': '7', 'raw': '0', 'value': '100', 'worst': '100', 'threshold': '000', 'type': 'Old_age', 'updated': 'Always', 'when_failed': '-'}, '198': {'flags': '8', 'raw': '0', 'value': '100', 'worst': '100', 'threshold': '000', 'type': 'Old_age', 'updated': 'Offline', 'when_failed': '-'}, '199': {'flags': '9', 'raw': '0', 'value': '200', 'worst': '200', 'threshold': '000', 'type': 'Old_age', 'updated': 'Always', 'when_failed': '-'}, '220': {'flags': '0', 'raw': '0', 'value': '100', 'worst': '100', 'threshold': '000', 'type': 'Old_age', 'updated': 'Always', 'when_failed': '-'}, '222': {'flags': '2', 'raw': '2155', 'value': '095', 'worst': '095', 'threshold': '000', 'type': 'Old_age', 'updated': 'Always', 'when_failed': '-'}, '223': {'flags': '3', 'raw': '0', 'value': '100', 'worst': '100', 'threshold': '000', 'type': 'Old_age', 'updated': 'Always', 'when_failed': '-'}, '224': {'flags': '4', 'raw': '0', 'value': '100', 'worst': '100', 'threshold': '000', 'type': 'Old_age', 'updated': 'Always', 'when_failed': '-'}, '226': {'flags': '6', 'raw': '189', 'value': '100', 'worst': '100', 'threshold': '000', 'type': 'Old_age', 'updated': 'Always', 'when_failed': '-'}, '240': {'flags': '0', 'raw': '0', 'value': '100', 'worst': '100', 'threshold': '001', 'type': 'Pre-fail', 'updated': 'Offline', 'when_failed': '-'}}]
^C^C
tim@komodo:~/code/glances$ sudo python2 -m glances --stdout smart
smart: [{u'199': {'raw': u'0', 'updated': u'Always', 'flags': u'9', 'when_failed': u'-', 'threshold': u'000', 'worst': u'200', 'type': u'Old_age', 'value': u'200'}, u'198': {'raw': u'0', 'updated': u'Offline', 'flags': u'8', 'when_failed': u'-', 'threshold': u'000', 'worst': u'100', 'type': u'Old_age', 'value': u'100'}, u'194': {'raw': u'33', 'updated': u'Always', 'flags': u'4', 'when_failed': u'-', 'threshold': u'000', 'worst': u'100', 'type': u'Old_age', 'value': u'100'}, u'197': {'raw': u'0', 'updated': u'Always', 'flags': u'7', 'when_failed': u'-', 'threshold': u'000', 'worst': u'100', 'type': u'Old_age', 'value': u'100'}, u'196': {'raw': u'0', 'updated': u'Always', 'flags': u'6', 'when_failed': u'-', 'threshold': u'000', 'worst': u'100', 'type': u'Old_age', 'value': u'100'}, u'191': {'raw': u'40', 'updated': u'Always', 'flags': u'1', 'when_failed': u'-', 'threshold': u'000', 'worst': u'100', 'type': u'Old_age', 'value': u'100'}, u'193': {'raw': u'6819', 'updated': u'Always', 'flags': u'3', 'when_failed': u'-', 'threshold': u'000', 'worst': u'100', 'type': u'Old_age', 'value': u'100'}, u'192': {'raw': u'29', 'updated': u'Always', 'flags': u'2', 'when_failed': u'-', 'threshold': u'000', 'worst': u'100', 'type': u'Old_age', 'value': u'100'}, 'DeviceName': '<SAT device on /dev/sda mod:TOSHIBA MQ01ABD100 sn:27JKP9U6T>', u'1': {'raw': u'0', 'updated': u'Always', 'flags': u'1', 'when_failed': u'-', 'threshold': u'050', 'worst': u'100', 'type': u'Pre-fail', 'value': u'100'}, u'3': {'raw': u'1684', 'updated': u'Always', 'flags': u'3', 'when_failed': u'-', 'threshold': u'001', 'worst': u'100', 'type': u'Pre-fail', 'value': u'100'}, u'2': {'raw': u'0', 'updated': u'Offline', 'flags': u'2', 'when_failed': u'-', 'threshold': u'050', 'worst': u'100', 'type': u'Pre-fail', 'value': u'100'}, u'5': {'raw': u'0', 'updated': u'Always', 'flags': u'5', 'when_failed': u'-', 'threshold': u'010', 'worst': u'100', 'type': u'Pre-fail', 'value': u'100'}, u'4': {'raw': u'682', 'updated': u'Always', 'flags': u'4', 'when_failed': u'-', 'threshold': u'000', 'worst': u'100', 'type': u'Old_age', 'value': u'100'}, u'7': {'raw': u'0', 'updated': u'Always', 'flags': u'7', 'when_failed': u'-', 'threshold': u'050', 'worst': u'100', 'type': u'Pre-fail', 'value': u'100'}, u'9': {'raw': u'2331', 'updated': u'Always', 'flags': u'9', 'when_failed': u'-', 'threshold': u'000', 'worst': u'095', 'type': u'Old_age', 'value': u'095'}, u'8': {'raw': u'0', 'updated': u'Offline', 'flags': u'8', 'when_failed': u'-', 'threshold': u'050', 'worst': u'100', 'type': u'Pre-fail', 'value': u'100'}, u'240': {'raw': u'0', 'updated': u'Offline', 'flags': u'0', 'when_failed': u'-', 'threshold': u'001', 'worst': u'100', 'type': u'Pre-fail', 'value': u'100'}, u'226': {'raw': u'189', 'updated': u'Always', 'flags': u'6', 'when_failed': u'-', 'threshold': u'000', 'worst': u'100', 'type': u'Old_age', 'value': u'100'}, u'224': {'raw': u'0', 'updated': u'Always', 'flags': u'4', 'when_failed': u'-', 'threshold': u'000', 'worst': u'100', 'type': u'Old_age', 'value': u'100'}, u'223': {'raw': u'0', 'updated': u'Always', 'flags': u'3', 'when_failed': u'-', 'threshold': u'000', 'worst': u'100', 'type': u'Old_age', 'value': u'100'}, u'222': {'raw': u'2155', 'updated': u'Always', 'flags': u'2', 'when_failed': u'-', 'threshold': u'000', 'worst': u'095', 'type': u'Old_age', 'value': u'095'}, u'220': {'raw': u'0', 'updated': u'Always', 'flags': u'0', 'when_failed': u'-', 'threshold': u'000', 'worst': u'100', 'type': u'Old_age', 'value': u'100'}, u'10': {'raw': u'0', 'updated': u'Always', 'flags': u'0', 'when_failed': u'-', 'threshold': u'030', 'worst': u'100', 'type': u'Pre-fail', 'value': u'113'}, u'12': {'raw': u'646', 'updated': u'Always', 'flags': u'2', 'when_failed': u'-', 'threshold': u'000', 'worst': u'100', 'type': u'Old_age', 'value': u'100'}}]

@nicolargo
Copy link
Owner

An implementation of a basic UI (Curse and WebUI) will be nice.

Any contributors ?

@tnibert
Copy link
Contributor

tnibert commented Sep 10, 2018

I'm happy to do this when I have a bit of time.

I gave the UI some thought and the only important attribute value for the UI to show, really, is the raw value. If we display the attribute name and the raw value, this should save some UI space. We can color the attribute if the raw value is outside the acceptable range.

@nicolargo
Copy link
Owner

UI (terminal only) implementation done in the DEVELOP branch.

Please can you test it with:

sudo python -m glances --enable-plugin smart

@tnibert
Copy link
Contributor

tnibert commented Nov 29, 2019

Tested on Ubuntu 18.04 64bit / Linux 4.15.0-70-generic. Tested on both Python 2.7.15 and 3.6.8.
Was able to observe SMART data in curses UI left side bar.

As an additional note, I was not able to see the entire smart output, as it extended past the bottom of the screen. It was not apparent to me if there was a method to scroll the left bar down. I was able to see more of the smart output by disabling the diskio plugin and top menu, but still wasn't able to view the full output in the visible UI.

@evrial
Copy link
Contributor

evrial commented Aug 28, 2023

python3 -m glances --stdout smart
smart: {}
smart: {}
smart: {}

I think you missed something in the dependencies, like smartmontools. Also hddtemp is very old and unmantained and requires escalated privileged and removed and pySMART.smartx is removed from github. TLDR: it's a steaming pile of shit.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

6 participants