Files
quantum-utils/quantum/src/logger/logger.c
Wesley Irvin 446fa704cc Log File
Added in the ability to write logs to a log file as well. For now the
logs write to ./quantum.log. All new log entries append onto the end of
the log. Also added timestamps in front of all log entries that are
generated when the log entry is made.
2024-02-10 13:59:43 -05:00

85 lines
2.8 KiB
C

#include "logger.h"
#include "../defines.h"
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
typedef enum level_color {
COLOR_FATAL,
COLOR_ERROR,
COLOR_WARN,
COLOR_INFO,
COLOR_DEBUG,
} level_color;
void send_to_console(const char *message, level_color color) {
const char *color_strings[] = {"41;97", "0;91", "0;93", "0;94", "0;92"};
printf("\033[%sm%s\033[0m\n", color_strings[color], message);
}
void send_to_error_log(const char *message) {
// First we need to open up our log file to append to it
FILE *log_file = fopen("./quantum.log", "a");
// Lets make sure we actually opened the file, and if not we return
if (log_file == NULL) {
send_to_console("[ERROR]: Could not open log file.", COLOR_ERROR);
return;
}
// Now we just need to write our message to the file
int chars_written = fprintf(log_file, "%s\n", message);
// fprintf returns a negative number on an error so let's check for that and
// display an error message
if (chars_written < 0) {
send_to_console("[ERROR]: Could not write to log file.", COLOR_ERROR);
}
// Now we need to make sure we close the file so that we do not leak
fclose(log_file);
}
void log_output(log_level level, const char *message, ...) {
const char *level_strings[] = {
"[FATAL]: ", "[ERROR]: ", "[WARN]: ", "[INFO]: ", "[DEBUG]: "};
// We are going to want to put a timestamp on our logs so lets get the current
// time and convert it into localtime
time_t cur_time = time(NULL);
struct tm local_time = *localtime(&cur_time);
// We are going to impose a 32K char limit on a single log entry
// we will hold this in format_message as a place to collect all
// the variadic arguments and process them together. We make sure
// that the memory is cleared to 0 before we start working on it.
const i32 msg_length = 32000;
char format_message[msg_length];
memset(format_message, 0, sizeof(format_message));
// Now we need to assemble the message from the message +
// the variadic arguments
__builtin_va_list arg_ptr;
va_start(arg_ptr, message);
vsnprintf(format_message, msg_length, message, arg_ptr);
va_end(arg_ptr);
// Now we prepend the message with a timestamp and our message level
char log_message[msg_length];
sprintf(log_message, "[%02d-%02d-%d %02d:%02d:%02d]%s%s",
local_time.tm_mon + 1, local_time.tm_mday, local_time.tm_year + 1900,
local_time.tm_hour, local_time.tm_min, local_time.tm_sec,
level_strings[level], format_message);
// Now we call the appropriate function depending on the level
if (level <= 1) {
send_to_console(log_message, level == FATAL ? COLOR_FATAL : COLOR_ERROR);
send_to_error_log(log_message);
} else {
send_to_console(log_message, (level_color)level);
}
}