diff --git a/src/database.rs b/src/database.rs
index 51c3895ad8905f3a9a2ad2b0a2553453d6095bf6..3f860c9684e496a62cdb2657f4fdd756c595e11f 100644
--- a/src/database.rs
+++ b/src/database.rs
@@ -39,7 +39,7 @@ impl Database {
     /// Tries to remove the old database but ignores all errors.
     pub fn try_remove(server_name: &str) -> Result<()> {
         let mut path = ProjectDirs::from("xyz", "koesters", "conduit")
-            .ok_or(Error::BadConfig(
+            .ok_or_else(|| Error::bad_config(
                 "The OS didn't return a valid home directory path.",
             ))?
             .data_dir()
@@ -59,7 +59,7 @@ pub fn load_or_create(config: &Config) -> Result<Self> {
             .map(|x| Ok::<_, Error>(x.to_owned()))
             .unwrap_or_else(|_| {
                 let path = ProjectDirs::from("xyz", "koesters", "conduit")
-                    .ok_or(Error::BadConfig(
+                    .ok_or_else(|| Error::bad_config(
                         "The OS didn't return a valid home directory path.",
                     ))?
                     .data_dir()
@@ -67,7 +67,7 @@ pub fn load_or_create(config: &Config) -> Result<Self> {
 
                 Ok(path
                     .to_str()
-                    .ok_or(Error::BadConfig("Database path contains invalid unicode."))?
+                    .ok_or_else(|| Error::bad_config("Database path contains invalid unicode."))?
                     .to_owned())
             })?;
 
@@ -79,7 +79,7 @@ pub fn load_or_create(config: &Config) -> Result<Self> {
                         .get_int("cache_capacity")
                         .unwrap_or(1024 * 1024 * 1024),
                 )
-                .map_err(|_| Error::BadConfig("Cache capacity needs to be a u64."))?,
+                .map_err(|_| Error::bad_config("Cache capacity needs to be a u64."))?,
             )
             .print_profile_on_drop(false)
             .open()?;
diff --git a/src/database/globals.rs b/src/database/globals.rs
index 37f10eec44041679b1bc9fdfd1986830a1c943ee..359d0643e59fc033d323d661fc4bebaeec1b9868 100644
--- a/src/database/globals.rs
+++ b/src/database/globals.rs
@@ -62,12 +62,12 @@ pub fn load(globals: sled::Tree, config: &rocket::Config) -> Result<Self> {
                 .unwrap_or("localhost")
                 .to_string()
                 .try_into()
-                .map_err(|_| Error::BadConfig("Invalid server_name."))?,
+                .map_err(|_| Error::bad_config("Invalid server_name."))?,
             max_request_size: config
                 .get_int("max_request_size")
                 .unwrap_or(20 * 1024 * 1024) // Default to 20 MB
                 .try_into()
-                .map_err(|_| Error::BadConfig("Invalid max_request_size."))?,
+                .map_err(|_| Error::bad_config("Invalid max_request_size."))?,
             registration_disabled: config.get_bool("registration_disabled").unwrap_or(false),
             encryption_disabled: config.get_bool("encryption_disabled").unwrap_or(false),
             federation_enabled: config.get_bool("federation_enabled").unwrap_or(false),
diff --git a/src/error.rs b/src/error.rs
index f521da43de37a02a2694c1d4427b8c957efafd87..d54b3faa79106f508abe1cfab063f9290fbdbf39 100644
--- a/src/error.rs
+++ b/src/error.rs
@@ -1,7 +1,14 @@
+use std::{time::Duration, collections::HashMap, sync::RwLock, time::Instant};
+
 use log::error;
-use ruma::api::client::{error::ErrorKind, r0::uiaa::UiaaInfo};
+use ruma::{
+    api::client::{error::ErrorKind, r0::uiaa::UiaaInfo},
+    events::room::message,
+};
 use thiserror::Error;
 
+use crate::{database::admin::AdminCommand, Database};
+
 #[cfg(feature = "conduit_bin")]
 use {
     crate::RumaResponse,
@@ -53,6 +60,11 @@ pub fn bad_database(message: &'static str) -> Self {
         error!("BadDatabase: {}", message);
         Self::BadDatabase(message)
     }
+
+    pub fn bad_config(message: &'static str) -> Self {
+        error!("BadConfig: {}", message);
+        Self::BadConfig(message)
+    }
 }
 
 #[cfg(feature = "conduit_bin")]
@@ -95,3 +107,50 @@ fn respond_to(self, r: &'r Request<'_>) -> response::Result<'o> {
         .respond_to(r)
     }
 }
+
+pub struct ConduitLogger {
+    pub db: Database,
+    pub last_logs: RwLock<HashMap<String, Instant>>,
+}
+
+impl log::Log for ConduitLogger {
+    fn enabled(&self, _metadata: &log::Metadata<'_>) -> bool {
+        true
+    }
+
+    fn log(&self, record: &log::Record<'_>) {
+        let output = format!("{} - {}", record.level(), record.args());
+
+        println!("{}", output);
+
+        if self.enabled(record.metadata())
+            && record
+                .module_path()
+                .map_or(false, |path| path.starts_with("conduit::"))
+        {
+            if self
+                .last_logs
+                .read()
+                .unwrap()
+                .get(&output)
+                .map_or(false, |i| i.elapsed() < Duration::from_secs(60 * 30))
+            {
+                return;
+            }
+
+            if let Ok(mut_last_logs) = &mut self.last_logs.try_write() {
+                mut_last_logs.insert(output.clone(), Instant::now());
+            }
+
+            self.db.admin.send(AdminCommand::SendTextMessage(
+                message::TextMessageEventContent {
+                    body: output,
+                    formatted: None,
+                    relates_to: None,
+                },
+            ));
+        }
+    }
+
+    fn flush(&self) {}
+}
diff --git a/src/main.rs b/src/main.rs
index 8fb5fda9ff9b1f13be3b1f695d31b7820af99d8a..f2edc1373a49c1108f277ee589591379d9e38b6c 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -11,7 +11,8 @@
 mod utils;
 
 pub use database::Database;
-pub use error::{Error, Result};
+pub use error::{ConduitLogger, Error, Result};
+use log::LevelFilter;
 pub use pdu::PduEvent;
 pub use rocket::State;
 pub use ruma_wrapper::{ConduitResult, Ruma, RumaResponse};
@@ -19,6 +20,9 @@
 use rocket::{fairing::AdHoc, routes};
 
 fn setup_rocket() -> rocket::Rocket {
+    // Force log level off, so we can use our own logger
+    std::env::set_var("ROCKET_LOG", "off");
+
     rocket::ignite()
         .mount(
             "/",
@@ -133,6 +137,12 @@ fn setup_rocket() -> rocket::Rocket {
             let data = Database::load_or_create(rocket.config().await).expect("valid config");
 
             data.sending.start_handler(&data.globals, &data.rooms);
+            log::set_boxed_logger(Box::new(ConduitLogger {
+                db: data.clone(),
+                last_logs: Default::default(),
+            }))
+            .unwrap();
+            log::set_max_level(LevelFilter::Info);
 
             Ok(rocket.manage(data))
         }))
@@ -140,10 +150,5 @@ fn setup_rocket() -> rocket::Rocket {
 
 #[rocket::main]
 async fn main() {
-    // Default log level
-    if std::env::var("ROCKET_LOG").is_err() {
-        std::env::set_var("ROCKET_LOG", "critical");
-    }
-
     setup_rocket().launch().await.unwrap();
 }
diff --git a/src/ruma_wrapper.rs b/src/ruma_wrapper.rs
index 7722a4256af431243bbd20dbaccd50efabeb19d5..8da3e17bb6a0573e75a6550530c76d9dce553513 100644
--- a/src/ruma_wrapper.rs
+++ b/src/ruma_wrapper.rs
@@ -97,7 +97,7 @@ fn from_data(
             handle.read_to_end(&mut body).await.unwrap();
 
             let http_request = http_request.body(body.clone()).unwrap();
-            log::info!("{:?}", http_request);
+            log::debug!("{:?}", http_request);
 
             match <T as Outgoing>::Incoming::try_from(http_request) {
                 Ok(t) => Success(Ruma {
diff --git a/src/server_server.rs b/src/server_server.rs
index 0f24e15323373e0903bd86f80ed582c144ae4a9a..0649bed199bc9f869a62fd4350e2c13751858859 100644
--- a/src/server_server.rs
+++ b/src/server_server.rs
@@ -58,12 +58,12 @@ pub async fn send_request<T: OutgoingRequest>(
     T: Debug,
 {
     if !globals.federation_enabled() {
-        return Err(Error::BadConfig("Federation is disabled."));
+        return Err(Error::bad_config("Federation is disabled."));
     }
 
     let resolver = AsyncResolver::tokio_from_system_conf()
         .await
-        .map_err(|_| Error::BadConfig("Failed to set up trust dns resolver with system config."))?;
+        .map_err(|_| Error::bad_config("Failed to set up trust dns resolver with system config."))?;
 
     let mut host = None;
 
@@ -213,7 +213,7 @@ pub async fn send_request<T: OutgoingRequest>(
 #[cfg_attr(feature = "conduit_bin", get("/_matrix/federation/v1/version"))]
 pub fn get_server_version(db: State<'_, Database>) -> ConduitResult<get_server_version::Response> {
     if !db.globals.federation_enabled() {
-        return Err(Error::BadConfig("Federation is disabled."));
+        return Err(Error::bad_config("Federation is disabled."));
     }
 
     Ok(get_server_version::Response {
@@ -276,7 +276,7 @@ pub async fn get_public_rooms_filtered_route(
     body: Ruma<get_public_rooms_filtered::v1::Request<'_>>,
 ) -> ConduitResult<get_public_rooms_filtered::v1::Response> {
     if !db.globals.federation_enabled() {
-        return Err(Error::BadConfig("Federation is disabled."));
+        return Err(Error::bad_config("Federation is disabled."));
     }
 
     let response = client_server::get_public_rooms_filtered_helper(
@@ -323,7 +323,7 @@ pub async fn get_public_rooms_route(
     body: Ruma<get_public_rooms::v1::Request<'_>>,
 ) -> ConduitResult<get_public_rooms::v1::Response> {
     if !db.globals.federation_enabled() {
-        return Err(Error::BadConfig("Federation is disabled."));
+        return Err(Error::bad_config("Federation is disabled."));
     }
 
     let response = client_server::get_public_rooms_filtered_helper(
@@ -370,7 +370,7 @@ pub fn send_transaction_message_route<'a>(
     body: Ruma<send_transaction_message::v1::Request<'_>>,
 ) -> ConduitResult<send_transaction_message::v1::Response> {
     if !db.globals.federation_enabled() {
-        return Err(Error::BadConfig("Federation is disabled."));
+        return Err(Error::bad_config("Federation is disabled."));
     }
 
     //dbg!(&*body);
@@ -423,7 +423,7 @@ pub fn get_missing_events_route<'a>(
     body: Ruma<get_missing_events::v1::Request<'_>>,
 ) -> ConduitResult<get_missing_events::v1::Response> {
     if !db.globals.federation_enabled() {
-        return Err(Error::BadConfig("Federation is disabled."));
+        return Err(Error::bad_config("Federation is disabled."));
     }
 
     let mut queued_events = body.latest_events.clone();
@@ -468,7 +468,7 @@ pub fn get_profile_information_route<'a>(
     body: Ruma<get_profile_information::v1::Request<'_>>,
 ) -> ConduitResult<get_profile_information::v1::Response> {
     if !db.globals.federation_enabled() {
-        return Err(Error::BadConfig("Federation is disabled."));
+        return Err(Error::bad_config("Federation is disabled."));
     }
 
     let mut displayname = None;
@@ -500,7 +500,7 @@ pub fn get_user_devices_route<'a>(
     body: Ruma<membership::v1::Request<'_>>,
 ) -> ConduitResult<get_profile_information::v1::Response> {
     if !db.globals.federation_enabled() {
-        return Err(Error::BadConfig("Federation is disabled."));
+        return Err(Error::bad_config("Federation is disabled."));
     }
 
     let mut displayname = None;