From fa0bd9a7c63a21bca7677cd575b271888948f541 Mon Sep 17 00:00:00 2001 From: Jordan Bancino Date: Fri, 29 Jul 2022 15:36:21 -0400 Subject: [PATCH] Apply #14 --- src/Log.c | 316 ++++++++++++++++++------------------ src/include/Array.h | 4 +- src/include/Base64.h | 2 +- src/include/CanonicalJson.h | 2 +- src/include/Config.h | 2 +- src/include/HashMap.h | 2 +- src/include/Http.h | 2 + src/include/Json.h | 2 +- src/include/Log.h | 134 +++++++++++---- src/include/Util.h | 42 ++++- 10 files changed, 309 insertions(+), 199 deletions(-) diff --git a/src/Log.c b/src/Log.c index f34eae0..e694c39 100644 --- a/src/Log.c +++ b/src/Log.c @@ -28,6 +28,7 @@ #include #include #include +#include #define LOG_TSBUFFER 64 @@ -38,8 +39,158 @@ struct LogConfig FILE *out; int flags; char *tsFmt; + + pthread_mutex_t lock; }; +LogConfig * +LogConfigCreate(void) +{ + LogConfig *config; + + config = calloc(1, sizeof(LogConfig)); + + if (!config) + { + return NULL; + } + + LogConfigLevelSet(config, LOG_MESSAGE); + LogConfigIndentSet(config, 0); + LogConfigOutputSet(config, NULL); /* Will set to stdout */ + LogConfigFlagSet(config, LOG_FLAG_COLOR); + LogConfigTimeStampFormatSet(config, "%y-%m-%d %H:%M:%S"); + + return config; +} + +void +LogConfigFlagClear(LogConfig * config, int flags) +{ + if (!config) + { + return; + } + + config->flags &= ~flags; +} + +static int +LogConfigFlagGet(LogConfig * config, int flags) +{ + if (!config) + { + return 0; + } + + return config->flags & flags; +} + +void +LogConfigFlagSet(LogConfig * config, int flags) +{ + if (!config) + { + return; + } + + config->flags |= flags; +} + +void +LogConfigFree(LogConfig * config) +{ + free(config); +} + +void +LogConfigIndent(LogConfig * config) +{ + if (config) + { + config->indent += 2; + } +} + +void +LogConfigIndentSet(LogConfig * config, size_t indent) +{ + if (!config) + { + return; + } + + config->indent = indent; +} + +LogLevel +LogConfigLevelGet(LogConfig * config) +{ + if (!config) + { + return -1; + } + + return config->level; +} + +void +LogConfigLevelSet(LogConfig * config, LogLevel level) +{ + if (!config) + { + return; + } + + switch (level) + { + case LOG_ERROR: + case LOG_WARNING: + case LOG_MESSAGE: + case LOG_DEBUG: + config->level = level; + default: + break; + } +} + +void +LogConfigOutputSet(LogConfig * config, FILE * out) +{ + if (!config) + { + return; + } + + if (out) + { + config->out = out; + } + else + { + config->out = stdout; + } + +} + +void +LogConfigTimeStampFormatSet(LogConfig * config, char *tsFmt) +{ + if (config) + { + config->tsFmt = tsFmt; + } +} + +void +LogConfigUnindent(LogConfig * config) +{ + if (config && config->indent >= 2) + { + config->indent -= 2; + } +} + void Log(LogConfig * config, LogLevel level, const char *msg,...) { @@ -65,6 +216,8 @@ Log(LogConfig * config, LogLevel level, const char *msg,...) return; } + pthread_mutex_lock(&config->lock); + for (i = 0; i < config->indent; i++) { fputc(' ', config->out); @@ -146,7 +299,7 @@ Log(LogConfig * config, LogLevel level, const char *msg,...) indicator = '*'; break; default: - indicator = ' '; + indicator = '?'; break; } @@ -172,163 +325,6 @@ Log(LogConfig * config, LogLevel level, const char *msg,...) { fflush(config->out); } -} - -LogConfig * -LogConfigCreate(void) -{ - LogConfig *config; - - config = calloc(1, sizeof(LogConfig)); - - if (!config) - { - return NULL; - } - - LogConfigLevelSet(config, LOG_MESSAGE); - LogConfigIndentSet(config, 0); - LogConfigOutputSet(config, NULL); /* Will set to stdout */ - LogConfigFlagSet(config, LOG_FLAG_COLOR); - LogConfigTimeStampFormatSet(config, "%y-%m-%d %H:%M:%S"); - - return config; -} - -void -LogConfigFlagClear(LogConfig * config, int flags) -{ - if (!config) - { - return; - } - - config->flags &= ~flags; -} - -int -LogConfigFlagGet(LogConfig * config, int flags) -{ - if (!config) - { - return 0; - } - - return config->flags & flags; -} - -void -LogConfigFlagSet(LogConfig * config, int flags) -{ - if (!config) - { - return; - } - - config->flags |= flags; -} - -void -LogConfigFree(LogConfig * config) -{ - free(config); -} - -void -LogConfigIndent(LogConfig * config) -{ - if (config) - { - config->indent += 2; - } -} - -size_t -LogConfigIndentGet(LogConfig * config) -{ - if (!config) - { - return 0; - } - - return config->indent; -} - -void -LogConfigIndentSet(LogConfig * config, size_t indent) -{ - if (!config) - { - return; - } - - config->indent = indent; -} - -LogLevel -LogConfigLevelGet(LogConfig * config) -{ - if (!config) - { - return -1; - } - - return config->level; -} - -void -LogConfigLevelSet(LogConfig * config, LogLevel level) -{ - if (!config) - { - return; - } - - switch (level) - { - case LOG_ERROR: - case LOG_WARNING: - case LOG_MESSAGE: - case LOG_DEBUG: - config->level = level; - default: - break; - } -} - -void -LogConfigOutputSet(LogConfig * config, FILE * out) -{ - if (!config) - { - return; - } - - if (out) - { - config->out = out; - } - else - { - config->out = stdout; - } - -} - -void -LogConfigTimeStampFormatSet(LogConfig * config, char *tsFmt) -{ - if (config) - { - config->tsFmt = tsFmt; - } -} - -void -LogConfigUnindent(LogConfig * config) -{ - if (config && config->indent >= 2) - { - config->indent -= 2; - } + + pthread_mutex_unlock(&config->lock); } diff --git a/src/include/Array.h b/src/include/Array.h index 6ff2062..a44fe75 100644 --- a/src/include/Array.h +++ b/src/include/Array.h @@ -50,8 +50,6 @@ typedef struct Array Array; /* * Create a new, empty array on the heap. * - * Params: none - * * Return: A pointer to an Array, or NULL if there was an error * allocating memory for the Array. */ @@ -214,4 +212,4 @@ extern void extern int ArrayTrim(Array *); -#endif +#endif /* TELODENDRIA_ARRAY_H */ diff --git a/src/include/Base64.h b/src/include/Base64.h index bbb098d..5f21263 100644 --- a/src/include/Base64.h +++ b/src/include/Base64.h @@ -152,4 +152,4 @@ extern void extern int Base64Pad(char **, size_t); -#endif +#endif /* TELODENDRIA_BASE64_H */ diff --git a/src/include/CanonicalJson.h b/src/include/CanonicalJson.h index 98af8e6..553e304 100644 --- a/src/include/CanonicalJson.h +++ b/src/include/CanonicalJson.h @@ -83,4 +83,4 @@ extern int extern char * CanonicalJsonEncodeToString(HashMap *); -#endif +#endif /* TELODENDRIA_CANONICALJSON_H */ diff --git a/src/include/Config.h b/src/include/Config.h index 9549644..314f439 100644 --- a/src/include/Config.h +++ b/src/include/Config.h @@ -205,4 +205,4 @@ extern HashMap * extern void ConfigFree(HashMap *); -#endif +#endif /* TELODENDRIA_CONFIG_H */ diff --git a/src/include/HashMap.h b/src/include/HashMap.h index 305bee7..b33d7d5 100644 --- a/src/include/HashMap.h +++ b/src/include/HashMap.h @@ -180,4 +180,4 @@ extern int extern void HashMapFree(HashMap *); -#endif +#endif /* TELODENDRIA_HASHMAP_H */ diff --git a/src/include/Http.h b/src/include/Http.h index 66d301a..6b28e7a 100644 --- a/src/include/Http.h +++ b/src/include/Http.h @@ -102,11 +102,13 @@ typedef enum HttpStatus struct HttpRequest { HttpRequestMethod method; + HashMap *headers; }; struct HttpResponse { HttpStatus status; + HashMap *headers; }; extern char * diff --git a/src/include/Json.h b/src/include/Json.h index 4bc839d..5e5005f 100644 --- a/src/include/Json.h +++ b/src/include/Json.h @@ -268,4 +268,4 @@ extern int extern HashMap * JsonDecode(FILE *); -#endif +#endif /* TELODENDRIA_JSON_H */ diff --git a/src/include/Log.h b/src/include/Log.h index 43cf5cb..6daec3e 100644 --- a/src/include/Log.h +++ b/src/include/Log.h @@ -61,7 +61,7 @@ typedef enum LogLevel /* * The possible flags that can be applied to alter the behavior of - * the logger + * the logger. */ typedef enum LogFlag { @@ -71,50 +71,126 @@ typedef enum LogFlag /* * The log configurations structure in which all settings exist. * It's not super elegant to pass around a pointer to the logging - * configuration + * configuration, but this really is the best way without having a + * global variable. It allows multiple loggers to exist if necessary, + * and makes things more thread safe. */ typedef struct LogConfig LogConfig; +/* + * Create a new log configuration on the heap. This will be passed to + * every Log() call after it is configured. + * + * Return: A pointer to a new LogConfig that can be configured and used + * for logging. It should have sane defaults; in other words, you should + * be able to immediately start logging with it. + */ extern LogConfig * LogConfigCreate(void); +/* + * Free a log configuration. Future attempts to log with the passed + * configuration will fail in an undefined way, such as by hanging the + * process or segfaulting. + * + * Params: + * + * (LogConfig *) The configuration to free. All memory associated with + * configuring the logging mechanism will be + * invalidated. + */ extern void - LogConfigFree(LogConfig * config); + LogConfigFree(LogConfig *); + +/* + * Set the current log level on the specified log configuration. This + * indicates that only messages at or above this level should be + * logged; all other messages are ignored by the Log() function. + * + * Params: + * + * (LogConfig *) The log configuration to set the log level on. + * (LogLevel) The log level to set. + */ +extern void + LogConfigLevelSet(LogConfig *, LogLevel); + +/* + * Indent the log output by two spaces. This can be helpful in + * generating stack traces, or otherwise producing hierarchical output. + * After calling this function, all future log messages using this + * configuration will be indented. + * + * Params: + * + * (LogConfig *) The log configuration to indent. + */ +extern void + LogConfigIndent(LogConfig *); + +/* + * Decrease the log output indent by two spaces. This can be helpful in + * generating stack traces, or otherwise producing hierarchical output. + * After calling this function, all future log messages using this + * configuration will be unindented, unless there was no indentation + * to begin with; in that case, this function will do nothing. + * + * Params: + * + * (LogConfig *) The log configuration to unindent. + */ +extern void + LogConfigUnindent(LogConfig *); + +/* +* Set the log output indent to an arbitrary amount. This can be helpful +* in generating stack traces, or otherwise producing hierarchical +* output. After calling this function, all future log messages using +* this configuration will be indented by the given amount. +* +* Params: +* +* (LogConfig *) The log configuration to apply the indent to. +*/ +extern void + LogConfigIndentSet(LogConfig *, size_t); extern void - LogConfigLevelSet(LogConfig * config, LogLevel level); - -extern LogLevel - LogConfigLevelGet(LogConfig * config); + LogConfigOutputSet(LogConfig *, FILE *); extern void - LogConfigIndentSet(LogConfig * config, size_t indent); - -extern size_t - LogConfigIndentGet(LogConfig * config); + LogConfigFlagSet(LogConfig *, int); extern void - LogConfigIndent(LogConfig * config); + LogConfigFlagClear(LogConfig *, int); extern void - LogConfigUnindent(LogConfig * config); + LogConfigTimeStampFormatSet(LogConfig *, char *); +/* + * Actually log a message to a console, file, or other output device, + * using the given log configuration. This function is thread-safe; it + * locks a mutex before writing a message, and then unlocks it after + * the message was written. It should therefore work well in + * multithreaded environments, and with multiple different log + * configurations, as each one has its own mutex. + * + * This function only logs messages if they are above the currently + * configured log level. In this way, it is easy to turn some messages + * on and off. + * + * This function is a printf() style function; it takes a format + * string and any number of parameters to format. + * + * Params: + * + * (LogConfig *) The logging configuration. + * (LogLevel) The level of the message to log. + * (const char *) The format string, or a plain message string. + * (...) Any items to map into the format string, printf() + * style. + */ extern void - LogConfigOutputSet(LogConfig * config, FILE * out); - -extern void - LogConfigFlagSet(LogConfig * config, int flags); - -extern void - LogConfigFlagClear(LogConfig * config, int flags); - -extern int - LogConfigFlagGet(LogConfig * config, int flags); - -extern void - LogConfigTimeStampFormatSet(LogConfig * config, char *tsFmt); - -extern void - Log(LogConfig * config, LogLevel level, const char *msg,...); + Log(LogConfig *, LogLevel, const char *,...); #endif diff --git a/src/include/Util.h b/src/include/Util.h index 59854a0..d1ada59 100644 --- a/src/include/Util.h +++ b/src/include/Util.h @@ -21,13 +21,51 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ + +/* + * Util.h: Some misc. helper functions that provide functionality that + * doesn't need its own full API. The functions here are entirely + * stand-alone, and generally don't depend on any of the other APIs + * defined by Telodendria. + */ #ifndef TELODENDRIA_UTIL_H #define TELODENDRIA_UTIL_H +/* + * Get the current type in milliseconds since the Unix epoch. This uses + * POSIX gettimeofday(2) and time_t, and converts it to a single number, + * which is returned. + * + * A note on the 2038 problem: that's a long ways away, screw future + * me! + * + * Kidding. As long as (sizeof(long) == 8), that is, as long as the + * long datatype is 64 bits, which is is on all modern 64-bit Unix-like + * operating systems, then everything should be fine. Expect + * Telodendria on 32-bit machines to break in 2038. I didn't want to + * try to hack together some system to store larger numbers than the + * architecture supports. We can always re-evaluate things over the + * next decade. + * + * Return: A long representing the current time in milliseconds since + * the beginning of the Unix epoch, just as the Matrix spec requires. + */ extern long UtilServerTs(void); +/* + * Encode a single UTF-8 codepoint as a string buffer containing + * between 1 and 4 bytes. The string buffer is allocated on the heap, + * so it should be freed when it is no longer needed. + * + * Params: + * + * (unsigned long) The UTF-8 codepoint to encode as a byte buffer. + * + * Return: a null-terminated byte buffer representing the UTF-8 + * codepoint. + */ extern char * - UtilUtf8Encode(unsigned long utf8); + UtilUtf8Encode(unsigned long); -#endif +#endif /* TELODENDRIA_UTIL_H */