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实现数通设备端口使用情况监控实例
Jul 15 Python
Python黑帽编程 3.4 跨越VLAN详解
Sep 28 Python
Python heapq使用详解及实例代码
Jan 25 Python
python+selenium识别验证码并登录的示例代码
Dec 21 Python
python实现Floyd算法
Jan 03 Python
Python3.5运算符操作实例详解
Apr 25 Python
Python分布式进程中你会遇到的问题解析
May 28 Python
PyQt5 窗口切换与自定义对话框的实例
Jun 20 Python
python之生产者消费者模型实现详解
Jul 27 Python
pygame实现俄罗斯方块游戏(AI篇1)
Oct 29 Python
python爬取本站电子书信息并入库的实现代码
Jan 20 Python
python将音频进行变速的操作方法
Apr 08 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
PHPWind 发帖回帖Api PHP版打包下载
2010/02/08 PHP
PHP UTF8中文字符截断函数代码
2012/09/11 PHP
ThinkPHP关联模型操作实例分析
2012/09/23 PHP
利用phpExcel实现Excel数据的导入导出(全步骤详细解析)
2013/11/26 PHP
Yii输入正确验证码却验证失败的解决方法
2017/06/06 PHP
Laravel中日期时间处理包Carbon的简单使用
2017/09/21 PHP
thinkPHP框架实现类似java过滤器的简单方法示例
2018/09/05 PHP
PHP中localeconv()函数的用法
2019/03/26 PHP
Nigma vs Liquid BO3 第二场2.14
2021/03/10 DOTA
JAVASCRIPT函数作用域和提前声明 分享
2013/08/22 Javascript
jquery form 隐藏的input 选择
2014/04/29 Javascript
Bootstrap响应式侧边栏改进版
2016/09/17 Javascript
微信小程序 生命周期函数详解
2017/05/24 Javascript
Vue代码分割懒加载的实现方法
2017/11/23 Javascript
小程序开发基础之view视图容器
2018/08/21 Javascript
JS实现的排列组合算法示例
2019/07/16 Javascript
layui的数据表格+springmvc实现搜索功能的例子
2019/09/28 Javascript
JS实现随机点名器
2020/04/12 Javascript
python如何将图片转换为字符图片
2020/08/19 Python
使用pandas实现连续数据的离散化处理方式(分箱操作)
2019/11/22 Python
解决pycharm同一目录下无法import其他文件
2020/02/12 Python
DataFrame.groupby()所见的各种用法详解
2020/06/14 Python
利用css3 translate完美实现表头固定效果
2017/02/28 HTML / CSS
收集的7个CSS3代码生成工具
2010/04/17 HTML / CSS
HTML5边玩边学(2)基础绘图实现方法
2010/09/21 HTML / CSS
20世纪40年代连衣裙和复古服装:The Seamstress Of Bloomsbury
2018/07/24 全球购物
矫正人员思想汇报
2014/01/08 职场文书
《蜗牛的奖杯》教后反思
2014/04/24 职场文书
情况说明书格式范文
2014/05/06 职场文书
2014教师研修学习体会
2014/07/08 职场文书
税务干部群众路线教育实践活动对照检查材料
2014/09/20 职场文书
2014年政务公开工作总结
2014/12/09 职场文书
关于颐和园的导游词
2015/01/30 职场文书
民事起诉状范文
2015/05/19 职场文书
Sleuth+logback 设置traceid 及自定义信息方式
2021/07/26 Java/Android
一小时迅速入门Mybatis之bind与多数据源支持 Java API
2021/09/15 Javascript