按组分开的行输出

时间:2014-09-09 06:18:39

标签: python

我的python脚本检查mysqldump以及是否有任何问题脚本打印:

  • 转储对于db来说是旧的;
  • db;
  • 的转储未完成
  • db;
  • 的转储为空
  • db;
  • 不存在MySQL转储

脚本逐行将这些记录记录到文件中。

我的问题是有一种方法可以在文件中格式化输出,如:

Dump is old for db;
Dump is old for db;
Dump is old for db;

Dump is not complete for db;
Dump is not complete for db;
Dump is not complete for db;

Dump is empty for db;
Dump is empty for db;
Dump is empty for db;

因为现在我的文件看起来像:

Dump is old for db;
Dump is empty for db;
Dump is old for db;
MySQL dump does not exist for db;
...
etc

这是我的小脚本:)

#!/bin/env python

import psycopg2
import sys,os
from subprocess import Popen, PIPE
from datetime import datetime
import smtplib

con = None
today = datetime.now().strftime("%Y-%m-%d")

log_dump_fail = '/tmp/mysqldump_FAIL'
log_fail = open(log_dump_fail,'w').close()
log_fail = open(log_dump_fail, 'a')

sender = 'PUT_SENDER_NAME_HERE'
receiver = ['receiver_name']
smtp_daemon_host = 'localhost'

def db_backup_file_does_not_exist(db_backup_file):
    if not os.path.exists(db_backup_file): return True
    else: return False

def dump_health(last_dump_row, file_name,db):
       last_row = last_dump_row.rsplit(" ")
       tms = ''.join(last_row[4:5])
       status = last_row[1:3]

       if (status) and (tms != today):
      log_fail.write("\nDB is old for "+ str(db) + str(file_name) + ", \nDump finished at " + str(''.join(tms)))
      log_fail.write("\n-------------------------------------------")
       elif not (status) and (tms == None):
      log_fail.write("\nDump is not complete for "+str(db) +  str(file_name) + " , end of file is not correct") 
      log_fail.write("\n-------------------------------------------")

suffixes = ['B', 'KB', 'MB', 'GB', 'TB', 'PB']
def humansize(nbytes):
    if nbytes == 0: return '0 B'
    i = 0
    while nbytes >= 1024 and i < len(suffixes)-1:
        nbytes /= 1024.
        i += 1
    f = ('%.2f' % nbytes).rstrip('0').rstrip('.')
    return '%s %s' % (f, suffixes[i])

def dump_size(dump_file, file_name,db):
       size = os.path.getsize(dump_file)
       if (size < 1024):
      human_readable = humansize(size)
          log_fail.write("\nDump is empty for " +str(db) + "\n" +"\t" + str (file_name)+", file size is " + str(human_readable))
      log_fail.write("\n-------------------------------------------")

def report_to_noc(isubject,text):
    TEXT = text
        SUBJECT = subject
        message = 'Subject: %s\n\n%s' % (SUBJECT, TEXT)
        server = smtplib.SMTP(smtp_daemon_host)
        server.sendmail(sender, receiver, message)
        server.quit()

try:    
    con = psycopg2.connect(database='**', user='***', password='***', host='****') 
    cur = con.cursor()
    cur.execute("""\
select ad.servicename, (select name from servers where id = ps.server_id) as servername 
from packages as p, account_data as ad, package_servers as ps 
where p.id=ad.package_id and 
p.date_deleted IS NULL and 
p.id=ps.package_id and 
p.aktuel IS NULL and 
p.pre_def_package_id = 4 and  
p.mother_package_id !=0 and 
ps.subservice_id=5 and  
p.mother_package_id NOT IN (select id from packages where date_deleted IS NOT NULL) 
ORDER BY servername; 
""")

    while (1):
        row = cur.fetchone ()
        if row == None:
            break

    db = row[0]
        server_name = str(row[1])
    if (''.join(server_name) == 'SKIP_THIS') or (''.join(server_name) == 'SKIP_THIS'):
        continue
    else:
        db_backup_file = '/storage/backup/db/mysql/' + str(db) + '/current/' + str(db) + '.mysql.gz'
        db_backup_file2 = '/storage/backup/' + str(''.join(server_name.split("DB"))) + '/mysql/' + str(db) + '/current/'+ str(db) + '.mysql.gz'

    db_file_does_not_exist = False
    db_file2_does_not_exist = False

    if db_backup_file_does_not_exist(db_backup_file):
        db_file_does_not_exist = True   
    if db_backup_file_does_not_exist(db_backup_file2):
        db_file2_does_not_exist = True

        if db_file_does_not_exist and db_file2_does_not_exist:
                log_fail.write("\nMySQL dump does not exist for " + str(db) +  "\n" + "\t" + str(db_backup_file2) + "\n" + "\t" +  str(db_backup_file))
        log_fail.write("\n-------------------------------------------")
        continue
    elif (db_file_does_not_exist) and not (db_file2_does_not_exist):
        p_zcat = Popen(["zcat", db_backup_file2], stdout=PIPE)
                p_tail = Popen(["tail", "-2"], stdin=p_zcat.stdout, stdout=PIPE)
                dump_status =  str(p_tail.communicate()[0])
                dump_health(dump_status,db_backup_file2,db)
                dump_size(db_backup_file2, db_backup_file2,db)
        elif (db_file2_does_not_exist) and not (db_file_does_not_exist):
        p_zcat = Popen(["zcat", db_backup_file], stdout=PIPE)
                p_tail = Popen(["tail", "-2"], stdin=p_zcat.stdout, stdout=PIPE)
                dump_status =  str(p_tail.communicate()[0])
                dump_health(dump_status,db_backup_file,db) 
        dump_size(db_backup_file,db_backup_file,db)       

    con.close()

except psycopg2.DatabaseError, e:
    print 'Error %s' % e    
    sys.exit(1)

log_fail.close()

if os.path.getsize(log_dump_fail) > 0:
        subject = "Not all MySQL dumps completed successfully. Log file backup:" + str(log_dump_fail)
        fh = open(log_dump_fail, 'r')
        text = fh.read()
        fh.close()
        report_to_noc(subject,text)
else:
        subject = "MySQL dump completed successfullyi for all DBs, listed in PC"
        text = "Hello! \nI am notifying you that I checked mysqldump files this morning.\nThere are nothing to worry about. :)"
        report_to_noc(subject,text)

3 个答案:

答案 0 :(得分:0)

您可以在编写日志文件后对其进行处理。

一个选项是读取您的文件并对行进行排序:

lines = open('log.txt').readlines()
lines.sort()
open('log_sorted.txt', 'w').write("\n".join(lines))

这不会在日志类型之间发出空行。

另一种选择是使用Counter

from collections import Counter
lines = open('log.txt').readlines()
counter = Counter()
for line in lines:
    counter[line] += 1

out_file = open('log_sorted.txt', 'w')
for line, num in counter.iteritems():
    out_file.write(line * num + "\n")

答案 1 :(得分:0)

看起来您想要对脚本的输出进行分组,而不是在搜索时记录信息。 最简单的方法是维护4个列表,每个列表为空,而不是空,等等。在脚本中将数据库名称添加到适当的列表而不是日志记录,然后将列表逐个转储到具有适当前缀的文件中(“对于”+ dbname不为空)。 例如,从函数中删除所有log_fail.write()并将其替换为list.append()并编写一个单独的函数,根据需要写入日志文件:

添加列表:

db_dump_is_old_list = []
db_dump_is_empty_list = []
db_dump_is_not_complete_list = []
db_dump_does_not_exist_list = []

修改功能:

def dump_health(last_dump_row, file_name,db):
   last_row = last_dump_row.rsplit(" ")
   tms = ''.join(last_row[4:5])
   status = last_row[1:3]

   if (status) and (tms != today):
    db_dump_is_old_list.append(str(db))
    #log_fail.write("\nDB is old for "+ str(db) + str(file_name) + ", \nDump finished at " + str(''.join(tms)))
    #log_fail.write("\n-------------------------------------------")
   elif not (status) and (tms == None):
    db_dump_is_not_complete_list.append(str(db)
    #log_fail.write("\nDump is not complete for "+str(db) +  str(file_name) + " , end of file is not correct") 
    #log_fail.write("\n-------------------------------------------")


def dump_size(dump_file, file_name,db):
       size = os.path.getsize(dump_file)
       if (size < 1024):
        human_readable = humansize(size)
        db_dump_is_empty_list.append(str(db))
        #log_fail.write("\nDump is empty for " +str(db) + "\n" +"\t" + str (file_name)+", file size is " + str(human_readable))
        #log_fail.write("\n-------------------------------------------")


if db_file_does_not_exist and db_file2_does_not_exist:
        db_dump_does_not_exist_list.append(str(db))
        #log_fail.write("\nMySQL dump does not exist for " + str(db) +  "\n" + "\t" + str(db_backup_file2) + "\n" + "\t" +  str(db_backup_file))
        #log_fail.write("\n-------------------------------------------")
        continue

并添加记录器功能:

def dump_info_to_log_file():
    log_dump_fail = '/tmp/mysqldump_FAIL'
    log_fail = open(log_dump_fail,'w').close()
    log_fail = open(log_dump_fail, 'a')

    for dbname in db_dump_is_old_list:
        log_fail.write("Dump is Old for" + str(dbname))

    log_fail.write("\n\n")

    for dbname in db_dump_is_empty_list:
        log_fail.write("Dump is Empty for" + str(dbname))

    log_fail.write("\n\n")

    for dbname in db_dump_is_not_complete_list:
        log_fail.write("Dump is Not Complete for" + str(dbname))

    log_fail.write("\n\n")

    for dbname in db_dump_does_not_exist_list:
        log_fail.write("Dump Does Not Exist for" + str(dbname))

    log_fail.close()

或者您只需按原样进行记录,然后读入文件,排序并回写文件。

答案 2 :(得分:0)

谢谢所有有趣的想法。 我真的尝试了所有选项:)

在我看来: 使用Counter对象,专业人员只需几行代码。 但缺点是 - 许多读/写操作。日志文件不大,但是,我决定减少read(s)\ write(s)

对于数组,缺点是多行代码:)但优点是 - 只写一次文件。

所以我实现了数组..:)

谢谢大家!!!