Files
sics/logger.c
zolliker 61341b52f4 various improvements
- use dig for resolving host names
- ascon.c: fix terminator parsing
- property callback: change property before callback
- logger.c:default for logger period must be the old value instead of 1
- add frappy type history writing
- increase max. logreader line length
- HIPNONE returns "null" with json protocol
- encode strings properly in formatNameValue
- fix memory leak in json2tcl
- scriptcontext: do not show debug messages when script starts with underscore or when the "send" property is empty
- scriptcontext: remove args for action timestamp
- scriptcontext: "que" function will replace an already queued action, e.g. for 'halt
- introduced updatestatus script
2021-09-16 12:26:18 +02:00

496 lines
13 KiB
C

/*---------------------------------------------------------------------------
logger.c
Markus Zolliker, Sept 2004
----------------------------------------------------------------------------
*/
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <assert.h>
#include <fortify.h>
#include <errno.h>
#include <ctype.h>
#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;
}