Skip to content

Commit 04f6eec

Browse files
committed
[dotnet] Sending GeckoDriver output to a log file.
Related to #12273
1 parent 79149e8 commit 04f6eec

File tree

2 files changed

+98
-2
lines changed

2 files changed

+98
-2
lines changed

dotnet/src/webdriver/DriverService.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -284,7 +284,7 @@ protected virtual void Dispose(bool disposing)
284284
/// Raises the <see cref="DriverProcessStarting"/> event.
285285
/// </summary>
286286
/// <param name="eventArgs">A <see cref="DriverProcessStartingEventArgs"/> that contains the event data.</param>
287-
protected void OnDriverProcessStarting(DriverProcessStartingEventArgs eventArgs)
287+
protected virtual void OnDriverProcessStarting(DriverProcessStartingEventArgs eventArgs)
288288
{
289289
if (eventArgs == null)
290290
{
@@ -298,7 +298,7 @@ protected void OnDriverProcessStarting(DriverProcessStartingEventArgs eventArgs)
298298
/// Raises the <see cref="DriverProcessStarted"/> event.
299299
/// </summary>
300300
/// <param name="eventArgs">A <see cref="DriverProcessStartedEventArgs"/> that contains the event data.</param>
301-
protected void OnDriverProcessStarted(DriverProcessStartedEventArgs eventArgs)
301+
protected virtual void OnDriverProcessStarted(DriverProcessStartedEventArgs eventArgs)
302302
{
303303
if (eventArgs == null)
304304
{

dotnet/src/webdriver/Firefox/FirefoxDriverService.cs

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
using System.Globalization;
2323
using System.IO;
2424
using System.Text;
25+
using System.Threading.Tasks;
2526

2627
namespace OpenQA.Selenium.Firefox;
2728

@@ -31,6 +32,11 @@ namespace OpenQA.Selenium.Firefox;
3132
public sealed class FirefoxDriverService : DriverService
3233
{
3334
private const string DefaultFirefoxDriverServiceFileName = "geckodriver";
35+
36+
/// <summary>
37+
/// Process management fields for the log writer.
38+
/// </summary>
39+
private StreamWriter? logWriter;
3440

3541
/// <summary>
3642
/// Initializes a new instance of the <see cref="FirefoxDriverService"/> class.
@@ -87,6 +93,16 @@ protected override DriverOptions GetDefaultDriverOptions()
8793
/// </summary>
8894
public bool OpenBrowserToolbox { get; set; }
8995

96+
/// <summary>
97+
/// Gets or sets the file path where log output should be written.
98+
/// </summary>
99+
/// <remarks>
100+
/// A <see langword="null"/> or <see cref="string.Empty"/> value indicates no log file to specify.
101+
/// This approach takes the process output and redirects it to a file because GeckoDriver does not
102+
/// offer a way to specify a log file path directly.
103+
/// </remarks>
104+
public string? LogPath { get; set; }
105+
90106
/// <summary>
91107
/// Gets or sets the level at which log output is displayed.
92108
/// </summary>
@@ -176,6 +192,74 @@ protected override string CommandLineArguments
176192
return argsBuilder.ToString().Trim();
177193
}
178194
}
195+
196+
/// <summary>
197+
/// Handles the event when the driver service process is starting.
198+
/// </summary>
199+
/// <param name="eventArgs">The event arguments containing information about the driver service process.</param>
200+
/// <remarks>
201+
/// This method initializes a log writer if a log path is specified and redirects output streams to capture logs.
202+
/// </remarks>
203+
protected override void OnDriverProcessStarting(DriverProcessStartingEventArgs eventArgs)
204+
{
205+
if (!string.IsNullOrEmpty(this.LogPath))
206+
{
207+
string? directory = Path.GetDirectoryName(this.LogPath);
208+
if (!string.IsNullOrEmpty(directory) && !Directory.Exists(directory))
209+
{
210+
Directory.CreateDirectory(directory);
211+
}
212+
213+
// Initialize the log writer
214+
logWriter = new StreamWriter(this.LogPath, append: true) { AutoFlush = true };
215+
216+
// Configure process to redirect output
217+
eventArgs.DriverServiceProcessStartInfo.RedirectStandardOutput = true;
218+
eventArgs.DriverServiceProcessStartInfo.RedirectStandardError = true;
219+
}
220+
221+
base.OnDriverProcessStarting(eventArgs);
222+
}
223+
224+
/// <summary>
225+
/// Handles the event when the driver process has started.
226+
/// </summary>
227+
/// <param name="eventArgs">The event arguments containing information about the started driver process.</param>
228+
/// <remarks>
229+
/// This method reads the output and error streams asynchronously and writes them to the log file if available.
230+
/// </remarks>
231+
protected override void OnDriverProcessStarted(DriverProcessStartedEventArgs eventArgs)
232+
{
233+
if (logWriter == null) return;
234+
if (eventArgs.StandardOutputStreamReader != null)
235+
{
236+
_ = Task.Run(() => ReadStreamAsync(eventArgs.StandardOutputStreamReader));
237+
}
238+
239+
if (eventArgs.StandardErrorStreamReader != null)
240+
{
241+
_ = Task.Run(() => ReadStreamAsync(eventArgs.StandardErrorStreamReader));
242+
}
243+
244+
base.OnDriverProcessStarted(eventArgs);
245+
}
246+
247+
/// <summary>
248+
/// Disposes of the resources used by the <see cref="FirefoxDriverService"/> instance.
249+
/// </summary>
250+
/// <param name="disposing">A value indicating whether the method is being called from Dispose.</param>
251+
/// <remarks>
252+
/// If disposing is true, it disposes of the log writer if it exists.
253+
/// </remarks>
254+
protected override void Dispose(bool disposing)
255+
{
256+
if (logWriter != null && disposing)
257+
{
258+
logWriter.Dispose();
259+
}
260+
261+
base.Dispose(disposing);
262+
}
179263

180264
/// <summary>
181265
/// Creates a default instance of the FirefoxDriverService.
@@ -258,4 +342,16 @@ private static string FirefoxDriverServiceFileName()
258342

259343
return fileName;
260344
}
345+
346+
private async Task ReadStreamAsync(StreamReader reader)
347+
{
348+
string? line;
349+
while ((line = await reader.ReadLineAsync()) != null)
350+
{
351+
if (logWriter != null)
352+
{
353+
logWriter.WriteLine($"{DateTime.Now:yyyy-MM-dd HH:mm:ss.fff} {line}");
354+
}
355+
}
356+
}
261357
}

0 commit comments

Comments
 (0)