python实现磁盘日志清理的示例


Posted in Python onNovember 05, 2020

一、描述:

以module的方式组件python代码,在磁盘文件清理上复用性更好

二、达到目标:

     清空过期日志文件,清理掉超过自定大小日志文件

三、原码

#!/usr/bin/env python
# -*- coding: utf-8 -*-
 
import commands
import os
import time
import re
import getopt
import sys
 
# commands.getstatusoutput 返回两个元素的元组tuple(status, result),status为int类型,result为string类型
def execute_local_shell_cmd(cmd):
  status, result = commands.getstatusoutput(cmd)
 
  result = result.split("\n")
 
  return status, result
 
def send_alert_mail():
  pass
 
 
 
'''
获取某一磁盘的空间使用率
'''
def get_disk_used(disk_name):
  status, result = execute_local_shell_cmd("df | grep %s | awk '{print $5}'" % disk_name)
  return status, result[0]
 
#print(get_disk_used('/data0'))
 
 
'''
判断文件是否在指定时间内修改过
'''
 
def file_modify_in(file_path,time_interval='1d'):
  current_time = time.time()
  # os.path.getmtime 返回最后修改时间。返回从unix纪元开始的跳秒数
  if current_time - os.path.getmtime(file_path) < translate_time_interval_to_second(time_interval):
    return True
  return False
 
def translate_file_size_to_kb(file_size):
  # 将字符串所有大写字符转为小写
  file_size = str(file_size.lower())
  # 创建匹配数字1次或多次的数字且小数点出现一次或者不出现的;小数点后数字重复0次或多次模式对象
  pattern = re.compile(r'\d+\.?\d*')
  match = pattern.match(file_size)
  file_size_number = None
  if match:
    # 使用Match获得分组信息
    #print(match.group())
    file_size_number = float(match.group())
  else:
    raise IOError("Input {0} can't translate to byte."
           "Current support g(gb)/m(mb)/k(kb)/b(byte)".format(file_size))
  # endswith() 方法用于判断字符串是否以指定后缀结尾,如果以指定后缀结尾返回True,否则返回False。
  # 可选参数"start"与"end"为检索字符串的开始与结束位置。
  if file_size.endswith("g") or file_size.endswith("gb"):
    return file_size_number * 1024 * 1024 * 1024
  elif file_size.endswith("m") or file_size.endswith("mb"):
    return file_size_number * 1024 * 1024
  elif file_size.endswith("k") or file_size.endswith("kb"):
    return file_size_number * 1024
  elif file_size.endswith("b") or file_size.endswith("byte"):
    return file_size_number
  else:
    raise IOError("Input {0} can't translate to byte."
            "Current support g(gb)/m(mb)/k(kb)/b(byte)".format(file_size))
#print(translate_file_size_to_kb('10g'))
 
def translate_time_interval_to_second(time_interval):
  date_interval = str(time_interval.lower())
  pattern = re.compile(r'\d+')
  match = pattern.match(date_interval)
  date_interval_number = None
  if match:
    date_interval_number = int(match.group())
  else:
    raise IOError("Input {0} can't translate to second."
           "Current support d(day)/h(hour)/m(min)/s(sec)".format(date_interval))
  if date_interval.endswith('d') or date_interval.endswith('day'):
    return date_interval_number * 24 * 3600
  elif date_interval.endswith('h') or date_interval.endswith('hour'):
    return date_interval_number * 3600
  elif date_interval.endswith('m') or date_interval.endswith('min'):
    return date_interval_number * 60
  elif date_interval.endswith('s') or date_interval.endswith('sec'):
    return date_interval_number
  else:
    raise IOError("Input {0} cant't translate to second."
           "Current support d(day)/h(hour)/m(min)/s(second)".format(date_interval))
 
#print(translate_time_interval_to_second('7d'))
'''
关断文件是否可能是当前log文件
1) 修改改时间1天内
2) 以pattern结尾
'''
def probable_current_log_file(file_path,pattern='log',modify_in='1d'):
  if file_modify_in(file_path,time_interval=modify_in):
    return True
  return str(file_path).endswith(pattern)
 
'''
获取超过天数设置log,注意不会返回可能是当前正在修改的文件,查看probable_current_log_file
确定如何做该判断
'''
def get_clean_log_list_by_date(target_dir,before_days_remove='7d',pattern="log"):
  before_seconds_remove = translate_time_interval_to_second(before_days_remove)
  current_time = time.time()
  # os.listdir 返回指定文件夹包含文件或文件夹的名字列表
  for candidate_file in os.listdir(target_dir):
    candidate_file_fullpath = "%s/%s" %(target_dir,candidate_file)
    # 是否存在一个普通文件
    if os.path.isfile(candidate_file_fullpath):
      candidate_file_mtime = os.path.getmtime(candidate_file_fullpath)
 
      # find\(\)根据是否包含字符串,如果包含有,返回开始的索引值,否则返回-1
      if current_time - candidate_file_mtime > before_seconds_remove \
        and candidate_file.find(pattern) != -1 \
        and not probable_current_log_file(candidate_file_fullpath):
        # yield 就是return一个值,并且记住这个返回值的位置,下次迭代就从这个位置后开始
        yield candidate_file_fullpath
 
'''
获取超过大小的日志文件(注意默认不会返回修改时间小于1天的文件)
'''
def get_clean_log_list_by_size(target_dir,file_size_limit='10g',pattern="log"):
  file_size_limit_byte = translate_file_size_to_kb(file_size_limit)
  for candidate_file in os.listdir(target_dir):
    candidate_file_fullpath = "%s/%s" %(target_dir,candidate_file)
    if os.path.isfile(candidate_file_fullpath):
      # stat返回相关文件的系统状态信息
      file_stat = os.stat(candidate_file_fullpath)
      if candidate_file.find(pattern) != -1 and \
              file_stat.st_size >= file_size_limit_byte:
        yield candidate_file_fullpath
      # 如果文件在modify_in之内修改过,则不返回
      # if not (modify_in and file_modify_in(candidate_file_fullpath, time_interval=modify_in)) and \
      #   not probable_current_log_file(candidate_file_fullpath):
      #    yield candidate_file_fullpath
 
'''
remove文件列表
'''
def remove_file_list(file_list,pattern='log',roll_back=False):
  for file_item in file_list:
    if roll_back or probable_current_log_file(file_item,pattern=pattern,modify_in='1d'):
      print('roll back file %s' % file_item)
      execute_local_shell_cmd("cat /dev/null > {0}".format(file_item))
    else:
      print('remove file %s' % file_item)
      # os.remove 删除指定路径文件。如果指定的路径是一个目录,将抛出OSError
      os.remove(file_item)
 
'''
清理掉超过日期的日志文件
'''
def remove_files_by_date(target_dir,before_days_remove='7d',pattern='log'):
  file_list = get_clean_log_list_by_date(target_dir,before_days_remove,pattern)
  remove_file_list(file_list)
 
'''
清理掉超过大小的日志文件
'''
def remove_files_by_size(target_dir,file_size_limit='10g',pattern='log'):
  file_list = get_clean_log_list_by_size(target_dir,file_size_limit,pattern)
  remove_file_list(file_list)
 
'''
清空当前的日志文件,使用cat /dev/null > {log_file}方式
'''
 
def clean_curren_log_file(target_dir,file_size_limit='10g',pattern='log'):
  for candidate_file in os.listdir(target_dir):
    candidate_file_fullpath = '%s/%s' % (target_dir,candidate_file)
    if candidate_file.endswith(pattern) and os.path.isfile(candidate_file_fullpath):
      file_stat = os.stat(candidate_file_fullpath)
      if file_stat.st_size >= translate_file_size_to_kb(file_size_limit):
        remove_file_list([candidate_file_fullpath],roll_back=True)
 
def clean_data_release_disk(disk_name, target_dir, disk_used_limit='80%', before_days_remove='7d',
              file_size_limit='10g', pattern='log'):
  disk_used_limit = disk_used_limit.replace('%', '')
  # 第一步执行按时间的日志清理
  print('Step one remove files {0} ago.'.format(before_days_remove))
  remove_files_by_date(target_dir, before_days_remove=before_days_remove, pattern=pattern)
 
  # 如果磁盘空间还是没有充分释放,则执行按大小的日志清理
  current_disk_used = int(get_disk_used(disk_name)[1].replace('%', ''))
  if current_disk_used > int(disk_used_limit):
    print("Disk {0}'s current used {1}% great than input used limit {2}%,"
       "so we will remove files bigger than {3}".
       format(disk_name, current_disk_used, disk_used_limit, file_size_limit))
    remove_files_by_size(target_dir, file_size_limit=file_size_limit, pattern=pattern)
 
  # 如果磁盘空间开没有释放,清空当前正在写的log文件,并alert
  current_disk_used = int(get_disk_used(disk_name)[1].replace('%', ''))
  if current_disk_used > int(disk_used_limit):
    print("Disk {0}'s current used {1}% great than input used limit {2}%,"
       "so we will roll back current log file".
       format(disk_name, current_disk_used, disk_used_limit, file_size_limit))
    clean_curren_log_file(target_dir, file_size_limit=file_size_limit, pattern=pattern)
 
  # 如果还是没有,alert mail
  if int(get_disk_used(disk_name)[1].replace('%', '')) > int(disk_used_limit):
    send_alert_mail()
 
def usage():
  print('clean.py -d <target_disk> -r <target_dirctory -u <diskUsedLimit(default 80%)> '
     '-f <fileSizeLimit(default 10gb,gb/mb/kb)> -p <filePattern(default log)> '
     '-t <beforeDaysRemove(default 7d,d)> ')
if __name__ == "__main__":
  target_disk_input = '/data0'
  target_dir_input = '/data0/hadoop2/logs'
  disk_used_limit_input = '80%'
  file_size_limit_input = '10g'
  pattern_input = 'log'
  before_days_remove_input = '7d'
  try:
    # getopt 命令解析,有短选项和长选项
    # getopt 返回两人个参数:一个对应参数选项和value元组,另一个一般为空
    opts,args = getopt.getopt(sys.argv[1:], 'hd:r:u:f:p:t:', ['help' 'disk=', 'directory=',
                                  'diskUsedLimit=', 'fileSizeLimit=',
                                  'filePattern=', 'beforeDaysRemove='])
  # getopt模块函数异常错误,捕获异常并打印错误
  except getopt.GetoptError as err:
    print err
    usage()
    sys.exit(2)
 
  if len(opts) < 6:
    usage()
    sys.exit(2)
 
  for opt,arg in opts:
    if opt == '-h':
      usage()
      sys.exit()
    elif opt in ("-d","--disk"):
      target_disk_input = arg.replace('/','')
    elif opt in ("-r","--directory"):
      target_dir_input = arg
    elif opt in ("-u","--diskUsedLimit"):
      disk_used_limit_input = arg
    elif opt in ("-f","--fileSizeLimit"):
      file_size_limit_input = arg
      translate_file_size_to_kb(file_size_limit_input)
    elif opt in ("-p","filePattern"):
      pattern_input = arg
    elif opt in ("-t","--beforeDaysRemove"):
      before_days_remove_input = arg
      translate_time_interval_to_second(before_days_remove_input)
 
  print ("{0} Start clean job.target_disk:{1},target_directory:{2},disk_used_limit:{3},"
      "file_size_limit:{4},pattern:{5},before_days_remove:{6}".format(time.ctime(time.time()),
                                      target_disk_input, target_dir_input,
                                      disk_used_limit_input, file_size_limit_input,
                                      pattern_input, before_days_remove_input))
  clean_data_release_disk(target_disk_input, target_dir_input,
              disk_used_limit=disk_used_limit_input, file_size_limit=file_size_limit_input,
              pattern=pattern_input, before_days_remove=before_days_remove_input)

四、统一调用目录定时删除

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import os
 
# 遍历目录
def Lisdir(targetdir):
  list_dirs = os.walk(targetdir)
  for root,list_dirs,files in list_dirs:
    for d in list_dirs:
      yield os.path.join(root,d)
 
def log_dir(targetdir):
  list_dirs = os.listdir(targetdir)
  for ph in list_dirs:
    if os.path.isdir(os.path.join(targetdir,ph)):
      yield Lisdir(os.path.join(targetdir,ph))
for path in log_dir('/data0/backup_log-bin'):
  for ppp in path:
    # 以log-bin结尾 为假
    if ppp.endswith('log-bin') is False:
      os.system("db_script/clean_robo.py -d /data0 -r {0} -u 75% -f 501M -p bin -t 5d".format(ppp))

以上就是python实现磁盘日志清理的示例的详细内容,更多关于python 磁盘日志清理的资料请关注三水点靠木其它相关文章!

Python 相关文章推荐
Python中的赋值、浅拷贝、深拷贝介绍
Mar 09 Python
python opencv之SURF算法示例
Feb 24 Python
python pandas中DataFrame类型数据操作函数的方法
Apr 08 Python
python 脚本生成随机 字母 + 数字密码功能
May 26 Python
浅析python继承与多重继承
Sep 13 Python
对pandas的层次索引与取值的新方法详解
Nov 06 Python
Python文件打开方式实例详解【a、a+、r+、w+区别】
Mar 30 Python
将Python文件打包成.EXE可执行文件的方法
Aug 11 Python
python制作朋友圈九宫格图片
Nov 03 Python
TensorFlow通过文件名/文件夹名获取标签,并加入队列的实现
Feb 17 Python
opencv 图像加法与图像融合的实现代码
Jul 08 Python
Python3爬虫ChromeDriver的安装实例
Feb 06 Python
Python常用外部指令执行代码实例
Nov 05 #Python
Python Pandas数据分析工具用法实例
Nov 05 #Python
Python jieba结巴分词原理及用法解析
Nov 05 #Python
Python根据字符串调用函数过程解析
Nov 05 #Python
python报错TypeError: ‘NoneType‘ object is not subscriptable的解决方法
Nov 05 #Python
Python利用matplotlib绘制折线图的新手教程
Nov 05 #Python
详解Django中异步任务之django-celery
Nov 05 #Python
You might like
Classes and Objects in PHP5-面向对象编程 [1]
2006/10/09 PHP
在WIN98下以apache模块方式安装php
2006/10/09 PHP
thinkphp验证码显示不出来的解决方法
2014/03/29 PHP
phpnow php探针环境检测代码
2014/11/04 PHP
PHP判断一个gif图片是否为动态图片的方法
2014/11/19 PHP
从wamp到xampp的升级之路
2015/04/08 PHP
php文件上传的两种实现方法
2016/04/04 PHP
用js判断浏览器是否是IE的比较好的办法
2007/05/08 Javascript
js汉字转拼音实现代码
2013/02/06 Javascript
我的Node.js学习之路(四)--单元测试
2014/07/06 Javascript
jquery 取子节点及当前节点属性值
2014/07/25 Javascript
13 款最热门的 jQuery 图像 360 度旋转插件推荐
2014/12/09 Javascript
jQuery文件上传控件 Uploadify 详解
2016/06/20 Javascript
Web安全测试之XSS实例讲解
2016/08/15 Javascript
原生js实现ajax方法(超简单)
2016/09/20 Javascript
react-router实现按需加载
2017/05/09 Javascript
基于require.js的使用(实例讲解)
2017/09/07 Javascript
Vue下滚动到页面底部无限加载数据的示例代码
2018/04/22 Javascript
Vue使用localStorage存储数据的方法
2019/05/27 Javascript
微信小程序利用Canvas绘制图片和竖排文字详解
2019/06/25 Javascript
小程序采集录音并上传到后台
2019/11/22 Javascript
JavaScript使用canvas绘制随机验证码
2020/02/17 Javascript
vue项目接口域名动态获取操作
2020/08/13 Javascript
vue实现路由懒加载的3种方法示例
2020/09/01 Javascript
PyTorch中Tensor的维度变换实现
2019/08/18 Python
python可视化实现KNN算法
2019/10/16 Python
python中Django文件上传方法详解
2020/08/05 Python
python中numpy数组与list相互转换实例方法
2021/01/29 Python
html5 视频播放解决方案
2016/11/06 HTML / CSS
回馈慈善的设计师太阳镜:DIFF eyewear
2019/10/17 全球购物
求职信的七个关键技巧
2014/02/05 职场文书
硕士生工作推荐信
2014/03/07 职场文书
小学端午节活动总结
2015/02/11 职场文书
2015年试用期自我评价范文
2015/03/10 职场文书
分享:关于学习的励志名言赏析
2019/08/16 职场文书
Java存储没有重复元素的数组
2022/04/29 Java/Android