diff options
| author | Francesco Abbate <francesco.bbt@gmail.com> | 2022-01-23 20:10:46 +0100 |
|---|---|---|
| committer | Francesco Abbate <francesco.bbt@gmail.com> | 2022-01-23 20:10:46 +0100 |
| commit | 13c94464d5a5efd19fef4d27cb685dd2a1199495 (patch) | |
| tree | 80266a89c749a6187a97ab394401d25a5cc57f71 | |
| parent | 68ba21ae9e5711fddfda1ae77667b49e61b350cf (diff) | |
| download | lite-xl-zlog-dmon-logging.tar.gz lite-xl-zlog-dmon-logging.zip | |
Import zlog into the projectzlog-dmon-logging
| -rw-r--r-- | lib/zlog/meson.build | 4 | ||||
| -rw-r--r-- | lib/zlog/zlog-config.h | 18 | ||||
| -rw-r--r-- | lib/zlog/zlog.c | 289 | ||||
| -rw-r--r-- | lib/zlog/zlog.h | 60 | ||||
| -rw-r--r-- | meson.build | 5 | ||||
| -rw-r--r-- | src/meson.build | 2 | ||||
| -rw-r--r-- | subprojects/zlog.wrap | 4 |
7 files changed, 374 insertions, 8 deletions
diff --git a/lib/zlog/meson.build b/lib/zlog/meson.build new file mode 100644 index 00000000..e64f20eb --- /dev/null +++ b/lib/zlog/meson.build @@ -0,0 +1,4 @@ +libzlog = static_library('zlog', 'zlog.c', dependencies: threads_dep) + +lite_includes += include_directories('.') + diff --git a/lib/zlog/zlog-config.h b/lib/zlog/zlog-config.h new file mode 100644 index 00000000..d77bc6b1 --- /dev/null +++ b/lib/zlog/zlog-config.h @@ -0,0 +1,18 @@ +#ifndef ZLOG_CONFIG_H_ +# define ZLOG_CONFIG_H_ + +// #define ZLOG_DISABLE_LOG 1 +#define ZLOG_BUFFER_STR_MAX_LEN 512 +#define ZLOG_BUFFER_SIZE (0x1 << 20) +// ZLOG_BUFFER_TIME_STR_MAX_LEN must < ZLOG_BUFFER_STR_MAX_LEN +#define ZLOG_BUFFER_TIME_STR_MAX_LEN 64 + +// only for debug, enabling this will slow down the log +// #define ZLOG_FORCE_FLUSH_BUFFER + +#define ZLOG_FLUSH_INTERVAL_SEC 180 +#define ZLOG_SLEEP_TIME_SEC 10 +// In practice: flush size < .8 * BUFFER_SIZE +#define ZLOG_BUFFER_FLUSH_SIZE (0.8 * ZLOG_BUFFER_SIZE) + +#endif diff --git a/lib/zlog/zlog.c b/lib/zlog/zlog.c new file mode 100644 index 00000000..96a5d1d4 --- /dev/null +++ b/lib/zlog/zlog.c @@ -0,0 +1,289 @@ +/* + * Zlog utility + * By: Eric Ma https://www.ericzma.com + * Released under Unlicense + */ + +#include <stdio.h> +#include <stdarg.h> +#include <sys/types.h> +#include <unistd.h> +#include <sys/time.h> +#include <string.h> +#include <time.h> +#include <pthread.h> +#include <errno.h> + +#ifdef _WIN32 +#include <windows.h> +#endif + +#include "zlog-config.h" +#include "zlog.h" + +#ifdef _WIN32 + +// Adapted from: https://stackoverflow.com/questions/10905892/equivalent-of-gettimeday-for-windows +static int zlog_write_timestamp(char *buffer, char *buffer_end) { + const size_t size = buffer_end - buffer; + char timebuf[ZLOG_BUFFER_TIME_STR_MAX_LEN]; + SYSTEMTIME system_time; + + GetLocalTime(&system_time); + + snprintf(timebuf, ZLOG_BUFFER_TIME_STR_MAX_LEN, "%d:%02d:%d", system_time.wHour, system_time.wMinute, system_time.wSecond); + snprintf(buffer, size, "[%s.%06lds] ", timebuf, (long) system_time.wMilliseconds * 1000); + return strlen(timebuf) + 11; // space for time +} +#else +static int zlog_write_timestamp(char *buffer, char *buffer_end) { + const size_t size = buffer_end - buffer; + char timebuf[ZLOG_BUFFER_TIME_STR_MAX_LEN]; + struct timeval tv; + struct tm *tm; + + gettimeofday(&tv, NULL); + tm = localtime(&tv.tv_sec); + snprintf(timebuf, ZLOG_BUFFER_TIME_STR_MAX_LEN, "%d:%02d:%d", tm->tm_hour, tm->tm_min, tm->tm_sec); + snprintf(buffer, size, "[%s.%06lds] ", timebuf, tv.tv_usec); + return strlen(timebuf) + 11; // space for time +} +#endif + +// -------------------------------------------------------------- +// zlog utilities +FILE* zlog_fout = NULL; +const char* zlog_file_log_name = NULL; + +char _zlog_buffer[ZLOG_BUFFER_SIZE][ZLOG_BUFFER_STR_MAX_LEN]; +int _zlog_buffer_size = 0; + +pthread_mutex_t _zlog_buffer_mutex = PTHREAD_MUTEX_INITIALIZER; +// -------------------------------------------------------------- + +static inline void _zlog_buffer_lock(void) +{ + pthread_mutex_lock(&_zlog_buffer_mutex); +} + +static inline void _zlog_buffer_unlock(void) +{ + pthread_mutex_unlock(&_zlog_buffer_mutex); +} + +static void _zlog_flush_buffer(void) +{ + int i = 0; + for (i = 0; i < _zlog_buffer_size; i++) { + fprintf(zlog_fout, "%s", _zlog_buffer[i]); + } + fflush(zlog_fout); + _zlog_buffer_size = 0; +} + +// first zlog_get_buffer, write to @return +// then zlog_finish_buffer +// +// zlog_get_buffer may flush the buffer, which require I/O ops +static inline char* zlog_get_buffer(void) +{ + _zlog_buffer_lock(); + if (_zlog_buffer_size == ZLOG_BUFFER_SIZE) { + _zlog_flush_buffer(); + } + + // allocate buffer + _zlog_buffer_size++; + return _zlog_buffer[_zlog_buffer_size-1]; +} + +static inline void zlog_finish_buffer(void) +{ +#ifdef ZLOG_FORCE_FLUSH_BUFFER + _zlog_flush_buffer(); +#endif + _zlog_buffer_unlock(); +} + +// Error reporting +static inline void print_error(const char *function_name, char *error_msg){ + fprintf(stderr, "Error in function %s: %s\n", function_name, error_msg); +} + +// -------------------------------------------------------------- + +void zlog_init(char const* log_file) +{ + zlog_file_log_name = strdup(log_file); + + zlog_fout = fopen(log_file, "a+"); + + if(!zlog_fout){ + print_error(__func__, strerror(errno)); + } +} + +void zlog_init_stdout(void) +{ + zlog_fout = stdout; +} + +void zlog_init_stderr(void) +{ + zlog_fout = stderr; +} + +static void* zlog_buffer_flush_thread(void *_unused) +{ + struct timeval tv; + time_t lasttime; + time_t curtime; + + gettimeofday(&tv, NULL); + + lasttime = tv.tv_sec; + + do { + sleep(ZLOG_SLEEP_TIME_SEC); + gettimeofday(&tv, NULL); + curtime = tv.tv_sec; + if ( (curtime - lasttime) >= ZLOG_FLUSH_INTERVAL_SEC ) { + // ZLOG_LOG_LEVEL is used to make the buffer flushing + // seamlessly for the users. It does not matter what level + // the messages are at this point because, if they do + // not meet message level requirement, that wouldn't + // have been buffered in the first place. + zlogf_time(ZLOG_LOG_LEVEL, "Flush buffer.\n"); + zlog_flush_buffer(); + lasttime = curtime; + } else { + _zlog_buffer_lock(); + if (_zlog_buffer_size >= ZLOG_BUFFER_FLUSH_SIZE ) { + _zlog_flush_buffer(); + } + _zlog_buffer_unlock(); + } + } while (1); + return NULL; +} + +void zlog_init_flush_thread(void) +{ + pthread_t thr; + pthread_create(&thr, NULL, zlog_buffer_flush_thread, NULL); + zlogf_time(ZLOG_LOG_LEVEL, "Flush thread is created.\n"); +} + +void zlog_flush_buffer(void) +{ + _zlog_buffer_lock(); + _zlog_flush_buffer(); + _zlog_buffer_unlock(); +} + +void zlog_finish(void) +{ + zlog_flush_buffer(); + if (zlog_fout != stdout || zlog_fout != stderr) { + fclose(zlog_fout); + zlog_fout = stdout; + } + +} + +inline void zlogf(int msg_level, char const * fmt, ...) +{ +#ifdef ZLOG_DISABLE_LOG + return ; +#endif + if(msg_level <= ZLOG_LOG_LEVEL){ + va_list va; + char* buffer = NULL; + + buffer = zlog_get_buffer(); + + va_start(va, fmt); + vsnprintf(buffer, ZLOG_BUFFER_STR_MAX_LEN, fmt, va); + zlog_finish_buffer(); + va_end(va); + } +} + +void zlogf_time(int msg_level, char const * fmt, ...) +{ +#ifdef ZLOG_DISABLE_LOG + return ; +#endif + + if(msg_level <= ZLOG_LOG_LEVEL){ + va_list va; + char *buffer = zlog_get_buffer(); + char * const buffer_end = buffer + ZLOG_BUFFER_STR_MAX_LEN; + + buffer += zlog_write_timestamp(buffer, buffer_end); + + va_start(va, fmt); + vsnprintf(buffer, buffer_end - buffer, fmt, va); + zlog_finish_buffer(); + va_end(va); + } +} + +static int zlog_write_location(char *buffer, char *buffer_end, char *filename, int line) { + const size_t size = buffer_end - buffer; + int write_size = snprintf(buffer, size, "[@%s:%d] ", filename, line); + if (write_size >= 0 && (size_t) write_size >= size) { + write_size = size - 1; + buffer[write_size] = 0; + } + return write_size; +} + +void zlog_time(int msg_level, char* filename, int line, char const * fmt, ...) +{ +#ifdef ZLOG_DISABLE_LOG + return ; +#endif + if(msg_level <= ZLOG_LOG_LEVEL){ + va_list va; + char *buffer = zlog_get_buffer(); + char * const buffer_end = buffer + ZLOG_BUFFER_STR_MAX_LEN; + + buffer += zlog_write_timestamp(buffer, buffer_end); + buffer += zlog_write_location(buffer, buffer_end, filename, line); + + va_start(va, fmt); + vsnprintf(buffer, buffer_end - buffer, fmt, va); + zlog_finish_buffer(); + va_end(va); + } +} + +void zlog(int msg_level, char* filename, int line, char const * fmt, ...) +{ +#ifdef ZLOG_DISABLE_LOG + return ; +#endif + if(msg_level <= ZLOG_LOG_LEVEL){ + va_list va; + char *buffer = zlog_get_buffer(); + char *const buffer_end = buffer + ZLOG_BUFFER_STR_MAX_LEN; + + buffer += zlog_write_location(buffer, buffer_end, filename, line); + + va_start(va, fmt); + vsnprintf(buffer, buffer_end - buffer, fmt, va); + zlog_finish_buffer(); + va_end(va); + } +} + +const char* zlog_get_log_file_name(void){ +#ifdef ZLOG_DISABLE_LOG + return ; +#endif + return zlog_file_log_name; +} + +// End zlog utilities + diff --git a/lib/zlog/zlog.h b/lib/zlog/zlog.h new file mode 100644 index 00000000..fc85f440 --- /dev/null +++ b/lib/zlog/zlog.h @@ -0,0 +1,60 @@ +/* + * Zlog utility + * By: Eric Ma https://www.ericzma.com + * Released under Unlicense + */ + +#ifndef ZLOG_H_ +# define ZLOG_H_ + +#include<stdio.h> + +#define ZLOG_LOC __FILE__, __LINE__ + +#define ZLOG_DEBUG_LOG_MSG 1 +#define ZLOG_INFO_LOG_MSG 0 + +#ifdef DEBUG + #define ZLOG_LOG_LEVEL 1 +#else + #define ZLOG_LOG_LEVEL 0 +#endif + +extern FILE* zlog_fout; +extern const char* zlog_file_log_name; + +// Start API + +// initialize zlog: flush to a log file +void zlog_init(char const* log_file); +// initialize zlog: flush to a STDOUT +void zlog_init_stdout(void); +// initialize zlog: flush to a STDERR +void zlog_init_stderr(void); +// creating a flushing thread +void zlog_init_flush_thread(void); +// finish using the zlog; clean up +void zlog_finish(void); +// Explicitly flush the buffer in memory +void zlog_flush_buffer(void); + +// log an entry; using the printf format +void zlogf(int msg_level, char const * fmt, ...); + +// log an entry with a timestamp +void zlogf_time(int msg_level, char const * fmt, ...); + +// log an entry with the filename and location; +// the first 2 arguments can be replaced by ZLOG_LOC which +// will be filled by the compiler +void zlog(int msg_level, char* filename, int line, char const * fmt, ...); + +// log an entry with the filename and location with a timestamp +void zlog_time(int msg_level, char* filename, int line, char const * fmt, ...); + +// return where logs are being written (file absolute path) +const char* zlog_get_log_file_name(void); + +// End API + +#endif diff --git a/meson.build b/meson.build index 1f101fc6..1ffb9a64 100644 --- a/meson.build +++ b/meson.build @@ -47,8 +47,6 @@ if not get_option('source-only') libm = cc.find_library('m', required : false) libdl = cc.find_library('dl', required : false) threads_dep = dependency('threads') - zlog_proj = subproject('zlog') - zlog_dep = zlog_proj.get_variable('zlog_dep') lua_dep = dependency('lua5.2', fallback: ['lua', 'lua_dep'], default_options: ['shared=false', 'use_readline=false', 'app=false'] ) @@ -61,7 +59,7 @@ if not get_option('source-only') ] ) - lite_deps = [zlog_dep, lua_dep, sdl_dep, reproc_dep, pcre2_dep, libm, libdl, threads_dep] + lite_deps = [lua_dep, sdl_dep, reproc_dep, pcre2_dep, libm, libdl, threads_dep] if host_machine.system() == 'windows' # Note that we need to explicitly add the windows socket DLL because @@ -124,6 +122,7 @@ configure_file( if not get_option('source-only') subdir('lib/font_renderer') subdir('lib/dmon') + subdir('lib/zlog') subdir('src') subdir('scripts') endif diff --git a/src/meson.build b/src/meson.build index 503fdc48..3f13cfdc 100644 --- a/src/meson.build +++ b/src/meson.build @@ -30,7 +30,7 @@ executable('lite-xl', dependencies: lite_deps, c_args: lite_cargs, objc_args: lite_cargs, - link_with: libfontrenderer, + link_with: [libfontrenderer, libzlog], link_args: lite_link_args, install_dir: lite_bindir, install: true, diff --git a/subprojects/zlog.wrap b/subprojects/zlog.wrap deleted file mode 100644 index da0ee8c7..00000000 --- a/subprojects/zlog.wrap +++ /dev/null @@ -1,4 +0,0 @@ -[wrap-git] -directory = zlog -url = https://github.com/zma/zlog.git -revision = fbe36fb7cd46fc4edd6b9c616c6bcbab46da2ac8 |
