diff --git a/inc/liblektor-rs/loging.h b/inc/liblektor-rs/loging.h
new file mode 100644
index 0000000000000000000000000000000000000000..7bc84a6affb48ea3f7dc2c7c1a08fad4708a2e8f
--- /dev/null
+++ b/inc/liblektor-rs/loging.h
@@ -0,0 +1,14 @@
+#if !defined(LIBLEKTOR_RS_LOGING___)
+#define LIBLEKTOR_RS_LOGING___
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+void lektor_init_rust_logging(void);
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif // LIBLEKTOR_RS_LOGING___
diff --git a/src/main/server.c b/src/main/server.c
index e36d292568e4b4a2818075d628ea3cbffb589943..865cdea43f3bd1939807eb771d070d53262f198b 100644
--- a/src/main/server.c
+++ b/src/main/server.c
@@ -10,6 +10,7 @@
 #include <lektor/logfile.h>
 
 #include <liblektor-rs/database.h>
+#include <liblektor-rs/loging.h>
 
 #include <wait.h>
 #include <spawn.h>
@@ -105,6 +106,7 @@ main(int argc, char *argv[])
 
     struct lkt_logfile *logfile = lkt_logfile_new(srv.db);
     lkt_set_log_logfile(logfile);
+    lektor_init_rust_logging();
 
     /* Read the configuration. We already know that the config is valid */
     database_config_get_int(srv.db, "player", "autoclear", &autoclear);
diff --git a/src/rust/liblektor-rs/lektor_unsafe/Cargo.toml b/src/rust/liblektor-rs/lektor_unsafe/Cargo.toml
index fd41d724398af083e0efbfcfd91ad2ab8db16f7b..5bbff867e3aff47a096a4c0fc97a250b27a4d3ec 100644
--- a/src/rust/liblektor-rs/lektor_unsafe/Cargo.toml
+++ b/src/rust/liblektor-rs/lektor_unsafe/Cargo.toml
@@ -8,6 +8,7 @@ crate-type = ["staticlib"]
 
 [dependencies]
 log.workspace = true
+lazy_static.workspace = true
 
 lektor_c_compat = { path = "../lektor_c_compat", features = ["c_types"] }
 lektor_repo = { path = "../lektor_repo" }
diff --git a/src/rust/liblektor-rs/lektor_unsafe/src/lib.rs b/src/rust/liblektor-rs/lektor_unsafe/src/lib.rs
index b99c1a476084ed7c7fa9c8ffa79c1628365d77a9..7df01add86dfd15231e490be4e9abf2919f5ae26 100644
--- a/src/rust/liblektor-rs/lektor_unsafe/src/lib.rs
+++ b/src/rust/liblektor-rs/lektor_unsafe/src/lib.rs
@@ -4,6 +4,7 @@
 #![allow(unused_variables)]
 
 pub mod db;
+pub mod loging;
 pub mod repo;
 
 pub(crate) use lektor_c_compat::{c::*, *};
diff --git a/src/rust/liblektor-rs/lektor_unsafe/src/loging.rs b/src/rust/liblektor-rs/lektor_unsafe/src/loging.rs
new file mode 100644
index 0000000000000000000000000000000000000000..ef1682e668fa9c7f7b7fce6b38eb9b7bdefb7e31
--- /dev/null
+++ b/src/rust/liblektor-rs/lektor_unsafe/src/loging.rs
@@ -0,0 +1,139 @@
+use lektor_c_compat::*;
+use log::{Level, Metadata, Record};
+use std::{convert::Into, fmt::format, sync::atomic::AtomicU8};
+
+enum LogLevel {
+    Debug,
+    Info,
+    Warning,
+    Error,
+}
+
+struct CLogger {
+    level: AtomicU8,
+}
+
+lazy_static::lazy_static! {
+    static ref LOGGER: CLogger = CLogger {
+        level: AtomicU8::new(Into::<c_int>::into(LogLevel::Warning) as u8),
+    };
+}
+
+impl log::Log for CLogger {
+    fn enabled(&self, metadata: &Metadata) -> bool {
+        use LogLevel::*;
+        let lvl = LogLevel::try_from(LOGGER.level.load(std::sync::atomic::Ordering::SeqCst))
+            .unwrap_or_default();
+        matches!(
+            (lvl, LogLevel::from(metadata.level())),
+            (Debug, _)
+                | (Info, Info | Warning | Error)
+                | (Warning, Warning | Error)
+                | (Error, Error)
+        )
+    }
+
+    fn log(&self, record: &Record) {
+        if self.enabled(record.metadata()) {
+            unsafe {
+                ___lkt_log(
+                    LogLevel::from(record.metadata().level()).into(),
+                    (format!("{}\0", record.target())).as_ptr() as *const _,
+                    b"*unknown-func*\0".as_ptr() as *const _,
+                    (format!("{}\0", record.file_static().unwrap_or("..."))).as_ptr() as *const _,
+                    record.line().unwrap_or_default() as i64,
+                    b"%s\0".as_ptr() as *const _,
+                    match record.args().as_str() {
+                        Some(str) => format!("{str}\0"),
+                        None => format!("{}\0", format(*record.args())),
+                    },
+                )
+            }
+        }
+    }
+
+    fn flush(&self) {}
+}
+
+impl Default for LogLevel {
+    fn default() -> Self {
+        LogLevel::Info
+    }
+}
+
+impl From<Level> for LogLevel {
+    fn from(lvl: Level) -> Self {
+        use LogLevel::*;
+        match lvl {
+            Level::Error => Error,
+            Level::Warn => Warning,
+            Level::Info => Info,
+            Level::Debug | Level::Trace => Debug,
+        }
+    }
+}
+
+impl From<LogLevel> for u8 {
+    fn from(lvl: LogLevel) -> Self {
+        match lvl {
+            LogLevel::Debug => 4,
+            LogLevel::Info => 3,
+            LogLevel::Warning => 2,
+            LogLevel::Error => 1,
+        }
+    }
+}
+
+impl From<LogLevel> for c_int {
+    fn from(lvl: LogLevel) -> Self {
+        (lvl as u8) as c_int
+    }
+}
+
+impl TryFrom<c_int> for LogLevel {
+    type Error = ();
+
+    fn try_from(value: c_int) -> Result<Self, <LogLevel as TryFrom<c_int>>::Error> {
+        use LogLevel::*;
+        match value {
+            1 => Ok(Error),
+            2 => Ok(Warning),
+            3 => Ok(Info),
+            4 => Ok(Debug),
+            _ => Err(()),
+        }
+    }
+}
+
+impl TryFrom<u8> for LogLevel {
+    type Error = ();
+
+    fn try_from(value: u8) -> Result<Self, <LogLevel as TryFrom<c_int>>::Error> {
+        TryFrom::<c_int>::try_from(value as c_int)
+    }
+}
+
+extern "C" {
+    fn ___lkt_log(
+        log_level: c_int,
+        section: *const c_char,
+        function: *const c_char,
+        file: *const c_char,
+        line: i64,
+        fmt: *const c_char,
+        ...
+    );
+
+    fn lkt_get_log_level() -> c_int;
+}
+
+#[no_mangle]
+pub extern "C" fn lektor_init_rust_logging() {
+    LOGGER.level.store(
+        Into::<u8>::into(LogLevel::try_from(unsafe { lkt_get_log_level() }).unwrap_or_default()),
+        std::sync::atomic::Ordering::SeqCst,
+    );
+    if let Err(err) = log::set_logger(&*LOGGER) {
+        panic!("failed to set logger: {err}")
+    }
+}