alog/alog.c

176 lines
4.6 KiB
C
Raw Normal View History

/* 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