0

I'm creating a simple Logging utility for an embedded C project I'm working on. This utility provides common logging capabilities (new-line append, log-levels, timestamping, etc), but we would like for each file in the project to be able to specify a "label", which should be prepended to all of that file's logs. I seem to have found a way to do this using only a header file (log.h), which simplifies the logger implementation.

In order for this to work, application files need to #define a LOG_LABEL above the #include log.h, and log.h needs to exclude part of its body from the "wrapper #ifndef" (SRC_LOG_H_).

This is a simplified version of my log.h, for demo purposes.

// log.h

/* Application files can define LOG_LABEL above the inclusion of log.h */
#ifdef LOG_LABEL
#define _LOG_LABEL "" LOG_LABEL " : "
#else
#define _LOG_LABEL
#endif

#ifndef LOG_H_
#define LOG_H_

/* #includes ... */

/* 'private' log function. Formats logs: "[timestamp] [level] Label? : Message" */

/* ... log functions LOG_ERROR, LOG_WARN, LOG_INFO, etc ... */

#endif // LOG_H_
// main.c
#define LOG_LABEL "MAIN"
#include "log.h"
#include "other.h"

int main() {
    LOG_INFO("Hello world");
    goodbye();
    return 0;
}
// other.c
#define LOG_LABEL "OTHER"
#include "log.h"
#include "other.h"

void goodbye(void) {
    LOG_INFO("goodbye");
}

Output:

[0] [INFO ] MAIN : Hello world

[0] [INFO ] OTHER : goodbye

Can anyone point out any issues with this implementation? I'm hesitant about using it because I haven't seen this pattern used anywhere really, so I kinda suspect there are some hidden problems with it, that may only be revealed down the road. Specifically, could the fact that part of the header file is not wrapped in the "once-only" #ifndef cause any build issues? Is the pattern bad-practice for any known reason?

Thanks in advance.

JDune
  • 567
  • 7
  • 10
  • 2
    1) That's fine. 2) Contrary to what you say, the `#ifdef LOG_LABEL` block would work perfectly fine inside the include guard (the "once-only" #ifndef). But like some other things inside a .h (e.g. function declarations), it doesn't need to be protected by the include guard either. – ikegami Oct 19 '20 at 18:00
  • As long as the project using this logging mechanism won't include C files inside other C files (`#include "file.c"`) it should be just fine. – Alex Lop. Oct 19 '20 at 18:06
  • The other approach would be to use `__FILE__` as prefix (just the filename as explained here https://stackoverflow.com/a/8488201/5218277) – Alex Lop. Oct 19 '20 at 18:08
  • @ikegami Thanks for your response! Regarding #2, can you explain why this works? I thought that if the `#ifdef LOG_LABEL` block is inside the include guard, it would only be processed the first time log.h is included, and therefore `_LOG_LABEL` would always be defined with the LOG_LABEL of the first file to include log.h. – JDune Oct 19 '20 at 18:45
  • @AlexLop. Thanks Alex. I did consider the `__FILE__` implementation, but we preferred to be able to label logs with an abbreviated name. – JDune Oct 19 '20 at 18:46
  • 1
    Re "*it would only be processed the first time log.h is included*", 1) It's only included once (directly or indirectly) in the compilation unit (.c), and 2) if it was included more than once, the block would have no effect because `_LOG_LABEL` wouldn't be used by any subsequent code. – ikegami Oct 19 '20 at 18:50
  • Ok understood! Didn't realize that - thanks again. – JDune Oct 19 '20 at 19:54

0 Answers0