Initial implementation of logging library
Signed-off-by: Aidan Hahn <aidan@aidanis.online>
This commit is contained in:
commit
32cea23421
6 changed files with 998 additions and 0 deletions
175
alog.c
Normal file
175
alog.c
Normal file
|
|
@ -0,0 +1,175 @@
|
|||
/* ALOG: A Logger
|
||||
* Copyright (C) 2022 Aidan Hahn
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation, either version 3 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see https://www.gnu.org/licenses/.
|
||||
*/
|
||||
|
||||
#include "alog.h"
|
||||
#include <stdlib.h>
|
||||
// ^^^ TODO: build a memory management library
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define TEST_ALOG_STATE() if (!ALOG_LOGGING_STATE) { _init_alog(); }
|
||||
|
||||
void _init_alog() {
|
||||
if (!ALOG_LOGGING_STATE) {
|
||||
ALOG_LOGGING_STATE = malloc(sizeof(struct _global_logging_state));
|
||||
ALOG_LOGGING_STATE->broadcast_to_all_fds = 0;
|
||||
ALOG_LOGGING_STATE->log_debug_messages = 0;
|
||||
}
|
||||
_alog_num_out_fds = 1;
|
||||
_alog_out_fds = malloc(sizeof(int) * 1);
|
||||
// stdout
|
||||
_alog_out_fds[0] = 1;
|
||||
|
||||
_alog_num_err_fds = 1;
|
||||
_alog_err_fds = malloc(sizeof(int) * 1);
|
||||
// stderr
|
||||
_alog_err_fds[1] = 2;
|
||||
}
|
||||
|
||||
// TODO: should I dont close stdin and stdout?
|
||||
void deinit_alog() {
|
||||
TEST_ALOG_STATE();
|
||||
free(ALOG_LOGGING_STATE);
|
||||
for (int i = 0; i < _alog_num_out_fds; i++) {
|
||||
close(_alog_out_fds[i]);
|
||||
}
|
||||
for (int i = 0; i < _alog_num_err_fds; i++) {
|
||||
close(_alog_err_fds[i]);
|
||||
}
|
||||
free(_alog_out_fds);
|
||||
free(_alog_err_fds);
|
||||
}
|
||||
|
||||
void alog_add_target(int fd, char is_err) {
|
||||
TEST_ALOG_STATE();
|
||||
int **fd_list = is_err ? &_alog_err_fds : &_alog_out_fds;
|
||||
int *size = is_err ? &_alog_num_err_fds : &_alog_num_out_fds;
|
||||
|
||||
int *fds = malloc(sizeof(int) * (*size + 1));
|
||||
for (int i = 0; i < *size; i++) {
|
||||
fds[i] = (*fd_list)[i];
|
||||
}
|
||||
|
||||
fds[*size] = fd;
|
||||
free(*fd_list);
|
||||
(*fd_list) = fds;
|
||||
(*size)++;
|
||||
}
|
||||
|
||||
// inefficient time wise, but avoids extra allocs
|
||||
// TODO: revisit this and see how to do it less tediously
|
||||
void alog_remove_target(int fd) {
|
||||
TEST_ALOG_STATE();
|
||||
int out_fds = 0;
|
||||
for (int i = 0; i < _alog_num_out_fds; i++) {
|
||||
if (_alog_out_fds[i] != fd) {
|
||||
out_fds++;
|
||||
}
|
||||
}
|
||||
|
||||
int *tmp_outs = malloc(sizeof(int) * out_fds);
|
||||
int tmp_iter_idx = 0;
|
||||
for (int i = 0; i < _alog_num_out_fds; i++) {
|
||||
if (_alog_out_fds[i] != fd) {
|
||||
tmp_outs[tmp_iter_idx] = _alog_out_fds[i];
|
||||
tmp_iter_idx++;
|
||||
}
|
||||
}
|
||||
|
||||
free(_alog_out_fds);
|
||||
_alog_out_fds = tmp_outs;
|
||||
_alog_num_out_fds = out_fds;
|
||||
|
||||
int err_fds = 0;
|
||||
for (int i = 0; i < _alog_num_err_fds; i++) {
|
||||
if (_alog_err_fds[i] != fd) {
|
||||
err_fds++;
|
||||
}
|
||||
}
|
||||
|
||||
int *tmp_errs = malloc(sizeof(int) * err_fds);
|
||||
tmp_iter_idx = 0;
|
||||
for (int i = 0; i < _alog_num_err_fds; i++) {
|
||||
if (_alog_err_fds[i] != fd) {
|
||||
tmp_errs[tmp_iter_idx] = _alog_err_fds[i];
|
||||
tmp_iter_idx++;
|
||||
}
|
||||
}
|
||||
|
||||
free(_alog_err_fds);
|
||||
_alog_err_fds = tmp_errs;
|
||||
_alog_num_err_fds = err_fds;
|
||||
}
|
||||
|
||||
void alog (
|
||||
alog_sev severity,
|
||||
const char * message,
|
||||
...
|
||||
) {
|
||||
TEST_ALOG_STATE();
|
||||
if (severity == DEBUG &&
|
||||
!ALOG_LOGGING_STATE->log_debug_messages) {
|
||||
// nop :)
|
||||
return;
|
||||
}
|
||||
|
||||
va_list fmt_list;
|
||||
va_start(fmt_list, message);
|
||||
|
||||
int size = snprintf(NULL, 0, message, fmt_list);
|
||||
char *buffer = malloc(size + 1);
|
||||
sprintf(buffer, message, fmt_list);
|
||||
|
||||
for (int i = 0; i < _alog_num_out_fds; i++) {
|
||||
if (write(_alog_out_fds[i], buffer, size) < size) {
|
||||
// TODO: how to handle? probably cant log another message lmao
|
||||
// perhaps it should be yanked from the list? maybe not?
|
||||
;;
|
||||
}
|
||||
fsync(_alog_out_fds[i]);
|
||||
}
|
||||
|
||||
if (severity == ERROR) {
|
||||
for (int i = 0; i < _alog_num_err_fds; i++) {
|
||||
if (write(_alog_err_fds[i], buffer, size) < size) {
|
||||
// TODO: see above
|
||||
;;
|
||||
}
|
||||
fsync(_alog_err_fds[i]);
|
||||
}
|
||||
}
|
||||
|
||||
free(buffer);
|
||||
va_end(fmt_list);
|
||||
}
|
||||
|
||||
#ifdef ALOG_HIJACK_PRINTF
|
||||
int printf(const char *format, ...) {
|
||||
TEST_ALOG_STATE();
|
||||
va_list fmt_list;
|
||||
va_start(fmt_list, format);
|
||||
/* TODO: this is a duplicate call given the implementation of alog.
|
||||
* Lets figure out a better way to handle this */
|
||||
int size = snprintf(NULL, 0, format, fmt_list);
|
||||
alog(PRINT, NULL, format, fmt_list);
|
||||
va_end(fmt_list);
|
||||
return size;
|
||||
/* potentially accept a mem leak at end of program for alog state.
|
||||
* That is, if the program using this is not already using alog correctly
|
||||
* or if ALOG has been LD_PRELOAD'ed into a program to override its printf */
|
||||
}
|
||||
#endif
|
||||
Loading…
Add table
Add a link
Reference in a new issue