carl.hiass
carl.hiass

Reputation: 1764

Doing a logger in C

In the following, I am trying to create a log utility in C:

#include <stdio.h>
#include <string.h>

enum LogLevel {DEBUG=10, INFO=20, WARN=30, ERROR=40};
typedef struct logger {
    int level;
    FILE** handlers; // NULL for sentinel
} Logger;
Logger LOGGER;

char* level_str(int level)
{
    switch (level) {
        case DEBUG: return "DEBUG";
        case INFO:  return "INFO";
        case WARN:  return "WARN";
        case ERROR:  return "ERROR";
        default: return "UNKNOWN";
    };
}
void logger(char* msg, int level)
{
    // skip if level is too low or no handlers set up
    if (level < LOGGER.level || !LOGGER.handlers) return;

    // write to each handler
    for (int i=0; LOGGER.handlers[i]; i++)
        fprintf(LOGGER.handlers[i], "[%s] %s\n", level_str(level), msg);
}
int main(void)
{
    LOGGER.level = DEBUG;
    FILE* handler1 = stderr;
    FILE* handler2 = fopen("z_log.txt", "w");
    LOGGER.handlers = &handler1;
    LOGGER.handlers[1] = handler2;
    LOGGER.handlers[2] = NULL;
    logger("Hello", INFO);
    return 0;
}

Working code here: https://onlinegdb.com/SJcoa5C7O.

My question is mainly about adding on some handler with these lines:

FILE* handler1 = stderr;
FILE* handler2 = fopen("z_log.txt", "w");
LOGGER.handlers = &handler1; // <-----------
LOGGER.handlers[1] = handler2;
LOGGER.handlers[2] = NULL;
logger("Hello", INFO);

I've noticed that the first handler needs a memory address, for example I can do:

LOGGER.handlers = &handler1;

But I cannot do:

LOGGER.handlers[0] = handler1;

Like I can with successive handlers that I set up. Why is this so? For example, why doesn't LOGGER.handlers[0] = handler1 set the memory address of LOGGER.handlers as I thought doing array[0] resolves to &array[0] so wouldn't that just be the initial memory address? Are there other ways to 'initialize' the pointer-to-pointers in the above?

Upvotes: 1

Views: 1157

Answers (1)

David Ranieri
David Ranieri

Reputation: 41017

You need to reserve space for the pointer to FILEs:

LOGGER.handlers = malloc(sizeof(*LOGGER.handlers) * 3);

then:

LOGGER.handlers[0] = handler1;
LOGGER.handlers[1] = handler2;
LOGGER.handlers[2] = NULL;

Or define FILE *handlers[3]; instead of FILE** handlers; if you know the number of elements beforehand.

Upvotes: 5

Related Questions