def load(self): config = ConfigParser.ConfigParser() conf1 = assistant.SF("%s/alwayson.conf" % (os.path.dirname(__file__))) conf2 = assistant.SF("%s/alwayson.conf" % (os.getcwd())) conf3 = "/etc/alwayson.conf" if os.path.isfile(conf1): conf = conf1 elif os.path.isfile(conf2): conf = conf2 else: conf = conf3 PLOG.info("using configer file:%s" % conf) config.readfp(open(conf1, "rb")) checkinterval = config.getint("alwayson", "interval") for section in config.sections(): try: if section == "alwayson": continue name = section newprog = program(name) newprog.command = config.get(section, "command") newprog.runpath = config.get(section, "runpath") # newprog.matchingregular=config.get(section, "matchingregular") newprog.matchingstring = config.get(section, "matchingstring") newprog.pidfile = config.get(section, "pidfile") newprog.bootwait = config.getint(section, "bootwait") newprog.rebootwait = config.getint(section, "rebootwait") newprog.enabled = config.getboolean(section, "enabled") newprog.init(self) PLOG.info("confim:%s" % name) except: PLOG.error("read configerfile failed!program=%s,Pass!" % name) continue self.programlist.append(newprog)
def run(self): self.status = "waiting start" if not self.enabled: self.status = "disabled" return if self.bootwait > 0: time.sleep(self.bootwait) while not self.thread_stop: self.status = "checking" # print '%s start checking at %s ...\n' %(self.name,time.ctime()) if self.processHandle != None and self.processHandle.poll( ) != None: print "recycle %s" % (self.name) self.processHandle = None if not check_pid(self._pid): self.update_pid() if not check_pid(self._pid): self._pid = 0 if self._pid == 0: self.processHandle = None PLOG.warn("%s check failed!restarting ..." % (self.name)) if self.rebootwait > 0: self.status = "waiting restart" PLOG.info("%s restarting wait %d second..." % (self.name, self.rebootwait)) time.sleep(self.rebootwait) try: self.status = "starting" # 修改当前路径 if len(self.runpath) > 0: try: if not os.path.isdir(self.runpath): os.makedirs(self.runpath) if not os.path.isdir(self.runpath): self.enabled = False PLOG.error("%s run path invalid!" % (self.name)) break os.chdir(self.runpath) except Exception, e: PLOG.error( "%s restart failed!change current path failed!err=%s" % (self.name, e)) PLOG.info("%s execute command:'%s'" % (self.name, self.command)) self.processHandle = subprocess.Popen( self.command, bufsize=0, executable=None, stdin=None, stdout=None, stderr=None, preexec_fn=None, close_fds=False, shell=True, cwd=self.runpath, env=None, universal_newlines=False, startupinfo=None, creationflags=0) self._pid = self.processHandle.pid except Exception, e: PLOG.error("%s restart failed!err=%s" % (self.name, e))
def load(self): config = ConfigParser.ConfigParser() conf1 = assistant.SF("%s/alwayson.conf" % (os.path.dirname(__file__))) conf2 = assistant.SF("%s/alwayson.conf" % (os.getcwd())) conf3 = "/etc/alwayson.conf" if os.path.isfile(conf1):conf = conf1 elif os.path.isfile(conf2):conf = conf2 else:conf = conf3 PLOG.info("using configer file:%s" % conf) config.readfp(open(conf1, "rb")) checkinterval = config.getint("alwayson", "interval") for section in config.sections(): try: if section == "alwayson":continue name = section newprog = program(name) newprog.command = config.get(section, "command") newprog.runpath = config.get(section, "runpath") # newprog.matchingregular=config.get(section, "matchingregular") newprog.matchingstring = config.get(section, "matchingstring") newprog.pidfile = config.get(section, "pidfile") newprog.bootwait = config.getint(section, "bootwait") newprog.rebootwait = config.getint(section, "rebootwait") newprog.enabled = config.getboolean(section, "enabled") newprog.init(self); PLOG.info("confim:%s" % name) except: PLOG.error("read configerfile failed!program=%s,Pass!" % name) continue self.programlist.append(newprog)
def InvokeStopRadius(): strStopradiusCMD = "service radiusd stop" try: PLOG.info("call:%s\n" % (strStopradiusCMD)) stopret = os.popen(strStopradiusCMD).read() PLOG.debug("output:%s\n" % (stopret)) except Exception, e: PLOG.info("执行命令失败,CMD=%s\nError=%s\n" % (strStopradiusCMD, e.args[1])) exit(1)
def InvokeStopRadius(): strStopradiusCMD = "service radiusd stop" try: PLOG.info("call:%s\n"%(strStopradiusCMD)) stopret = os.popen(strStopradiusCMD).read() PLOG.debug("output:%s\n"%(stopret) ) except Exception, e: PLOG.info("执行命令失败,CMD=%s\nError=%s\n"%(strStopradiusCMD,e.args[1])) exit(1)
def addJsonInfo(jsonSourcefile,destJson): filedir = os.path.dirname(jsonSourcefile) parentDirName = os.path.split(filedir)[-1] primaryFilename = "" jsSourceFileInfo = None with open(jsonSourcefile,"r") as f: jsSourceFileInfo = json.load(f,'utf8') if jsSourceFileInfo !=None and isinstance(jsSourceFileInfo,dict): if jsSourceFileInfo.has_key("file"): primaryFilename = jsSourceFileInfo["file"] if primaryFilename != "": jsSourceFileInfo["id"] = str(uuid.uuid1()) if primaryFilename.startswith("https:") : # ios info file filetimestamp = time.localtime( os.path.getmtime(jsonSourcefile)) primaryFileTime = time.strftime('%Y-%m-%d %H:%M:%S',filetimestamp) jsSourceFileInfo["filetime"] = primaryFileTime if not jsSourceFileInfo.has_key("filesize") : jsSourceFileInfo["filesize"] = "0" #destJson["list"].append(jsSourceFileInfo) else: try: primaryFileSize = os.path.getsize(os.path.join(filedir,primaryFilename)) filetimestamp = time.localtime( os.path.getmtime(os.path.join(filedir,primaryFilename)) ) primaryFileTime = time.strftime('%Y-%m-%d %H:%M:%S',filetimestamp) jsSourceFileInfo["filesize"] = str(primaryFileSize) jsSourceFileInfo["filetime"] = primaryFileTime if jsSourceFileInfo.has_key("file") : jsSourceFileInfo["file"] = parentDirName +'/' + jsSourceFileInfo["file"] except: PLOG.info("generate file info of dir %s failed,primary File %s not find,skip it"% (filedir,primaryFilename)) return if jsSourceFileInfo.has_key("poster") : jsSourceFileInfo["poster"] = parentDirName +'/' + jsSourceFileInfo["poster"] if jsSourceFileInfo.has_key("thumbnail") : jsSourceFileInfo["thumbnail"] = parentDirName +'/' + jsSourceFileInfo["thumbnail"] if jsSourceFileInfo.has_key("extend") : jsextend = jsSourceFileInfo["extend"] if jsextend.has_key("screenshot") : jsscreenshottmp = [] for picture in jsextend["screenshot"] : picture = parentDirName +'/' + picture jsscreenshottmp.append(picture) jsextend["screenshot"] =jsscreenshottmp destJson["list"].append(jsSourceFileInfo) PLOG.debug('generate file info of dir "%s" success'%(filedir)) else: PLOG.debug("generate file info of dir %s failed,primary File name is empty"% (filedir)) else : PLOG.debug('not find "file" node in info file %s , skip it' %(jsonSourcefile)) else: PLOG.warn('js file %s is null,maybe path error! skip it' %(jsonSourcefile))
def run(): init() # radius 日志检查 beforeInvoketime = datetime.datetime.now() currentLogFile = getCurrentLogfile() beforeInvokeLogFileSize = os.path.getsize(currentLogFile) # radius auth请求检查 ret = InvokeProc() # radius auth请求检查 end if (ret == 1): # radius 运行状态正常,检查log afterInvoketime = datetime.datetime.now() if beforeInvoketime.day == afterInvoketime.day: if os.path.getsize(currentLogFile) > beforeInvokeLogFileSize: PLOG.info("radius log status is ok") else: PLOG.info("radius log status error,no growth,stop radius") InvokeStopRadius() else: # 调用前后不是同一天(可能写入新日志,也可能写入旧日志,or判断) logfile = getCurrentLogfile() if (logfile != None and len(logfile) > 0 and os.path.getsize(logfile) > 0 ) or os.path.getsize(currentLogFile) > beforeInvokeLogFileSize: PLOG.info("radius log status is ok") else: PLOG.info( "radius log status error,no growth or no new log,stop radius" ) InvokeStopRadius()
def processRPC(self, msg): ret = "" PLOG.info("RPC:\n%s" % msg) if msg == "status": ret = "alwayson working...\n" items = [] for p in self.programlist: items.append((p.name, p.status)) fmt = '%-40s %9s' ret = '\n'.join([fmt % (x, '[%s]' % y) for x, y in items]) PLOG.info("report runing status:\n%s" % ret) elif msg == "stop": pass return ret
def run(): init() # radius 日志检查 beforeInvoketime = datetime.datetime.now() currentLogFile = getCurrentLogfile() beforeInvokeLogFileSize = os.path.getsize(currentLogFile) # radius auth请求检查 ret = InvokeProc() # radius auth请求检查 end if (ret == 1) : # radius 运行状态正常,检查log afterInvoketime = datetime.datetime.now() if beforeInvoketime.day == afterInvoketime.day: if os.path.getsize(currentLogFile) > beforeInvokeLogFileSize : PLOG.info("radius log status is ok") else: PLOG.info("radius log status error,no growth,stop radius") InvokeStopRadius() else: # 调用前后不是同一天(可能写入新日志,也可能写入旧日志,or判断) logfile = getCurrentLogfile() if ( logfile != None and len(logfile) >0 and os.path.getsize(logfile) > 0 ) or os.path.getsize(currentLogFile) > beforeInvokeLogFileSize: PLOG.info("radius log status is ok") else: PLOG.info("radius log status error,no growth or no new log,stop radius") InvokeStopRadius()
def run(self): self.status = "waiting start" if not self.enabled: self.status = "disabled" return if self.bootwait > 0:time.sleep(self.bootwait) while not self.thread_stop: self.status = "checking" # print '%s start checking at %s ...\n' %(self.name,time.ctime()) if self.processHandle!=None and self.processHandle.poll()!=None: print "recycle %s" % (self.name) self.processHandle=None if not check_pid(self._pid):self.update_pid() if not check_pid(self._pid):self._pid = 0 if self._pid == 0: self.processHandle=None PLOG.warn("%s check failed!restarting ..." % (self.name)) if self.rebootwait > 0: self.status = "waiting restart" PLOG.info("%s restarting wait %d second..." % (self.name, self.rebootwait)) time.sleep(self.rebootwait) try: self.status = "starting" # 修改当前路径 if len(self.runpath) > 0: try: if not os.path.isdir(self.runpath):os.makedirs(self.runpath) if not os.path.isdir(self.runpath): self.enabled = False PLOG.error("%s run path invalid!"%(self.name)) break os.chdir(self.runpath) except Exception, e: PLOG.error("%s restart failed!change current path failed!err=%s" % (self.name, e)) PLOG.info("%s execute command:'%s'"%(self.name,self.command)) self.processHandle=subprocess.Popen(self.command, bufsize=0, executable=None, stdin=None, stdout=None, stderr=None, preexec_fn=None, close_fds=False, shell=True, cwd=self.runpath, env=None, universal_newlines=False, startupinfo=None, creationflags=0) self._pid=self.processHandle.pid except Exception, e: PLOG.error("%s restart failed!err=%s" % (self.name, e))
def loadconfig(): config = ConfigParser.ConfigParser() configfile = assistant.SF("%s/SAPeakData.conf" % (os.path.dirname(__file__))) PLOG.info("Load configer file:%s" % configfile) config.readfp(open(configfile, "rb")) SAPeakDataPublic.st.loglevel = config.get("system", "loglevel") SAPeakDataPublic.st.queryunit = config.getint("system", "queryunit") SAPeakDataPublic.st.queryrepeattimes = config.getint("system", "queryrepeattimes") if 24%SAPeakDataPublic.st.queryunit != 0: PLOG.debug("queryunit is invalid,please check config!") sys.exit(2) SAPeakDataPublic.sadb.host = config.get("system", "datasource") SAPeakDataPublic.sadb.dbuser = config.get("system", "dbuser") SAPeakDataPublic.sadb.dbpwd = config.get("system", "dbpwd") SAPeakDataPublic.sadb.dbname = config.get("system", "dbname") SAPeakDataPublic.sadb.tablename = config.get("system", "tablename")
def loadconfig(): config = ConfigParser.ConfigParser() configfile = assistant.SF("%s/SAPeakData.conf" % (os.path.dirname(__file__))) PLOG.info("Load configer file:%s" % configfile) config.readfp(open(configfile, "rb")) SAPeakDataPublic.st.loglevel = config.get("system", "loglevel") SAPeakDataPublic.st.queryunit = config.getint("system", "queryunit") SAPeakDataPublic.st.queryrepeattimes = config.getint( "system", "queryrepeattimes") if 24 % SAPeakDataPublic.st.queryunit != 0: PLOG.debug("queryunit is invalid,please check config!") sys.exit(2) SAPeakDataPublic.sadb.host = config.get("system", "datasource") SAPeakDataPublic.sadb.dbuser = config.get("system", "dbuser") SAPeakDataPublic.sadb.dbpwd = config.get("system", "dbpwd") SAPeakDataPublic.sadb.dbname = config.get("system", "dbname") SAPeakDataPublic.sadb.tablename = config.get("system", "tablename")
def update_pid(self): try: self._pid = 0 if len(self.pidfile) > 0: pidfile = open(self.pidfile, 'r') pid = int(pidfile.readline()) if pid != 0: if self.getCommandForPID(pid) != None: self._pid = pid PLOG.info("%s PID confim for pid:%d" % (self.name, pid)) elif len(self.matchingstring) > 0: pid = self.getPIDForString(self.matchingstring) if pid != None: self._pid = pid PLOG.info("%s PID confim for regular:%d" % (self.name, pid)) else: PLOG.error("%s Unknow check type!!!" % self.name) except Exception, e: PLOG.error("%s update_pid except!err=%s" % (self.name, e))
def InvokeProc(): #echo "User-Name = radiusSelfCheck, User-Password = radiusSelfCheck" | ./radclient -xxxx 127.0.0.1:1812 auth testing123 strCMD="echo \"User-Name = radiusSelfCheck,User-Password = radiusSelfCheck\" | %s -xxxx %s:1812 auth %s" % \ (conf.clientPath,conf.radiusIP,conf.secret) try: PLOG.info("call:%s\n"%(strCMD)) beforeInvokeAuth = int(time.time()) retstr = os.popen(strCMD).read() afterInvokeAuth = int(time.time()) PLOG.debug("output:%s\n"%(retstr)) if ( afterInvokeAuth - beforeInvokeAuth > conf.reponseTimeout ): PLOG.info("radius auth reponse timeout,stop radius") InvokeStopRadius() return 0 if(retstr.find("rad_recv:") != -1 and retstr.find("Reply-Message") != -1) : # 收到回应 if( retstr.find("radius status is ok") != -1 ) : # radius运行正常 PLOG.info("radius run status is ok") return 1 else: # radius状态不正确,关掉radius repmsg = "" repMsgpattern=re.compile('Reply-Message\s*=\s*(?P<repmsg>.*)\s*') m=repMsgpattern.search(retstr) if ( m != None and m.group('repmsg') != None): repmsg = m.group('repmsg') PLOG.info("radius run status error,errmsg = %s ,stop radius" % repmsg) InvokeStopRadius() return 0 else: # radius状态不正确,关掉radius PLOG.info("radius run status error,no response,stop radius") InvokeStopRadius() return 0 except Exception, e: PLOG.info("执行命令失败,CMD=%s\nError=%s\n"%(strCMD,e.args[1])) exit(1)
def InvokeProc(): #echo "User-Name = radiusSelfCheck, User-Password = radiusSelfCheck" | ./radclient -xxxx 127.0.0.1:1812 auth testing123 strCMD="echo \"User-Name = radiusSelfCheck,User-Password = radiusSelfCheck\" | %s -xxxx %s:1812 auth %s" % \ (conf.clientPath,conf.radiusIP,conf.secret) try: PLOG.info("call:%s\n" % (strCMD)) beforeInvokeAuth = int(time.time()) retstr = os.popen(strCMD).read() afterInvokeAuth = int(time.time()) PLOG.debug("output:%s\n" % (retstr)) if (afterInvokeAuth - beforeInvokeAuth > conf.reponseTimeout): PLOG.info("radius auth reponse timeout,stop radius") InvokeStopRadius() return 0 if (retstr.find("rad_recv:") != -1 and retstr.find("Reply-Message") != -1): # 收到回应 if (retstr.find("radius status is ok") != -1): # radius运行正常 PLOG.info("radius run status is ok") return 1 else: # radius状态不正确,关掉radius repmsg = "" repMsgpattern = re.compile( 'Reply-Message\s*=\s*(?P<repmsg>.*)\s*') m = repMsgpattern.search(retstr) if (m != None and m.group('repmsg') != None): repmsg = m.group('repmsg') PLOG.info("radius run status error,errmsg = %s ,stop radius" % repmsg) InvokeStopRadius() return 0 else: # radius状态不正确,关掉radius PLOG.info("radius run status error,no response,stop radius") InvokeStopRadius() return 0 except Exception, e: PLOG.info("执行命令失败,CMD=%s\nError=%s\n" % (strCMD, e.args[1])) exit(1)
def statisticsCurrentDayData(daydate): nextday = daydate + datetime.timedelta(days=1) startquerytime = daydate endquerytime = daydate + datetime.timedelta( hours=SAPeakDataPublic.st.queryunit) while endquerytime <= nextday: acctquerysql = "select acctinputoctets,acctoutputoctets,acctstarttime,acctstoptime,regionid from %s where acctstarttime>='%s' and acctstarttime<'%s'"%\ (SAPeakDataPublic.sadb.tablename,startquerytime.strftime('%Y-%m-%d %H:%M:%S'),endquerytime.strftime('%Y-%m-%d %H:%M:%S')) PLOG.debug("sql=%s" % acctquerysql) startquerytime = endquerytime endquerytime = endquerytime + datetime.timedelta( hours=SAPeakDataPublic.st.queryunit) i = 0 while i < SAPeakDataPublic.st.queryrepeattimes: res = SAPeakDataPublic.querysql(acctquerysql) if res != None: break else: i = i + 1 if i == 3 or res == None: print( "%s statistics data failed! db query appear error %d consecutive times,please execute again later!" % (daydate.strftime('%Y-%m-%d'), SAPeakDataPublic.st.queryrepeattimes)) PLOG.info( "%s statistics data failed! db query appear error %d consecutive times,please execute again later!" % (daydate.strftime('%Y-%m-%d'), SAPeakDataPublic.st.queryrepeattimes)) return # 统计数据 PLOG.trace("start statistics...") for row in res: if row[2] == None or row[3] == None or row[4] == None: PLOG.warn("lack essential data!skip this data") continue regionid = row[4] totalflow = 0 if row[0] != None: totalflow += row[0] if row[1] != None: totalflow += row[1] if row[3].day > row[2].day: # 跨天 endMinute = 23 * 60 + 59 elif row[3].day < row[2].day: PLOG.info( "stoptime day less than starttime day,invalid data,skip") else: endMinute = row[3].hour * 60 + row[3].minute startMinute = row[2].hour * 60 + row[2].minute #startMinute = datetime.datetime.strptime(row[2],'%Y-%m-%d %H:%M:%S') #endMinute = datetime.datetime.strptime(row[3],'%Y-%m-%d %H:%M:%S') totalMinute = endMinute - startMinute + 1 if totalMinute <= 0: PLOG.info("stoptime less than starttime,invalid data,skip") continue if SAStopDefine.stopDc.stops.has_key(regionid): stop = SAStopDefine.stopDc.stops[regionid] startindex = startMinute endindex = endMinute flowOneMinute = float(totalflow) / totalMinute / 1024 / 1024 index = startindex while index <= endindex: stop.dayArray[index][0] += 1 stop.dayArray[index][1] += flowOneMinute if stop.dayArray[index][0] > stop.peakonlinenum: stop.peakonlinenum = stop.dayArray[index][0] stop.peakonlinetime = datetime.datetime( daydate.year, daydate.month, daydate.day, index / 60, index % 60) if stop.dayArray[index][0] > stop.peakbandwidth: stop.peakbandwidth = stop.dayArray[index][1] stop.peakbandwidthtime = datetime.datetime( daydate.year, daydate.month, daydate.day, index / 60, index % 60) index += 1 PLOG.trace("statistics end") # 数据处理结束,输出各站点峰值数据 for stopid, stop in stopsCentor.stops.items(): peakbandwidth = stop.peakbandwidth * 8 / 60 print("%s %s %d %.2f" % (daydate.strftime('%Y-%m-%d'), stop.name, stop.peakonlinenum, peakbandwidth)) PLOG.debug( "%s %s %d %.2f %s %s" % (daydate.strftime('%Y-%m-%d'), stop.name, stop.peakonlinenum, peakbandwidth, stop.peakonlinetime.strftime('%H:%M'), stop.peakbandwidthtime.strftime('%H:%M')))
def statisticsCurrentDayData(daydate) : nextday = daydate+datetime.timedelta(days=1) startquerytime = daydate endquerytime = daydate+datetime.timedelta(hours=SAPeakDataPublic.st.queryunit) while endquerytime<=nextday: acctquerysql = "select acctinputoctets,acctoutputoctets,acctstarttime,acctstoptime,regionid from %s where acctstarttime>='%s' and acctstarttime<'%s'"%\ (SAPeakDataPublic.sadb.tablename,startquerytime.strftime('%Y-%m-%d %H:%M:%S'),endquerytime.strftime('%Y-%m-%d %H:%M:%S')) PLOG.debug("sql=%s"%acctquerysql) startquerytime=endquerytime endquerytime=endquerytime+datetime.timedelta(hours=SAPeakDataPublic.st.queryunit) i = 0 while i<SAPeakDataPublic.st.queryrepeattimes: res = SAPeakDataPublic.querysql(acctquerysql) if res!=None: break else: i = i+1 if i==3 or res==None: print("%s statistics data failed! db query appear error %d consecutive times,please execute again later!"%(daydate.strftime('%Y-%m-%d'),SAPeakDataPublic.st.queryrepeattimes)) PLOG.info("%s statistics data failed! db query appear error %d consecutive times,please execute again later!"%(daydate.strftime('%Y-%m-%d'),SAPeakDataPublic.st.queryrepeattimes)) return # 统计数据 PLOG.trace("start statistics...") for row in res: if row[2] ==None or row[3] ==None or row[4] ==None: PLOG.warn("lack essential data!skip this data") continue regionid = row[4] totalflow = 0 if row[0]!=None: totalflow += row[0] if row[1]!=None: totalflow += row[1] if row[3].day > row[2].day: # 跨天 endMinute = 23*60+59 elif row[3].day < row[2].day: PLOG.info("stoptime day less than starttime day,invalid data,skip") else: endMinute = row[3].hour*60+row[3].minute startMinute = row[2].hour*60+row[2].minute #startMinute = datetime.datetime.strptime(row[2],'%Y-%m-%d %H:%M:%S') #endMinute = datetime.datetime.strptime(row[3],'%Y-%m-%d %H:%M:%S') totalMinute = endMinute-startMinute + 1 if totalMinute <=0: PLOG.info("stoptime less than starttime,invalid data,skip") continue if SAStopDefine.stopDc.stops.has_key(regionid): stop = SAStopDefine.stopDc.stops[regionid] startindex = startMinute endindex = endMinute flowOneMinute = float(totalflow)/totalMinute/1024/1024 index = startindex while index <= endindex: stop.dayArray[index][0] += 1 stop.dayArray[index][1] += flowOneMinute if stop.dayArray[index][0] > stop.peakonlinenum: stop.peakonlinenum = stop.dayArray[index][0] stop.peakonlinetime = datetime.datetime(daydate.year,daydate.month,daydate.day,index/60,index%60) if stop.dayArray[index][0] > stop.peakbandwidth: stop.peakbandwidth = stop.dayArray[index][1] stop.peakbandwidthtime = datetime.datetime(daydate.year,daydate.month,daydate.day,index/60,index%60) index += 1 PLOG.trace("statistics end") # 数据处理结束,输出各站点峰值数据 for stopid,stop in stopsCentor.stops.items(): peakbandwidth = stop.peakbandwidth*8/60 print("%s %s %d %.2f"%(daydate.strftime('%Y-%m-%d'),stop.name,stop.peakonlinenum,peakbandwidth)) PLOG.debug("%s %s %d %.2f %s %s"%(daydate.strftime('%Y-%m-%d'),stop.name,stop.peakonlinenum,peakbandwidth,stop.peakonlinetime.strftime('%H:%M'),stop.peakbandwidthtime.strftime('%H:%M')))