logging finished

This commit is contained in:
overflowerror 2019-03-03 13:23:34 +01:00
parent 7dfa80572d
commit 4b6cbba04f
4 changed files with 327 additions and 3 deletions

View file

@ -7,15 +7,16 @@ BIN_NAME = cfloor
all: $(BIN_NAME) all: $(BIN_NAME)
test: obj/test.o obj/networking.o obj/linked.o test: obj/test.o obj/networking.o obj/linked.o obj/logging.o
$(LD) $(LDFLAGS) -o $@ $^ $(LD) $(LDFLAGS) -o $@ $^
valgrind: CFLAGS += -static -g valgrind: CFLAGS += -static -g
valgrind: clean test valgrind: clean test
valgrind --leak-check=yes ./test valgrind --leak-check=yes ./test
obj/test.o: src/networking.h obj/test.o: src/networking.h src/linked.h src/logging.h
obj/networking.o: src/networking.h src/headers.h obj/networking.o: src/networking.h src/headers.h src/linked.h
obj/linked.o: src/linked.h obj/linked.o: src/linked.h
obj/loggin.o: src/logging.h
obj/%.o: src/%.c obj obj/%.o: src/%.c obj
$(CC) $(CFLAGS) -c -o $@ $< $(CC) $(CFLAGS) -c -o $@ $<

269
src/logging.c Normal file
View file

@ -0,0 +1,269 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <errno.h>
#include <stdarg.h>
#include <sys/time.h>
#include <time.h>
#include <assert.h>
#include "logging.h"
#ifdef BACKTRACE
#include <execinfo.h>
#endif
struct {
FILE* file;
enum loglevel loglevel;
bool color;
} logger[MAX_LOGGER];
int loggerCount = 0;
void (*_criticalHandler)() = NULL;
void setLogging(FILE* file, enum loglevel loglevel, bool color) {
if (loggerCount == MAX_LOGGER - 1) {
return;
}
bool found = false;
for (int i = 0; i < loggerCount; i++) {
if ((logger[i].file == file)) {
found = true;
logger[i].loglevel = loglevel;
logger[i].color = color;
break;
}
}
if (!found) {
logger[loggerCount].file = file;
logger[loggerCount].loglevel = loglevel;
logger[loggerCount].color = color;
loggerCount++;
}
}
void setCriticalHandler(void (*handler)()) {
_criticalHandler = handler;
}
void callCritical() {
if (_criticalHandler != NULL)
_criticalHandler();
}
#define BACKTRACE_BUFFER_SIZE 16
void printBacktrace() {
#ifdef BACKTRACE
void* buffer[BACKTRACE_BUFFER_SIZE];
char** strings;
int entries = backtrace(buffer, BACKTRACE_BUFFER_SIZE);
strings = backtrace_symbols(buffer, entries);
if (strings == NULL) {
fprintf(stderr, "Error while backtracing: %s\n", strerror(errno));
return;
}
int tmp = (entries < BACKTRACE_BUFFER_SIZE) ? entries : entries - 1;
// from 1 to ignore printBacktrace
for (int i = 1; i < tmp; i++) {
fprintf(stderr, " at %s\n", strings[i]);
}
if (tmp < entries) {
fprintf(stderr, " ...\n");
}
#else
fprintf(stderr, "Error: Not compiled with backtrace support.\n");
#endif
}
char* getTimestamp() {
#define MSEC_LENGTH (3)
#define TIME_LENGTH (4 + 1 + 2 + 1 + 2 + 1 + 2 + 1 + 2 + 1 + 2 + 1 + MSEC_LENGTH)
char* result = malloc(TIME_LENGTH + 1);
if (result == NULL) {
fprintf(stderr, "\nDEVASTATING: Couldn't malloc for log time.\n");
callCritical();
exit(EXIT_DEVASTATING);
}
int millisec;
struct tm* tm_info;
struct timeval tv;
gettimeofday(&tv, NULL);
millisec = (int) (tv.tv_usec / 1000.0);
if (millisec >= 1000) {
millisec -=1000;
tv.tv_sec++;
}
tm_info = localtime(&tv.tv_sec);
strftime(result, 26, "%Y-%m-%dT%H:%M:%S", tm_info);
char* msecBuffer = malloc(1 + MSEC_LENGTH + 1);
if (msecBuffer == NULL) {
fprintf(stderr, "\nDEVASTATING: Couldn't malloc for log time.\n");
callCritical();
exit(EXIT_DEVASTATING);
}
snprintf(msecBuffer, 1 + MSEC_LENGTH + 1, ".%03d", millisec);
strncat(result, msecBuffer, TIME_LENGTH + 1);
free(msecBuffer);
return result;
}
char* getLoglevelString(enum loglevel loglevel, bool color) {
#define DEBUG_STRING "[DEBUG]"
#define VERBOSE_STRING "[VERBOSE]"
#define INFO_STRING "[INFO]"
#define WARN_STRING "[WARNING]"
#define ERROR_STRING "[ERROR]"
#define CRITICAL_STRING "[CRITICAL]"
#define UNKNOWN_STRING "[UNKNOWN]"
#define DEBUG_COLOR "\033[37m"
#define VERBOSE_COLOR "\033[35m"
#define INFO_COLOR "\033[36m"
#define WARN_COLOR "\033[33m"
#define ERROR_COLOR "\033[31m"
#define CRITICAL_COLOR "\033[41m\033[30m"
#define UNKNOWN_COLOR "\033[41m\033[30m"
#define COLOR_END "\033[0m"
switch(loglevel) {
case DEBUG:
if (color)
return DEBUG_COLOR DEBUG_STRING COLOR_END;
else
return DEBUG_STRING;
break;
case VERBOSE:
if (color)
return VERBOSE_COLOR VERBOSE_STRING COLOR_END;
else
return VERBOSE_STRING;
break;
case INFO:
if (color)
return INFO_COLOR INFO_STRING COLOR_END;
else
return INFO_STRING;
break;
case WARN:
if (color)
return WARN_COLOR WARN_STRING COLOR_END;
else
return WARN_STRING;
break;
case ERROR:
if (color)
return ERROR_COLOR ERROR_STRING COLOR_END;
else
return ERROR_STRING;
break;
case CRITICAL:
if (color)
return CRITICAL_COLOR CRITICAL_STRING COLOR_END;
else
return CRITICAL_STRING;
break;
default:
if (color)
return UNKNOWN_COLOR UNKNOWN_STRING COLOR_END;
else
return UNKNOWN_STRING;
break;
}
assert(false);
return NULL;
}
void vlogging(enum loglevel loglevel, const char* format, va_list argptr) {
char* timestamp = getTimestamp();
for(int i = 0; i < loggerCount; i++) {
if (loglevel < logger[i].loglevel)
continue;
char* loglevelString = getLoglevelString(loglevel, logger[i].color);
fprintf(logger[i].file, "%s %s ", timestamp, loglevelString);
vfprintf(logger[i].file, format, argptr);
fprintf(logger[i].file, "\n");
}
free(timestamp);
if (loglevel == CRITICAL)
callCritical();
}
void logging(enum loglevel loglevel, const char* format, ...) {
va_list argptr;
va_start(argptr, format);
vlogging(loglevel, format, argptr);
va_end(argptr);
}
void debug(const char* format, ...) {
va_list argptr;
va_start(argptr, format);
vlogging(DEBUG, format, argptr);
va_end(argptr);
}
void verbose(const char* format, ...) {
va_list argptr;
va_start(argptr, format);
vlogging(VERBOSE, format, argptr);
va_end(argptr);
}
void info(const char* format, ...) {
va_list argptr;
va_start(argptr, format);
vlogging(INFO, format, argptr);
va_end(argptr);
}
void warn(const char* format, ...) {
va_list argptr;
va_start(argptr, format);
vlogging(WARN, format, argptr);
va_end(argptr);
}
void error(const char* format, ...) {
va_list argptr;
va_start(argptr, format);
vlogging(ERROR, format, argptr);
va_end(argptr);
}
void critical(const char* format, ...) {
va_list argptr;
va_start(argptr, format);
vlogging(CRITICAL, format, argptr);
va_end(argptr);
}

29
src/logging.h Normal file
View file

@ -0,0 +1,29 @@
#ifndef LOGGING_H
#define LOGGING_H
#include <stdarg.h>
enum loglevel {
DEBUG, VERBOSE, INFO, WARN, ERROR, CRITICAL
};
#define EXIT_DEVASTATING (255)
#define DEFAULT_LOGLEVEL (WARN)
#define MAX_LOGGER (10)
void setLogging(FILE* file, enum loglevel loglevel, bool color);
void setCriticalHandler(void (*handler)());
void printBacktrace();
void logging(enum loglevel loglevel, const char* format, ...);
void debug(const char* format, ...);
void verbose(const char* format, ...);
void info(const char* format, ...);
void warn(const char* format, ...);
void error(const char* format, ...);
void critical(const char* format, ...);
#endif

View file

@ -5,6 +5,7 @@
#include "networking.h" #include "networking.h"
#include "linked.h" #include "linked.h"
#include "logging.h"
bool global = true; bool global = true;
@ -84,6 +85,22 @@ void testLinkedList() {
linked_destroy(&list); linked_destroy(&list);
} }
void criticalHandler() {
printf("This is the critical handler.\n");
printBacktrace();
}
void testLogging() {
setLogging(stderr, DEFAULT_LOGLEVEL, true);
info("This info should not be displayed.");
warn("This warning should be displayed.");
error("This error should be displayed.");
setCriticalHandler(&criticalHandler);
critical("This critical should be displayed.");
}
handler_t handlerGetter(struct metaData metaData, const char* host) { handler_t handlerGetter(struct metaData metaData, const char* host) {
return NULL; return NULL;
} }
@ -109,6 +126,14 @@ int main(int argc, char** argv) {
printf("linked lists: %s\n\n", global ? "OK" : "FAILED"); printf("linked lists: %s\n\n", global ? "OK" : "FAILED");
global = true; global = true;
printf("logging\n");
printf("============\n\n");
testLogging();
if (!global)
overall = false;
printf("logging: %s\n\n", global ? "OK" : "FAILED");
global = true;
printf("\nOverall: %s\n", overall ? "OK" : "FAILED"); printf("\nOverall: %s\n", overall ? "OK" : "FAILED");
} }