2222using System . Globalization ;
2323using System . IO ;
2424using System . Text ;
25+ using System . Threading . Tasks ;
2526
2627namespace OpenQA . Selenium . Firefox ;
2728
@@ -32,6 +33,11 @@ public sealed class FirefoxDriverService : DriverService
3233{
3334 private const string DefaultFirefoxDriverServiceFileName = "geckodriver" ;
3435
36+ /// <summary>
37+ /// Process management fields for the log writer.
38+ /// </summary>
39+ private StreamWriter ? logWriter ;
40+
3541 /// <summary>
3642 /// Initializes a new instance of the <see cref="FirefoxDriverService"/> class.
3743 /// </summary>
@@ -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>
@@ -177,6 +193,75 @@ protected override string CommandLineArguments
177193 }
178194 }
179195
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+ logWriter = null ;
260+ }
261+
262+ base . Dispose ( disposing ) ;
263+ }
264+
180265 /// <summary>
181266 /// Creates a default instance of the FirefoxDriverService.
182267 /// </summary>
@@ -258,4 +343,24 @@ private static string FirefoxDriverServiceFileName()
258343
259344 return fileName ;
260345 }
346+
347+ private async Task ReadStreamAsync ( StreamReader reader )
348+ {
349+ try
350+ {
351+ string ? line ;
352+ while ( ( line = await reader . ReadLineAsync ( ) ) != null )
353+ {
354+ if ( logWriter != null )
355+ {
356+ logWriter . WriteLine ( $ "{ DateTime . Now : yyyy-MM-dd HH:mm:ss.fff} { line } ") ;
357+ }
358+ }
359+ }
360+ catch ( Exception ex )
361+ {
362+ // Log or handle the exception appropriately
363+ System . Diagnostics . Debug . WriteLine ( $ "Error reading stream: { ex . Message } ") ;
364+ }
365+ }
261366}
0 commit comments