diff --git a/src/MauiDevFlow.Agent.Core/AgentOptions.cs b/src/MauiDevFlow.Agent.Core/AgentOptions.cs
index 854787e..0a3aa1c 100644
--- a/src/MauiDevFlow.Agent.Core/AgentOptions.cs
+++ b/src/MauiDevFlow.Agent.Core/AgentOptions.cs
@@ -29,6 +29,13 @@ public class AgentOptions
///
public bool EnableFileLogging { get; set; } = true;
+ ///
+ /// Whether to register the FileLogProvider as an ILoggerProvider so that
+ /// ILogger output is written to the rotating log files. Default: true.
+ /// Requires to be true.
+ ///
+ public bool CaptureILogger { get; set; } = true;
+
///
/// Maximum size of each log file in bytes before rotation. Default: 1MB.
///
@@ -39,6 +46,19 @@ public class AgentOptions
///
public int MaxLogFiles { get; set; } = 5;
+ ///
+ /// Whether to capture Console.Out and Console.Error output into the file log pipeline.
+ /// Output is tee'd — original streams still receive everything. Default: true.
+ /// Requires to be true.
+ ///
+ public bool CaptureConsole { get; set; } = true;
+
+ ///
+ /// Whether to capture Trace/Debug output into the file log pipeline. Default: true.
+ /// Requires to be true.
+ ///
+ public bool CaptureTrace { get; set; } = true;
+
///
/// Whether to intercept HttpClient requests for network monitoring. Default: true.
/// When enabled, all IHttpClientFactory-created HttpClients are automatically monitored.
diff --git a/src/MauiDevFlow.Agent.Gtk/GtkAgentServiceExtensions.cs b/src/MauiDevFlow.Agent.Gtk/GtkAgentServiceExtensions.cs
index 3326e6c..991125e 100644
--- a/src/MauiDevFlow.Agent.Gtk/GtkAgentServiceExtensions.cs
+++ b/src/MauiDevFlow.Agent.Gtk/GtkAgentServiceExtensions.cs
@@ -72,7 +72,15 @@ public static MauiAppBuilder AddMauiDevFlowAgent(this MauiAppBuilder builder, Ac
"mauidevflow-logs");
var logProvider = new FileLogProvider(logDir, options.MaxLogFileSize, options.MaxLogFiles);
service.SetLogProvider(logProvider);
- builder.Logging.AddProvider(logProvider);
+
+ if (options.CaptureILogger)
+ builder.Logging.AddProvider(logProvider);
+
+ if (options.CaptureConsole || options.CaptureTrace)
+ {
+ var capture = new ConsoleLogCapture(logProvider.Writer);
+ capture.Install(captureConsole: options.CaptureConsole, captureTrace: options.CaptureTrace);
+ }
}
if (options.EnableNetworkMonitoring)
diff --git a/src/MauiDevFlow.Agent/AgentServiceExtensions.cs b/src/MauiDevFlow.Agent/AgentServiceExtensions.cs
index 68349c7..8bb094d 100644
--- a/src/MauiDevFlow.Agent/AgentServiceExtensions.cs
+++ b/src/MauiDevFlow.Agent/AgentServiceExtensions.cs
@@ -95,7 +95,15 @@ public static MauiAppBuilder AddMauiDevFlowAgent(this MauiAppBuilder builder, Ac
var logDir = Path.Combine(FileSystem.CacheDirectory, "mauidevflow-logs");
var logProvider = new FileLogProvider(logDir, options.MaxLogFileSize, options.MaxLogFiles);
service.SetLogProvider(logProvider);
- builder.Logging.AddProvider(logProvider);
+
+ if (options.CaptureILogger)
+ builder.Logging.AddProvider(logProvider);
+
+ if (options.CaptureConsole || options.CaptureTrace)
+ {
+ var capture = new ConsoleLogCapture(logProvider.Writer);
+ capture.Install(captureConsole: options.CaptureConsole, captureTrace: options.CaptureTrace);
+ }
}
// Auto-inject network monitoring handler into all IHttpClientFactory-created clients
diff --git a/src/MauiDevFlow.Logging/ConsoleLogCapture.cs b/src/MauiDevFlow.Logging/ConsoleLogCapture.cs
new file mode 100644
index 0000000..3bc634b
--- /dev/null
+++ b/src/MauiDevFlow.Logging/ConsoleLogCapture.cs
@@ -0,0 +1,232 @@
+using System.Diagnostics;
+using System.Text;
+
+namespace MauiDevFlow.Logging;
+
+///
+/// Captures Console.Write/WriteLine and Trace/Debug output into the FileLogWriter pipeline.
+/// Output is tee'd — the original console stream still receives everything.
+/// Call once after the FileLogWriter is available.
+/// Call (or Dispose) to restore original streams and listeners.
+///
+public sealed class ConsoleLogCapture : IDisposable
+{
+ private readonly FileLogWriter _writer;
+ private readonly TextWriter _originalOut;
+ private readonly TextWriter _originalError;
+ private readonly LogTextWriter _outWriter;
+ private readonly LogTextWriter _errorWriter;
+ private readonly LogTraceListener _traceListener;
+ private volatile bool _installed;
+ private volatile bool _disposed;
+
+ public ConsoleLogCapture(FileLogWriter writer)
+ {
+ _writer = writer;
+ _originalOut = Console.Out;
+ _originalError = Console.Error;
+ _outWriter = new LogTextWriter(_originalOut, writer, "console.out");
+ _errorWriter = new LogTextWriter(_originalError, writer, "console.error");
+ _traceListener = new LogTraceListener(writer);
+ }
+
+ ///
+ /// Redirects Console.Out, Console.Error, and/or adds a TraceListener based on flags.
+ /// Safe to call multiple times — only installs once.
+ ///
+ public void Install(bool captureConsole = true, bool captureTrace = true)
+ {
+ if (_installed || _disposed) return;
+ _installed = true;
+
+ if (captureConsole)
+ {
+ Console.SetOut(_outWriter);
+ Console.SetError(_errorWriter);
+ }
+
+ if (captureTrace)
+ {
+ Trace.Listeners.Add(_traceListener);
+ }
+ }
+
+ ///
+ /// Restores original Console streams and removes the TraceListener.
+ ///
+ public void Uninstall()
+ {
+ if (!_installed) return;
+ _installed = false;
+
+ Console.SetOut(_originalOut);
+ Console.SetError(_originalError);
+ Trace.Listeners.Remove(_traceListener);
+ }
+
+ public void Dispose()
+ {
+ if (_disposed) return;
+ _disposed = true;
+ Uninstall();
+ }
+
+ ///
+ /// A TextWriter that tees output to both the original stream and the FileLogWriter.
+ /// Buffers partial writes and flushes complete lines as log entries.
+ ///
+ private sealed class LogTextWriter : TextWriter
+ {
+ private readonly TextWriter _inner;
+ private readonly FileLogWriter _logWriter;
+ private readonly string _source;
+ private readonly StringBuilder _lineBuffer = new();
+ private readonly object _lock = new();
+
+ public LogTextWriter(TextWriter inner, FileLogWriter logWriter, string source)
+ {
+ _inner = inner;
+ _logWriter = logWriter;
+ _source = source;
+ }
+
+ public override Encoding Encoding => _inner.Encoding;
+
+ public override void Write(char value)
+ {
+ _inner.Write(value);
+
+ lock (_lock)
+ {
+ if (value == '\n')
+ FlushLine();
+ else
+ _lineBuffer.Append(value);
+ }
+ }
+
+ public override void Write(string? value)
+ {
+ if (value == null) return;
+ _inner.Write(value);
+
+ lock (_lock)
+ {
+ foreach (var ch in value)
+ {
+ if (ch == '\n')
+ FlushLine();
+ else
+ _lineBuffer.Append(ch);
+ }
+ }
+ }
+
+ public override void WriteLine(string? value)
+ {
+ _inner.WriteLine(value);
+
+ lock (_lock)
+ {
+ _lineBuffer.Append(value);
+ FlushLine();
+ }
+ }
+
+ public override void WriteLine()
+ {
+ _inner.WriteLine();
+
+ lock (_lock)
+ {
+ FlushLine();
+ }
+ }
+
+ public override void Flush()
+ {
+ _inner.Flush();
+
+ lock (_lock)
+ {
+ if (_lineBuffer.Length > 0)
+ FlushLine();
+ }
+ }
+
+ private void FlushLine()
+ {
+ var line = _lineBuffer.ToString().TrimEnd('\r');
+ _lineBuffer.Clear();
+
+ if (string.IsNullOrEmpty(line)) return;
+
+ _logWriter.Write(new FileLogEntry(
+ Timestamp: DateTime.UtcNow,
+ Level: _source == "console.error" ? "Warning" : "Information",
+ Category: _source,
+ Message: line,
+ Source: _source
+ ));
+ }
+ }
+
+ ///
+ /// TraceListener that writes Trace/Debug output to the FileLogWriter.
+ ///
+ private sealed class LogTraceListener : TraceListener
+ {
+ private readonly FileLogWriter _logWriter;
+ private readonly StringBuilder _lineBuffer = new();
+ private readonly object _lock = new();
+
+ public LogTraceListener(FileLogWriter logWriter) : base("MauiDevFlowTrace")
+ {
+ _logWriter = logWriter;
+ }
+
+ public override void Write(string? message)
+ {
+ if (message == null) return;
+
+ lock (_lock)
+ {
+ _lineBuffer.Append(message);
+ }
+ }
+
+ public override void WriteLine(string? message)
+ {
+ lock (_lock)
+ {
+ _lineBuffer.Append(message);
+ FlushLine();
+ }
+ }
+
+ public override void Flush()
+ {
+ lock (_lock)
+ {
+ if (_lineBuffer.Length > 0)
+ FlushLine();
+ }
+ }
+
+ private void FlushLine()
+ {
+ var line = _lineBuffer.ToString();
+ _lineBuffer.Clear();
+
+ if (string.IsNullOrEmpty(line)) return;
+
+ _logWriter.Write(new FileLogEntry(
+ Timestamp: DateTime.UtcNow,
+ Level: "Debug",
+ Category: "trace",
+ Message: line,
+ Source: "trace"
+ ));
+ }
+ }
+}