网络编程
位置:首页>> 网络编程>> Python编程>> python实现磁盘日志清理的示例

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

作者:py3study  发布时间:2021-05-10 07:08:21 

标签:python,磁盘,日志

一、描述:

以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))

来源:https://cloud.tencent.com/developer/article/1570647

0
投稿

猜你喜欢

  • 做设计类网址导航的初衷是为了资源整合,也是在尝试解决问题。假定访问用户都是行业人士,或者目地性很强的有一定了解的用户,应该如何考虑这个组织系
  • 通过 register_shutdown_function 方法,可以让我们设置一个当执行关闭时可以被调用的另一个函数。也就是说,当我们的脚
  • 以前大家谈了很多有关打开数据库连接安全的问题,现在我再提出一种思路:使用activex dll来保护你的代码。(既可以不用为使用共享的加密软
  • 滚动图片可以说是做网站经常会遇到的,特别是做企业网站,最常用的像产品展示,图片展示等,滚动的好处是吸引眼球,让人一下就注意到。之前本站发了一
  • java连接sqlserver2008数据库代码如下所示:public class SqlServer { public static vo
  • <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN&
  • 在网络设计领域关于Eye-Tracking的研究十分火爆,但是如何把这些研究结果转变为具体可行的设计来运作依旧是个难点。以下就是一些来自于E
  • JavaScript中的字符串函数没有像VBScript\ASP中的内部函数那么全.不能像VB那样直接利用left和right函数来实现对字
  • 方法不是主流的。有一组数据,大概10万个左右,每一单位的值不会大于30000,要求按照由大到小的顺序不重复输出。参考无忧cosin的方法后(
  • 首先,这片文章纯粹是我的个人经验之谈,适用于我常见的环境及项目中。个人建议,数据库字符集尽量使用utf8(HTML页面对应的是utf-8),
  • 如何用Sleep函数编译一个定时组件?见下: Private Declare Sub Sleep L
  • 因DWS内核目前支持的线程数很少,个人门户首页打开后,如果并发请求加载的模块数过多,很容易导致DWS崩溃,故而给之前写的AJAX类加了个顺序
  • 很多朋友希望,我能把我做网站的一些流程及经验跟大家分享一下,最近刚好做一次内部培训,所以稍微整理了一下,这些只是针对网页初学者,具有一定平面
  • 最近在研究网页的切片算法,很可能很多人不知道什么是切片算法,其实这是一种面向搜索引擎的网页分块、切片的原理,目前随着工作的深入,逐渐碰到了各
  • WAP站点,这似乎是一个有点落伍的东西。在诞生之初,它很简陋,只能通过一个叫WML的标记语言来搭建没有任何美感的文字+链接页面。而今,绝大部
  • 从MySQL 5.0.2开始,通过mysql_stmt_attr_set() C API函数实现了服务器端光标。服务器端光标允许在服务器端生
  • 思路:队列使用说明:multiprocessing.Queue()#用于进程间通信,单主进程与子进程无法通信(使用进程池时尽量不要使用这个)
  • 在进行数据库的查询时,会经常遇到这样的情况:例如想在一个用户数据库中查询他的用户名和他的密码,但恰好该用户使用的名字和密码中有特殊的字符,例
  • 像在下拉菜单中选择省、市这样的操作,我一直用ASP来创建生成列表函数,把它们保存在一个Include文件中,用的时候就加载。这样做确实有个不
  • 本文实例讲述了Python实现抓取HTML网页并以PDF文件形式保存的方法。分享给大家供大家参考,具体如下:一、前言今天介绍将HTML网页抓
手机版 网络编程 asp之家 www.aspxhome.com