前言
最近学习了Python,试图将其融入日常的工作中,先从一些简单的小案例开始实验吧,在实例中去提升和探究更复杂的使用方法。
需求
例如,目前有一个nfs挂载出来的路径/scratch01,我们需要监控它的使用量不超过90%。如果超过,提出警告,并且进入该路径中,找出使用量超过预期的子文件夹,并输出。
一、判断指定路径当前使用量
判断指定路径当前使用量,(linux中使用 df -h可以看到的Size Used Avail Use%等信息),如果超过规定百分比,则输出日志/告警。
import os
import logging
def SpaceMonitor(path):
'''
This alarm is generated when the disk usage exceeds 90%
:return:usedflag
'''
try:
usedflag=0
st = os.statvfs(path)
total = st.f_blocks * st.f_frsize
# 文件系统数据块总数 * 分栈大小
used = (st.f_blocks - st.f_bfree) * st.f_frsize
# (文件系统数据块总数 - 可用块数)* 分栈大小
logging.basicConfig(filename='example.log', format='%(asctime)s:%(levelname)s:%(message)s', level=logging.DEBUG)
logging.info('Start')
except FileNotFoundError:
print('File path Not Found Error')
logging.error('File path Not Found Error')
if used / total > 0.5 :
# 这里设定50%为了测试,成功后可更改为80%、90%
usedflag=1
print('No enough space')
logging.debug('No enough space!')
logging.info('Finished')
return usedflag
# 以下为单独测试函数可行性
# path = '/scratch01'
# SpaceMonitor(path)
以上实现了对指定路径信息的读取和判断
涉及模块os、模块logging
1、os.statvfs([path])方法,详细参考:https://www.runoob.com/python/os-statvfs.html
2、logging.basicConfig(filename=‘example.log’, format=’%(asctime)s:%(levelname)s:%(message)s’, level=logging.DEBUG)
指定日志输出文件,文件格式,及输出的level,debug即所有的信息都输入进去
思路分析:
在这个函数中,实现判断一块磁盘总使用量是否超过预期值,返回一个usedflag值,为后续操作铺垫。如usedflag ==0,则输入无需操作,如usedflag ==1,则进入该路径中,遍历获取子目录。
拆分功能,先设计遍历获取子目录,待所有涉及的功能完成后,通过调用函数的方式,完成整个流,在进行Log输出的调整。
二、遍历输出子目录
def get_the_subdirlist(path):
dirlist=[]
for dir in os.listdir(path):
print(path+'/'+dir)
if os.path.isdir(path+'/'+dir):
dirlist.append(dir)
return dirlist
# 以下为单独测试函数可行性
# print(get_the_subdirlist('/scratch01'))
涉及模块os
涉及方法分析:
os.listdir(path)
返回path指定的文件夹包含的文件或文件夹的名字的列表
这里为什么不使用os.walk()方法?
因为walk会进行深度遍历,将所有子目录返回,我们只需要找出指定路径的子目录中占用量大的文件夹进行清理就可以了。
os.path.isfile()
判断路径是否为文件
os.path.isdir(path)
判断路径是否为目录
利用这个筛除文件,只统计目录。
思路分析:
现在我们获得了子目录的列表,接下来我们需要获取每一个子目录的du -sh的值,我们可以获取一个列表,因为他们是一一对应的,再将他们合成一个字典(key=dirname,value=usedsize),对字典进行操作,可以得到用量超过设定值的子目录名和它的占用量。
三、获取文件夹的占用空间大小
import re
def get_dir_usage_size_by_shell(dir_path):
userused = 0
response = os.popen(f'du -sh {dir_path}')
str_size = response.read().split()[0]
# 指定分隔符对字符串进行切片,返回一个数组,默认空格包括\n
dir_size = float(re.findall(r'[.\d]+', str_size)[0])
# .\d,\d匹配数字,+表示任意位数,用于匹配一个数字
if dir_size == 0.0:
size_unit = '0'
else:
size_unit = re.findall(r'[A-Z]', str_size)[0]
if size_unit == 'M':
dir_size = round(dir_size/1024, 2)
if size_unit == 'K':
dir_size = round(dir_size/1024/1024, 2)
return dir_size
分析:
os.popen() 函数使用 command 参数打开进程文件指针。
这里注意linux中的du -sh命令,返回值单位为K/M/G,所以要进行统一单位处理,以G为单位,统一后获取值作为后续比较即可,还要注意空文件夹会返回0.0,要进行单独处理。
在本函数中,还需要注意处理数据类型的转换。
思路分析:我们可以使用一个循环,循环访问/scratch01/xxx进行如上函数,又可以获得一个对应的占用空间量的List,这时候dirlist与usedlist就是一一对应的,如下。
usedlist=[]
for i in dirlist:
usedlist.append(get_dir_usage_size_by_shell(spacepath+'/'+i))
四、获取超额占用的文件夹
def get_used_over_budget(dict):
overdict={}
for dirname,used in dict.items():
if used > 10:
overdict[dirname] = used
return overdict
简单的字典遍历操作,就处理完成了数据。
现在几个模块功能已经基本完成,后续更新整个函数,我已经测试好了,但是在一些特殊情况还有一些问题需要调整,待我完善后一起更新,加油!
欢迎加我一起学习~
希望有一天也能有一个学习小组,加油!
2302185974
拒绝广告
实际使用种又进行了一些调整,脚本贴在下面
import os
import re
import logging
import sys
def SpaceMonitor(path):
'''
This alarm is generated when the disk usage exceeds 90%
:return:usedflag
'''
try:
usedflag=0
st = os.statvfs(path)
total = st.f_blocks * st.f_frsize
used = (st.f_blocks - st.f_bfree) * st.f_frsize
logging.basicConfig(filename='example.log', format='%(asctime)s:%(levelname)s:%(message)s', level=logging.DEBUG)
logging.info('Start')
except FileNotFoundError:
print('File path Not Found Error')
logging.error('File path Not Found Error')
else:
if used / total > 0.5 :
usedflag=1
print('No enough space')
logging.debug('No enough space!')
return usedflag
def get_the_subdirlist(path):
dirlist=[]
for dir in os.listdir(path):
if os.path.isfile(path+'/'+dir) == False:
dirlist.append(dir)
return dirlist
def get_dir_usage_size_by_shell(dir_path) :
response = os.popen(f'du -sh {dir_path}')
str_size = response.read().split()[0]
dir_size = float(re.findall(r'[.\d]+', str_size)[0])
if dir_size == 0.0:
size_unit = '0'
else:
size_unit = re.findall(r'[A-Z]', str_size)[0]
if size_unit == 'M':
dir_size = round(dir_size/1024, 2)
if size_unit == 'K':
dir_size = round(dir_size/1024/1024, 2)
return dir_size
def get_used_over_budget(dict):
overdict = {}
for dirname, used in dict.items():
if used > 50.0 :
overdict[dirname] = used
return overdict
spacepath=sys.argv[1]
if SpaceMonitor(spacepath) :
dirlist = get_the_subdirlist(spacepath)
#print(dirlist)
usedlist = []
for i in dirlist:
usedlist.append(get_dir_usage_size_by_shell(spacepath + '/' + i))
#print(usedlist)
totaldict = {dirlist[i]: usedlist[i] for i in range(len(dirlist))}
overdict = get_used_over_budget(totaldict)
#print(overdict)
print(len(overdict), 'users')
overlist = sorted(overdict.items(), key=lambda x: x[1], reverse=True)
for i in overlist:
print(i[0], '\t%sG' % int(i[1]))
sys.exit(1)
else:
print('enough space')
logging.debug('the spacepath is enough space')
sys.exit(0)
加入了包括引入参数,和排序的输出
有问题可以留言噢
这个脚本至此基本完成,我目前也在学习别的内容,如有涉及再行更新