Capture logs
MapLibre Native sends records to the platform logger by default. Android and Apple platforms use the system log; other platforms use the console. Install a callback to send records to a host logger, file, crash reporter, or test.
A record contains a severity, category, optional numeric code, and message. The callback return value either consumes the record or forwards it to the platform logger as well. Forward records while validating a new host logger.
static uint32_t forward_to_host( void* user_data, uint32_t severity, uint32_t event, int64_t code, const char* message) { (void)user_data; (void)code;
host_log((int)severity, category_name(event), message);
// Non-zero consumes the record. Return zero instead to let MapLibre's own // platform logger print it as well. return 1;}One callback serves the whole process rather than one runtime, and MapLibre stores it by reference. Install it before the first runtime exists to catch setup records, and keep it valid until you replace or clear it.
// The process-global callback remains valid for every runtime's lifetime.return mln_log_set_callback(forward_to_host, NULL);The callback runs on MapLibre’s threads
Section titled “The callback runs on MapLibre’s threads”MapLibre invokes the callback on the thread that produced the record, including worker and network threads. The callback can run while MapLibre holds logging locks.
Make the callback thread-safe and return quickly. Do not call a MapLibre function from the callback; the call can deadlock. Copy and queue the record before returning when the host needs more processing.
Synchronous and asynchronous records
Section titled “Synchronous and asynchronous records”Errors reach the callback synchronously. Informational and warning records may arrive after the work that produced them. Asynchronous delivery keeps MapLibre threads available while the host logger runs.
Clear the mask when every record must be ordered with the call that produced it, such as in a log assertion. Production hosts usually keep the default because synchronous delivery blocks MapLibre threads on the host logger.
// Errors are already synchronous by default. Clearing the other bits orders// every record against the call that produced it, at the cost of blocking// MapLibre's threads on the host logger.return mln_log_set_async_severity_mask(0);