QuartermindGames/hei

Implement interface for log output, ensure it's safe too!

Closed this issue · 1 comments

hogsy commented

See platform_log.c for initial implementation.

  • Need a solution for supporting multi-level log messages, e.g. error, warning, debug and more (which can then be toggled on the fly?)
  • This could probably be merged into the console?

Below is a quick mock I whipped up, completely untested but similar to what I'd like to do.

// EXAMPLE CODE, COMPLETELY UNTESTED AND PROBABLY FULL OF HOLES

// public
enum {
  PL_LOG_LEVEL_HIGH = -1,
  PL_LOG_LEVEL_MEDIUM = -2,
  PL_LOG_LEVEL_LOW = -3,

  PL_LOG_LEVEL_GRAPHICS = -4,
  PL_LOG_LEVEL_FILESYSTEM = -5,

  PL_LOG_LEVEL_END = 10,
};

///////////////////////////////////////////////////////////
// private

#define MAX_LOG_LEVELS  128

typedef struct LogLevel {
  int id;
  bool is_enabled;

  char prefix[64];   // e.g. 'warning', 'error'
  PLColour colour;   // colour that it'll display
} LogLevel;

LogLevel levels[MAX_LOG_LEVELS];
LogLevel *GetLogLevel(int level) {
  static bool mem_cleared = false;
  if(!mem_cleared) {
    memset(levels, 0, sizeof(LogLevel) * MAX_LOG_LEVELS);
    mem_cleared = true;

    plSetupLogLevel(PL_LOG_LEVEL_LOW, "pl", (PLColour){255, 255, 255}, false);
    plSetupLogLevel(PL_LOG_LEVEL_MEDIUM, "pl-warn", (PLColour){255, 255, 0}, false);
    plSetupLogLevel(PL_LOG_LEVEL_HIGH, "pl-error", (PLColour){255, 0, 0}, true);
  
    plSetupLogLevel(PL_LOG_LEVEL_GRAPHICS, "pl-gfx", (PLColour){0, 255, 255}, false);
    plSetupLogLevel(PL_LOG_LEVEL_FILESYSTEM, "pl-fs", (PLColour){0, 255, 255}, false);
  }

  // the following ensures there's no conflict
  // between internal/external log levels
  if(level < 0) {
    level *= -1;
  } else {
    level += PL_LOG_LEVEL_END;
  }

  if(level > MAX_LOG_LEVELS) {
    ReportError(PL_RESULT_ENDOFARRAY, "failed to find slot for log level %d", level);
    return NULL;
  }

  LogLevel *l = &levels[level];
  if(l->id == 0) {
    // register it as a new level
    l->id = level;
    l->is_enabled = false;
  }

  return l;
}

///////////////////////////////////////////////////////////
// public

void plSetLogLevelStatus(int level, bool status) {
  LogLevel *l = GetLogLevel(level);
  if(l == NULL) {
    return;
  }

  l->is_enabled = status;
}

void plSetupLogLevel(int level, const char *prefix, PLColour colour, bool status) {
  LogLevel *l = GetLogLevel(level);
  if(l == NULL) {
    return;
  }

  if(prefix != NULL && prefix[0] != '\0') {
    snprintf(l->prefix, sizeof(l->prefix), "%s", prefix);
  }
  
  l->colour = colour;
  l->is_enabled = status;
}

void plLogMessage(int level, const char *msg, ...) {
  LogLevel *l = GetLogLevel(level);
  if(l == NULL) {
    return;
  }

  if(!l->is_enabled) {
    return;
  }

  char buf[4096] = {'\0'};
  
  // add the prefix to the start
  int c = 0;
  if(l->prefix[0] != '\0') {
    c = snprintf(buf, sizeof(buf), "[%s] %s:", plGetFormattedTime(), l->prefix);
  } else {
    c = snprintf(buf, sizeof(buf), "[%s]:", plGetFormattedTime());
  }

  va_list args;
  va_start(args, msg);
  vsnprintf(buf + c, sizeof(buf) - c, msg, args);
  va_end(args);

  // todo, decide how we're going to pass it to the console/log
}
hogsy commented

done