Files
sicspsi/mongolog.c

205 lines
6.1 KiB
C

/*
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 <stdio.h>
#include <logv2.h>
#include <bson.h>
#include <mongoc.h>
#include <sicsutil.h>
#include <sics.h>
#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);
}