Files
sics/logsetup.c
zolliker 61341b52f4 various improvements
- 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
2021-09-16 12:26:18 +02:00

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);
}