forked from KaisenAmin/c_std
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
d5e32c5
commit 5f984fe
Showing
4 changed files
with
288 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -29,8 +29,7 @@ x86/ | |
bld/ | ||
[Bb]in/ | ||
[Oo]bj/ | ||
[Ll]og/ | ||
[Ll]ogs/ | ||
|
||
|
||
# Visual Studio 2015/2017 cache/options directory | ||
.vs/ | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
|
||
## Example 1 : initialize logger with `log_init` | ||
|
||
```c | ||
#include "log/log.h" | ||
|
||
int main() { | ||
Log* config = log_init(); | ||
|
||
if (!config) { | ||
fmt_fprintf(stderr, "Error: Can not Create log object.\n"); | ||
exit(-1); | ||
} | ||
|
||
return 0; | ||
} | ||
``` | ||
|
||
## Example 2 : different log level | ||
|
||
```c | ||
#include "log/log.h" | ||
|
||
int main() { | ||
Log* logger = log_init(); | ||
if (!logger) { | ||
fmt_fprintf(stderr, "Failed to initialize logging system.\n"); | ||
return -1; | ||
} | ||
|
||
log_message(logger, LOG_LEVEL_DEBUG, "This is a debug message - might not be displayed."); | ||
log_message(logger, LOG_LEVEL_INFO, "This is an info message."); | ||
log_message(logger, LOG_LEVEL_WARN, "This is a warning message."); | ||
log_message(logger, LOG_LEVEL_ERROR, "This is an error message."); | ||
|
||
// Clean up and deallocate the logging system | ||
log_deallocate(logger); | ||
return 0; | ||
} | ||
``` | ||
|
||
## Example 3 : Logging with Timestamps Enabled | ||
|
||
```c | ||
#include "log/log.h" | ||
|
||
int main() { | ||
Log* logger = log_init(); | ||
if (!logger) { | ||
fmt_fprintf(stderr, "Error: Cannot create log object.\n"); | ||
return -1; | ||
} | ||
|
||
// Enable timestamps in log messages | ||
log_enable_timestamp(logger, true); | ||
|
||
log_message(logger, LOG_LEVEL_INFO, "Application started with timestamp."); | ||
log_message(logger, LOG_LEVEL_WARN, "Low disk space warning logged with timestamp."); | ||
log_message(logger, LOG_LEVEL_ERROR, "File not found error logged with timestamp."); | ||
|
||
log_deallocate(logger); | ||
return 0; | ||
} | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,172 @@ | ||
#include "log.h" | ||
#include "../file_io/file_writer.h" | ||
#include "../file_io/file_reader.h" | ||
#include "../string/string.h" | ||
#include <string.h> | ||
#include <time.h> | ||
#include <stdlib.h> | ||
|
||
|
||
static const char* log_level_to_string(LogLevel level) { | ||
switch (level) { | ||
case LOG_LEVEL_DEBUG: | ||
return "DEBUG"; | ||
case LOG_LEVEL_INFO: | ||
return "INFO"; | ||
case LOG_LEVEL_WARN: | ||
return "WARN"; | ||
case LOG_LEVEL_ERROR: | ||
return "ERROR"; | ||
case LOG_LEVEL_FATAL: | ||
return "FATAL"; | ||
default: return "UNKNOWN"; | ||
} | ||
} | ||
|
||
Log* log_init() { | ||
Log *config = (Log*) malloc(sizeof(Log)); | ||
|
||
if (!config) { | ||
#ifdef LOG_ENABLE_LOGGING | ||
fmt_fprintf(stderr, "Error: Memory allocation failed for config in log_init.\n"); | ||
#endif | ||
return NULL; | ||
} | ||
|
||
config->level = LOG_LEVEL_DEBUG; | ||
config->output = LOG_OUTPUT_BOTH; | ||
config->file_writer = file_writer_open("log.txt", WRITE_TEXT); | ||
|
||
if (!config->file_writer) { | ||
#ifdef LOG_ENABLE_LOGGING | ||
fmt_fprintf(stderr, "Error: Failed to open log file. Defaulting to console output in log_init.\n"); | ||
#endif | ||
config->output = LOG_OUTPUT_CONSOLE; | ||
} | ||
|
||
config->file_reader = NULL; | ||
config->enable_timestamp = true; | ||
config->enable_log_level = true; | ||
|
||
#ifdef LOG_ENABLE_LOGGING | ||
fmt_fprintf(stdout, "Info: Logging system initialized in log_init.\n"); | ||
#endif | ||
|
||
return config; | ||
} | ||
|
||
bool log_set_output(Log* config, LogOutput output) { | ||
if (!config) { | ||
#ifdef LOG_ENABLE_LOGGING | ||
fmt_fprintf(stderr, "Error: log object is null and invalid.\n"); | ||
#endif | ||
return false; | ||
} | ||
|
||
config->output = output; | ||
if (output == LOG_OUTPUT_FILE && !config->file_writer) { | ||
// Attempt to open log file if not already open | ||
config->file_writer = file_writer_open("log.txt", WRITE_TEXT); | ||
if (!config->file_writer) { | ||
config->output = LOG_OUTPUT_CONSOLE; | ||
} | ||
|
||
#ifdef LOG_ENABLE_LOGGING | ||
fmt_fprintf(stderr, "Success: LogOutput set successfully.\n"); | ||
#endif | ||
return true; | ||
} | ||
#ifdef LOG_ENABLE_LOGGING | ||
fmt_fprintf(stderr, "Error: LogOutput not set.\n"); | ||
#endif | ||
return false; | ||
} | ||
|
||
bool log_enable_timestamp(Log* config, bool enable) { | ||
if (!config) { | ||
#ifdef LOG_ENABLE_LOGGING | ||
fmt_fprintf(stderr, "Error: log configuration object is null in log_enable_timestamp.\n"); | ||
#endif | ||
return false; | ||
} | ||
config->enable_timestamp = enable; | ||
return true; | ||
} | ||
|
||
void log_message(Log* config, LogLevel level, const char* message, ...) { | ||
if (!config) { | ||
#ifdef LOG_ENABLE_LOGGING | ||
fmt_fprintf(stderr, "Error: Log configuration is null.\n"); | ||
#endif | ||
return; | ||
} | ||
|
||
if (level < config->level) { | ||
#ifdef LOG_ENABLE_LOGGING | ||
fmt_fprintf(stderr, "Error: Current log level (%d) is higher than the message log level (%d); message not logged.\n", config->level, level); | ||
#endif | ||
return; | ||
} | ||
|
||
va_list args; | ||
char formatted_message[1024]; // Use a fixed size buffer for simplicity | ||
char log_buffer[2048]; // Larger buffer to accommodate timestamps, log level, and message | ||
|
||
// Generate timestamp if enabled | ||
char timestamp[64] = ""; // Buffer to hold timestamp | ||
if (config->enable_timestamp) { | ||
time_t now = time(NULL); | ||
struct tm *tm_info = localtime(&now); | ||
strftime(timestamp, sizeof(timestamp), "%Y-%m-%d %H:%M:%S", tm_info); // Customize this format as needed | ||
} | ||
|
||
// Prepare log message with vsnprintf to prevent buffer overflows | ||
va_start(args, message); | ||
vsnprintf(formatted_message, sizeof(formatted_message), message, args); | ||
va_end(args); | ||
|
||
// Construct the final log message with optional log level and timestamp | ||
const char* level_str = log_level_to_string(level); | ||
snprintf(log_buffer, sizeof(log_buffer), "%s [%s] %s", timestamp, level_str, formatted_message); | ||
|
||
// Actual logging | ||
if (config->output == LOG_OUTPUT_CONSOLE || config->output == LOG_OUTPUT_BOTH) { | ||
fmt_fprintf(stdout, "%s\n", log_buffer); | ||
} | ||
if ((config->output == LOG_OUTPUT_FILE || config->output == LOG_OUTPUT_BOTH) && config->file_writer) { | ||
fmt_fprintf(config->file_writer->file_writer, "%s\n", log_buffer); | ||
} | ||
} | ||
|
||
void log_deallocate(Log* config) { | ||
if (!config) { | ||
#ifdef LOG_ENABLE_LOGGING | ||
fmt_fprintf(stderr, "Error: Log configuration is null in log_deallocate.\n"); | ||
#endif | ||
return; | ||
} | ||
|
||
// Close the file writer if it's open | ||
if (config->file_writer) { | ||
file_writer_close(config->file_writer); | ||
config->file_writer = NULL; // Avoid dangling pointer | ||
#ifdef LOG_ENABLE_LOGGING | ||
fmt_fprintf(stderr, "Success: file_writer of Log now is free in log_deallocate.\n"); | ||
#endif | ||
} | ||
// if you had allocated memory for `file_reader` | ||
if (config->file_reader) { | ||
file_reader_close(config->file_reader); | ||
config->file_reader = NULL; | ||
#ifdef LOG_ENABLE_LOGGING | ||
fmt_fprintf(stderr, "Success: file_reader of Log now is free in log_deallocate.\n"); | ||
#endif | ||
} | ||
|
||
// Finally, free the log config itself | ||
free(config); | ||
|
||
#ifdef LOG_ENABLE_LOGGING | ||
fmt_fprintf(stderr, "Success: Log Object now is free in log_deallocate.\n"); | ||
#endif | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
#ifndef LOG_H_ | ||
#define LOG_H_ | ||
|
||
#include <stddef.h> | ||
#include <stdbool.h> | ||
#include <stdarg.h> | ||
#include "../fmt/fmt.h" | ||
|
||
#define LOG_ENABLE_LOGGING | ||
// Log levels | ||
typedef enum { | ||
LOG_LEVEL_DEBUG, | ||
LOG_LEVEL_INFO, | ||
LOG_LEVEL_WARN, | ||
LOG_LEVEL_ERROR, | ||
LOG_LEVEL_FATAL | ||
} LogLevel; | ||
|
||
// Log output options | ||
typedef enum { | ||
LOG_OUTPUT_CONSOLE, | ||
LOG_OUTPUT_FILE, | ||
LOG_OUTPUT_BOTH | ||
} LogOutput; | ||
|
||
// Log configuration structure | ||
typedef struct { | ||
LogLevel level; | ||
LogOutput output; | ||
FileWriter* file_writer; | ||
FileReader* file_reader; | ||
bool enable_timestamp; | ||
bool enable_log_level; | ||
} Log; | ||
|
||
// Initialize the logging system | ||
Log* log_init(); | ||
|
||
// Log a message at a specified level | ||
void log_message(Log* config, LogLevel level, const char* message, ...); | ||
|
||
// Set the log output | ||
bool log_set_output(Log* config, LogOutput output); | ||
|
||
// Enable or disable timestamps in log messages | ||
bool log_enable_timestamp(Log* config, bool enable); | ||
|
||
// Clean up the logging system | ||
void log_deallocate(Log* config); | ||
|
||
#endif // LOG_H_ |