/*--------------------------------------------------------------------------- logger.c Markus Zolliker, Sept 2004 ---------------------------------------------------------------------------- */ #include #include #include #include #include #include #include #include #include "logger.h" static char *dir = NULL; static Logger *list; static time_t lastLife = 0; static time_t lastWritten = 0; static time_t omitCheck = 0; /*--------------------------------------------------------------------------*/ 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) { if (0 == strcasecmp(name, p->name)) { return p; } p = p->next; } return NULL; } /*--------------------------------------------------------------------------*/ Logger *LoggerList(void) { return list; } /*--------------------------------------------------------------------------*/ #define LASTLOGTXT "#last logging entry at:\n" time_t LoggerGetLastLife(char *dirarg) { char path[256], line[32]; FILE *fil; time_t t = 0; if (dirarg == NULL) { return lastWritten; } snprintf(path, sizeof path, "%s/lastlife.dat", dirarg); fil = fopen(path, "r"); if (fil) { line[0]='\0'; fgets(line, sizeof line, fil); if (strcmp(line, LASTLOGTXT) == 0) { fgets(line, sizeof line, fil); t = atol(line); if (t < 1000000000) { printf("bad lastLife %ld\n", (long) t); } } fclose(fil); } else { /* printf("can not read %s\n", path); */ } return t; } /*--------------------------------------------------------------------------*/ time_t LoggerSetDir(char *dirarg) { dir = dirarg; lastLife = LoggerGetLastLife(dir); return lastLife; } /*--------------------------------------------------------------------------*/ char *LoggerGetDir(void) { char path[256]; FILE *fil; static time_t last; lastWritten = time(NULL); if (lastWritten != last) { /* do not write more than once per second */ snprintf(path, sizeof path, "%s/lastlife.dat", dir); fil = fopen(path, "w"); if (fil) { fprintf(fil, "%s%ld\n", LASTLOGTXT, (long) lastWritten); fclose(fil); } else { printf("can not write %s\n", path); } last = lastWritten; } return dir; } /*--------------------------------------------------------------------------*/ int LoggerVarPath(char *dir, char *path, int pathLen, char *name, struct tm *t) { int l; l = strlen(dir); if (l + strlen(name) + 8 >= pathLen) { path[0] = '\0'; return 0; } strcpy(path, dir); strftime(path + l, pathLen - l, "/%Y/", t); l += 6; 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]; struct tm tm, lasttm; int l, ext, writeInfo; FILE *fil; time_t beforenow; char *nl; if (log->name[0] == '\0') return 0; LoggerGetDir(); if (dir == NULL) return 0; if (now == 0) { printf("now==0\n"); } lasttm = *localtime(&log->last); tm = *localtime(&now); l = LoggerVarPath(dir, path, sizeof path, log->name, &tm); strftime(path + l, sizeof path - l, "%m-%d.log", &tm); strftime(stim, sizeof stim, "#%Y-%m-%d %H:%M:%S", &tm); if (period <= 0) { if (log->period > 0) { period = log->period; } else { period = 1; } } writeInfo = (tm.tm_isdst != lasttm.tm_isdst || tm.tm_yday != lasttm.tm_yday || (period != log->period && log->numeric)); if (strcmp(value, log->old) != 0 || writeInfo) { fil = fopen(path, "r+"); if (fil == NULL) { /* create new file */ fil = fopen(path, "w+"); if (fil == NULL) return 0; fprintf(fil, "%s isdst %d period %d exact %d\n", stim, tm.tm_isdst, period, log->exact); } else { /* check if file is from today */ fgets(buf, sizeof buf, fil); if (0 != strncmp(buf, stim, 11)) { fclose(fil); /* it was file from an earlier year */ fil = fopen(path, "w+"); /* overwrite old logfile */ if (fil == NULL) return 0; fprintf(fil, "%s isdst %d period %d exact %d\n", stim, tm.tm_isdst, period, log->exact); } else { fseek(fil, 0, SEEK_END); /* set position to end */ if (writeInfo) { fprintf(fil, "#isdst %d period %d exact %d\n", tm.tm_isdst, period, log->exact); } if (log->lastWrite != 0 && now >= log->lastWrite + 2 * period) { /* this is only useful for direct access of the log files */ beforenow = now - period; lasttm = *localtime(&beforenow); if (lasttm.tm_yday == tm.tm_yday) { strftime(stim, sizeof stim, "%H:%M:%S", &lasttm); } else { snprintf(stim, sizeof stim, "00:00:00"); } fprintf(fil, "%s\t%s\n", stim, log->old); } } } strftime(stim, sizeof stim, "%H:%M:%S", &tm); nl = strchr(value, '\n'); if (nl == NULL) { fprintf(fil, "%s\t%s\n", stim, value); } else { /* newline within string! do write only characters before nl */ fprintf(fil, "%s\t%.*s\n", stim, (int)(nl - value), value); } log->lastWrite = now; fclose(fil); } log->period = period; l = strlen(value); if (l >= log->oldsize) { /* increase log->old size, optimized for linux/i386 */ 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); if (log->old != value) { strcpy(log->old, value); } assert(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; char *valp; char buf[32]; int l; FILE *fil; char path[256]; char tim[256]; if (log->name[0] == '\0') return 0; tm = localtime(&now); if (tm->tm_yday != yday) { /* new day */ tm->tm_hour = 0; tm->tm_min = 0; tm->tm_sec = 0; h0 = mktime(tm); yday = tm->tm_yday; /* -- debug logging if dir/debug exists */ l = LoggerVarPath(dir, path, sizeof path, "debug", tm); 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) { /* debug logging */ 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 = p->next; } if (fil) fclose(fil); } if (now < log->last + log->period && strcmp(log->old, value) != 0) { log->omitValue = strtod(value, &valp); if (value != valp && valp[0] == '\0') { /* value was a plain number */ log->omitTime = now; return 1; } } else { log->omitTime = 0; } if (now > omitCheck + 5) { /* check for omitted values only every 5 seconds */ for (p = list; p != NULL; p = p->next) { if (p->omitTime > 0 && now > p->omitTime + p->period) { snprintf(buf, sizeof buf, "%.7g", p->omitValue); LoggerWrite0(p, p->omitTime, p->period, buf); p->omitTime = 0; } } omitCheck = now; } return LoggerWrite0(log, now, period, value); } /*--------------------------------------------------------------------------*/ time_t LoggerLastTime(Logger * log) { if (log->last != 0 && log->period > 0) { return log->last; } return 0; } /*--------------------------------------------------------------------------*/ int LoggerPeriod(Logger * log) { return log->period; } /*--------------------------------------------------------------------------*/ void LoggerChange(Logger * log, int period, char *newname) { Logger *other; time_t t; if (period < 0) { period = log->period; } if (strcasecmp(newname, log->name) != 0) { if (log->name[0] != '\0') { /* was not defunct */ LoggerWrite0(log, time(NULL), log->period, log->old); LoggerWrite0(log, time(NULL), log->period, ""); } other = LoggerFind(newname); /* look if logger with new name already exists */ if (other) { /* make defunct */ LoggerWrite0(other, time(NULL), other->period, other->old); LoggerWrite0(other, time(NULL), other->period, ""); other->name[0] = '\0'; } free(log->name); log->name = strdup(newname); 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 */ } else { LoggerWrite0(log, time(NULL), period, log->old); } } /*--------------------------------------------------------------------------*/ 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 */ if (list != NULL) { /* LoggerFreeAll not yet called */ LoggerWrite(log, time(NULL), 0, ""); } } /*--------------------------------------------------------------------------*/ int LoggerMakeDir(char *path) { static char buffer[4096]; struct stat st; int i, lpath, l; char *slash; i = stat(path, &st); if (i >= 0) { if (((st.st_mode >> 12) & 15) != 4) { /* exists, but is no directory */ return 0; } return 1; } i = mkdir(path, S_IRWXU + S_IRGRP + S_IXGRP + S_IROTH + S_IXOTH); if (i < 0) { if (errno != ENOENT) return 0; /* mkdir failed */ snprintf(buffer, sizeof buffer, "%s", path); lpath = strlen(buffer); /* Discard any trailing slash characters */ while (lpath > 0 && buffer[lpath - 1] == '/') buffer[--lpath] = '\0'; do { slash = strrchr(buffer, '/'); if (!slash) return 0; *slash = '\0'; i = mkdir(buffer, S_IRWXU + S_IRGRP + S_IXGRP + S_IROTH + S_IXOTH); } while (i < 0 && errno == ENOENT); l = strlen(buffer); while (l < lpath) { buffer[l] = '/'; i = mkdir(buffer, S_IRWXU + S_IRGRP + S_IXGRP + S_IROTH + S_IXOTH); if (i < 0) return 0; l = strlen(buffer); } } return 1; } /*--------------------------------------------------------------------------*/ Logger *LoggerMake(char *name, int period, int exact) { Logger *log; char path[256]; time_t t; struct tm tm; LoggerGetDir(); if (dir == NULL) return NULL; time(&t); tm = *localtime(&t); LoggerVarPath(dir, path, sizeof path, name, &tm); if (LoggerMakeDir(path) == 0) return NULL; log = LoggerFind(name); /* look if logger already exists */ if (log == NULL) { log = calloc(1, sizeof *log); if (log == NULL) return NULL; log->name = strdup(name); if (log->name == NULL) { free(log); return NULL; } log->period = -1; log->exact = exact; log->old = calloc(1, 12); log->oldsize = 12; log->last = 0; log->lastWrite = 0; log->numeric = 1; 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 */ } else { LoggerWrite0(log, time(NULL), period, log->old); } return log; } /*--------------------------------------------------------------------------*/ void LoggerFreeAll(void) { Logger *p, *next; p = list; while (p != NULL) { next = p->next; if (p->name) free(p->name); if (p->old) free(p->old); if (p->secop_old) free(p->secop_old); if (p->secop_id) free(p->secop_id); free(p); p = next; } list = NULL; }