/* This is a module which implements output of the log to a sqlite database. The database is much easier for searching the log copyright: see file COPYRIGHT Mark Koennecke, February 2016 */ #include #include #include #include #include static sqlite3 *db = NULL; static char sqliteFile[1024]; static unsigned int lineCount = 0; static unsigned int sqlActive = 0; /*----------------------------------------------------------------------------------*/ static void SqlFlush(void) { char *err; if(sqlActive == 1 && db != NULL){ sqlite3_exec(db,"END TRANSACTION",NULL,NULL,&err); lineCount = 0; } } /*---------------------------------------------------------------------------------- The callback function for entering data into the log ------------------------------------------------------------------------------------*/ static void SqliteCallback(unsigned int severity, const char *timeStamp, const char *subsystem, const char *message, void *userData) { double tVal = DoubleTime(); char sql[2024]; int status; char *err; if(logFilter(severity,subsystem,message) == 1) { return; } if(lineCount == 0){ sqlite3_exec(db,"BEGIN TRANSACTION",NULL,NULL,&err); } sqlite3_snprintf(sizeof(sql),sql,"INSERT into log VALUES(%f,\"%s\",%d,\"%s\",\"%w\")", tVal,timeStamp,severity,subsystem,message); status = sqlite3_exec(db,sql,NULL,NULL,&err); if(status != SQLITE_OK){ printf("Sqlite logging error: %s from %s\n", err, sql); sqlite3_free(err); } lineCount++; if(lineCount >= 1000){ SqlFlush(); } } /*-----------------------------------------------------------------------------------*/ static void SqlClose(void *data) { char *err; if(sqlActive == 1 && db != NULL){ sqlite3_exec(db,"END TRANSACTION",NULL,NULL,&err); sqlite3_close(db); RemoveLogCallback(SqliteCallback); sqlActive = 0; } } /*------------------------------------------------------------------------------------*/ static int SQLLogConfigAction(SConnection * pCon, SicsInterp * pSics, void *pData, int argc, char *argv[]) { int status; if(argc < 2) { SCWrite(pCon,"ERROR: need keyword", eError); return 0; } strtolower(argv[1]); if(strcmp(argv[1],"open") == 0){ if(argc < 3){ SCWrite(pCon,"ERROR: need dbfilename parameter for open",eError); return 0; } strncpy(sqliteFile,argv[2],sizeof(sqliteFile)); status = sqlite3_open(sqliteFile,&db); if(status){ SCPrintf(pCon,eError,"ERROR: failed to open database %s", argv[2]); sqlite3_close(db); return 0; } else { RegisterLogCallback(SqliteCallback,NULL); sqlActive = 1; SCSendOK(pCon); } } else if(strcmp(argv[1],"close") == 0) { SqlClose(NULL); SCSendOK(pCon); } else if(strcmp(argv[1],"flush") == 0) { SqlFlush(); SCSendOK(pCon); } else if(strcmp(argv[1],"filename") == 0) { SCPrintf(pCon,eValue,"sqlitedb = %s", sqliteFile); } else { SCPrintf(pCon,eError,"ERROR: keyword %s not recognised", argv[1]); return 0; } return 1; } /*-----------------------------------------------------------------------------*/ void SqliteLogInit(void) { AddCommand(pServ->pSics,"sqlconfig", SQLLogConfigAction, SqlClose, NULL); }