Skip to content
Eduard Mishkurov edited this page May 13, 2026 · 2 revisions

C API

logme provides a native C API for pure C translation units and mixed C/C++ projects. The public entry point is the same as for C++:

#include <Logme/Logme.h>

When this header is included from C code, logme exposes the C API and C logging macros. The C layer is intentionally smaller than the C++ API, but it supports the normal production path: channels, basic backends, levels, printf-style messages, subsystem tags, per-message overrides, configuration loading, and shutdown.

Minimal example

#include <Logme/Logme.h>

int main(void)
{
  LogmeCreateChannel(
    "app"
    , LEVEL_DEBUG
  );

  LogmeAddConsoleBackend("app", 0);

  LogmeI("hello from C");
  LogmeW_Ch("app", "warning from channel");
  LogmeE_Sid("CORE", "error from subsystem");

  LogmeShutdown();
  return 0;
}

The repository also contains a dedicated examples/CApi example. Example wiki pages are generated from the corresponding examples/<name>/README.md files by tools/sync_examples.py.

Logging levels

The C API uses the same level enum values as the C++ API:

LEVEL_DEBUG
LEVEL_INFO
LEVEL_WARN
LEVEL_ERROR
LEVEL_CRITICAL

Basic logging macros

The C macros use printf-style formatting:

LogmeD("debug value: %d", value);
LogmeI("information message");
LogmeW("warning message");
LogmeE("error message");
LogmeC("critical message");

Unlike the C++ macros, the C macros do not provide stream-style output. They always write a formatted message.

Channels and subsystems

C does not have the same overload mechanism as C++, so channel and subsystem variants use explicit macro names:

LogmeI_Ch("network", "message for channel");
LogmeI_Sid("HTTP", "message for subsystem");
LogmeI_ChSid("network", "HTTP", "message for channel and subsystem");

Conditional variants are also available:

LogmeI_If(condition, "message only when condition is true");

Channel API

Create or delete a channel

int LogmeCreateChannel(
  const char* channel
  , LogmeLevel level
);

void LogmeDeleteChannel(const char* channel);

Change channel state

void LogmeSetChannelLevel(
  const char* channel
  , LogmeLevel level
);

void LogmeSetChannelEnabled(
  const char* channel
  , int enabled
);

Change channel flags

void LogmeSetChannelFlags(
  const char* channel
  , LogmeOutputFlags flags
);

LogmeOutputFlags is the C-visible form of the same OutputFlags bit-field set used by the C++ API.

Backend API

Console backend

int LogmeAddConsoleBackend(
  const char* channel
  , int async
);

Debug backend

int LogmeAddDebugBackend(const char* channel);

File backend

int LogmeAddFileBackend(
  const char* channel
  , const char* fileName
  , int append
  , size_t maxSize
  , int dailyRotation
  , int maxParts
);

Backend cleanup and flushing

void LogmeRemoveChannelBackends(const char* channel);
void LogmeFlushChannel(const char* channel);

Direct write API

The macros are the normal way to write log messages from C, but the lower-level functions are also exposed:

void LogmeWrite(
  LogmeLevel level
  , const char* channel
  , const char* subsystem
  , const char* function
  , const char* file
  , int line
  , const char* format
  , ...
);

void LogmeWriteV(
  LogmeLevel level
  , const char* channel
  , const char* subsystem
  , const char* function
  , const char* file
  , int line
  , const char* format
  , va_list args
);

Overrides from C

The C API exposes a C-compatible override structure:

typedef struct LogmeCOverride
{
  LogmeOutputFlags Add;
  LogmeOutputFlags Remove;
  int MaxRepetitions;
  int Repetitions;
  uint64_t MaxFrequency;
  uint64_t LastTime;
  const LogmeCShortenerPair* Shortener;
} LogmeCOverride;

Initialize it before use:

LogmeCOverride once;
LogmeInitOverride(
  &once
  , 1
  , 0
);

LogmeI_Ovr(&once, "this message is printed once");
LogmeI_Ovr(&once, "this message is suppressed");

For rate-limited logging, keep the same LogmeCOverride object alive between calls because the repetition and timing state is stored inside it:

static LogmeCOverride everySecond;
static int initialized = 0;

if (!initialized)
{
  LogmeInitOverride(
    &everySecond
    , -1
    , 1000
  );
  initialized = 1;
}

LogmeI_Ovr(&everySecond, "printed at most once per second");

Override macro variants follow the same naming style:

LogmeI_Ovr(&overrideData, "message");
LogmeI_ChOvr("app", &overrideData, "message");
LogmeI_SidOvr("CORE", &overrideData, "message");
LogmeI_ChSidOvr("app", "CORE", &overrideData, "message");

Configuration and shutdown

C code can load the same configuration files as C++ code:

char error[512];

if (!LogmeLoadConfigurationFile(
  "logme.json"
  , NULL
  , error
  , sizeof(error)
))
{
  LogmeE("configuration error: %s", error);
}

The raw configuration text variant is also available:

int LogmeLoadConfiguration(
  const char* configData
  , const char* section
  , char* errorBuffer
  , size_t errorBufferSize
);

Call LogmeShutdown() when the application wants to flush and stop logging explicitly:

LogmeShutdown();

Limitations compared with C++

The C API intentionally does not expose the full C++ surface. The following features remain C++-only:

  • stream-style logging with operator <<
  • fLogme... macros based on std::format
  • C++ overload-based macro dispatch
  • C++ RAII helpers
  • direct construction of C++ backend objects

Use the explicit C macro families (_Ch, _Sid, _Ovr) and the C wrapper functions instead.

Clone this wiki locally