Native / Non-Rust Integration via micromegas-capi¶
micromegas-capi is a thin C ABI shim over the Micromegas telemetry producer stack.
It lets any non-Rust process — a Python script, a C/C++ tool, a game engine plugin —
emit logs and metrics into Micromegas without building a Rust project.
How it works¶
Your process
└── libmicromegas_capi.{so,dll,dylib} (loaded at runtime via dlopen/ctypes/LoadLibrary)
├── flat C ABI (mm_init / mm_log / mm_metric_* / mm_flush / mm_shutdown)
├── holds TelemetryGuard (buffers + flush state)
└── HttpEventSink ── own OS thread + tokio runtime ──► ingestion-srv
The transport thread is internal to the library and starts when mm_init succeeds.
Your calling thread is never blocked waiting on the network.
Building the library¶
# Linux / WSL
cd rust/
cargo build --package micromegas-capi --release
# produces: rust/target/release/libmicromegas_capi.so
# rust/target/release/libmicromegas_capi.a
# Windows (from a MSVC-capable shell)
cargo build --package micromegas-capi --release --target x86_64-pc-windows-msvc
# produces: rust/target/x86_64-pc-windows-msvc/release/micromegas_capi.dll
# rust/target/x86_64-pc-windows-msvc/release/micromegas_capi.lib
C API reference¶
Include rust/capi/include/micromegas.h.
Level constants¶
| Constant | Value | Meaning |
|---|---|---|
MM_LEVEL_FATAL |
1 | Crash / panic |
MM_LEVEL_ERROR |
2 | Serious error |
MM_LEVEL_WARN |
3 | Warning |
MM_LEVEL_INFO |
4 | Informational |
MM_LEVEL_DEBUG |
5 | Debug detail |
MM_LEVEL_TRACE |
6 | Very verbose |
mm_init¶
Initializes the telemetry system and returns an opaque handle.
Returns NULL on failure.
MmConfig fields:
| Field | Type | Meaning |
|---|---|---|
sink_url |
const char * |
Ingestion endpoint (NULL → reads MICROMEGAS_TELEMETRY_URL) |
property_keys |
const char ** |
Parallel array of process-property key strings |
property_values |
const char ** |
Parallel array of process-property value strings |
property_count |
unsigned int |
Length of the arrays above (0 = no properties) |
Authentication is always read from environment variables:
MICROMEGAS_INGESTION_API_KEY— API key (simplest option)MICROMEGAS_OIDC_TOKEN_ENDPOINT/MICROMEGAS_OIDC_CLIENT_ID/MICROMEGAS_OIDC_CLIENT_SECRET— OIDC client credentials
mm_shutdown¶
Flushes all pending events, joins the transport thread, and frees the handle.
Must be called before process exit. Safe to call with NULL.
mm_log¶
Emits a log event. target is a subsystem name (e.g. "myapp.render").
A NULL target is substituted with "capi"; a NULL msg is silently ignored (no event is emitted).
mm_log_tagged¶
void mm_log_tagged(MmHandle *handle, int level, const char *target, const char *msg,
const char *const *property_keys, const char *const *property_values,
unsigned int property_count);
Same as mm_log, with properties read from parallel key/value arrays like MmConfig's.
A pair with a NULL key or value, or an empty or non-UTF-8 key, is skipped; a value that
is not UTF-8 is kept as an empty string. NULL arrays or a zero count mean no
properties. Logs filter target and level keys out of what the sink sees, and the
entry keeps the target and level arguments.
const char *keys[] = { "request_id", "region" };
const char *vals[] = { "c0ffee", "eu" };
mm_log_tagged(h, MM_LEVEL_INFO, "myapp.net", "request done", keys, vals, 2);
mm_metric_i / mm_metric_f¶
void mm_metric_i(MmHandle *handle, const char *name, const char *unit, uint64_t value);
void mm_metric_f(MmHandle *handle, const char *name, const char *unit, double value);
Emit an integer or floating-point metric. A NULL or empty name is a no-op; a NULL
unit is an empty string.
Cardinality contract
Names, units, targets, keys and values are copied into the current block and freed with it; the library keeps none of them for the life of the process. Distinct names and values still cost series and dictionary entries in queries, so keep metric names low-cardinality and bounded — never pass session IDs, per-frame counters, or asset paths as metric names.
mm_metric_i_tagged / mm_metric_f_tagged¶
void mm_metric_i_tagged(MmHandle *handle, const char *name, const char *unit,
const char *const *property_keys, const char *const *property_values,
unsigned int property_count, uint64_t value);
void mm_metric_f_tagged(MmHandle *handle, const char *name, const char *unit,
const char *const *property_keys, const char *const *property_values,
unsigned int property_count, double value);
Same as mm_metric_i / mm_metric_f, with properties read as in mm_log_tagged. Only
the exact lowercase target key replaces a metric's default "capi" target (analytics
matches it case-sensitively). The name and unit arguments win over keys of the same
name, and both appear in the properties column of the measure.
const char *keys[] = { "queue", "target" };
const char *vals[] = { "render", "myapp.queues" };
mm_metric_i_tagged(h, "queue.depth", "count", keys, vals, 2, 12);
mm_flush¶
Flushes in-memory log and metric buffers. The transport thread then ships
them to the server. Call this periodically (e.g., every 30 s) and always
before shutdown. Safe to call with NULL.
Minimal C example¶
#include "micromegas.h"
#include <stdint.h>
#include <stdio.h>
int main(void) {
const char *keys[] = { "app", "version" };
const char *values[] = { "my-tool", "1.0" };
MmConfig cfg = {
.sink_url = "http://my-ingestion-server:9000",
.property_keys = keys,
.property_values = values,
.property_count = 2,
};
MmHandle *h = mm_init(&cfg);
if (!h) { fprintf(stderr, "mm_init failed\n"); return 1; }
mm_log(h, MM_LEVEL_INFO, "my-tool.main", "starting up");
mm_metric_i(h, "my_tool.items_processed", "count", 42);
mm_metric_f(h, "my_tool.latency_ms", "ms", 7.5);
mm_flush(h);
mm_shutdown(h);
return 0;
}
Python / ctypes example¶
The Blender add-on ships a ready-to-use ctypes binding in
blender/micromegas_blender/binding.py. You can adapt it for any Python
project:
from micromegas_blender.binding import MicromegasLib, LEVEL_INFO
lib = MicromegasLib("/path/to/libmicromegas_capi.so")
handle = lib.init(
sink_url="http://my-server:9000",
properties={"app": "my-script", "version": "1.0"},
)
lib.log(handle, LEVEL_INFO, "my-script", "hello from Python")
lib.metric_f(handle, "latency_ms", "ms", 12.3)
lib.flush(handle)
lib.shutdown(handle)
Threading model¶
mm_init/mm_shutdownmust be called from a single thread (the init/cleanup thread).mm_log,mm_metric_i,mm_metric_f,mm_flushare safe to call from any thread simultaneously; internal dispatch uses a per-streamMutex.- The HTTP transport runs on a dedicated OS thread spawned by
mm_init. Your threads never block on network I/O.
Platform matrix¶
| Target | Artifact | Notes |
|---|---|---|
x86_64-unknown-linux-gnu |
libmicromegas_capi.so |
WSL2 counts as Linux |
x86_64-pc-windows-msvc |
micromegas_capi.dll |
CRT statically linked |
macOS and ARM64 are not currently supported.