#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 []"); /* or logsetup 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); }