/*--------------------------------------------------------------------------- logger.c Markus Zolliker, Sept 2004 ---------------------------------------------------------------------------- */ #include #include #include #include #include #include #include #include "splitter.h" #include "sics.h" #include "logger.h" #define LOGGER_NAN -999999. struct Logger { char *name; char old[256]; int period; time_t last; long pos; Logger *next; }; static char *dir = NULL; static Logger *vars = NULL; static Logger *list; static time_t lastLife = 0; /*--------------------------------------------------------------------------*/ Logger *LoggerFind(char *name) { Logger *p; p = list; while (p != NULL) { if (0==strcasecmp(name, p->name)) { return p; } p = p->next; } return NULL; } /*--------------------------------------------------------------------------*/ char *LoggerGetDir(void) { char path[256], line[32]; FILE *fil; time_t now; static time_t last; #define LASTLOGTXT "#last logging entry at:\n" if (dir == NULL) { dir = IFindOption(pSICSOptions, "LoggerDir"); snprintf(path, sizeof path, "%s/lastlife.dat", dir); fil = fopen(path, "r"); if (fil) { fgets(line, sizeof line, fil); if (strcmp(line, LASTLOGTXT) == 0) { fgets(line, sizeof line, fil); lastLife = atol(line); if (lastLife < 1000000000) { printf("bad lastLife %ld\n", lastLife); } } fclose(fil); } else { perror("open read error \n"); } } now = time(NULL); if (now != last) { snprintf(path, sizeof path, "%s/lastlife.dat", dir); fil = fopen(path, "w"); if (fil) { fprintf(fil, "%s%ld\n", LASTLOGTXT, now); fclose(fil); } else { printf("can not open %s\n", path); perror("open write error \n"); } last = now; } return dir; } /*--------------------------------------------------------------------------*/ int LoggerWrite(Logger *log, time_t now, int period, char *value) { char path[256], stim[32], buf[32]; struct tm *tm; int yday, isdst; int l; int newday; FILE *fil; long pos; LoggerGetDir(); if (dir == NULL) return 0; if (now == 0) { printf("now==0\n"); } tm = localtime(&log->last); yday = tm->tm_yday; tm = localtime(&now); if (tm->tm_yday != yday) { log->period = 0; } else if (0 == strncmp(value, log->old, sizeof(log->old))) { return 0; } log->last = now; snprintf(path, sizeof path, "%s/%s/", dir, log->name); l = strlen(path); strftime(path + l, sizeof path - l, "%m-%d.log", tm); strftime(stim, sizeof stim, "#%Y-%m-%d %H:%M:%S\n", tm); fil = fopen(path, "r+"); if (fil == NULL) { /* create new file */ fil = fopen(path, "w+"); if (fil == NULL) return 0; fputs(stim, fil); } else { /* check if file is actual */ fgets(buf, sizeof buf, fil); if (0 != strncmp(buf, stim, 11)) { fclose(fil); fil=fopen(path, "w+"); /* overwrite old logfile */ if (fil == NULL) return 0; fputs(stim, fil); } else { fseek(fil, 0, SEEK_END); /* set position to end */ } } if (period != log->period) { log->period = period; snprintf(buf, sizeof buf, "\t%d", period); log->pos = 0; } else { buf[0]='\0'; } /* if (log->pos > 0) { fseek(fil, log->pos, SEEK_SET); } log->pos = ftell(fil); */ strftime(stim, sizeof stim,"%H:%M:%S", tm); fprintf(fil, "%s\t%s%s\n", stim, value, buf); l = strlen(value); if (l >= sizeof(log->old)) { l = sizeof(log->old) - 1; } strncpy(log->old, value, l); log->old[l] = '\0'; fclose(fil); return 1; } /*--------------------------------------------------------------------------*/ void LoggerKill(Logger *log) { /* we do not really free the logger, it might be reused for the same variable later. We set the value to undefined */ LoggerWrite(log, time(NULL), 0, ""); } /*--------------------------------------------------------------------------*/ Logger *LoggerMake(char *name, int period) { Logger *log, *p; char path[256]; struct stat st; int i; time_t t; LoggerGetDir(); if (dir == NULL) return NULL; snprintf(path, sizeof path, "%s/%s", dir, name); i = stat(path, &st); if (i >= 0) { if (((st.st_mode >> 12) & 15) != 4) { /* exists, but is no directory */ return NULL; } } else { i = mkdir(path, S_IRWXU+S_IRGRP+S_IXGRP+S_IROTH+S_IXOTH); if (i < 0) return NULL; /* mkdir failed */ } log = LoggerFind(name); /* look if logger already exists */ if (log == NULL) { log = malloc(sizeof *log); if (log == NULL) return NULL; log->name = strdup(name); if (log->name == NULL) { free(log); return NULL; } log->period = 0; log->old[0] = '\0'; log->last = 0; log->pos = 0; log->next = list; list = log; t = time(NULL) -1; if (lastLife != 0 && lastLife + period < t) { t = lastLife + period; } LoggerWrite(log, t, period, ""); /* value was undefined since last life of server */ } return log; } /*--------------------------------------------------------------------------*/ typedef enum { numeric, text } CompType; typedef struct { SConnection *pCon; CompType type; time_t step; time_t tlim; time_t tmin, tmax, tlast, told; float ymin, ymax, ylast, yold; char slast[256]; char set[256]; } Compressor; static void LoggerInit(Compressor *c, SConnection *pCon, time_t step) { c->pCon = pCon; c->step = step; c->tmin = -2; c->tmax = 0; c->tlast = 0; c->tlim = 0; c->told = 0; c->ylast = LOGGER_NAN; } static void LoggerOutStr(Compressor *c, time_t t, char *str) { char line[256]; /* printf("out %ld %g\n", t, y); */ if (0 != strcmp(str, c->slast)) { snprintf(line, sizeof line, "%ld %s\n", t - c->tlast, str); c->tlast = t; c->slast[0]='\0'; strncat(c->slast, str, sizeof c->slast - 1); SCWrite(c->pCon, line, eStatus); } } static void LoggerOut(Compressor *c, time_t t, float y) { char line[80]; /* printf("out %ld %g\n", t, y); */ if (y != c->ylast) { c->ylast = y; if (y == LOGGER_NAN) { snprintf(line, sizeof line, "%ld\n", t - c->tlast); } else { snprintf(line, sizeof line, "%ld %g\n", t - c->tlast, y); } /* printf("-%s\n", line); */ c->tlast = t; SCWrite(c->pCon, line, eStatus); } } static void LoggerPut(Compressor *c, time_t t, char *value) { char *p; double y; if (c->type == numeric) { if (t == 0) { /* finish */ t = c->tlim + 3 * c->step; y = 0; } else { y = strtod(value, &p); if (p == value) { y = LOGGER_NAN; } else { if (y == LOGGER_NAN) y *= 1.0000002; } } /* printf("put %ld %g\n", t, y); */ if (c->tlim == 0) goto first; if (t >= c->tlim) { c->tlim += c->step; if (c->tmin > c->tmax) { LoggerOut(c, c->tmax, c->ymax); c->ymax = c->ymin; c->tmax = c->tmin; } else { LoggerOut(c, c->tmin, c->ymin); if (c->tmin == c->tmax) goto first; c->ymin = c->ymax; c->tmin = c->tmax; } if (t >= c->tlim) { LoggerOut(c, c->tmin, c->ymin); if (t >= c->tlim + c->step) { LoggerOut(c, c->told, c->yold); } goto first; } } if (y <= c->ymin) { c->ymin = y; c->tmin = t; } else if (y > c->ymax) { c->ymax = y; c->tmax = t; } c->yold = y; c->told = t; return; first: c->tlim = t + 2 * c->step; c->tmin = t; c->tmax = t; c->ymin = y; c->ymax = y; return; } else if (c->type == text) { if (t != 0) LoggerOutStr(c, t, value); } } /*--------------------------------------------------------------------------*/ int LoggerGraph(SConnection *pCon, SicsInterp *pSics, void *pData, int argc, char *argv[]) { time_t from, to, step, xs, lastt, now; long lxs; char *p; int i, l, yday, iret, loss; int inRange; time_t t, startim; struct tm tm; char stim[32], path[256], line[256], lastval[256]; char *lin, *val, *stp; FILE *fil; Compressor c; float yy, lasty; Logger *log; if (argc < 2) goto illarg; strtolower(argv[1]); if (strcmp(argv[1], "vars") == 0) { /* default variables on a graph */ if (vars == NULL) { vars = LoggerMake("vars", 1); if (vars == NULL) return 0; } Arg2Text(argc-2, argv+2, line, sizeof line); LoggerWrite(vars, time(NULL), 1, line); SCSendOK(pCon); return 1; } argtolower(argc, argv); if (argc < 4) goto illarg; now = time(NULL); from = strtol(argv[1], &p, 0); /* unix time, not year 2038 safe */ if (p == argv[1]) goto illarg; to = strtol(argv[2], NULL, 0); if (p == argv[2]) goto illarg; if (strcmp(argv[3],"text") == 0) { /* non-numeric values */ step = 1; c.type = text; } else { step = strtol(argv[3], NULL, 0); c.type = numeric; } if (p == argv[3]) goto illarg; if (from <= 0) from += now; if (to <= 0) to += now; if (step <= 0) step = 1; LoggerGetDir(); if (dir == NULL) { SCWrite(pCon, "LoggerDir not found", eError); return 0; } loss = 0; for (i=4; i= log->last) { c.slast[0]='\0'; LoggerOutStr(&c, now, log->old); } } if (fil) { fclose(fil); fil = NULL; } } snprintf(line, sizeof line, "*%d %ld %ld\n", loss, from, to); SCWrite(pCon, line, eStatus); return 1; illarg: SCWrite(pCon, "illegal argument(s)", eError); return 0; }