Compare commits

..

No commits in common. "56f87419f164e4fb0f1b79e53f308084432fdb7e" and "1e9b7015420d8e2e85611b2c4387faeb444d14bf" have entirely different histories.

7 changed files with 45 additions and 144 deletions

View file

@ -1,33 +0,0 @@
image: debian:latest
before_script:
- apt update
- apt install -y make
- apt install -y gcc
- export CC=$(which gcc)
stages:
- build
- test
build:
stage: build
script:
- echo "compiling with $CC"
- make alog-so
artifacts:
paths:
- target/alog.so
expire_in: 1 week
test:
stage: test
script:
- make alog-tests
valgrind:
stage: test
script:
- apt install -y valgrind
- make log_test
- valgrind -s --leak-check=full --show-leak-kinds=all --error-exitcode=1 target/log_test

View file

@ -12,21 +12,20 @@ ifdef ALOG_DEBUG
CFLAGS += -g CFLAGS += -g
endif endif
ALOG_TOP_DIR := $(dir $(lastword $(MAKEFILE_LIST))) ALOG_SRC = alog.c
ALOG_SRC = $(ALOG_TOP_DIR)alog.c
ALOG_OBJ = $(BUILD_DIR)/alog.o ALOG_OBJ = $(BUILD_DIR)/alog.o
ALOG_LIB = $(TARGET_DIR)/alog.so ALOG_LIB = $(TARGET_DIR)/alog.so
include $(dir $(lastword $(MAKEFILE_LIST)))tests/tests.mk include tests/tests.mk
.PHONY: alog-so .PHONY: so
alog-so: $(if $(shell stat $(ALOG_LIB)), alog-clean) $(ALOG_LIB) so: $(if $(shell stat $(ALOG_LIB)), clean) $(ALOG_LIB)
$(ALOG_LIB): $(TARGET_DIR) $(ALOG_OBJ) $(ALOG_LIB): $(TARGET_DIR) $(ALOG_OBJ)
$(CC) $(LDFLAGS) -o $(ALOG_LIB) $(ALOG_OBJ) $(CC) $(LDFLAGS) -o $(ALOG_LIB) $(ALOG_OBJ)
$(ALOG_OBJ): $(BUILD_DIR) $(ALOG_OBJ): $(BUILD_DIR)
$(CC) $(CFLAGS) -fPIC -c $(ALOG_SRC) -o $(ALOG_OBJ) $(CC) $(CFLAGS) -fPIC -c alog.c -o $(ALOG_OBJ)
$(BUILD_DIR): $(BUILD_DIR):
mkdir $(BUILD_DIR) mkdir $(BUILD_DIR)
@ -35,5 +34,5 @@ $(TARGET_DIR):
mkdir $(TARGET_DIR) mkdir $(TARGET_DIR)
.PHONY: clean .PHONY: clean
alog-clean: clean:
rm $(ALOG_LIB) $(ALOG_OBJ) rm $(ALOG_LIB) $(ALOG_OBJ)

View file

@ -17,16 +17,14 @@ Anything that is a file descriptor and can be written to with write() and fsync(
# How to build # How to build
```bash ```bash
$ make alog-so $ make so
``` ```
# How to test # How to test
``` ```
$ make alog-tests
```
# Variables # Variables
The following (shell) variables can be set at compile time: The following (shell) variables can be set to influence behavior at runtime:
- **ALOG_DEBUG**: Set this variable to compile with debug symbols - **ALOG_DEBUG**: Set this variable to compile with debug symbols
- **ALOG_HIJACK_PRINTF**: Set this variable to compile along with a printf implementation that leverages alog. Probably dont though. - **ALOG_HIJACK_PRINTF**: Set this variable to compile along with a printf implementation that leverages alog. Probably dont though.

78
alog.c
View file

@ -24,13 +24,6 @@
#include <time.h> #include <time.h>
#define TEST_ALOG_STATE() if (!ALOG_LOGGING_STATE) { _init_alog(); } #define TEST_ALOG_STATE() if (!ALOG_LOGGING_STATE) { _init_alog(); }
#define MAX_TIMESTAMP 30
struct _global_logging_state *ALOG_LOGGING_STATE;
int _alog_num_out_fds;
int *_alog_out_fds;
int _alog_num_err_fds;
int *_alog_err_fds;
void _init_alog() { void _init_alog() {
if (!ALOG_LOGGING_STATE) { if (!ALOG_LOGGING_STATE) {
@ -49,10 +42,6 @@ void _init_alog() {
_alog_err_fds[0] = 2; _alog_err_fds[0] = 2;
} }
void init_alog() {
TEST_ALOG_STATE();
}
// TODO: should I dont close stdin and stdout? // TODO: should I dont close stdin and stdout?
void deinit_alog() { void deinit_alog() {
TEST_ALOG_STATE(); TEST_ALOG_STATE();
@ -144,60 +133,46 @@ void alog_remove_target(int fd) {
// TODO: use preprocessor directives to gate off the posix timestamp stuff // TODO: use preprocessor directives to gate off the posix timestamp stuff
// unless the right variable is passed in at compile time // unless the right variable is passed in at compile time
int _alog ( void alog (
alog_sev severity, alog_sev severity,
const char * message, const char * message,
va_list fmt ...
) { ) {
TEST_ALOG_STATE();
if (severity == DEBUG && if (severity == DEBUG &&
!ALOG_LOGGING_STATE->log_debug_messages) { !ALOG_LOGGING_STATE->log_debug_messages) {
// nop :) // nop :)
return -1; return;
} }
va_list fmt_list; va_list fmt_list;
va_copy(fmt_list, fmt); va_start(fmt_list, message);
char *buffer; char *buffer;
int size; int size;
if (severity != PRINT) { if (severity != PRINT) {
// GET TIMESTAMP // GET TIMESTAMP
// TODO: try to get this all into 1 call to sprintf
time_t t = time(NULL); time_t t = time(NULL);
struct tm * p = localtime(&t); struct tm * p = localtime(&t);
int timestamp_len = strftime(NULL, MAX_TIMESTAMP, "[%c]", p) + 1; int timestamp_size = strftime(NULL, 0, "[%c]", p);
char *timestamp = calloc(timestamp_len , sizeof(char)); char *timestamp = malloc(sizeof(char) * (timestamp_size+1));
strftime(timestamp, timestamp_len+1, "[%c]", p); strftime(timestamp, timestamp_size, "[%c]", p);
char *msg_and_timestamp = malloc(sizeof(char) * (timestamp_size + strlen(message) + 3));
size = (timestamp_len + strlen(message) + 1);
char *msg_and_timestamp = calloc(size, sizeof(char));
sprintf(msg_and_timestamp, "%s %s\n", timestamp, message); sprintf(msg_and_timestamp, "%s %s\n", timestamp, message);
free(timestamp); free(timestamp);
size = snprintf(NULL, 0, msg_and_timestamp, fmt_list);
// TODO: Why even use msg_and_timestamp if I am going to write it wholesale into buffer?
size = vsnprintf(NULL, 0, msg_and_timestamp, fmt_list);
va_end(fmt_list);
va_copy(fmt_list, fmt);
buffer = malloc(size + 1); buffer = malloc(size + 1);
vsprintf(buffer, msg_and_timestamp, fmt_list); sprintf(buffer, msg_and_timestamp, fmt_list);
va_end(fmt_list);
free(msg_and_timestamp); free(msg_and_timestamp);
// if severity is PRINT we avoid timestamp // if severity is PRINT we avoid timestamp
} else { } else {
size = vsnprintf(NULL, 0, message, fmt_list); size = snprintf(NULL, 0, message, fmt_list);
va_end(fmt_list);
va_copy(fmt_list, fmt);
buffer = malloc(size + 1); buffer = malloc(size + 1);
vsprintf(buffer, message, fmt_list); sprintf(buffer, message, fmt_list);
va_end(fmt_list);
} }
int written = 0;
for (int i = 0; i < _alog_num_out_fds; i++) { for (int i = 0; i < _alog_num_out_fds; i++) {
int num = write(_alog_out_fds[i], buffer, size); if (write(_alog_out_fds[i], buffer, size) < size) {
written += num;
if (num < size) {
// TODO: how to handle? probably cant log another message lmao // TODO: how to handle? probably cant log another message lmao
// perhaps it should be yanked from the list? maybe not? // perhaps it should be yanked from the list? maybe not?
;; ;;
@ -207,9 +182,7 @@ int _alog (
if (severity == ERROR) { if (severity == ERROR) {
for (int i = 0; i < _alog_num_err_fds; i++) { for (int i = 0; i < _alog_num_err_fds; i++) {
int num = write(_alog_err_fds[i], buffer, size); if (write(_alog_err_fds[i], buffer, size) < size) {
written += num;
if (num < size) {
// TODO: see above // TODO: see above
;; ;;
} }
@ -218,31 +191,20 @@ int _alog (
} }
free(buffer); free(buffer);
return written;
}
int alog (
alog_sev severity,
const char * message,
...
) {
TEST_ALOG_STATE();
va_list fmt_list;
va_start(fmt_list, message);
int res = _alog(severity, message, fmt_list);
va_end(fmt_list); va_end(fmt_list);
return res;
} }
#ifdef ALOG_HIJACK_PRINTF #ifdef ALOG_HIJACK_PRINTF
int printf(const char *format, ...) { int printf(const char *format, ...) {
TEST_ALOG_STATE(); TEST_ALOG_STATE();
va_list fmt_list; va_list fmt_list;
va_start(fmt_list, format); va_start(fmt_list, format);
int i = _alog(PRINT, format, fmt_list); /* 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); va_end(fmt_list);
return i; return size;
/* potentially accept a mem leak at end of program for alog state. /* 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 * 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 */ * or if ALOG has been LD_PRELOAD'ed into a program to override its printf */

17
alog.h
View file

@ -30,7 +30,7 @@ struct _global_logging_state {
* I am sticking with it here. * I am sticking with it here.
* *
* Alloc'ed/Initialized by a call to init_alog()*/ * Alloc'ed/Initialized by a call to init_alog()*/
extern struct _global_logging_state *ALOG_LOGGING_STATE; struct _global_logging_state *ALOG_LOGGING_STATE;
/* alternative impl I didnt want to write /* alternative impl I didnt want to write
* it would have required a bunch of getters and setters * it would have required a bunch of getters and setters
@ -42,10 +42,10 @@ extern struct _global_logging_state *ALOG_LOGGING_STATE;
#define LOG_DEBUG_MSGS_FIELD = 2; #define LOG_DEBUG_MSGS_FIELD = 2;
int flags = 0; */ int flags = 0; */
extern int _alog_num_out_fds; int _alog_num_out_fds;
extern int *_alog_out_fds; int *_alog_out_fds;
extern int _alog_num_err_fds; int _alog_num_err_fds;
extern int *_alog_err_fds; int *_alog_err_fds;
typedef enum { typedef enum {
// Not printed by default. Useful for debug info // Not printed by default. Useful for debug info
@ -65,7 +65,6 @@ typedef enum {
* err fds: stderr * err fds: stderr
*/ */
void _init_alog(); void _init_alog();
void init_alog();
/* deinitializes all global state memory used in this library */ /* deinitializes all global state memory used in this library */
void deinit_alog(); void deinit_alog();
@ -78,13 +77,11 @@ void alog_add_target(int, char);
/* removes an fd from both out fds and err fds */ /* removes an fd from both out fds and err fds */
void alog_remove_target(int); void alog_remove_target(int);
/* call to log a message. Takes a severity, a message, and format stuff /* call to log a message. Takes a severity, a message, and format stuff */
* returns number of bytes written*/ void alog(alog_sev, const char *, ...);
int alog(alog_sev, const char *, ...);
/* overrides all calls to printf with a call to alog */ /* overrides all calls to printf with a call to alog */
#ifdef ALOG_HIJACK_PRINTF #ifdef ALOG_HIJACK_PRINTF
int printf(const char *format, ...); int printf(const char *format, ...);
#endif // ALOG_HIJACK_PRINTF #endif // ALOG_HIJACK_PRINTF
#endif // ALOG_H #endif // ALOG_H

View file

@ -4,24 +4,14 @@
#include <sys/types.h> #include <sys/types.h>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <semaphore.h>
#include <fcntl.h>
int out_fd[2]; int out_fd[2];
int err_fd[2]; int err_fd[2];
const char *out_message = "standard message"; const char *out_message = "standard message";
const char *err_message = "error message"; const char *err_message = "error message";
const char *sem_name = "/alog_testing_sem";
int main() { int main() {
// RPC sync mechanism. Start locked
sem_t *sem = sem_open(sem_name, O_CREAT, 0x777, 0);
if (sem_unlink(sem_name)) {
perror("couldnt unlink semaphore");
// might as well proceed since it is a leak anyways
}
// make RPC pipe // make RPC pipe
pipe(out_fd); pipe(out_fd);
pipe(err_fd); pipe(err_fd);
@ -33,9 +23,7 @@ int main() {
pid_t childpid; pid_t childpid;
if ((childpid = fork()) == -1) { if ((childpid = fork()) == -1) {
perror("cannot fork"); perror("fork fail");
sem_close(sem);
deinit_alog();
return 1; return 1;
} }
@ -52,23 +40,14 @@ int main() {
alog(ERROR, err_message); alog(ERROR, err_message);
alog(PRINT, out_message); alog(PRINT, out_message);
if (sem_post(sem)) { exit(0);
perror("cannot increment semaphore");
return 1;
}
// clean up
sem_close(sem);
deinit_alog();
// parent process // parent process
} else { } else {
// we can do checks from here // we can do checks from here
char out_read_buffer[128] = {0}; char out_read_buffer[128] = {0};
char err_read_buffer[128] = {0}; char err_read_buffer[128] = {0};
if (sem_wait(sem)) {
perror("cannot decrement semaphore"); usleep(10);
}
read(err_fd[0], err_read_buffer, 128); read(err_fd[0], err_read_buffer, 128);
// cant check read len because of timestamp // cant check read len because of timestamp
@ -96,8 +75,8 @@ int main() {
printf("out and err log printing are successfull.\n"); printf("out and err log printing are successfull.\n");
sem_close(sem);
deinit_alog();
} }
deinit_alog();
return 0; return 0;
} }

View file

@ -1,13 +1,12 @@
ALOG_TEST_DIR := $(dir $(lastword $(MAKEFILE_LIST))) ALOG_TEST_SRCS = $(shell find tests -iname "*.c" -exec basename {} \;)
ALOG_TEST_SRCS = $(shell find $(ALOG_TEST_DIR) -iname "*.c" -exec basename {} \;)
ALOG_TESTS = $(ALOG_TEST_SRCS:.c=) ALOG_TESTS = $(ALOG_TEST_SRCS:.c=)
$(ALOG_TESTS): $(ALOG_LIB) $(ALOG_TESTS): $(ALOG_LIB)
$(CC) $(CFLAGS) -g -o $(BUILD_DIR)/$@.o -c $(ALOG_TEST_DIR)$@.c $(CC) $(CFLAGS) -g -o $(BUILD_DIR)/$@.o -c tests/$@.c
$(CC) -o $(TARGET_DIR)/$@ $(BUILD_DIR)/$@.o $(ALOG_LIB) -lpthread $(CC) -o $(TARGET_DIR)/$@ $(BUILD_DIR)/$@.o $(ALOG_LIB)
chmod +x $(TARGET_DIR)/$@ chmod +x $(TARGET_DIR)/$@
alog-tests: $(ALOG_TESTS) run-tests: $(ALOG_TESTS)
for test in $^ ; do \ for test in $^ ; do \
$(TARGET_DIR)/$$test ; \ $(TARGET_DIR)/$$test ; \
done done