- use dig for resolving host names - ascon.c: fix terminator parsing - property callback: change property before callback - logger.c:default for logger period must be the old value instead of 1 - add frappy type history writing - increase max. logreader line length - HIPNONE returns "null" with json protocol - encode strings properly in formatNameValue - fix memory leak in json2tcl - scriptcontext: do not show debug messages when script starts with underscore or when the "send" property is empty - scriptcontext: remove args for action timestamp - scriptcontext: "que" function will replace an already queued action, e.g. for 'halt - introduced updatestatus script
342 lines
8.4 KiB
C
342 lines
8.4 KiB
C
#include "logger.h"
|
|
#include "logsetup.h"
|
|
#include "sics.h"
|
|
#include "sicshipadaba.h"
|
|
|
|
static char *loggerID = "loggerID";
|
|
static char *histDir = NULL;
|
|
/* static char basepath[1024] = "/"; */
|
|
|
|
typedef struct _HistWriter {
|
|
char *name;
|
|
int old_hour;
|
|
FILE *fd;
|
|
time_t timestamp;
|
|
} HistWriter;
|
|
|
|
HistWriter mainWriter={""};
|
|
|
|
int FlushTask(void *data) {
|
|
HistWriter *wr = data;
|
|
|
|
if (wr->fd) fflush(wr->fd);
|
|
return 1;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
int HistPath(char *dir, char *path, int pathLen, struct tm *t)
|
|
{
|
|
int l;
|
|
|
|
l = strlen(dir);
|
|
if (l + 17 >= pathLen) {
|
|
path[0] = '\0';
|
|
return 0;
|
|
}
|
|
strcpy(path, dir);
|
|
strftime(path + l, pathLen - l, "/%Y/%Y-%m-%d/", t);
|
|
l += 17;
|
|
path[l] = '\0';
|
|
return l;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
static void HistWriteType(Logger *logger)
|
|
{
|
|
HistWriter *wr = logger->histWriter;
|
|
if (logger->numeric) {
|
|
fprintf(wr->fd, "#NUM %s %s\n", logger->secop_id, logger->name);
|
|
} else {
|
|
fprintf(wr->fd, "#STR %s %s\n", logger->secop_id, logger->name);
|
|
}
|
|
}
|
|
/*--------------------------------------------------------------------------*/
|
|
static void HistWrite(Logger *logger, pHdb node, time_t t, char *value)
|
|
{
|
|
HistWriter *wr = logger->histWriter;
|
|
char path[1024];
|
|
time_t now;
|
|
int l;
|
|
struct tm tm, tm0;
|
|
FILE *fd;
|
|
Logger *lg;
|
|
char *secop_id;
|
|
time_t current_hour;
|
|
int hour_of_day;
|
|
int reopen = 0;
|
|
|
|
secop_id = GetHdbProp(node, "secop_id");
|
|
if (!secop_id || !secop_id[0]) {
|
|
if (logger->secop_old) {
|
|
free(logger->secop_old);
|
|
logger->secop_old = NULL;
|
|
}
|
|
return;
|
|
}
|
|
if (!logger->secop_id) logger->secop_id = strdup("");
|
|
if (strcmp(secop_id, logger->secop_id) != 0) {
|
|
free(logger->secop_id);
|
|
logger->secop_id = strdup(secop_id);
|
|
}
|
|
time(&now);
|
|
tm = *localtime(&now);
|
|
current_hour = now / 3600;
|
|
if (current_hour != wr->old_hour) {
|
|
if (wr->fd) {
|
|
fprintf(wr->fd, "# %ld\n#END\n", (wr->timestamp / 3600 + 1) * 3600);
|
|
fclose(wr->fd);
|
|
wr->fd = NULL;
|
|
}
|
|
reopen = 1;
|
|
}
|
|
if (!wr->fd) {
|
|
if (histDir == NULL || reopen) {
|
|
histDir = IFindOption(pSICSOptions, "HistoryDir");
|
|
if (histDir == NULL) goto failed;
|
|
HistPath(histDir, path, sizeof path, &tm);
|
|
if (LoggerMakeDir(path) == 0) goto failed;
|
|
} else if (!*histDir) {
|
|
/* history writing not configured, or failed for current hour */
|
|
return;
|
|
}
|
|
/* last midnight: */
|
|
tm.tm_hour = 0;
|
|
tm.tm_min = 0;
|
|
tm.tm_sec = 0;
|
|
tm.tm_isdst = -1;
|
|
hour_of_day = (now - mktime(&tm)) / 3600;
|
|
l = HistPath(histDir, path, sizeof path, &tm);
|
|
strftime(path + l, sizeof path - l, "%Y-%m-%d", &tm);
|
|
l += 10;
|
|
if (l + 12 >= sizeof path) goto failed;
|
|
snprintf(path + l, sizeof path - l, "_%02d_hist.txt", hour_of_day);
|
|
fd = fopen(path, "r");
|
|
if (!fd) {
|
|
wr->fd = fopen(path, "w");
|
|
if (!wr->fd) goto failed; /* can not create file */
|
|
} else {
|
|
fclose(fd);
|
|
wr->fd = fopen(path, "a");
|
|
if (!wr->fd) goto failed; /* no write access to file */
|
|
}
|
|
fprintf(wr->fd, "#FRAPPY_HISTORY\n");
|
|
if (!wr->old_hour) {
|
|
TaskRegisterP(pServ->pTasker, "flush", FlushTask, 0, 0, wr, 0, 0.1, 0.1);
|
|
}
|
|
wr->old_hour = current_hour;
|
|
fprintf(wr->fd, "# %ld\n", t);
|
|
wr->timestamp = t;
|
|
for (lg = LoggerList(); lg != NULL; lg = lg->next) {
|
|
if (lg->secop_old) {
|
|
HistWriteType(lg);
|
|
fprintf(wr->fd, "%s %s\n", lg->secop_id, lg->secop_old);
|
|
}
|
|
}
|
|
if (logger->secop_old) free(logger->secop_old);
|
|
logger->secop_old = NULL;
|
|
}
|
|
if (logger->secop_old == NULL) {
|
|
if (value[0] == '\0') {
|
|
return;
|
|
}
|
|
HistWriteType(logger);
|
|
logger->secop_old = strdup("");
|
|
}
|
|
if (strcmp(logger->secop_old, value) != 0) {
|
|
if (t != wr->timestamp) {
|
|
fprintf(wr->fd, "# %ld\n", t);
|
|
wr->timestamp = t;
|
|
}
|
|
fprintf(wr->fd, "%s %s\n", secop_id, value);
|
|
free(logger->secop_old);
|
|
logger->secop_old = strdup(value);
|
|
}
|
|
return;
|
|
failed:
|
|
histDir = "";
|
|
}
|
|
|
|
|
|
static hdbCallbackReturn LoggerUpdateCallback(pHdb node,
|
|
void *userData,
|
|
pHdbMessage message)
|
|
{
|
|
Logger *logger = userData;
|
|
pDynString str;
|
|
SConnection *conn = NULL;
|
|
hdbValue value;
|
|
pHdbDataMessage mm = NULL;
|
|
pHdbDataSearch dsm = NULL;
|
|
pHdbMessage killmsg = NULL;
|
|
time_t now;
|
|
char *strvalue;
|
|
|
|
if ((dsm = GetHdbDataSearchMessage(message)) != NULL) {
|
|
if (dsm->testPtr == loggerID) {
|
|
dsm->result = userData;
|
|
return hdbAbort;
|
|
}
|
|
return hdbContinue;
|
|
}
|
|
|
|
if ((killmsg = GetHdbKillNodeMessage(message)) != NULL) {
|
|
if (logger->histWriter) {
|
|
time(&now);
|
|
HistWrite(logger, node, now, "");
|
|
if (logger->secop_old) {
|
|
free(logger->secop_old);
|
|
logger->secop_old = NULL;
|
|
}
|
|
}
|
|
return hdbContinue;
|
|
}
|
|
|
|
if ((mm = GetHdbUpdateMessage(message)) == NULL) {
|
|
return hdbContinue;
|
|
}
|
|
|
|
value = *(mm->v);
|
|
|
|
time(&now);
|
|
|
|
if (GetHdbProp(node, "geterror") == NULL) {
|
|
str = formatValue(value, node);
|
|
strvalue = GetCharArray(str);
|
|
} else {
|
|
str = NULL;
|
|
strvalue = "";
|
|
}
|
|
/* testwise >= */
|
|
if (now >= LoggerLastTime(logger)) { /* never write more than once per second */
|
|
LoggerWrite(logger, now, LoggerPeriod(logger), strvalue);
|
|
}
|
|
if (logger->histWriter) {
|
|
HistWrite(logger, node, now, strvalue);
|
|
}
|
|
if (str) {
|
|
DeleteDynString(str);
|
|
}
|
|
return hdbContinue;
|
|
}
|
|
|
|
int LogMakeInternal(pHdb node, char *path, int period) {
|
|
char buf[1024];
|
|
char secop_id[1024];
|
|
char secop_par[1024];
|
|
char *module;
|
|
int pos, l;
|
|
pHdb nd;
|
|
int numeric;
|
|
Logger *logger;
|
|
char *p, *name;
|
|
pHdbCallback cb;
|
|
|
|
if (strncmp(path, "/sics/", 6) == 0) {
|
|
snprintf(buf, sizeof buf, "%s", path+5);
|
|
} else {
|
|
snprintf(buf, sizeof buf, "%s", path);
|
|
}
|
|
for (p = buf; *p != '\0'; p++) {
|
|
if (*p == '/')
|
|
*p = '.';
|
|
}
|
|
if (buf[0] == '.') {
|
|
name = buf + 1;
|
|
} else {
|
|
name = buf;
|
|
}
|
|
if (node->value.dataType == HIPFLOAT || node->value.dataType == HIPINT) {
|
|
numeric = 1;
|
|
} else {
|
|
numeric = 0;
|
|
}
|
|
logger = FindHdbCallbackData(node, loggerID);
|
|
if (logger != 0) { /* logger exists already */
|
|
LoggerChange(logger, period, name);
|
|
} else {
|
|
logger = LoggerMake(name, period, !numeric);
|
|
/* If that failed, we cannot continue - it crashes in the callback */
|
|
if (logger == NULL) {
|
|
return 0;
|
|
}
|
|
|
|
logger->histWriter = &mainWriter;
|
|
LoggerSetNumeric(logger, numeric);
|
|
SetHdbProperty(node, "logger_name", name);
|
|
cb = MakeHipadabaCallback(LoggerUpdateCallback, logger,
|
|
(void (*)(void *)) LoggerKill);
|
|
assert(cb);
|
|
AppendHipadabaCallback(node, cb);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static int LogSetup(SConnection * pCon, SicsInterp * pSics, void *pData,
|
|
int argc, char *argv[])
|
|
{
|
|
pHdb node;
|
|
static char *loggerDir = NULL;
|
|
int period;
|
|
Logger *logger;
|
|
char *p;
|
|
pDynString result;
|
|
time_t now;
|
|
|
|
if (argc < 2 || argc > 3) {
|
|
SCPrintf(pCon, eError,
|
|
"ERROR: should be: logsetup <node> [<period>]");
|
|
/* or logsetup <node> clear */
|
|
return 0;
|
|
}
|
|
/* seems not used
|
|
if (strcasecmp(argv[1], "basepath") == 0) {
|
|
if (argc > 2) {
|
|
snprintf(basepath, sizeof basepath, "%s", argv[2]);
|
|
}
|
|
SCPrintf(pCon, eValue, "%s", basepath);
|
|
return 1;
|
|
}
|
|
*/
|
|
if (loggerDir == NULL) {
|
|
loggerDir = IFindOption(pSICSOptions, "LoggerDir");
|
|
if (loggerDir == NULL)
|
|
loggerDir = "./";
|
|
LoggerSetDir(loggerDir);
|
|
}
|
|
if (strcasecmp(argv[1], "directory") == 0) {
|
|
/* not used ? M.Z. 10.2020 */
|
|
if (argc > 2) {
|
|
loggerDir = strdup(argv[2]);
|
|
}
|
|
SCPrintf(pCon, eValue, "%s", loggerDir);
|
|
return 1;
|
|
}
|
|
node = FindHdbIntern(argv[1]);
|
|
if (node == NULL) {
|
|
SCPrintf(pCon, eError, "ERROR: %s not found", argv[1]);
|
|
return 0;
|
|
}
|
|
period = 0; /* default period */
|
|
if (argc > 2 && argv[2][0]) {
|
|
if (strcasecmp(argv[2], "clear") == 0) {
|
|
logger = FindHdbCallbackData(node, loggerID);
|
|
time(&now);
|
|
if (logger) { /* silently ignore clear on a missing logger */
|
|
LoggerWrite(logger, now, LoggerPeriod(logger), "");
|
|
HistWrite(logger, node, now, "");
|
|
}
|
|
return 1;
|
|
}
|
|
period = atoi(argv[2]);
|
|
}
|
|
if (!LogMakeInternal(node, argv[1], period)) {
|
|
SCPrintf(pCon, eError, "ERROR: logger %s not created", argv[1]);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
void LogSetupInit(void)
|
|
{
|
|
AddCmd("LogSetup", LogSetup);
|
|
}
|