This commit is contained in:
Jordan Bancino 2022-07-29 15:36:21 -04:00
parent 27acd6dc45
commit fa0bd9a7c6
10 changed files with 309 additions and 199 deletions

316
src/Log.c
View file

@ -28,6 +28,7 @@
#include <unistd.h> #include <unistd.h>
#include <ctype.h> #include <ctype.h>
#include <stdarg.h> #include <stdarg.h>
#include <pthread.h>
#define LOG_TSBUFFER 64 #define LOG_TSBUFFER 64
@ -38,8 +39,158 @@ struct LogConfig
FILE *out; FILE *out;
int flags; int flags;
char *tsFmt; 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 void
Log(LogConfig * config, LogLevel level, const char *msg,...) Log(LogConfig * config, LogLevel level, const char *msg,...)
{ {
@ -65,6 +216,8 @@ Log(LogConfig * config, LogLevel level, const char *msg,...)
return; return;
} }
pthread_mutex_lock(&config->lock);
for (i = 0; i < config->indent; i++) for (i = 0; i < config->indent; i++)
{ {
fputc(' ', config->out); fputc(' ', config->out);
@ -146,7 +299,7 @@ Log(LogConfig * config, LogLevel level, const char *msg,...)
indicator = '*'; indicator = '*';
break; break;
default: default:
indicator = ' '; indicator = '?';
break; break;
} }
@ -172,163 +325,6 @@ Log(LogConfig * config, LogLevel level, const char *msg,...)
{ {
fflush(config->out); fflush(config->out);
} }
}
pthread_mutex_unlock(&config->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;
}
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;
}
} }

View file

@ -50,8 +50,6 @@ typedef struct Array Array;
/* /*
* Create a new, empty array on the heap. * Create a new, empty array on the heap.
* *
* Params: none
*
* Return: A pointer to an Array, or NULL if there was an error * Return: A pointer to an Array, or NULL if there was an error
* allocating memory for the Array. * allocating memory for the Array.
*/ */
@ -214,4 +212,4 @@ extern void
extern int extern int
ArrayTrim(Array *); ArrayTrim(Array *);
#endif #endif /* TELODENDRIA_ARRAY_H */

View file

@ -152,4 +152,4 @@ extern void
extern int extern int
Base64Pad(char **, size_t); Base64Pad(char **, size_t);
#endif #endif /* TELODENDRIA_BASE64_H */

View file

@ -83,4 +83,4 @@ extern int
extern char * extern char *
CanonicalJsonEncodeToString(HashMap *); CanonicalJsonEncodeToString(HashMap *);
#endif #endif /* TELODENDRIA_CANONICALJSON_H */

View file

@ -205,4 +205,4 @@ extern HashMap *
extern void extern void
ConfigFree(HashMap *); ConfigFree(HashMap *);
#endif #endif /* TELODENDRIA_CONFIG_H */

View file

@ -180,4 +180,4 @@ extern int
extern void extern void
HashMapFree(HashMap *); HashMapFree(HashMap *);
#endif #endif /* TELODENDRIA_HASHMAP_H */

View file

@ -102,11 +102,13 @@ typedef enum HttpStatus
struct HttpRequest struct HttpRequest
{ {
HttpRequestMethod method; HttpRequestMethod method;
HashMap *headers;
}; };
struct HttpResponse struct HttpResponse
{ {
HttpStatus status; HttpStatus status;
HashMap *headers;
}; };
extern char * extern char *

View file

@ -268,4 +268,4 @@ extern int
extern HashMap * extern HashMap *
JsonDecode(FILE *); JsonDecode(FILE *);
#endif #endif /* TELODENDRIA_JSON_H */

View file

@ -61,7 +61,7 @@ typedef enum LogLevel
/* /*
* The possible flags that can be applied to alter the behavior of * The possible flags that can be applied to alter the behavior of
* the logger * the logger.
*/ */
typedef enum LogFlag typedef enum LogFlag
{ {
@ -71,50 +71,126 @@ typedef enum LogFlag
/* /*
* The log configurations structure in which all settings exist. * The log configurations structure in which all settings exist.
* It's not super elegant to pass around a pointer to the logging * 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; 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 * extern LogConfig *
LogConfigCreate(void); 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 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 extern void
LogConfigLevelSet(LogConfig * config, LogLevel level); LogConfigOutputSet(LogConfig *, FILE *);
extern LogLevel
LogConfigLevelGet(LogConfig * config);
extern void extern void
LogConfigIndentSet(LogConfig * config, size_t indent); LogConfigFlagSet(LogConfig *, int);
extern size_t
LogConfigIndentGet(LogConfig * config);
extern void extern void
LogConfigIndent(LogConfig * config); LogConfigFlagClear(LogConfig *, int);
extern void 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 extern void
LogConfigOutputSet(LogConfig * config, FILE * out); Log(LogConfig *, LogLevel, const char *,...);
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,...);
#endif #endif

View file

@ -21,13 +21,51 @@
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. * 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 #ifndef TELODENDRIA_UTIL_H
#define 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 extern long
UtilServerTs(void); 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 * extern char *
UtilUtf8Encode(unsigned long utf8); UtilUtf8Encode(unsigned long);
#endif #endif /* TELODENDRIA_UTIL_H */