#!/usr/bin/python # -*- coding: utf-8 -*- # @todo: 服务器留存分析, 仅针对单 serverID 统计,不管合服后 import CommFunc import ConfigParser import mylog import logging cfg = ConfigParser.ConfigParser() cfg.read("../../InterfaceConfig.php") ServerPath = cfg.get("ServerInfo", "ServerPath") # 需要处理的流向名及顺序列表 DRNameList = ["FirstLogin", "LogInOut", "CTGOK"] def queryServerKeepLoginInfo(argvDict): logging.info("queryServerKeepLoginInfo %s" % str(argvDict)) if "serverID" not in argvDict: print "not serverID" return argvDict["OnlyServerID"] = argvDict["serverID"] # 只查本服 loginDayList = eval(argvDict.get("loginDayList", str(range(2, 22)))) # 留存天(当日) maxDay = max(loginDayList) logging.info("loginDayList %s" % str(loginDayList)) startDate = argvDict.get("startDate", "") endDate = argvDict.get("endDate", "") eventType = argvDict.get("eventType", "") createRoleEndDate = argvDict.get("createRoleEndDate", "") if not createRoleEndDate: createRoleEndDate = endDate if endDate else startDate argvDict["createRoleEndDate"] = createRoleEndDate # 留存创角/首充结束天 createRoleEndDateTime = CommFunc.strToDatetime(createRoleEndDate) endDateTime = CommFunc.getDiffDaysDate(maxDay - 1, createRoleEndDateTime) argvDict["endDate"] = str(endDateTime)[:10] logging.info(" upd endDate=%s" % endDate) logging.info(" upd createRoleEndDate=%s" % createRoleEndDate) else: createRoleEndDateTime = CommFunc.strToDatetime(createRoleEndDate) doCount = 0 logInOutDateList = [] createRoleDateTime = CommFunc.strToDatetime(startDate) logging.info("createRoleDateTime=%s" % createRoleDateTime) logging.info("createRoleEndDateTime=%s" % createRoleEndDateTime) while createRoleDateTime <= createRoleEndDateTime and doCount < 365: doCount += 1 for loginDay in loginDayList: loginDateTime = CommFunc.getDiffDaysDate(loginDay - 1, createRoleDateTime) loginDate = str(loginDateTime)[:10] if loginDate not in logInOutDateList: logInOutDateList.append(loginDate) createRoleDateTime = CommFunc.getDiffDaysDate(1, createRoleDateTime) logInOutDateList.sort() startDate = argvDict.get("startDate", "") endDate = argvDict.get("endDate", "") createDateAccIDInfo = {} # {"首登日期":["账号", ...], ...} loginDateAccIDInfo = {} # {"登录日期":["账号", ...], ...} firstCTGRealAccIDInfo = {} # {"首充日期":["账号", ...], ...} # 查询中心备份的 if CommFunc.isQueryCenterbak(argvDict): queryCenterBak(startDate, endDate, logInOutDateList, argvDict) return needQueryCenterbak = CommFunc.loopMainServerDR(cfg, startDate, endDate, argvDict, checkDrFileNeedParseFunc, parseLineFunc, createDateAccIDInfo, loginDateAccIDInfo, logInOutDateList, firstCTGRealAccIDInfo, argvDict, drNameList=DRNameList) logging.info("needQueryCenterbak %s" % needQueryCenterbak) if needQueryCenterbak: bakDataInfo = CommFunc.queryBackupCenterDR(cfg, argvDict) logging.info("queryBackupCenterDR OK") if bakDataInfo == None: return createDateAccIDInfoBak, loginDateAccIDInfoBak, firstCTGRealAccIDInfoBak = bakDataInfo # 合并数据 for bakDate, firstLoginAccIDList in createDateAccIDInfoBak.items(): if bakDate not in createDateAccIDInfo: createDateAccIDInfo[bakDate] = firstLoginAccIDList else: createDateAccIDInfo[bakDate] = list(set(firstLoginAccIDList + createDateAccIDInfo[bakDate])) for bakDate, firstCTGRealAccIDList in firstCTGRealAccIDInfoBak.items(): if bakDate not in firstCTGRealAccIDInfo: firstCTGRealAccIDInfo[bakDate] = firstCTGRealAccIDList else: firstCTGRealAccIDInfo[bakDate] = list(set(firstCTGRealAccIDList + firstCTGRealAccIDInfo[bakDate])) for bakDate, loginAccIDList in loginDateAccIDInfoBak.items(): if bakDate not in loginDateAccIDInfo: loginDateAccIDInfo[bakDate] = loginAccIDList else: loginDateAccIDInfo[bakDate] = list(set(loginAccIDList + loginDateAccIDInfo[bakDate])) logging.info("query all data OK") loginStyleInfo = {} loginTDList = ["DateStr", "FirstAccIDCount"] for loginDay in loginDayList: loginTDList.append(loginDay) title = _(u"次日留存") if loginDay == 2 else (_(u"第%s日留存") % loginDay) loginStyleInfo[loginDay] = {"align":"left", "title":title} # 创角用户留存 loginDrList = calcLoginDr(createDateAccIDInfo, loginDayList, loginDateAccIDInfo) # 首充用户留存 ctgLoginDrList = calcLoginDr(firstCTGRealAccIDInfo, loginDayList, loginDateAccIDInfo) printStr = "

%s

" % _(u"留存分析") if startDate: printStr += "%s: %s
" % (_(u"查询统计开始日期"), startDate) if createRoleEndDate: printStr += "%s: %s
" % (_(u"查询统计结束日期"), createRoleEndDate) printStr += "
" # 表格输出 printStr += "【%s】
" % _(u"创角留存") loginStyleInfo.update({"DateStr":{"title":_(u"创角日期")}, "FirstAccIDCount":{"title":_(u"首登人数")}, }) printStr += CommFunc.editTableHtml(loginDrList, loginTDList, styleInfo=loginStyleInfo, printCount=False) printStr += "
" printStr += "【%s】
" % _(u"首充留存") loginStyleInfo.update({"DateStr":{"title":_(u"首充日期")}, "FirstAccIDCount":{"title":_(u"首充人数")}, }) printStr += CommFunc.editTableHtml(ctgLoginDrList, loginTDList, styleInfo=loginStyleInfo, printCount=False) printStr += "
%s" \ % (eventType, startDate, createRoleEndDate, loginDayList, _(u"查看其他")) logging.info("show OK") # 只会返回最后一个print的内容 print printStr return def calcLoginDr(firstAccIDInfo, loginDayList, loginDateAccIDInfo): dateStrList = firstAccIDInfo.keys() dateStrList.sort() loginDrList = [] for dateStr in dateStrList: dateObj = CommFunc.strToDatetime(dateStr) firstAccIDList = firstAccIDInfo[dateStr] firstAccIDCount = len(firstAccIDList) # 留存 loginDrInfo = {"DateStr":dateStr, "FirstAccIDCount":firstAccIDCount} for loginDay in loginDayList: loginDateObj = CommFunc.getDiffDaysDate(loginDay - 1, dateObj) loginDateStr = str(loginDateObj)[:10] if loginDateStr not in loginDateAccIDInfo: continue loginAccIDList = loginDateAccIDInfo[loginDateStr] loginPlayerCount = 0 for accID in firstAccIDList: if accID in loginAccIDList: loginPlayerCount += 1 if loginPlayerCount > 0: loginRate = loginPlayerCount / float(firstAccIDCount) if firstAccIDCount > 0 else 0 loginRatePer = round(loginRate * 100, 2) loginDrInfo[loginDay] = "%s%% (%s)" % (loginRatePer, loginPlayerCount) else: loginDrInfo[loginDay] = "" if firstAccIDCount: loginDrList.append(loginDrInfo) return loginDrList def queryCenterBak(startDate, endDate, logInOutDateList, argvDict): createDateAccIDInfoBak, loginDateAccIDInfoBak, firstCTGRealAccIDInfoBak = {}, {}, {} if not CommFunc.loopCenterbakRarDR(cfg, startDate, endDate, argvDict, checkDrFileNeedParseFunc, parseLineFunc, createDateAccIDInfoBak, loginDateAccIDInfoBak, logInOutDateList, firstCTGRealAccIDInfoBak, argvDict, drNameList=DRNameList): return return CommFunc.queryBackupCenterOK([createDateAccIDInfoBak, loginDateAccIDInfoBak, firstCTGRealAccIDInfoBak]) def checkDrFileNeedParseFunc(drFileName, *parseArgs, **kv): ''' 检查流向是否需要处理 @param drFileName: 流向文件名 xxx_日期.txt @param *parseArgs: 自定义参数 @return: isNeed, checkNeedParseRetInfo ''' _, _, logInOutDateList, _, argvDict = parseArgs if drFileName.startswith("FirstLogin_") or drFileName.startswith("CTGOK_"): dateStr = drFileName[:drFileName.rindex(".")].split("_")[1] createRoleStartDate = str(argvDict["startDate"]) createRoleEndDate = str(argvDict["createRoleEndDate"]) if dateStr < createRoleStartDate or dateStr > createRoleEndDate: return False, None elif drFileName.startswith("LogInOut_"): dateStr = drFileName[:drFileName.rindex(".")].split("_")[1] if dateStr not in logInOutDateList: return False, None return True, None def parseLineFunc(drName, dateStr, checkNeedParseRetInfo, line, *parseArgs, **kv): ''' 解析流向行内容 @param drName: 流向名 @param dateStr: 对应日期字符串 @param checkNeedParseRetInfo: checkDrFileNeedParseFunc 返回的内容 @param line: 本行内容 @param *parseArgs: 自定义参数 ''' createDateAccIDInfo, loginDateAccIDInfo, _, firstCTGRealAccIDInfo, argvDict = parseArgs serverID = argvDict.get("serverID", "") sServerID = "@s%s" % serverID # 首登 if drName == "FirstLogin": if sServerID not in line: return drDict = eval(line) accID = drDict["AccID"] if not accID.endswith(sServerID): return if dateStr not in createDateAccIDInfo: createDateAccIDInfo[dateStr] = [] firstLoginAccIDList = createDateAccIDInfo[dateStr] if accID not in firstLoginAccIDList: firstLoginAccIDList.append(accID) # 真实货币首充 elif drName == "CTGOK": if sServerID not in line: return if "ctgRealFirstTime" not in line: return drDict = eval(line) accID = drDict["AccID"] if not accID.endswith(sServerID): return ctgRealFirstDate = drDict["ctgRealFirstTime"][:10] if ctgRealFirstDate != dateStr: return if dateStr not in firstCTGRealAccIDInfo: firstCTGRealAccIDInfo[dateStr] = [] firstCTGRealAccIDList = firstCTGRealAccIDInfo[dateStr] if accID not in firstCTGRealAccIDList: firstCTGRealAccIDList.append(accID) # 统计登录 elif drName == "LogInOut": if "logout" in line: return if sServerID not in line: return if "127.0.0.1" in line: #logging.info(" 脱机登录,不处理") return drDict = eval(line) if drDict["Type"] != "login": return accID = drDict["AccID"] if not accID.endswith(sServerID): return if dateStr not in loginDateAccIDInfo: loginDateAccIDInfo[dateStr] = [] loginAccIDList = loginDateAccIDInfo[dateStr] if accID not in loginAccIDList: loginAccIDList.append(accID) return def main(): CommFunc.setdefaultencoding() argvDict = CommFunc.parse_args() mylog.InitMyLog(argvDict.get("eventType", "")) CommFunc.gettextInstall(argvDict.get("lang", "")) queryServerKeepLoginInfo(argvDict) return if __name__ == "__main__": try: main() except: CommFunc.printExceptionError()