175 lines
4.6 KiB
C
175 lines
4.6 KiB
C
/* 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
|