- introduced logsetup and savehdb

- moved logger.c and logreader.c for sics/psi/ to sics/
- make comments in status file
This commit is contained in:
zolliker
2008-02-13 10:01:34 +00:00
parent 217de95b29
commit 2d7699ea39
7 changed files with 1080 additions and 3 deletions

492
logreader.c Normal file
View File

@ -0,0 +1,492 @@
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <fortify.h>
#include <errno.h>
#include <dirent.h>
#include "logger.h"
#include "sics.h"
#define LOGGER_NAN -999999.
#define ONE_YEAR (366*24*3600)
#define LLEN 1024
typedef enum { NUMERIC, TEXT } CompType;
typedef struct {
SConnection *pCon;
char var[1024];
int exact;
CompType type;
time_t step;
time_t tlim;
time_t tmin, tmax, tlast, told;
float ymin, ymax, ylast, yold;
char slast[LLEN];
/* char set[LLEN]; */
int np;
char *none;
} Compressor;
static char *dir = NULL;
static char *dir2 = NULL;
static void InitCompressor(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->slast[0]='\0';
c->ylast = LOGGER_NAN;
}
static void OutString(Compressor *c, time_t t, char *str) {
char line[LLEN];
/* printf("out %ld %g\n", t, y); */
if (0 != strcmp(str, c->slast)) {
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, eWarning);
c->np--;
}
}
static void OutFloat(Compressor *c, time_t t, float y) {
char line[80];
/* printf("out %ld %g\n", t, y); */
if (y != c->ylast || (!c->exact && t != c->tlast)) {
c->ylast = y;
if (y == LOGGER_NAN) {
if (c->none) {
snprintf(line, sizeof line, "%ld %s\n", (long)(t - c->tlast), c->none);
} else {
snprintf(line, sizeof line, "%ld\n", (long)(t - c->tlast));
}
} else {
snprintf(line, sizeof line, "%ld %g\n", (long)(t - c->tlast), y);
}
/* printf("-%s\n", line); */
c->tlast = t;
SCWrite(c->pCon, line, eWarning);
c->np--;
}
}
static void PutValue(Compressor *c, time_t t, char *value) {
char *p;
double y;
if (c->var[0]) {
SCPrintf(c->pCon, eWarning, "*%s exact %d\n", c->var, c->exact);
c->var[0] = 0;
}
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) {
OutFloat(c, c->tmax, c->ymax);
c->ymax = c->ymin;
c->tmax = c->tmin;
} else {
OutFloat(c, c->tmin, c->ymin);
if (c->tmin == c->tmax) goto first;
c->ymin = c->ymax;
c->tmin = c->tmax;
}
if (t >= c->tlim) {
OutFloat(c, c->tmin, c->ymin);
if (t >= c->tlim + c->step) {
OutFloat(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) OutString(c, t, value);
}
}
/*--------------------------------------------------------------------------*/
static long getOpt(char *line, int *isdst, int *exact) {
long lxs;
char *opt;
opt = strstr(line, "isdst");
if (opt) {
sscanf(opt, "isdst %d", isdst);
}
opt = strstr(line, "exact");
if (opt) {
sscanf(opt, "exact %d", exact);
}
opt = strstr(line, "period");
if (opt) {
sscanf(opt, "period %ld", &lxs);
return lxs;
} else {
return -1;
}
}
/*--------------------------------------------------------------------------*/
static int LogReader(SConnection *pCon, SicsInterp *pSics, void *pData,
int argc, char *argv[]) {
/* Usage:
graph <start time> <end time> [ none <none value> ] np <number of points> <variable> [<variable> ...]
graph <start time> <end time> text <variable>
graph <start time> <end time> <step> <variable> [<variable> ...]
<start time> and <end time> are seconds since epoch (unix time) or, if the value
is below one day, a time relative to the actual time
The <none value> is optional. if not given, unknown values are returned as empty strings
<number of points> is the maximal number of points to be returned. If more values
are present and the values are numeric, the data is reduced. If the data is not
numeric, the last values may be skipped in order to avoid overflow.
<variable> is the name of a variable (several vaiables may be given).
Note that slashes are converted to dots, and that the first slash is ignored.
The seconds variant is for text values, which can not be reduced. In any case, all values
are returned.
The third variant is old style and can be replaced by the first variant, where
<number of points> = (<start time> - <end time>) / <step> + 2
Output format:
First line: returning the actual time on the server (this time is used for relative times)
For each variable which has data in the given interval,
the variable name is returned preceeded by a '*', followed by some options* separated with
blanks.
After the header line for every data point a line follows with
a time relative to the last point and the value.
The first time value relative to zero, e.g. absolute.
The data value is valid until the next datapoint. Empty values are returned as an
empty string or as the <none value>.
At the very end *<loss> <overflow> is returned.
<loss> is 1, when the data had to be reduced, 0 else
<overflow> is 1, when overflow occured, 0 else. Overflow may happen only
when np is given and a text variable was demanded.
*actually only one option exists (you might ignore it):
exact <value>
<value> is 1 when the value is exact, i.e. an integer.
<value> is 0 else.
*/
time_t from, to, step, xs, lastt, now;
long lxs;
char *p, *varp;
int i, j, iarg, l, iret, loss, np;
int inRange;
int yday=0;
time_t t, startim;
struct tm tm;
char stim[32], path[LLEN], line[LLEN], lastval[LLEN];
char *lin, *val, *stp;
FILE *fil;
Compressor c={0};
float yy, lasty;
CompType type0;
DIR *dr;
char *opt;
int isdst;
int overflow;
/* 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], &p, 0);
if (p == argv[2]) goto illarg;
if (from < ONE_YEAR) {
from += now;
}
if (to < ONE_YEAR) {
to += now;
}
iarg = 3;
while (1) {
if (iarg>=argc) goto illarg;
if (strcasecmp(argv[iarg],"text") == 0) { /* non-numeric values */
iarg++;
step = 1;
type0 = TEXT;
np = to - from + 2;
break;
} else if (strcasecmp(argv[iarg],"none") == 0) { /* none */
iarg++;
if (iarg >= argc) goto illarg;
c.none = argv[iarg];
iarg++;
} else if (strcasecmp(argv[iarg],"np") == 0) { /* max. number of points */
iarg++;
if (iarg >= argc) goto illarg;
type0 = NUMERIC;
np = strtol(argv[iarg], &p, 0);
if (p == argv[iarg]) goto illarg;
iarg++;
if (to <= from) {
step = 1;
} else if (np <= 2) {
step = to - from;
} else {
step = (to - from) / (np - 2) + 1;
}
break;
} else {
step = strtol(argv[iarg], &p, 0);
if (p == argv[iarg]) goto illarg;
iarg++;
if (step <= 0) step = 1;
type0 = NUMERIC;
np = (from - to) / step + 2;
}
}
if (step <= 0) step = 1;
snprintf(line, sizeof line, "%ld\n", (long)now);
SCWrite(pCon, line, eWarning);
if (dir == NULL) {
dir = IFindOption(pSICSOptions, "LoggerDir");
if (dir == NULL) {
SCWrite(pCon, "ERROR: LoggerDir not found", eError);
return 0;
}
LoggerSetDir(dir);
}
if (dir2 == NULL) {
dir2 = IFindOption(pSICSOptions, "LoggerDir2");
if (dir2 == NULL) dir2="";
}
loss = 0;
overflow = 0;
for (i=iarg; i<argc; i++) {
startim = from;
t = 0;
lastt = 0;
inRange = 0;
xs = step;
InitCompressor(&c, pCon, step);
/* convert slashes to dots */
varp = argv[i];
if (*varp == '/') varp++;
for (j = 0; j < sizeof(c.var) && *varp != 0; j++, varp++) {
if (*varp == '/') {
c.var[j] = '.';
} else {
c.var[j] = *varp;
}
}
c.type = type0;
c.np = np;
l = LoggerVarPath(dir, path, sizeof path, c.var);
dr = opendir(path);
if (dr) {
closedir(dr);
} else {
l = LoggerVarPath(dir2, path, sizeof path, c.var);
dr = opendir(path);
if (dr) {
closedir(dr);
}
}
isdst = -1;
fil = NULL;
while (startim <= to && c.tlast <= to) {
tm = *localtime(&startim);
if (tm.tm_yday != yday) {
if (fil != NULL) { /* close file if day changed */
fclose(fil);
fil=NULL;
}
}
if (fil == NULL) {
yday = tm.tm_yday;
strftime(path + l, sizeof path - l, "%m-%d.log", &tm);
fil = fopen(path, "r");
if (fil != NULL) { /* check if file is from the given year */
strftime(stim, sizeof stim, "#%Y-%m-%d", &tm);
fgets(line, sizeof line, fil);
if (0 != strncmp(line, stim, 11)) {
fclose(fil);
fil = NULL;
} else {
lxs = getOpt(line, &isdst, &c.exact);
if (lxs >= 0) {
if (lxs == 0) {
c.type = TEXT;
} else {
c.type = type0;
xs = lxs;
}
if (xs < step) {
loss = 1;
xs = step;
}
}
}
}
}
if (fil == NULL) {
lin = NULL;
} else {
do {
lin = fgets(line, sizeof line, fil);
/* printf("%s\n", line); */
if (lin == NULL) break;
if (line[0] == '#') {
lxs = getOpt(line, &isdst, &c.exact);
if (lxs >= 0) {
if (lxs == 0) {
c.type = TEXT;
} else {
c.type = type0;
xs = lxs;
}
if (xs < step) {
loss = 1;
xs = step;
}
}
lin[0]='\0';
} else {
p = strchr(line, '\n'); if (p) *p='\0';
p = strchr(line, '#'); if (p) *p='\0';
}
} while (lin[0] == '\0');
}
if (lin != NULL) {
/* printf(" %s\n", line); */
p = strchr(line, '\t');
if (p) {
*p='\0';
val = p+1;
} else {
val = "";
}
p = strchr(val, '\t');
if (p) {
stp = p+1;
*p='\0';
iret = sscanf(stp, "%ld", &lxs);
if (iret == 1) {
if (lxs == 0) {
c.type = TEXT;
} else {
c.type = type0;
xs = lxs;
}
if (xs < step) {
loss = 1;
xs = step;
}
}
}
iret = sscanf(line, "%d:%d:%d", &tm.tm_hour, &tm.tm_min, &tm.tm_sec);
if (iret != 3) {
lin = NULL;
} else {
tm.tm_isdst = isdst;
t=mktime(&tm);
if (!inRange) {
if (t < startim) {
lastval[0]='\0';
strncat(lastval, val, sizeof lastval - 1);
lastt = t;
} else {
inRange=1;
if (lastt != 0) {
PutValue(&c, lastt, lastval);
}
PutValue(&c, t, val);
}
} else {
PutValue(&c, t, val);
}
}
}
if (lin == NULL) {
tm.tm_hour = 24; /* try next day */
tm.tm_min = 0;
tm.tm_sec = 0;
tm.tm_isdst = -1;
startim=mktime(&tm);
continue;
}
}
if (!inRange) {
if (lastt != 0) {
PutValue(&c, lastt, lastval);
}
}
c.ylast = LOGGER_NAN; /* force output of last value */
PutValue(&c, 0, ""); /* finish */
if (fil) {
fclose(fil);
fil = NULL;
}
if (c.np < 0) overflow = 1;
}
snprintf(line, sizeof line, "*%d %d\n", loss, overflow);
SCWrite(pCon, line, eWarning);
return 1;
illarg:
SCWrite(pCon, "illegal argument(s)", eError);
return 0;
}
/*--------------------------------------------------------------------------*/
static void KillLogReader(void *data) {
Logger *p, *next;
KillDummy(data);
LoggerFreeAll();
}
/*--------------------------------------------------------------------------*/
void LogReaderInit(void) {
AddCommand(pServ->pSics,"Graph",LogReader,KillLogReader,NULL);
}