Python使用開源庫psutil庫監控Linux


Psutil庫是一個開源且跨平台的庫,其提供了便利的函數來獲取操作系統的信息,如CPU,內存,磁盤,網絡等信息。

安裝方式:pip install psutil.

下面介紹一下相關的監控函數,具體操作的環境在ipython中,安裝:yum install ipython

1、CPU

cpu相關的功能函數

1)cpu_count默認返回邏輯cpu的個數,也可以指定logical=false獲取物理cpu的個數。

In [1]: import psutil

In [2]: psutil.cpu_count()

Out[2]: 2

In [4]: psutil.cpu_count(logical=False)

Out[4]: 2

2)cpu_percent返回cpu的利用率,可以通過interval參數阻塞式地獲取interval時間范圍內的cpu利用率,否則,獲取上一次調用cpu_percent這段時間以來的cpu利用率。可以使用percent參數指定獲取每個cpu的利用率,默認獲取整體的cpu利用率。

In [5]: psutil.cpu_percent()

Out[5]: 0.1

In [7]: psutil.cpu_percent(percpu=True)

Out[7]: [0.1, 0.0]

3)cpu_times以命名元組的形式返回cpu的時間花費,也可以通過percpu參數指定獲取每個cpu的統計時間。

In [8]: psutil.cpu_times()

Out[8]: scputimes(user=23.62, nice=0.0, system=38.07, idle=17458.43, iowait=16.43, irq=0.0, softirq=0.24, steal=0.0, guest=0.0, guest_nice=0.0)

4)cpu_times_percent與cpu_times類似,但是返回的是耗費時間的比例。

In [9]: psutil.cpu_times_percent()

Out[9]: scputimes(user=0.0, nice=0.0, system=0.1, idle=99.9, iowait=0.0, irq=0.0, softirq=0.0, steal=0.0, guest=0.0, guest_nice=0.0)

5)cpu_stats以命令元組的形式返回cpu的統計信息,包括上下文切換、中斷、軟中斷和系統調用的次數。

In [10]: psutil.cpu_stats()

Out[10]: scpustats(ctx_switches=1070599, interrupts=639997, soft_interrupts=620611, syscalls=0)

2、內存

與內存相關的功能函數

1)virtual_memory以命名元組的形式返回內存使用情況,包括總內存、可用內存、內存利用率、buffer\cached等。

In [11]: psutil.virtual_memory()

Out[11]: svmem(total=1907970048, available=1509765120, percent=20.9, used=240463872, free=1449373696, active=199106560, inactive=139300864, buffers=2125824, cached=216006656, shared=10063872, slab=54452224)

In [12]: psutil.virtual_memory().total

Out[12]: 1907970048

#將字節轉換成人類可讀的函數

def bytes2human(n):

        symbols = ('K','M','G','T','P','E','Z','Y')

        prefix = {}

        for i,s in enumerate(symbols):

            prefix[s] = 1 << (i + 1) *10

        for s in reversed(symbols):

            if n >= prefix[s]:

                value = float(n) / prefix[s]

                return '%.1f%s' % (value,s)

        return "%sB" % n
In [14]:  bytes2human(psutil.virtual_memory().total)

Out[14]: '1.8G'

2)swap_memory以命名元組的形式返回swap memory的使用情況。

In [15]: psutil.swap_memory()

Out[15]: sswap(total=2147479552, used=0, free=2147479552, percent=0.0, sin=0, sout=0)

3、磁盤

與磁盤相關的功能函數

1)disk_partitions返回所有已經掛的磁盤,以命名元組的形式返回。命名元組包含磁盤名稱、掛載點、文件系統類型等信息。

In [16]: psutil.disk_partitions()

Out[16]:

[sdiskpart(device='/dev/sda3' mountpoint='/', fstype='xfs', opts='rw,relatime,attr2,inode64,noquota'),

 sdiskpart(device='/dev/sda1', mountpoint='/boot', fstype='xfs', opts='rw,relatime,attr2,inode64,noquota')] 

def get_disk_via_mountpoint(mountpoint):

        disk = [item for item in psutil.disk_partitions() if item.mountpoint == mountpoint]

        return disk[0].device

In [18]: get_disk_via_mountpoint('/')

Out[18]: '/dev/sda3'

In [19]: get_disk_via_mountpoint('/boot')

Out[19]: '/dev/sda1'

2)disk_usage獲取磁盤的使用情況,包括磁盤的容量、磁盤的空間利用率。

In [21]: psutil.disk_usage('/')

Out[21]: sdiskusage(total=18242076672, used=6832975872, free=11409100800, percent=37.5)

In [22]: bytes2human(psutil.disk_usage('/').total)

Out[22]: '17.0G'

3)disk_io_counters以命名元組的形式返回磁盤io統計信息,包括讀的次數,寫的次數,讀字節數,寫字節數。

In [23]: psutil.disk_io_counters()

Out[23]: sdiskio(read_count=8407, write_count=2567, read_bytes=195427840, write_bytes=54457856, read_time=38577, write_time=34691, read_merged_count=2, write_merged_count=613, busy_time=24421)

4、網絡

與網絡相關的功能函數

1)net_io_counter返回當前系統中網絡io統計信息是監控系統中最需要關注的網絡信息。net_io_counter函數以命名元組的形式返回了每塊網卡的網絡io統計信息,包括收發字節數,收發包的數量,出錯情況與刪包情況。

In [24]: psutil.net_io_counters()

Out[24]: snetio(bytes_sent=658478, bytes_recv=290760, packets_sent=3387, packets_recv=2735, errin=0, errout=0, dropin=0, dropout=0) 

In [25]: psutil.net_io_counters(pernic=True)

Out[25]:

{'ens33': snetio(bytes_sent=385132, bytes_recv=293910, packets_sent=1740, packets_recv=2765, errin=0, errout=0, dropin=0, dropout=0),

 'ens37': snetio(bytes_sent=275804, bytes_recv=0, packets_sent=1662, packets_recv=0, errin=0, errout=0, dropin=0, dropout=0),

 'lo': snetio(bytes_sent=0, bytes_recv=0, packets_sent=0, packets_recv=0, errin=0, errout=0, dropin=0, dropout=0)}

2)net_connections以列表的形式返回第個網絡網接詳細信息。可以行使查看網絡連連狀態。統計連接個數以及處於特定狀態的網絡連接個數。

In [26]: psutil.net_connections()

Out[26]:

[sconn(fd=1, family=2, type=2, laddr=addr(ip='127.0.0.1', port=323), raddr=(), status='NONE', pid=6155),

 sconn(fd=22, family=10, type=1, laddr=addr(ip='::', port=3306), raddr=(), status='LISTEN', pid=7054),

 sconn(fd=3, family=2, type=1, laddr=addr(ip='0.0.0.0', port=22), raddr=(), status='LISTEN', pid=6550),

 sconn(fd=4, family=10, type=1, laddr=addr(ip='::', port=22), raddr=(), status='LISTEN', pid=6550),

 sconn(fd=2, family=10, type=2, laddr=addr(ip='::1', port=323), raddr=(), status='NONE', pid=6155),

 sconn(fd=3, family=2, type=1, laddr=addr(ip='10.0.0.171', port=22), raddr=addr(ip='10.0.0.1', port=20590), status='ESTABLISHED', pid=6705),

 sconn(fd=13, family=2, type=1, laddr=addr(ip='127.0.0.1', port=25), raddr=(), status='LISTEN', pid=7832),

 sconn(fd=14, family=10, type=1, laddr=addr(ip='::1', port=25), raddr=(), status='LISTEN', pid=7832),

 sconn(fd=7, family=2, type=2, laddr=addr(ip='0.0.0.0', port=68), raddr=(), status='NONE', pid=17166),

 sconn(fd=3, family=2, type=1, laddr=addr(ip='10.0.0.171', port=22), raddr=addr(ip='10.0.0.1', port=20696), status='ESTABLISHED', pid=15983)]

3)net_if_addrs以字典的形式返回網卡的配置信息,包括ip地址、子網掩碼、MAC地址和廣播地址。

In [27]: psutil.net_if_addrs()

Out[27]:

{'ens33': [snicaddr(family=2, address='10.0.0.171', netmask='255.255.255.0', broadcast='10.0.0.255', ptp=None),

  snicaddr(family=10, address='fe80::479e:194c:b6bb:9553%ens33', netmask='ffff:ffff:ffff:ffff::', broadcast=None, ptp=None),

  snicaddr(family=17, address='00:0c:29:a2:07:95', netmask=None, broadcast='ff:ff:ff:ff:ff:ff', ptp=None)],

 'ens37': [snicaddr(family=17, address='00:0c:29:a2:07:9f', netmask=None, broadcast='ff:ff:ff:ff:ff:ff', ptp=None)],

 'lo': [snicaddr(family=2, address='127.0.0.1', netmask='255.0.0.0', broadcast=None, ptp=None),

  snicaddr(family=10, address='::1', netmask='ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff', broadcast=None, ptp=None),

  snicaddr(family=17, address='00:00:00:00:00:00', netmask=None, broadcast=None, ptp=None)]}

4)net_if_stats返回網卡的詳細信息,包括是否啟動、通信類型、傳輸速度與mtu。

In [29]: psutil.net_if_stats()

Out[29]:

{'ens33': snicstats(isup=True, duplex=2, speed=1000, mtu=1500),

 'ens37': snicstats(isup=True, duplex=2, speed=1000, mtu=1500),

 'lo': snicstats(isup=True, duplex=0, speed=0, mtu=65536)}

5、其他

1)users以命名元組的方式返回當前登錄用戶的信息,包括用戶名,登錄時間,終端與主機的信息。

In [30]: psutil.users()

Out[30]:

[suser(name='root', terminal='tty1', host='', started=1591761024.0, pid=6176),

 suser(name='root', terminal='pts/0', host='10.0.0.1', started=1591761024.0, pid=6884),

 suser(name='root', terminal='pts/1', host='10.0.0.1', started=1591761152.0, pid=15985)]

2)boot_time以時間戳的形式返回系統的啟動時間

In [31]: psutil.boot_time()

Out[31]: 1591760992.0

 datetime.datetime.fromtimestamp(psutil.boot_time()).strftime("%Y-%M-%D %H:%M:%S")

Out[33]: '2020-49-06/10/20 11:49:52'

6、一個案例:使用psutil實現監控程序

在程序中,使用psutil收集了cpu的信息,開機時間,內存信息,磁盤信息,網絡信息等。

monitor.py具體內容如下:

#!/usr/bin/python
# -*- coding: UTF-8 -*-
from __future__ import unicode_literals
import os
import socket
from datetime import datetime

import jinja2
import yagmail
import psutil


EMAIL_USER = 'mick_bing@126.com'        #發送郵箱帳號
EMAIL_PASSWORD = '***********'     #發送郵箱登錄碼或授權碼
RECIPIENTS = ['eeexu123@163.com','eee@sohu.com']       #接收郵件的帳號


#將獲取到的監控信息寫入monitor.html中
def render(tpl_path, **kwargs):
    path, filename = os.path.split(tpl_path)
    return jinja2.Environment(
        loader=jinja2.FileSystemLoader(path or './')
    ).get_template(filename).render(**kwargs)

#將獲取的信息轉化為人類可讀
def bytes2human(n):
    symbols = ('K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y')
    prefix = {}
    for i, s in enumerate(symbols):
        prefix[s] = 1 << (i + 1) * 10
    for s in reversed(symbols):
        if n >= prefix[s]:
            value = float(n) / prefix[s]
            return '%.1f%s' % (value, s)
    return "%sB" % n

#獲取CPU的信息
def get_cpu_info():
    cpu_count = psutil.cpu_count()  #CPU的邏輯個數
    cpu_percent = psutil.cpu_percent(interval=1)    #CPU的利用率
    return dict(cpu_count=cpu_count, cpu_percent=cpu_percent)

#獲取內存的信息
def get_memory_info():
    virtual_mem = psutil.virtual_memory()

    mem_total = bytes2human(virtual_mem.total)  #內存總量  
    mem_percent = virtual_mem.percent   #內存的利用率
    mem_free = bytes2human(virtual_mem.free + virtual_mem.buffers + virtual_mem.cached) #內存的可使用空間
    mem_used = bytes2human(virtual_mem.total * virtual_mem.percent) #內存的已使用空間

    return dict(mem_total=mem_total, mem_percent=mem_percent,
                mem_free=mem_free, mem_used=mem_used)

#獲取磁盤的信息
def get_disk_info():
    disk_usage = psutil.disk_usage('/')

    disk_total = bytes2human(disk_usage.total)  #磁盤的總量
    disk_percent = disk_usage.percent   #磁盤的利用率
    disk_free = bytes2human(disk_usage.free)    #磁盤可用空間
    disk_used = bytes2human(disk_usage.used)    #磁盤已用空間

    return dict(disk_total=disk_total, disk_percent=disk_percent,
                disk_free=disk_free, disk_used=disk_used)

#獲取網絡信息
def get_net_info():
    net_info = psutil.net_io_counters()  
    net_sent = net_info.bytes_sent         #網絡發送字節數
    net_recv = net_info.bytes_recv         #網絡接收字節數
    packet_sent = net_info.packets_sent     #網絡發送數據包
    packet_recv = net_info.packets_recv     #網絡接收數據包

    return dict(net_sent=net_sent,net_recv=net_recv,packet_sent=packet_sent,packet_recv=packet_recv)

#獲取系統開機時間
def get_boot_info():
    boot_time = datetime.fromtimestamp(psutil.boot_time()).strftime("%Y-%m-%d %H:%M:%S")    #獲取開機的時間戳,並將時間戳轉化年月日
    return dict(boot_time=boot_time)

#獲取信息更新
def collect_monitor_data():
    data = {}
    data.update(get_boot_info())
    data.update(get_cpu_info())
    data.update(get_memory_info())
    data.update(get_disk_info())
    data.update(get_net_info())
    return data


def main():

    hostname = socket.gethostname() #獲取系統主機的時間
    data = collect_monitor_data()
    data.update(dict(hostname=hostname))

    content = render('monitor.html', **data)
    print content

    with yagmail.SMTP(user=EMAIL_USER, password=EMAIL_PASSWORD,
                      host='smtp.126.com') as yag:
        for recipient in RECIPIENTS:
            yag.send(recipient, "監控信息".encode('utf-8'), content.encode('utf-8'))


if __name__ == '__main__':
    main()

我們將所有收集的監控數據保存在一個字典中,並以解引用的方式傳遞給render函數。render函數的作用非常簡單,在默認的情況下根據模板的名稱在當前目錄下查找模板,然后使用jinja2進行模板渲染。模板渲染以后,就得到一個HTML形式的字符串。在此例中,模板形式如下:

<html>
    <head><title>監控信息</title>
    <body>
        <table border="1">
            <tr><td>服務器名稱</td><td>{{hostname}}</td></tr>
            <tr><td>開機時間</td><td>{{boot_time}}</td></tr>

            <tr><td>CPU個數</td><td>{{cpu_count}}</td></tr>
            <tr><td>CPU利用率</td><td>{{cpu_percent}}%</td></tr>

            <tr><td>內存總量</td><td>{{mem_total}}</td></tr>
            <tr><td>內存利用率</td><td>{{mem_percent}}%</td></tr>
            <tr><td>內存已用空間</td><td>{{mem_used}}</td></tr>
            <tr><td>內存可用空間</td><td>{{mem_free}}</td></tr>

            <tr><td>磁盤空間總量</td><td>{{disk_total}}</td></tr>
            <tr><td>磁盤空間利用率</td><td>{{disk_percent}}%</td></tr>
            <tr><td>磁盤已用空間</td><td>{{disk_used}}</td></tr>
            <tr><td>磁盤可用空間</td><td>{{disk_free}}</td></tr>

            <tr><td>網絡發送數據包</td><td>{{packet_sent}}</td></tr>
            <tr><td>網絡接收數據包</td><td>{{packet_recv}}</td></tr>
        </table>
    </body>
</html>         

運行程序所得如下:

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM