Les exploitants au quotidien

Logger C

technique 9 juin 2022

label.h

#ifndef LABEL_H
#define LABEL_H

typedef enum {
  labelString,
  labelInt,
  labelFloat,
  labelDouble,
  labelBool
} LoggerLabelType;

typedef struct {
  LoggerLabelType type;

  char *name;

  union {
    char *s;
    int i;
    float f;
    double d;
    bool b;
  } value;
} LoggerLabel;

LoggerLabel* LabelError(const char *value);
LoggerLabel *LabelString(const char *name, const char *value);
LoggerLabel *LabelInt(const char *name, int value);
LoggerLabel *LabelFloat(const char *name, float value);
LoggerLabel *LabelDouble(const char *name, double value);
LoggerLabel *LabelBool(const char *name, bool value);

void LabelFree(LoggerLabel*);

void LabelPrint(LoggerLabel*);

#endif // LABEL_H

label.c

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

#include "label.h"

static const char *boolName[2] = {
  "false",
  "true",
};

static LoggerLabel* labelInit(const char* name, LoggerLabelType type) {
  LoggerLabel* label = calloc(1, sizeof(LoggerLabel));

  unsigned long nameLength = strlen(name);

  label->type = type;
  label->name = calloc(nameLength + 1, sizeof(char));
  strncpy(label->name, name, nameLength);

  return label;
}

LoggerLabel* LabelError(const char *value) {
  return LabelString("err", value);
}

LoggerLabel* LabelString(const char* name, const char* value) {
  LoggerLabel* label = labelInit(name, labelString);

  unsigned long valueLength = strlen(value);
  label->value.s = calloc(valueLength + 1, sizeof(char));
  strncpy(label->value.s, value, valueLength);

  return label;
}

LoggerLabel* LabelInt(const char* name, int value) {
  LoggerLabel* label = labelInit(name, labelInt);

  label->value.i = value;

  return label;
}

LoggerLabel* LabelFloat(const char* name, float value) {
  LoggerLabel* label = labelInit(name, labelFloat);

  label->value.f = value;

  return label;
}

LoggerLabel* LabelDouble(const char* name, double value) {
  LoggerLabel* label = labelInit(name, labelDouble);

  label->value.d = value;

  return label;
}

LoggerLabel* LabelBool(const char* name, bool value) {
  LoggerLabel* label = labelInit(name, labelBool);

  label->value.b = value;

  return label;
}

void LabelFree(LoggerLabel* label) {
  switch(label->type) {
    case labelString:
      free(label->value.s);
      break;
    default:
      break;
  }

  free(label);
}

void LabelPrint(LoggerLabel* label) {
  printf("%s=", label->name);
  switch(label->type) {
    case labelString:
      printf("%s", label->value.s);
      break;
    case labelInt:
      printf("%d", label->value.i);
      break;
    case labelFloat:
      printf("%f", label->value.f);
      break;
    case labelDouble:
      printf("%f", label->value.d);
      break;
    case labelBool:
      printf("%s", boolName[label->value.b]);

    default:
      break;
  }
}

logger.h

#ifndef LOGGER_H
#define LOGGER_H

#include <stdarg.h>

// __WILL_BE_OWNED by the receiving end. no need to free a pointer after that, cannot use it anymore
#define __WILL_BE_OWNED 

typedef enum {
  DEBUG,
  INFO,
  WARN,
  ERROR,

  LEVELS
} LogLevel;

void printLog(LogLevel level, const char *message, __WILL_BE_OWNED ...);

#define LOG(level, message, ...) \
  printLog(level, message, ##__VA_ARGS__, NULL) // https://stackoverflow.com/a/18968248

#include "logger/label.h"

#endif // LOGGER_H

logger.c

#include <stdio.h>
#include <stdarg.h>
#include <time.h>

#include "logger.h"
#include "label.h"

static const char *name[LEVELS] = {
  "DEBUG",
  "INFO",
  "WARN",
  "ERROR",
};

void printLog(LogLevel level, const char *message, ...) {
  va_list argumentList;

  printf("[%s]\t%s\t", name[level], message);

  va_start(argumentList, message);

  LoggerLabel *label = va_arg(argumentList, LoggerLabel*);
  for ( ; label != NULL; ) {
    LabelPrint(label);
    LabelFree(label);

    if ((label = va_arg(argumentList, LoggerLabel*)) != NULL) {
      printf(",");
    }
  }
  puts("");
}

Mots clés

SOARES Lucas

28 ans, développeur C/Go/Kotlin/C++/Java (quel enfer)/Python