Simple logging library in C This header implements a very simple set of C (only) functions for logging.
This is part of a larger collection of utility functions aimed to be used during the development process, meaning that they are intended to provide quick, easy to use solutions that could be replaced in the production code if needed.

To ease with reading the code, I've removed the (rather verbose) comments with the documentation. You can find it in the README.md file here.

Beside the printf()-like functions, there are a couple of functions that may be used for testing and debugging purpose.

I'm very interested in any feedback you may have, especially in the area of usability.

#ifndef UTL_H
#define UTL_H

#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;stdint.h&gt;
#include &lt;string.h&gt;
#include &lt;stdarg.h&gt;
#include &lt;stddef.h&gt;
#include &lt;time.h&gt;
#include &lt;ctype.h&gt;

#ifndef UTL_NOLOG

#define logprintf(...)  utl_log_printf(__VA_ARGS__)

#define logclose()      utl_log_close("LOG STOP")
#define logopen(f,m)    utl_log_open(f,m)

#ifndef NDEBUG          
#define logcheck(e)     utl_log_check(!!(e),#e,__FILE__,__LINE__)
#define logassert(e)    utl_log_assert(!!(e),#e,__FILE__,__LINE__)
#define logdebug        logprintf
#else                   
#define logcheck(e)     utl_log_one()
#define logassert(e)    ((void)0)
#define logdebug(...)   ((void)0)
#endif                  

#define _logprintf(...) ((void)0)
#define _logdebug(...)  ((void)0)
#define _logcheck(...)  utl_log_one()
#define _logassert(...) ((void)0)
#define _logopen(f,m)   ((void)0)
#define _logclose()     ((void)0)

void utl_log_close(char *msg);
void utl_log_open(char *fname, char *mode);
int  utl_log_check(int res, char *test, char *file, int line);
void utl_log_assert(int res, char *test, char *file, int line);
void utl_log_printf(char *format, ...);
int  utl_log_one(void);

#ifdef UTL_MAIN

static FILE *utl_log_file = NULL;

void utl_log_close(char *msg)
{
  if (msg) logprintf(msg);
  if (utl_log_file &amp;&amp; utl_log_file != stderr) fclose(utl_log_file);
  utl_log_file = NULL;
}

void utl_log_open(char *fname, char *mode)
{
  char md[2];
  md[0] = (mode &amp;&amp; *mode == 'w')? 'w' : 'a'; md[1] = '\0';
  utl_log_close(NULL);
  utl_log_file = fopen(fname,md);
  logprintf("LOG START");
}

void utl_log_printf(char *format, ...)
{
  va_list  args;
  char     log_tstr[32];
  time_t   log_time;

  if (!utl_log_file) utl_log_file = stderr;
  time(&amp;log_time);
  strftime(log_tstr,32,"%Y-%m-%d %X",localtime(&amp;log_time));
  fprintf(utl_log_file,"%s ",log_tstr);
  va_start(args, format);
  vfprintf(utl_log_file, format, args);
  va_end(args);
  fputc('\n',utl_log_file);
  fflush(utl_log_file);
}

int utl_log_check(int res, char *test, char *file, int line)
{
  logprintf("CHK %s (%s) %s:%d", (res?"PASS":"FAIL"), test, file, line);
  return res;
}

void utl_log_assert(int res, char *test, char *file, int line)
{
  if (!utl_log_check(res,test,file,line)) {
    logprintf("CHK EXITING ON FAIL");
    logclose();
    exit(1);
  }
}

int utl_log_one() {return 1;} /* to avoid warnings */

#endif /* UTL_MAIN */
#endif /* UTL_NOLOG */
#endif /* UTL_H */
Exit
There should never be a call to exit() in a library. If for example this code was included in a daemon or some other part of an operating system you would be shutting down the system without meaning to. The best you could do here is to require that a setjmp() command is used in the linking program and do a longjump() from the assert function. This allows the calling program to clean up and perform the correct actions in this case. A library will never know what other actions are necessary.

Incorrect Usage of Header Files
Header files should generally not have executable functions in them. Part of the reason is that if multiple files include the header then at link time the linker will complain about multiple definitions of the functions.

You seem to have worked around the multiple definition problem with complex #ifdef statements. It would be much simpler to have both a utl.h and and a utl.c. The utl.c file contains the executable functions and the utl.h file contains the function prototypes. This is a very common practice and could be
considered a standard. This would also remove the requirement for most of the header files included by this header file.

If you are creating a library that may be used by multiple programs you should probably turn utl.c into either an archive library (libmylog.a) or a dynamically linked library (libmylog.so or libmylog.dll based on the operating system).