diff --git a/Cargo.lock b/Cargo.lock
index 4dd8a95..8cc3820 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -85,6 +85,12 @@ version = "0.2.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "fc7eb209b1518d6bb87b283c20095f5228ecda460da70b44f0802523dea6da04"
 
+[[package]]
+name = "android-tzdata"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0"
+
 [[package]]
 name = "android_system_properties"
 version = "0.1.5"
@@ -497,6 +503,20 @@ dependencies = [
  "num-traits",
 ]
 
+[[package]]
+name = "chrono"
+version = "0.4.40"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1a7964611d71df112cb1730f2ee67324fcf4d0fc6606acbbe9bfe06df124637c"
+dependencies = [
+ "android-tzdata",
+ "iana-time-zone",
+ "js-sys",
+ "num-traits",
+ "wasm-bindgen",
+ "windows-link",
+]
+
 [[package]]
 name = "codespan-reporting"
 version = "0.12.0"
@@ -990,6 +1010,30 @@ version = "0.2.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "dfa686283ad6dd069f105e5ab091b04c62850d3e4cf5d67debad1933f55023df"
 
+[[package]]
+name = "iana-time-zone"
+version = "0.1.63"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b0c919e5debc312ad217002b8048a17b7d83f80703865bbfcfebb0458b0b27d8"
+dependencies = [
+ "android_system_properties",
+ "core-foundation-sys",
+ "iana-time-zone-haiku",
+ "js-sys",
+ "log",
+ "wasm-bindgen",
+ "windows-core",
+]
+
+[[package]]
+name = "iana-time-zone-haiku"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f"
+dependencies = [
+ "cc",
+]
+
 [[package]]
 name = "image"
 version = "0.25.6"
@@ -3268,6 +3312,12 @@ dependencies = [
  "syn",
 ]
 
+[[package]]
+name = "windows-link"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38"
+
 [[package]]
 name = "windows-result"
 version = "0.2.0"
@@ -3694,7 +3744,10 @@ dependencies = [
 name = "zlog"
 version = "0.1.0"
 dependencies = [
+ "chrono",
  "pretty_assertions",
+ "serde",
+ "serde_json",
  "tracing",
  "tracing-subscriber",
 ]
diff --git a/subcrates/zlog/Cargo.toml b/subcrates/zlog/Cargo.toml
index f55e6de..b8e90fc 100644
--- a/subcrates/zlog/Cargo.toml
+++ b/subcrates/zlog/Cargo.toml
@@ -6,6 +6,14 @@ edition = "2024"
 [dependencies]
 tracing = "0.1.41"
 tracing-subscriber = "0.3.19"
+serde = { version = "1.0.219", optional = true }
+serde_json = { version = "1.0.140", optional = true }
+chrono = { version = "0.4.40", optional = true }
 
 [dev-dependencies]
 pretty_assertions = "1.4.1"
+
+[features]
+default = ["json"]
+json = ["dep:serde_json", "dep:chrono", "serde"]
+serde = ["dep:serde"]
\ No newline at end of file
diff --git a/subcrates/zlog/src/config.rs b/subcrates/zlog/src/config.rs
index bb3fb76..dc50fbe 100644
--- a/subcrates/zlog/src/config.rs
+++ b/subcrates/zlog/src/config.rs
@@ -12,6 +12,11 @@ pub struct LoggerConfig {
     pub(crate) stdout_include_time: bool,
     pub(crate) file_include_time: bool,
     pub(crate) crate_max_level: Option<LogLevel>,
+    pub(crate) log_use_json: bool,
+    pub(crate) log_json_show_timestamp: bool,
+    pub(crate) log_json_show_level: bool,
+    pub(crate) log_json_show_message: bool,
+    pub(crate) log_json_show_additional_fields: bool,
 }
 
 impl LoggerConfig {
@@ -49,6 +54,31 @@ impl LoggerConfig {
         self.file_include_time = i;
         self
     }
+
+    pub fn log_use_json(mut self, i: bool) -> Self {
+        self.log_use_json = i;
+        self
+    }
+
+    pub fn log_json_show_timestamp(mut self, i: bool) -> Self {
+        self.log_json_show_timestamp = i;
+        self
+    }
+
+    pub fn log_json_show_level(mut self, i: bool) -> Self {
+        self.log_json_show_level = i;
+        self
+    }
+
+    pub fn log_json_show_message(mut self, i: bool) -> Self {
+        self.log_json_show_message = i;
+        self
+    }
+    
+    pub fn log_json_show_additional_fields(mut self, i: bool) -> Self {
+        self.log_json_show_additional_fields = i;
+        self
+    }
 }
 
 impl Default for LoggerConfig {
@@ -62,6 +92,11 @@ impl Default for LoggerConfig {
             stdout_color: true,
             stdout_include_time: false,
             file_include_time: false,
+            log_use_json: false,
+            log_json_show_timestamp: false,
+            log_json_show_level: false,
+            log_json_show_message: false,
+            log_json_show_additional_fields: false
         }
     }
 }
diff --git a/subcrates/zlog/src/lib.rs b/subcrates/zlog/src/lib.rs
index c069b34..e6b64a4 100644
--- a/subcrates/zlog/src/lib.rs
+++ b/subcrates/zlog/src/lib.rs
@@ -25,6 +25,15 @@ use tracing_subscriber::{
     util::SubscriberInitExt,
 };
 
+#[cfg(feature = "json")]
+use serde::{Deserialize, Serialize};
+
+#[cfg(feature = "json")]
+use serde_json::Value;
+
+#[cfg(feature = "json")]
+use chrono::{DateTime, Utc};
+
 #[derive(Debug, Clone, PartialEq, Eq)]
 enum LogEvent {
     Log(LogEntry),
@@ -36,6 +45,8 @@ pub struct LogEntry {
     timestamp: SystemTime,
     level: Level,
     message: String,
+    #[cfg(feature = "json")]
+    additional_fields: serde_json::Map<String, Value>,
 }
 
 impl PartialOrd for LogEntry {
@@ -91,6 +102,8 @@ where
         let metadata = event.metadata();
         let level = *metadata.level();
         let timestamp = SystemTime::now();
+        #[cfg(feature = "json")]
+        let additional_fields = serde_json::Map::new();
         let mut message = String::new();
         let mut visitor = LogVisitor::new(&mut message);
         event.record(&mut visitor);
@@ -99,6 +112,8 @@ where
             timestamp,
             level,
             message,
+            #[cfg(feature = "json")]
+            additional_fields
         });
 
         if let LogEvent::Log(ref entry) = log_entry {
@@ -189,20 +204,19 @@ impl Logger {
         let mut senders = Vec::new();
         let mut handles = Vec::new();
 
-        if config.log_to_stdout {
+        if config.log_to_stdout || config.log_use_json {
             let (tx, rx) = mpsc::channel();
             senders.push(tx);
             let config_clone = config.clone();
             let handle = thread::spawn(move || {
                 for msg in rx {
                     match msg {
-                        LogEvent::Log(entry) => {
+                        LogEvent::Log(mut entry) => {
                             println!(
                                 "{}",
                                 format_entry(
-                                    &entry,
-                                    config_clone.stdout_color,
-                                    config_clone.stdout_include_time
+                                    &mut entry,
+                                    &config_clone
                                 )
                             );
                         }
@@ -216,8 +230,8 @@ impl Logger {
         if config.log_to_file {
             let (tx, rx) = mpsc::channel();
             senders.push(tx);
+            let config_clone = config.clone();
             let path = config.log_file_path.clone();
-            let include_time = config.file_include_time;
             let handle = thread::spawn(move || {
                 let file = OpenOptions::new()
                     .append(true)
@@ -227,8 +241,8 @@ impl Logger {
                 let mut writer = BufWriter::new(file);
                 for msg in rx {
                     match msg {
-                        LogEvent::Log(entry) => {
-                            let line = format_entry(&entry, false, include_time);
+                        LogEvent::Log(mut entry) => {
+                            let line = format_entry(&mut entry, &config_clone);
                             writeln!(writer, "{}", line).expect("Failed to write to log file");
                             writer.flush().expect("Failed to flush log file");
                         }
@@ -280,8 +294,20 @@ impl Drop for Logger {
     }
 }
 
-fn format_entry(entry: &LogEntry, use_color: bool, _: bool) -> String {
-    let lvl = if use_color {
+fn format_entry(entry: &mut LogEntry, log_config: &LoggerConfig) -> String {
+    if log_config.log_use_json {
+        return format_entry_json(entry, log_config);
+    }
+    
+    if log_config.log_to_stdout || log_config.log_to_file {
+        return format_entry_string(entry, log_config);
+    } else {
+        return String::new();
+    } 
+}
+
+fn format_entry_string(entry: &LogEntry, log_config: &LoggerConfig) -> String {
+    let lvl = if log_config.stdout_color {
         match entry.level {
             Level::ERROR => "\x1b[31mERROR\x1b[0m",
             Level::WARN => "\x1b[33mWARN\x1b[0m",
@@ -295,3 +321,26 @@ fn format_entry(entry: &LogEntry, use_color: bool, _: bool) -> String {
 
     format!("{} {}", lvl, entry.message)
 }
+
+/// Formats the log entry as a json object ([`serde_json`]) and returns it as a [`String`]
+fn format_entry_json(entry: &mut LogEntry, log_config: &LoggerConfig) -> String {
+    let mut json_object = serde_json::Map::new();
+
+    if log_config.log_json_show_timestamp {
+        json_object.insert("timestamp".to_string(), Value::String(DateTime::<Utc>::from(entry.timestamp).to_rfc3339()));
+    }
+
+    if log_config.log_json_show_level {
+        json_object.insert("level".to_string(), Value::String(entry.level.to_string()));
+    }
+
+    if log_config.log_json_show_message {
+        json_object.insert("message".to_string(), Value::String(entry.message.to_string()));
+    }
+
+    if log_config.log_json_show_additional_fields {
+        json_object.append(&mut entry.additional_fields);
+    }
+
+    serde_json::to_string(&json_object).unwrap()
+}
\ No newline at end of file
diff --git a/subcrates/zlog/src/tests.rs b/subcrates/zlog/src/tests.rs
index a6a6542..13c90ab 100644
--- a/subcrates/zlog/src/tests.rs
+++ b/subcrates/zlog/src/tests.rs
@@ -1,5 +1,7 @@
 use pretty_assertions::assert_eq;
 use tracing::Level;
+use serde_json::Map;
+use serde::{Serialize, Deserialize};
 
 use super::*;
 
@@ -90,3 +92,48 @@ fn test_logger_sequential_consistency() {
     counts.dedup();
     assert_eq!(counts.len(), 4096 * 128, "Found duplicate log entries");
 }
+
+#[test]
+fn test_logger_sequential_consistency_json() {
+    use std::sync::atomic::{AtomicUsize, Ordering};
+
+    use tracing::{debug, error, info, trace, warn};
+
+    let config = LoggerConfig::default()
+        .log_to_stdout(false)
+        .log_to_file(false)
+        .log_use_json(true)
+        .log_json_show_timestamp(true)
+        .log_json_show_level(true)
+        .log_json_show_message(true)
+        .log_json_show_additional_fields(false); // Not implemented yet
+    let logger = Logger::new(config);
+
+    static COUNTER: AtomicUsize = AtomicUsize::new(0);
+
+    for i in 0..4096 * 128 {
+        let count = COUNTER.fetch_add(1, Ordering::SeqCst);
+        match i % 5 {
+            0 => error!("Error message {}", count),
+            1 => warn!("Warning message {}", count),
+            2 => info!("Info message {}", count),
+            3 => debug!("Debug message {}", count),
+            _ => trace!("Trace message {}", count),
+        }
+    }
+
+    let mut log_json: Vec<Map<String, Value>> = vec![];
+
+    for log in logger.get_logs(LogQuery::All) {
+        let mut json_object = serde_json::Map::new();
+        json_object.insert("timestamp".to_string(), Value::String(DateTime::<Utc>::from(log.timestamp).to_rfc3339()));
+        json_object.insert("level".to_string(), Value::String(log.level.to_string()));
+        json_object.insert("message".to_string(), Value::String(log.message.to_string()));
+
+        log_json.push(json_object);
+    }
+
+    for log in log_json {
+        serde_json::to_string(&log).unwrap();
+    }
+}
\ No newline at end of file