-
-
Notifications
You must be signed in to change notification settings - Fork 8.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[dotnet] Possibility to output internal log messages to file (#13249)
* INitial implementation * With context * Update HttpCommandExecutor.cs * Nullable handlers * Don't capture logger * Log message issuer * Simplify things * Continue * Update nunit adapter to work with dotnet 7 and be more friendly with windows * Rename to LogEventLevel * Typo * Introduce LogContextManager * Typo again * Rename to Timestamp * Make ILogger as static field * Support hierarchical contexts * Rename to EmitMessage * Do not emit message to parent context * Deep copy of loggers and handlers per context * Make fields private * Static works with current log context * Create context with minimum level * Set minimum level for context * Rename to WithHandler * Set minimum level per issuer * Simplify getting internal logger * Use DateTimeOffset * Docs for log event level * Docs for ILogger * Docs for Logger * Docs for others * Make ILogger interface as internal * Revert "Make ILogger interface as internal" This reverts commit 3cf6e48. * First test * Update LogTest.cs * Fix build error * Info minimum log level by default * Remove unnecessary log call in ChromeDriver * Adjust log levels in console output * Make it length fixed * Make webdriver assembly internals visible to tests * Make ILogger hidden from user * More tests for log context * Init * Rename back to AddHandler * Make format script happy? * Make format script happy? * Rename back to SetLevel * Console handler by default * Output logs to stderr * New api to mange log handlers * Use logging in DriverFactory * Revert "Use logging in DriverFactory" This reverts commit e3255a6. * Verbose driver creation in tests * Search driver type in loaded assemblies * Decalare internals visible to in csproj to not conflict with bazel * Clean specific assembly name for driver type * Old school using to make bazel happy * Fix targeting packs for test targets * It works * Small clean up * Lock in ctor * Dispose at process exit * Remove redundant Clone for log handlers * Dispose log handlers when context finishes * Lock writing to the disk globally * Fix new list of log handlers for context * Don't lock in ctor * Add docs * Change format of datetime in file log * Thread safe disposing * Add finilizer * Docs for finilizer * Add tests * Recreating missing dirs
- Loading branch information
1 parent
1bcb948
commit b949dca
Showing
5 changed files
with
155 additions
and
23 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
using System; | ||
using System.IO; | ||
|
||
namespace OpenQA.Selenium.Internal.Logging | ||
{ | ||
/// <summary> | ||
/// Represents a log handler that writes log events to a file. | ||
/// </summary> | ||
public class FileLogHandler : ILogHandler, IDisposable | ||
{ | ||
// performance trick to avoid expensive Enum.ToString() with fixed length | ||
private static readonly string[] _levels = { "TRACE", "DEBUG", " INFO", " WARN", "ERROR" }; | ||
|
||
private FileStream _fileStream; | ||
private StreamWriter _streamWriter; | ||
|
||
private readonly object _lockObj = new object(); | ||
private bool _isDisposed; | ||
|
||
/// <summary> | ||
/// Initializes a new instance of the <see cref="FileLogHandler"/> class with the specified file path. | ||
/// </summary> | ||
/// <param name="path">The path of the log file.</param> | ||
public FileLogHandler(string path) | ||
{ | ||
if (string.IsNullOrEmpty(path)) throw new ArgumentException("File log path cannot be null or empty.", nameof(path)); | ||
|
||
var directory = Path.GetDirectoryName(path); | ||
if (!string.IsNullOrWhiteSpace(directory) && !Directory.Exists(directory)) | ||
{ | ||
Directory.CreateDirectory(directory); | ||
} | ||
|
||
_fileStream = File.Open(path, FileMode.OpenOrCreate, FileAccess.Write, FileShare.Read); | ||
_fileStream.Seek(0, SeekOrigin.End); | ||
_streamWriter = new StreamWriter(_fileStream, System.Text.Encoding.UTF8) | ||
{ | ||
AutoFlush = true | ||
}; | ||
} | ||
|
||
/// <summary> | ||
/// Handles a log event by writing it to the log file. | ||
/// </summary> | ||
/// <param name="logEvent">The log event to handle.</param> | ||
public void Handle(LogEvent logEvent) | ||
{ | ||
lock (_lockObj) | ||
{ | ||
_streamWriter.WriteLine($"{logEvent.Timestamp:r} {_levels[(int)logEvent.Level]} {logEvent.IssuedBy.Name}: {logEvent.Message}"); | ||
} | ||
} | ||
|
||
/// <summary> | ||
/// Disposes the file log handler and releases any resources used. | ||
/// </summary> | ||
public void Dispose() | ||
{ | ||
Dispose(true); | ||
GC.SuppressFinalize(this); | ||
} | ||
|
||
/// <summary> | ||
/// Finalizes the file log handler instance. | ||
/// </summary> | ||
~FileLogHandler() | ||
{ | ||
Dispose(false); | ||
} | ||
|
||
/// <summary> | ||
/// Disposes the file log handler and releases any resources used. | ||
/// </summary> | ||
/// <param name="disposing">A flag indicating whether to dispose managed resources.</param> | ||
protected virtual void Dispose(bool disposing) | ||
{ | ||
lock (_lockObj) | ||
{ | ||
if (!_isDisposed) | ||
{ | ||
if (disposing) | ||
{ | ||
_streamWriter?.Dispose(); | ||
_streamWriter = null; | ||
_fileStream?.Dispose(); | ||
_fileStream = null; | ||
} | ||
|
||
_isDisposed = true; | ||
} | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
using NUnit.Framework; | ||
using System; | ||
using System.IO; | ||
|
||
namespace OpenQA.Selenium.Internal.Logging | ||
{ | ||
public class FileLogHandlerTest | ||
{ | ||
[Test] | ||
[TestCase(null)] | ||
[TestCase("")] | ||
public void ShouldNotAcceptIncorrectPath(string path) | ||
{ | ||
var act = () => new FileLogHandler(path); | ||
|
||
Assert.That(act, Throws.ArgumentException); | ||
} | ||
|
||
[Test] | ||
public void ShouldHandleLogEvent() | ||
{ | ||
var tempFile = Path.GetTempFileName(); | ||
|
||
try | ||
{ | ||
using (var fileLogHandler = new FileLogHandler(tempFile)) | ||
{ | ||
fileLogHandler.Handle(new LogEvent(typeof(FileLogHandlerTest), DateTimeOffset.Now, LogEventLevel.Info, "test message")); | ||
} | ||
|
||
Assert.That(File.ReadAllText(tempFile), Does.Contain("test message")); | ||
} | ||
catch (Exception) | ||
{ | ||
throw; | ||
} | ||
finally | ||
{ | ||
File.Delete(tempFile); | ||
} | ||
} | ||
} | ||
} |