Skip to content
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 55 additions & 0 deletions dotnet/src/webdriver/DriverService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using OpenQA.Selenium.Internal.Logging;

namespace OpenQA.Selenium;

Expand All @@ -37,6 +38,8 @@ public abstract class DriverService : ICommandServer
private bool isDisposed;
private Process? driverServiceProcess;

private static readonly ILogger _logger = Log.GetLogger(typeof(DriverService));

/// <summary>
/// Initializes a new instance of the <see cref="DriverService"/> class.
/// </summary>
Expand Down Expand Up @@ -151,6 +154,12 @@ public int ProcessId
/// </summary>
public string? DriverServicePath { get; set; }

/// <summary>
/// Collects the driver log output and writes it to the console. Defaults to <see langword="true"/>.
/// Internal variable to avoid using the stream when logs are sent to a file.
/// </summary>
protected bool WriteDriverLogToConsole { get; set; } = true;

/// <summary>
/// Gets the command-line arguments for the driver service.
/// </summary>
Expand Down Expand Up @@ -243,6 +252,9 @@ public void Start()
this.driverServiceProcess.StartInfo.UseShellExecute = false;
this.driverServiceProcess.StartInfo.CreateNoWindow = this.HideCommandPromptWindow;

this.driverServiceProcess.StartInfo.RedirectStandardOutput = this.WriteDriverLogToConsole;
this.driverServiceProcess.StartInfo.RedirectStandardError = this.WriteDriverLogToConsole;

DriverProcessStartingEventArgs eventArgs = new DriverProcessStartingEventArgs(this.driverServiceProcess.StartInfo);
this.OnDriverProcessStarting(eventArgs);

Expand Down Expand Up @@ -305,6 +317,16 @@ protected virtual void OnDriverProcessStarted(DriverProcessStartedEventArgs even
throw new ArgumentNullException(nameof(eventArgs), "eventArgs must not be null");
}

if (this.WriteDriverLogToConsole && eventArgs.StandardOutputStreamReader != null)
{
_ = Task.Run(() => ReadStreamAsync(eventArgs.StandardOutputStreamReader, "stdout"));
}

if (this.WriteDriverLogToConsole && eventArgs.StandardErrorStreamReader != null)
{
_ = Task.Run(() => ReadStreamAsync(eventArgs.StandardErrorStreamReader, "stderr"));
}

this.DriverProcessStarted?.Invoke(this, eventArgs);
}

Expand Down Expand Up @@ -386,4 +408,37 @@ private bool WaitForServiceInitialization()

return isInitialized;
}

private async Task ReadStreamAsync(StreamReader reader, string streamType)
{
try
{
string? line;
while ((line = await reader.ReadLineAsync()) != null)
{
if (streamType.Equals("stdout", StringComparison.OrdinalIgnoreCase))
{
if (_logger.IsEnabled(LogEventLevel.Info))
{
_logger.Info(line);
}
}
else
{
if (_logger.IsEnabled(LogEventLevel.Error))
{
_logger.Error(line);
}
}
}
}
catch (Exception ex)
{
if (_logger.IsEnabled(LogEventLevel.Error))
{
_logger.Error($"Error reading stream: {ex.Message}");
}
}
}

}
16 changes: 9 additions & 7 deletions dotnet/src/webdriver/Firefox/FirefoxDriverService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
using System.IO;
using System.Text;
using System.Threading.Tasks;
using OpenQA.Selenium.Internal.Logging;

namespace OpenQA.Selenium.Firefox;

Expand All @@ -32,6 +33,7 @@ namespace OpenQA.Selenium.Firefox;
public sealed class FirefoxDriverService : DriverService
{
private const string DefaultFirefoxDriverServiceFileName = "geckodriver";
private static readonly ILogger _logger = Log.GetLogger(typeof(FirefoxDriverService));

/// <summary>
/// Process management fields for the log writer.
Expand Down Expand Up @@ -204,16 +206,15 @@ protected override void OnDriverProcessStarting(DriverProcessStartingEventArgs e
{
if (!string.IsNullOrEmpty(this.LogPath))
{
this.WriteDriverLogToConsole = false;
string? directory = Path.GetDirectoryName(this.LogPath);
if (!string.IsNullOrEmpty(directory) && !Directory.Exists(directory))
{
Directory.CreateDirectory(directory);
}

// Initialize the log writer
logWriter = new StreamWriter(this.LogPath, append: true) { AutoFlush = true };

// Configure process to redirect output
eventArgs.DriverServiceProcessStartInfo.RedirectStandardOutput = true;
eventArgs.DriverServiceProcessStartInfo.RedirectStandardError = true;
}
Expand All @@ -230,13 +231,12 @@ protected override void OnDriverProcessStarting(DriverProcessStartingEventArgs e
/// </remarks>
protected override void OnDriverProcessStarted(DriverProcessStartedEventArgs eventArgs)
{
if (logWriter == null) return;
if (eventArgs.StandardOutputStreamReader != null)
if (!string.IsNullOrEmpty(this.LogPath) && eventArgs.StandardOutputStreamReader != null)
{
_ = Task.Run(() => ReadStreamAsync(eventArgs.StandardOutputStreamReader));
}

if (eventArgs.StandardErrorStreamReader != null)
if (!string.IsNullOrEmpty(this.LogPath) && eventArgs.StandardErrorStreamReader != null)
{
_ = Task.Run(() => ReadStreamAsync(eventArgs.StandardErrorStreamReader));
}
Expand Down Expand Up @@ -359,8 +359,10 @@ private async Task ReadStreamAsync(StreamReader reader)
}
catch (Exception ex)
{
// Log or handle the exception appropriately
System.Diagnostics.Debug.WriteLine($"Error reading stream: {ex.Message}");
if (_logger.IsEnabled(LogEventLevel.Error))
{
_logger.Error($"Error reading stream: {ex.Message}");
}
}
}
}
70 changes: 66 additions & 4 deletions dotnet/test/firefox/FirefoxDriverServiceTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,25 +17,52 @@
// under the License.
// </copyright>

using System;
using System.Collections.Generic;
using NUnit.Framework;
using System.IO;
using System.Linq;
using OpenQA.Selenium.Internal.Logging;

namespace OpenQA.Selenium.Firefox;

[TestFixture]
public class FirefoxDriverServiceTest : DriverTestFixture
public class FirefoxDriverServiceTest
{
private TestLogHandler testLogHandler;

private void ResetGlobalLog()
{
Log.SetLevel(LogEventLevel.Info);
Log.Handlers.Clear().Handlers.Add(new TextWriterHandler(Console.Error));
}

[SetUp]
public void SetUp()
{
ResetGlobalLog();

testLogHandler = new TestLogHandler();
}

[TearDown]
public void TearDown()
{
ResetGlobalLog();
}

[Test]
public void ShouldRedirectGeckoDriverLogsToFile()
{
FirefoxOptions options = new FirefoxOptions();
string logPath = Path.GetTempFileName();
options.LogLevel = FirefoxDriverLogLevel.Trace;
options.LogLevel = FirefoxDriverLogLevel.Info;

FirefoxDriverService service = FirefoxDriverService.CreateDefaultService();
service.LogPath = logPath;

IWebDriver driver2 = new FirefoxDriver(service, options);
IWebDriver firefoxDriver = new FirefoxDriver(service, options);
firefoxDriver.Quit();

try
{
Expand All @@ -45,9 +72,44 @@ public void ShouldRedirectGeckoDriverLogsToFile()
}
finally
{
driver2.Quit();
File.Delete(logPath);
}
}

[Test]
public void ShouldRedirectGeckoDriverLogsToConsole()
{
Log.SetLevel(LogEventLevel.Info).Handlers.Add(testLogHandler);
FirefoxOptions options = new FirefoxOptions();
options.LogLevel = FirefoxDriverLogLevel.Info;

FirefoxDriverService service = FirefoxDriverService.CreateDefaultService();

IWebDriver firefoxDriver = new FirefoxDriver(service, options);

try
{
Assert.That(testLogHandler.Events, Has.Count.AtLeast(1));
Assert.That(testLogHandler.Events.Any(e => e.Message.Contains("geckodriver")), Is.True);
}
finally
{
firefoxDriver.Quit();
}
}
}

class TestLogHandler : ILogHandler
{
public ILogHandler Clone()
{
return this;
}

public void Handle(LogEvent logEvent)
{
Events.Add(logEvent);
}

public IList<LogEvent> Events { get; internal set; } = new List<LogEvent>();
}
Loading