/* This is a module which implements output of the log to a mongodb NoSQL database. The database is much easier for searching the log copyright: see file COPYRIGHT Mark Koennecke, February 2016 */ #include #include #include #include #include #include #include "sicslogquery.h" static char mongoURL[1024]; static char inst[132]; static mongoc_client_t *client; static mongoc_collection_t *collection; static void MongoCallback(unsigned int severity, const char *timeStamp, const char *subsystem, const char *message, void *userData); /*-----------------------------------------------------------------------------------*/ static void MongoClose(void *data) { RemoveLogCallback(MongoCallback); if(collection != NULL){ mongoc_collection_destroy (collection); mongoc_client_destroy (client); mongoc_cleanup (); } client = NULL; collection = NULL; } /*---------------------------------------------------------------------------------- The callback function for entering data into the log ------------------------------------------------------------------------------------*/ static void MongoCallback(unsigned int severity, const char *timeStamp, const char *subsystem, const char *message, void *userData) { double tVal = DoubleTime(); int status; bson_t *doc; bson_error_t error; bson_oid_t oid; if(client == NULL){ return; } if(logFilter(severity,subsystem,message) == 1) { return; } doc = bson_new (); bson_oid_init (&oid, NULL); BSON_APPEND_OID (doc, "_id", &oid); BSON_APPEND_DOUBLE(doc,"timestamp",tVal); BSON_APPEND_INT32(doc,"severity",severity); BSON_APPEND_UTF8(doc,"timetext",timeStamp); BSON_APPEND_UTF8(doc,"sub",subsystem); BSON_APPEND_UTF8(doc,"message",message); if (!mongoc_collection_insert (collection, MONGOC_INSERT_NONE, doc, NULL, &error)) { fprintf (stdout, "%s\n", error.message); MongoClose(NULL); Log(FATAL,"sys", "Lost connection to mongo server at %s", mongoURL); } bson_destroy (doc); } /*------------------------------------------------------------------------------------*/ static int MongoConfigAction(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 mongourl and instrument parameters for open",eError); return 0; } strncpy(mongoURL,argv[2],sizeof(mongoURL)); strncpy(inst, argv[3],sizeof(inst)); mongoc_init(); client = mongoc_client_new (mongoURL); if(!client){ SCWrite(pCon,"ERROR: failed to connect to mongodb, bad URL?", eError); return 0; } collection = mongoc_client_get_collection (client, inst, "log"); if(!collection){ SCWrite(pCon,"ERROR: failed to connect link to mongo DB", eError); return 0; } RegisterLogCallback(MongoCallback,NULL); SCSendOK(pCon); } else if(strcmp(argv[1],"reopen") == 0) { mongoc_init(); client = mongoc_client_new (mongoURL); if(!client){ SCWrite(pCon,"ERROR: failed to connect to mongodb, bad URL?", eError); return 0; } collection = mongoc_client_get_collection (client, inst, "log"); if(!collection){ SCWrite(pCon,"ERROR: failed to connect link to mongo DB", eError); return 0; } RegisterLogCallback(MongoCallback,NULL); SCSendOK(pCon); }else if(strcmp(argv[1],"status") == 0){ if(client == NULL){ SCWrite(pCon,"Mongo is disconnected", eValue); } else { SCWrite(pCon,"Mongo is connected", eValue); } } else if(strcmp(argv[1],"close") == 0) { MongoClose(NULL); SCSendOK(pCon); } else if(strcmp(argv[1],"filename") == 0) { SCPrintf(pCon,eValue,"mongodb = %s", mongoURL); } else { SCPrintf(pCon,eError,"ERROR: keyword %s not recognised", argv[1]); return 0; } return 1; } /*----------------------------------------------------------------------------*/ static void QueryCallback(const bson_t *doc, void *userData) { pDynString result = (pDynString)userData; bson_iter_t iter; unsigned int severity; uint32_t length; const char *message, *timeText, *sub; char sevBuf[20]; bson_iter_init(&iter,doc); bson_iter_find(&iter,"timetext"); timeText = bson_iter_utf8(&iter,&length); DynStringConcat(result,(char *)timeText); DynStringConcatChar(result,' '); bson_iter_init(&iter,doc); bson_iter_find(&iter,"severity"); severity = bson_iter_int32(&iter); formatSeverity(severity,sevBuf,sizeof(sevBuf)); DynStringConcat(result,(char *)sevBuf); DynStringConcatChar(result,' '); bson_iter_find(&iter,"sub"); sub = bson_iter_utf8(&iter,&length); DynStringConcat(result,(char *)sub); DynStringConcatChar(result,' '); bson_iter_find(&iter,"message"); message = bson_iter_utf8(&iter,&length); DynStringConcat(result,(char *)message); DynStringConcatChar(result,'\n'); } /*-----------------------------------------------------------------------------*/ static int MongoQueryAction(SConnection * pCon, SicsInterp * pSics, void *pData, int argc, char *argv[]) { pDynString result; char *error = NULL; int status; sicslogSetup(mongoURL,inst); result = CreateDynString(132,132); status = sicslogQuery(argc,argv,QueryCallback,result); if(status != 0){ error = sicslogGetError(); if(strstr(error,"Options") != NULL){ SCPrintf(pCon,eValue,"%s", error); } else { SCPrintf(pCon,eError,"Error %s querying mongodb", error); } } else { SCPureSockWrite(pCon,GetCharArray(result),eLog); } DeleteDynString(result); return 1; } /*-----------------------------------------------------------------------------*/ void MongoLogInit(void) { AddCommand(pServ->pSics,"mongoconfig", MongoConfigAction, MongoClose, NULL); AddCommand(pServ->pSics,"showlog", MongoQueryAction, MongoClose, NULL); }