Skip to content

Commit

Permalink
[dotnet] Internal logging (#13140)
Browse files Browse the repository at this point in the history
* Update HttpCommandExecutor.cs

* Nullable handlers

* Don't capture logger

* Log message issuer

* Update nunit adapter to work with dotnet 7 and be more friendly with windows

* Introduce LogContextManager

* Make ILogger as static field

* Support hierarchical contexts

* Do not emit message to parent context

* Deep copy of loggers and handlers per context

* Static works with current log context

* Create context with minimum level

* Set minimum level for context

* Set minimum level per issuer

* Use DateTimeOffset

* Docs for everything

* Info minimum log level by default

* Adjust log levels in console output

* Make webdriver assembly internals visible to tests

* Make ILogger hidden from user

* Console handler by default

* Output logs to stderr

* New api to mange log handlers

* Verbose driver creation in tests

* Search driver type in loaded assemblies

* Declare internals visible to in csproj to not conflict with bazel

* Clean specific assembly name for driver type

* Fix targeting packs for test targets
  • Loading branch information
nvborisenko authored Dec 3, 2023
1 parent 9571248 commit 6b24636
Show file tree
Hide file tree
Showing 32 changed files with 1,146 additions and 45 deletions.
5 changes: 5 additions & 0 deletions dotnet/src/webdriver/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ csharp_library(
"**/*.cs",
]) + devtools_version_targets(),
out = "WebDriver",
internals_visible_to = [
"WebDriver.Common.Tests",
],
langversion = "10.0",
resources = [
"//javascript/atoms/fragments:find-elements.js",
"//javascript/atoms/fragments:is-displayed.js",
Expand Down Expand Up @@ -64,6 +68,7 @@ csharp_library(
]) + devtools_version_targets(),
out = "WebDriver.StrongNamed",
keyfile = "//dotnet:WebDriver.snk",
langversion = "10.0",
resources = [
"//javascript/atoms/fragments:find-elements.js",
"//javascript/atoms/fragments:is-displayed.js",
Expand Down
1 change: 1 addition & 0 deletions dotnet/src/webdriver/Chrome/ChromeDriver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
using System.Collections.ObjectModel;
using OpenQA.Selenium.Remote;
using OpenQA.Selenium.Chromium;
using OpenQA.Selenium.Internal.Logging;

namespace OpenQA.Selenium.Chrome
{
Expand Down
49 changes: 49 additions & 0 deletions dotnet/src/webdriver/Internal/Logging/ConsoleLogHandler.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// <copyright file="ConsoleLogHandler.cs" company="WebDriver Committers">
// Licensed to the Software Freedom Conservancy (SFC) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The SFC licenses this file
// to you under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// </copyright>

using System;

namespace OpenQA.Selenium.Internal.Logging
{
/// <summary>
/// Represents a log handler that writes log events to the console.
/// </summary>
public class ConsoleLogHandler : ILogHandler
{
// performance trick to avoid expensive Enum.ToString() with fixed length
private static readonly string[] _levels = { "TRACE", "DEBUG", " INFO", " WARN", "ERROR" };

/// <summary>
/// Handles a log event by writing it to the console.
/// </summary>
/// <param name="logEvent">The log event to handle.</param>
public void Handle(LogEvent logEvent)
{
Console.Error.WriteLine($"{logEvent.Timestamp:HH:mm:ss.fff} {_levels[(int)logEvent.Level]} {logEvent.IssuedBy.Name}: {logEvent.Message}");
}

/// <summary>
/// Creates a new instance of the <see cref="ConsoleLogHandler"/> class.
/// </summary>
/// <returns>A new instance of the <see cref="ConsoleLogHandler"/> class.</returns>
public ILogHandler Clone()
{
return this;
}
}
}
83 changes: 83 additions & 0 deletions dotnet/src/webdriver/Internal/Logging/ILogContext.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
// <copyright file="ILogContext.cs" company="WebDriver Committers">
// Licensed to the Software Freedom Conservancy (SFC) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The SFC licenses this file
// to you under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// </copyright>

using System;

namespace OpenQA.Selenium.Internal.Logging
{
/// <summary>
/// Represents a logging context that provides methods for creating sub-contexts, retrieving loggers, emitting log messages, and configuring minimum log levels.
/// </summary>
public interface ILogContext : IDisposable
{
/// <summary>
/// Creates a new logging context.
/// </summary>
/// <returns>A new instance of <see cref="ILogContext"/>.</returns>
ILogContext CreateContext();

/// <summary>
/// Creates a new logging context with the specified minimum log level.
/// </summary>
/// <param name="minimumLevel">The minimum log level for the new context.</param>
/// <returns>A new instance of <see cref="ILogContext"/> with the specified minimum log level.</returns>
ILogContext CreateContext(LogEventLevel minimumLevel);

/// <summary>
/// Gets a logger for the specified type.
/// </summary>
/// <typeparam name="T">The type for which to retrieve the logger.</typeparam>
/// <returns>An instance of <see cref="ILogger"/> for the specified type.</returns>
internal ILogger GetLogger<T>();

/// <summary>
/// Gets a logger for the specified type.
/// </summary>
/// <param name="type">The type for which to retrieve the logger.</param>
/// <returns>An instance of <see cref="ILogger"/> for the specified type.</returns>
internal ILogger GetLogger(Type type);

/// <summary>
/// Emits a log message using the specified logger, log level, and message.
/// </summary>
/// <param name="logger">The logger to emit the log message.</param>
/// <param name="level">The log level of the message.</param>
/// <param name="message">The log message.</param>
internal void EmitMessage(ILogger logger, LogEventLevel level, string message);

/// <summary>
/// Sets the minimum log level for the current context.
/// </summary>
/// <param name="level">The minimum log level.</param>
/// <returns>The current instance of <see cref="ILogContext"/> with the minimum log level set.</returns>
ILogContext SetLevel(LogEventLevel level);

/// <summary>
/// Sets the minimum log level for the specified type in the current context.
/// </summary>
/// <param name="issuer">The type for which to set the minimum log level.</param>
/// <param name="level">The minimum log level.</param>
/// <returns>The current instance of <see cref="ILogContext"/> with the minimum log level set for the specified type.</returns>
ILogContext SetLevel(Type issuer, LogEventLevel level);

/// <summary>
/// Gets a list of log handlers.
/// </summary>
ILogHandlerList Handlers { get; }
}
}
38 changes: 38 additions & 0 deletions dotnet/src/webdriver/Internal/Logging/ILogHandler.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// <copyright file="ILogHandler.cs" company="WebDriver Committers">
// Licensed to the Software Freedom Conservancy (SFC) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The SFC licenses this file
// to you under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// </copyright>

namespace OpenQA.Selenium.Internal.Logging
{
/// <summary>
/// Represents a log handler that handles log events.
/// </summary>
public interface ILogHandler
{
/// <summary>
/// Handles a log event.
/// </summary>
/// <param name="logEvent">The log event to handle.</param>
void Handle(LogEvent logEvent);

/// <summary>
/// Creates a clone of the log handler.
/// </summary>
/// <returns>A clone of the log handler.</returns>
ILogHandler Clone();
}
}
48 changes: 48 additions & 0 deletions dotnet/src/webdriver/Internal/Logging/ILogHandlerList.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// <copyright file="ILogHandlerList.cs" company="WebDriver Committers">
// Licensed to the Software Freedom Conservancy (SFC) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The SFC licenses this file
// to you under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// </copyright>

using System.Collections.Generic;

namespace OpenQA.Selenium.Internal.Logging
{
/// <summary>
/// Represents a list of log handlers.
/// </summary>
public interface ILogHandlerList : IEnumerable<ILogHandler>
{
/// <summary>
/// Adds a log handler to the list.
/// </summary>
/// <param name="handler">The log handler to add.</param>
/// <returns>The log context.</returns>
ILogContext Add(ILogHandler handler);

/// <summary>
/// Removes a log handler from the list.
/// </summary>
/// <param name="handler">The log handler to remove.</param>
/// <returns>The log context.</returns>
ILogContext Remove(ILogHandler handler);

/// <summary>
/// Clears all log handlers from the list.
/// </summary>
/// <returns>The log context.</returns>
ILogContext Clear();
}
}
68 changes: 68 additions & 0 deletions dotnet/src/webdriver/Internal/Logging/ILogger.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
// <copyright file="ILogger.cs" company="WebDriver Committers">
// Licensed to the Software Freedom Conservancy (SFC) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The SFC licenses this file
// to you under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// </copyright>

using System;

namespace OpenQA.Selenium.Internal.Logging
{
/// <summary>
/// Defines the interface through which log messages are emitted.
/// </summary>
internal interface ILogger
{
/// <summary>
/// Writes a trace-level log message.
/// </summary>
/// <param name="message">The log message.</param>
void Trace(string message);

/// <summary>
/// Writes a debug-level log message.
/// </summary>
/// <param name="message">The log message.</param>
void Debug(string message);

/// <summary>
/// Writes an info-level log message.
/// </summary>
/// <param name="message">The log message.</param>
void Info(string message);

/// <summary>
/// Writes a warning-level log message.
/// </summary>
/// <param name="message">The log message.</param>
void Warn(string message);

/// <summary>
/// Writes an error-level log message.
/// </summary>
/// <param name="message">The log message.</param>
void Error(string message);

/// <summary>
/// Gets or sets the log event level.
/// </summary>
LogEventLevel Level { get; set; }

/// <summary>
/// Gets the type of the logger issuer.
/// </summary>
Type Issuer { get; }
}
}
Loading

0 comments on commit 6b24636

Please sign in to comment.