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)
├── string interner (runtime metric names → &'static metadata, bounded)
└── 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_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.
Cardinality contract
Each unique (name, unit) pair is permanently interned in memory
(Box::leak). Keep metric names low-cardinality and bounded —
never pass session IDs, per-frame counters, or asset paths as metric names.
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.