diff --git a/logger.c b/logger.c index 4a6781a..caae64f 100644 --- a/logger.c +++ b/logger.c @@ -12,28 +12,49 @@ Markus Zolliker, Sept 2004 #include #include #include +#include +#include #include "splitter.h" -#include "sics.h" #include "logger.h" +#ifndef TECS_LOG +#include "sics.h" +#endif + #define LOGGER_NAN -999999. +#define ONE_YEAR (366*24*3600) struct Logger { char *name; - char old[256]; + char *old; + int oldsize; int period; time_t last; - long pos; + int lastLn; /* 0 or the number chars counted from the second + last newline character. */ + int overwrite; /* overwrite last line when value has not changed */ + int oldValue; /* old value to be overwritten */ + int numeric; + int exact; Logger *next; }; static char *dir = NULL; -static Logger *vars = NULL; static Logger *list; static time_t lastLife = 0; /*--------------------------------------------------------------------------*/ -Logger *LoggerFind(char *name) { +char *LoggerName(Logger *log) { + return log->name; +} +/*--------------------------------------------------------------------------*/ +void LoggerSetNumeric(Logger *log, int numeric) { + if (log) { + log->numeric = numeric; + } +} +/*--------------------------------------------------------------------------*/ +Logger *LoggerFind(const char *name) { Logger *p; p = list; while (p != NULL) { @@ -45,38 +66,42 @@ Logger *LoggerFind(char *name) { return NULL; } /*--------------------------------------------------------------------------*/ -char *LoggerGetDir(void) { +#define LASTLOGTXT "#last logging entry at:\n" + +void LoggerSetDir(char *dirarg) { char path[256], line[32]; FILE *fil; + + dir = dirarg; + 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", (long)lastLife); + } + } + fclose(fil); + } else { + perror("open read error \n"); + } +} +/*--------------------------------------------------------------------------*/ +char *LoggerGetDir(void) { + char path[256]; + 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); + fprintf(fil, "%s%ld\n", LASTLOGTXT, (long)now); fclose(fil); } else { printf("can not open %s\n", path); @@ -87,14 +112,32 @@ char *LoggerGetDir(void) { 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 LoggerVarPath(char *dir, char *path, int pathLen, char *name) { int l; - int newday; + + l = strlen(dir); + if (l + strlen(name) + 2 >= pathLen) { + path[0]='\0'; + return 0; + } + strcpy(path, dir); + path[l] = '/'; l++; + for (;*name != '\0'; name++, l++) { + path[l] = tolower(*name); + } + path[l] = '/'; l++; + path[l] = '\0'; + return l; +} +/*--------------------------------------------------------------------------*/ +int LoggerWrite0(Logger *log, time_t now, int period, char *value) { + char path[256], stim[32], buf[32], chr; + struct tm *tm; + int yday; + int isdst; + int l, ext, skip, changed; FILE *fil; - long pos; + long endPos, pos1, p; LoggerGetDir(); if (dir == NULL) return 0; @@ -102,76 +145,193 @@ int LoggerWrite(Logger *log, time_t now, int period, char *value) { printf("now==0\n"); } tm = localtime(&log->last); + isdst = tm->tm_isdst; 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->period = -1; } - log->last = now; - snprintf(path, sizeof path, "%s/%s/", dir, log->name); - l = strlen(path); + l = LoggerVarPath(dir, path, sizeof path, log->name); strftime(path + l, sizeof path - l, "%m-%d.log", tm); - strftime(stim, sizeof stim, "#%Y-%m-%d %H:%M:%S\n", tm); + strftime(stim, sizeof stim, "#%Y-%m-%d %H:%M:%S", tm); fil = fopen(path, "r+"); + skip = 0; if (fil == NULL) { /* create new file */ fil = fopen(path, "w+"); if (fil == NULL) return 0; - fputs(stim, fil); - } else { /* check if file is actual */ + fprintf(fil, "%s isdst %d period %d exact %d\n", stim, tm->tm_isdst, period, log->exact); + endPos = ftell(fil); + fseek(fil, -1, SEEK_CUR); + } else { /* check if file is from today */ 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); + endPos = ftell(fil); + fseek(fil, -1, SEEK_CUR); + log->period = -1; } else { - fseek(fil, 0, SEEK_END); /* set position to end */ + fseek(fil, -log->lastLn, SEEK_END); /* set position to last line */ + endPos = ftell(fil) + log->lastLn; + if (endPos > 0 && log->lastLn == 0) { + /* find last newline in newly opened file */ + fseek(fil, -1, SEEK_CUR); + chr = fgetc(fil); + while (chr != '\n' && ftell(fil) >= 2) { + fseek(fil, -2, SEEK_CUR); + chr = fgetc(fil); + } + fseek(fil, -1, SEEK_CUR); + } else if (now != log->last) { + skip = 1; + } } } + changed = (0 != strcmp(value, log->old)); if (period != log->period) { log->period = period; - snprintf(buf, sizeof buf, "\t%d", period); - log->pos = 0; + if (log->numeric) { + snprintf(buf, sizeof buf, "\t%d", period); + } else { + strcpy(buf, "\t0"); + } + changed = 1; } else { buf[0]='\0'; + if (log->overwrite && !changed) { + skip = 0; + } } - /* - if (log->pos > 0) { - fseek(fil, log->pos, SEEK_SET); + pos1 = 0; + chr = fgetc(fil); + while (chr != EOF) { + if (chr == '\n') { + skip--; + if (skip < 0) break; + } + chr = fgetc(fil); } - log->pos = ftell(fil); - */ + if (chr == EOF) { + if (pos1 == 0) { + fputs("\n#no newline found\n", fil); + } else { + fseek(fil, pos1, SEEK_SET); + } + } + if (tm->tm_isdst != isdst) { + fprintf(fil, "#isdst %d\n", tm->tm_isdst); + } + pos1 = 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; + for (p = ftell(fil); p < endPos; p++) { /* overwrite dirt after last line */ + fprintf(fil, " "); } - strncpy(log->old, value, l); - log->old[l] = '\0'; + endPos = ftell(fil); fclose(fil); + log->lastLn = (endPos - pos1) + 1; + /* overwrite next time when value has not changed */ + log->overwrite = ! changed; + l = strlen(value); + if (l >= log->oldsize) { + ext = ((l - log->oldsize)/16 + 1) * 16; + if (ext < log->oldsize / 4) ext += (log->oldsize / 64) * 16; + log->oldsize += ext; + free(log->old); + log->old = calloc(1, log->oldsize); + assert(log->old); + assert(l < log->oldsize); + } + strcpy(log->old, value); + log->old[l] = '\0'; + log->last = now; + return 1; +} +/*--------------------------------------------------------------------------*/ +int LoggerWrite(Logger *log, time_t now, int period, char *value) { + Logger *p; + time_t h0; + static int yday = -1; + struct tm *tm; + + int l; + FILE *fil; + char path[PATH_MAX]; + char tim[256]; + + tm = localtime(&now); + if (tm->tm_yday != yday) { + tm->tm_hour = 0; + tm->tm_min = 0; + tm->tm_sec = 0; + h0 = mktime(tm); + + yday = tm->tm_yday; + + l = LoggerVarPath(dir, path, sizeof path, "debug"); + strftime(path + l, sizeof path - l, "%m-%d.log", tm); + fil=fopen(path, "a"); + if (fil) { + strftime(tim, sizeof tim, "h0 %m-%d %H:%M:%S\n", localtime(&h0)); + fputs(tim, fil); + } + + /* log old values (forced midnight log) */ + p = list; + while (p != NULL) { + if (fil) { + strftime(tim, sizeof tim, "last %m-%d %H:%M:%S, ", localtime(&p->last)); + fputs(tim, fil); + fprintf(fil, "period %d, name %s, old %s\n", p->period, p->name, p->old); + } + if (p->last < h0 && p->last != 0 && + p->period >= 0 && p->old[0] != '\0') { + LoggerWrite0(p, h0, p->period, p->old); + p->overwrite = 0; + } + p = p->next; + } + if (fil) fclose(fil); + } + return LoggerWrite0(log, now, period, value); +} +/*--------------------------------------------------------------------------*/ +time_t LoggerLastTime(Logger *log) { + if (log->last != 0 && log->period > 0) { + return log->last; + } + return 0; +} +/*--------------------------------------------------------------------------*/ +int LoggerGetValue(void *data, char *value, int size) { + Logger *log = data; + value[0]='\0'; + strncat(value, log->old, size - 1); 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, ""); + + if (list != NULL) { /* LoggerFreeAll not yet called */ + LoggerWrite(log, time(NULL), 0, ""); + } } /*--------------------------------------------------------------------------*/ -Logger *LoggerMake(char *name, int period) { - Logger *log, *p; +Logger *LoggerMake(char *name, int period, int exact) { + Logger *log; 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); + LoggerVarPath(dir, path, sizeof path, name); i = stat(path, &st); if (i >= 0) { if (((st.st_mode >> 12) & 15) != 4) { /* exists, but is no directory */ @@ -183,17 +343,20 @@ Logger *LoggerMake(char *name, int period) { } log = LoggerFind(name); /* look if logger already exists */ if (log == NULL) { - log = malloc(sizeof *log); + log = calloc(1, 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->period = -1; + log->exact = exact; + log->old = calloc(1,12); + log->oldsize = 12; log->last = 0; - log->pos = 0; + log->lastLn = 0; + log->numeric = 1; log->next = list; list = log; t = time(NULL) -1; @@ -205,10 +368,13 @@ Logger *LoggerMake(char *name, int period) { return log; } /*--------------------------------------------------------------------------*/ -typedef enum { numeric, text } CompType; +#ifndef TECS_LOG +typedef enum { NUMERIC, TEXT } CompType; typedef struct { SConnection *pCon; + char *var; + int exact; CompType type; time_t step; time_t tlim; @@ -216,9 +382,12 @@ typedef struct { float ymin, ymax, ylast, yold; char slast[256]; char set[256]; + int np; } Compressor; -static void LoggerInit(Compressor *c, SConnection *pCon, time_t step) { +static char *dir2 = NULL; + +static void LoggerInitC(Compressor *c, SConnection *pCon, time_t step) { c->pCon = pCon; c->step = step; c->tmin = -2; @@ -226,6 +395,7 @@ static void LoggerInit(Compressor *c, SConnection *pCon, time_t step) { c->tlast = 0; c->tlim = 0; c->told = 0; + c->slast[0]='\0'; c->ylast = LOGGER_NAN; } @@ -234,11 +404,12 @@ static void LoggerOutStr(Compressor *c, time_t t, char *str) { /* printf("out %ld %g\n", t, y); */ if (0 != strcmp(str, c->slast)) { - snprintf(line, sizeof line, "%ld %s\n", t - c->tlast, str); + snprintf(line, sizeof line, "%ld %s\n", (long)(t - c->tlast), str); c->tlast = t; c->slast[0]='\0'; strncat(c->slast, str, sizeof c->slast - 1); - SCWrite(c->pCon, line, eStatus); + SCWrite(c->pCon, line, eWarning); + c->np--; } } @@ -249,13 +420,14 @@ static void LoggerOut(Compressor *c, time_t t, float y) { if (y != c->ylast) { c->ylast = y; if (y == LOGGER_NAN) { - snprintf(line, sizeof line, "%ld\n", t - c->tlast); + snprintf(line, sizeof line, "%ld\n", (long)(t - c->tlast)); } else { - snprintf(line, sizeof line, "%ld %g\n", t - c->tlast, y); + snprintf(line, sizeof line, "%ld %g\n", (long)(t - c->tlast), y); } /* printf("-%s\n", line); */ c->tlast = t; - SCWrite(c->pCon, line, eStatus); + SCWrite(c->pCon, line, eWarning); + c->np--; } } @@ -263,7 +435,11 @@ static void LoggerPut(Compressor *c, time_t t, char *value) { char *p; double y; - if (c->type == numeric) { + if (c->var) { + SCPrintf(c->pCon, eWarning, "*%s exact %d\n", c->var, c->exact); + c->var = NULL; + } + if (c->type == NUMERIC) { if (t == 0) { /* finish */ t = c->tlim + 3 * c->step; y = 0; @@ -314,7 +490,7 @@ static void LoggerPut(Compressor *c, time_t t, char *value) { c->ymin = y; c->ymax = y; return; - } else if (c->type == text) { + } else if (c->type == TEXT) { if (t != 0) LoggerOutStr(c, t, value); } } @@ -324,8 +500,9 @@ int LoggerGraph(SConnection *pCon, SicsInterp *pSics, void *pData, time_t from, to, step, xs, lastt, now; long lxs; char *p; - int i, l, yday, iret, loss; + int i, iarg0, l, iret, loss, np; int inRange; + int yday=0; time_t t, startim; struct tm tm; char stim[32], path[256], line[256], lastval[256]; @@ -333,59 +510,93 @@ int LoggerGraph(SConnection *pCon, SicsInterp *pSics, void *pData, FILE *fil; Compressor c; float yy, lasty; - Logger *log; + CompType type0; + DIR *dr; + char *opt; + int isdst; + int overflow; - 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); + /* 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 */ + if (from < ONE_YEAR) { + from += now; + } + if (to < ONE_YEAR) { + to += now; + } + iarg0 = 4; + if (strcasecmp(argv[3],"text") == 0) { /* non-numeric values */ step = 1; - c.type = text; + type0 = TEXT; + np = from - to + 2; + } else if (strcasecmp(argv[3],"np") == 0) { /* max. number of points */ + type0 = NUMERIC; + iarg0 = 5; + np = strtol(argv[4], NULL, 0); + if (to <= from) { + step = 1; + } else if (np <= 2) { + step = to - from; + } else { + step = (to - from) / (np - 2) + 1; + } } else { step = strtol(argv[3], NULL, 0); - c.type = numeric; + if (step <= 0) step = 1; + type0 = NUMERIC; + np = (from - to) / step + 2; } if (p == argv[3]) goto illarg; - if (from <= 0) from += now; - if (to <= 0) to += now; if (step <= 0) step = 1; - LoggerGetDir(); + snprintf(line, sizeof line, "%ld\n", (long)now); + SCWrite(pCon, line, eWarning); + if (dir == NULL) { - SCWrite(pCon, "LoggerDir not found", eError); - return 0; + dir = IFindOption(pSICSOptions, "LoggerDir"); + if (dir == NULL) { + SCWrite(pCon, "LoggerDir not found", eError); + return 0; + } + LoggerSetDir(dir); + } + if (dir2 == NULL) { + dir2 = IFindOption(pSICSOptions, "LoggerDir2"); + if (dir2 == NULL) dir2=""; } loss = 0; - for (i=4; i= log->last) { - c.slast[0]='\0'; - LoggerOutStr(&c, now, log->old); - } - } if (fil) { fclose(fil); fil = NULL; } + if (c.np < 0) overflow = 1; } - snprintf(line, sizeof line, "*%d %ld %ld\n", loss, from, to); - SCWrite(pCon, line, eStatus); + snprintf(line, sizeof line, "*%d %d\n", loss, overflow); + SCWrite(pCon, line, eWarning); return 1; illarg: SCWrite(pCon, "illegal argument(s)", eError); return 0; } +/*--------------------------------------------------------------------------*/ +void LoggerFreeAll(void *data) { + Logger *p, *next; + + KillDummy(data); + p = list; + while (p != NULL) { + next = p->next; + if (p->name) free(p->name); + if (p->old) free(p->old); + free(p); + p = next; + } + list = NULL; +} +/*--------------------------------------------------------------------------*/ +void LoggerInit(void) { + AddCommand(pServ->pSics,"Graph",LoggerGraph,LoggerFreeAll,NULL); +} +#endif /* TECS_LOG */ diff --git a/logger.h b/logger.h index 95a26bb..9fbe820 100644 --- a/logger.h +++ b/logger.h @@ -1,5 +1,5 @@ /*--------------------------------------------------------------------------- -logger.c +logger.h Markus Zolliker, Sept 2004 ---------------------------------------------------------------------------- @@ -12,8 +12,15 @@ Markus Zolliker, Sept 2004 typedef struct Logger Logger; -Logger *LoggerMake(char *name, int period); +Logger *LoggerMake(char *name, int period, int exact); void LoggerKill(Logger *log); int LoggerWrite(Logger *log, time_t now, int period, char *value); +char *LoggerName(Logger *log); +void LoggerSetNumeric(Logger *log, int numeric); +void LoggerSetDir(char *dirarg); +void LoggerWriteOld(Logger *log, time_t now); +time_t LoggerLastTime(Logger *log); +int LoggerGetStatus(Logger *log); +void LoggerSetStatus(Logger *log, int status); #endif