📄 log.c
字号:
/* * Softcam plugin to VDR (C++) * * This code is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This code is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * Or, point your browser to http://www.gnu.org/copyleft/gpl.html */#include <stdlib.h>#include <stdio.h>#include <stdarg.h>#include <unistd.h>#include <time.h>#include <vdr/tools.h>#include <vdr/thread.h>#include "log.h"#include "misc.h"#define LMOD_SUP 32#define LMOD_CFG_VALID 0x80000000struct LogHeader { int c; char stamp[32]; char tag[64]; };struct LogConfig logcfg = { 1,0,0, "/var/log/vdr-sc" };static const struct LogModule lm_general = { (LMOD_ENABLE|L_GEN_ALL)&LOPT_MASK, (LMOD_ENABLE|L_GEN_ALL)&LOPT_MASK, "general", { "error","warn","info","debug","misc" } };static const struct LogModule *mods[LMOD_SUP] = { &lm_general };static int config[LMOD_SUP] = { LMOD_ENABLE|L_GEN_ALL|LMOD_CFG_VALID };static int cmask[LMOD_SUP] = { LMOD_ENABLE|L_GEN_ALL };static cMutex logfileMutex;static FILE *logfile=0;static bool logfileShutup=false, logfileReopen=false;static unsigned int lastCrc=0;static int lastC=0, lastCount=0;static cTimeMs lastTime;static cMutex lastMutex;// -- cLogging -----------------------------------------------------------------bool cLogging::AddModule(int m, const struct LogModule *lm){ if(m<LMOD_SUP) { if(mods[m]) Printf(L_GEN_DEBUG,"duplicate logging module id %d (%s & %s)",m,mods[m]->Name,lm->Name); mods[m]=lm; if(config[m]&LMOD_CFG_VALID) UpgradeOptions(m); else SetModuleDefault(LCLASS(m,0));//printf("module %-16s added. mod=%x supp=%x def=%x cfg=%x\n",lm->Name,m,lm->OptSupported,lm->OptDefault,config[m]); } else Printf(L_GEN_DEBUG,"failed to add logging module %d (%s)",m,lm->Name); return true;}const struct LogModule *cLogging::GetModule(int c){ int m=LMOD(c); return m<LMOD_SUP ? mods[m] : 0;}bool cLogging::GetHeader(int c, struct LogHeader *lh){ const struct LogModule *lm=GetModule(c); if(lm) { time_t tt=time(0); struct tm tm_r; strftime(lh->stamp,sizeof(lh->stamp),"%b %e %T",localtime_r(&tt,&tm_r)); int i, o=LOPT(c)&~LMOD_ENABLE; for(i=0; i<LOPT_NUM; i++,o>>=1) if(o&1) break; snprintf(lh->tag,sizeof(lh->tag),"%s.%s",lm->Name,(i>=1 && i<LOPT_NUM && lm->OptName[i-1])?lm->OptName[i-1]:"unknown"); lh->c=c; return true; } return false; }void cLogging::LogLine(const struct LogHeader *lh, const char *txt, bool doCrc){ if(doCrc) { unsigned int crc=crc32_le(0,(const unsigned char *)txt,strlen(txt)+1); lastMutex.Lock(); if(lastCrc==crc && lastC==lh->c && ++lastCount<4000000 && lastTime.Elapsed()<=30*1000) { lastMutex.Unlock(); return; } else { unsigned int saveCrc=lastCrc; int saveCount=lastCount, saveC=lastC; lastTime.Set(); lastCrc=crc; lastC=lh->c; lastCount=0; lastMutex.Unlock(); if(saveCount>1) { struct LogHeader lh2; if(GetHeader(saveC,&lh2)) { char buff[128]; snprintf(buff,sizeof(buff),"last message repeated %d times",saveCount); LogLine(&lh2,buff,false); } if(saveCrc==crc && saveC==lh->c) return; } } } if(logcfg.logCon) printf("%s [%s] %s\n",lh->stamp,lh->tag,txt); if(logcfg.logFile) { if((!logfile && !logfileShutup) || logfileReopen) { logfileMutex.Lock(); if(logfileReopen) { logfileReopen=false; if(logfile) { PRINTF(L_GEN_DEBUG,"logfile closed, reopen as '%s'",logcfg.logFilename); fclose(logfile); logfile=0; } } if(!logfile) { logfile=fopen(logcfg.logFilename,"a"); if(logfile) { setlinebuf(logfile); PRINTF(L_GEN_DEBUG,"logfile '%s' opened",logcfg.logFilename); } else { logfileShutup=true; PRINTF(L_GEN_ERROR,"failed to open logfile '%s': %s",logcfg.logFilename,strerror(errno)); } } logfileMutex.Unlock(); } if(logfile) fprintf(logfile,"%s [%s] %s\n",lh->stamp,lh->tag,txt); } if(logcfg.logSys || LMOD(lh->c)==L_GEN) { int pri=-1; switch(lh->c) { case L_GEN_ERROR: case L_GEN_WARN: if(SysLogLevel>0) pri=LOG_ERR; break; case L_GEN_INFO: if(SysLogLevel>1) pri=LOG_INFO; break; case L_GEN_DEBUG: if(SysLogLevel>2) pri=LOG_DEBUG; break; case L_GEN_MISC: if(logcfg.logSys) pri=LOG_DEBUG; break; default: pri=LOG_DEBUG; break; } if(pri>=0) syslog(pri,"[%d] [%s] %s",cThread::ThreadId(),lh->tag,txt); }}bool cLogging::Enabled(int c){ int m=LMOD(c); int o=LOPT(c)|LMOD_CFG_VALID|LMOD_ENABLE; return m<LMOD_SUP && (config[m] & o)==o;}void cLogging::Printf(int c, const char *format, ...){ if(Enabled(c)) { struct LogHeader lh; if(GetHeader(c,&lh)) { char buff[1024]; va_list ap; va_start(ap,format); vsnprintf(buff,sizeof(buff),format,ap); va_end(ap); LogLine(&lh,buff); } }}void cLogging::Puts(int c, const char *txt){ if(txt && Enabled(c)) { struct LogHeader lh; if(GetHeader(c,&lh)) { LogLine(&lh,txt); } }}void cLogging::PutLB(int c, cLineBuff *lb){ if(lb->Length()>0) { Puts(c,lb->Line()); lb->Flush(); }}void cLogging::Dump(int c, const void *data, int n, const char *format, ...){ if(Enabled(c)) { struct LogHeader lh; if(GetHeader(c,&lh)) { char buff[1024]; va_list ap; va_start(ap,format); vsnprintf(buff,sizeof(buff),format,ap); va_end(ap); LogLine(&lh,buff); const unsigned char *d=(const unsigned char *)data; for(int i=0; i<n;) { int q=sprintf(buff,"%04x:",i); for(int l=0 ; l<16 && i<n ; l++) q+=sprintf(&buff[q]," %02x",d[i++]); LogLine(&lh,buff); } } }}void cLogging::LineDump(int c, const void *data, int n, const char *format, ...){ if(Enabled(c)) { struct LogHeader lh; if(GetHeader(c,&lh)) { char buff[4096]; va_list ap; va_start(ap,format); unsigned int q=vsnprintf(buff,sizeof(buff),format,ap); va_end(ap); const unsigned char *d=(const unsigned char *)data; for(int i=0; i<n; i++) { if(q>=sizeof(buff)-8) { q+=snprintf(&buff[q],sizeof(buff)-q,"...."); break; } q+=snprintf(&buff[q],sizeof(buff)-q," %02x",d[i]); } LogLine(&lh,buff); } }}void cLogging::SetModuleDefault(int c){ const struct LogModule *lm=GetModule(c); if(lm) { int m=LMOD(c); config[m]=(lm->OptDefault&LOPT_MASK)|LMOD_CFG_VALID; cmask[m] = lm->OptSupported&LOPT_MASK; }}void cLogging::SetModuleOptions(int c){ const struct LogModule *lm=GetModule(c); if(lm) config[LMOD(c)]=(LOPT(c)&(lm->OptSupported&LOPT_MASK))|LMOD_CFG_VALID;}int cLogging::GetModuleOptions(int c){ const struct LogModule *lm=GetModule(c); return lm ? LOPT(config[LMOD(c)]) : -1;}void cLogging::SetModuleOption(int c, bool on){ const struct LogModule *lm=GetModule(c); if(lm) { int m=LMOD(c); int o=LOPT(c)&(lm->OptSupported&LOPT_MASK); if(o) { if(on) config[m]|=o; else config[m]&=(~o); config[m]|=LMOD_CFG_VALID; } }}void cLogging::UpgradeOptions(int m){ const struct LogModule *lm=mods[m]; if(lm) { config[m]&=(lm->OptSupported&LOPT_MASK); config[m]|=(lm->OptDefault&LOPT_MASK)&(~cmask[m]); cmask[m] =lm->OptSupported&LOPT_MASK; config[m]|=LMOD_CFG_VALID; }}const char *cLogging::GetModuleName(int c){ const struct LogModule *lm=GetModule(c); return lm ? lm->Name : 0;}const char *cLogging::GetOptionName(int c){ const struct LogModule *lm=GetModule(c); if(lm) { int o=LOPT(c)&~LMOD_ENABLE; if(lm->OptSupported & o) { int i; for(i=0; i<LOPT_NUM; i++,o>>=1) if(o&1) break; return (i>=1 && i<LOPT_NUM && lm->OptName[i-1]) ? lm->OptName[i-1] : 0; } } return 0;}bool cLogging::GetConfig(cLineBuff *lb){ lb->Flush(); bool cont=false; for(int m=1; m<LMOD_SUP; m++) if(config[m]&LMOD_CFG_VALID) { lb->Printf("%s%d:%x:%x",cont?",":"",m,config[m]&~LMOD_CFG_VALID,cmask[m]); cont=true; } return cont;}void cLogging::ParseConfig(const char *txt){ int n=0, l, m, o, d; while(sscanf(&txt[n],"%d:%x:%x%n",&m,&o,&d,&l)==3) { if(m>=1 && m<LMOD_SUP) { config[m]=(o&LOPT_MASK)|LMOD_CFG_VALID; cmask[m] =(d&LOPT_MASK); UpgradeOptions(m); } n+=l; if(txt[n]!=',') break; n++; }}void cLogging::ReopenLogfile(void){ logfileMutex.Lock(); logfileReopen=true; logfileMutex.Unlock();}int cLogging::GetClassByName(const char *name){ const char *s=index(name,'.'); if(s) { unsigned int l=s-name; for(int m=1; m<LMOD_SUP; m++) { const struct LogModule *lm=mods[m]; if(lm && strlen(lm->Name)==l && !strncasecmp(name,lm->Name,l)) { s++; if(!strcasecmp(s,"enable")) return LCLASS(m,1); for(int o=1; o<LOPT_NUM; o++) if((lm->OptSupported&(1<<o)) && lm->OptName[o-1] && !strcasecmp(s,lm->OptName[o-1])) return LCLASS(m,1<<o); break; } } } return -1; }// -- cLogLineBuff -------------------------------------------------------------cLogLineBuff::cLogLineBuff(int C):cLineBuff(256){ c=C;}cLogLineBuff::~cLogLineBuff(){ Flush();}void cLogLineBuff::Flush(void){ cLogging::PutLB(c,this);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -