Skip to content

Commit

Permalink
Update codebase and remove files
Browse files Browse the repository at this point in the history
Several changes have included updating test project and pulse logger class, also deleting several scripts, 'Frank.PulseFlow.Sample' project, '.gitignore', and 'Directory.Build.props'. These changes streamline the project, increase code readability and improve logging mechanism. The removal of unnecessary files and scripts reduces clutter, enhancing maintainability.
  • Loading branch information
frankhaugen committed Jan 5, 2024
1 parent 5739344 commit 3237dc5
Show file tree
Hide file tree
Showing 21 changed files with 213 additions and 628 deletions.
66 changes: 59 additions & 7 deletions Frank.PulseFlow.Logging/LogPulse.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,76 @@

namespace Frank.PulseFlow.Logging;

public class LogPulse<TState> : BasePulse
/// <summary>
/// Represents a log pulse.
/// </summary>
public class LogPulse : BasePulse
{
/// <summary>
/// Gets the log level of the application.
/// </summary>
/// <value>The log level.</value>
public LogLevel LogLevel { get; }

/// <summary>
/// Gets the unique identifier of an event.
/// </summary>
public EventId EventId { get; }

/// <summary>
/// Gets the exception associated with the property.
/// </summary>
/// <value>
/// The exception associated with the property, or null if no exception occurred.
/// </value>
public Exception? Exception { get; }

/// <summary>
/// Gets the name of the category.
/// </summary>
/// <value>The name of the category.</value>
public string CategoryName { get; }
public TState State { get; }
public Func<TState, Exception?, string> Formatter { get; }

public LogPulse(LogLevel logLevel, EventId eventId, TState state, Exception? exception, Func<TState, Exception?, string> formatter, string categoryName)
/// <summary>
/// Gets the message associated with this property.
/// </summary>
public string Message { get; }

/// <summary>
/// Gets the state of the object.
/// </summary>
/// <remarks>
/// The state is represented as a collection of key-value pairs, where the key is a string and the value is an object.
/// The state is read-only and can be null if there is no state available.
/// </remarks>
/// <returns>A read-only list of key-value pairs representing the state of the object.</returns>
public IReadOnlyList<KeyValuePair<string, object?>>? State { get; }

/// <summary>
/// Represents a log pulse, which encapsulates information about a log event.
/// </summary>
/// <param name="logLevel">The level of the log event.</param>
/// <param name="eventId">The identifier of the log event.</param>
/// <param name="exception">The exception associated with the log event, if any.</param>
/// <param name="categoryName">The name of the log category.</param>
/// <param name="message">The log message.</param>
public LogPulse(LogLevel logLevel, EventId eventId, Exception? exception, string categoryName, string message)
{
LogLevel = logLevel;
EventId = eventId;
State = state;
Exception = exception;
Formatter = formatter;
CategoryName = categoryName;
Message = message;
}

public override string ToString() => Formatter(State, Exception);
/// <summary>
/// Returns a string representation of the object.
/// </summary>
/// <returns>
/// A string representing the object. The string consists of the log level,
/// event ID, category name, message, and exception, formatted in the following way:
/// [LogLevel] (EventId) CategoryName: 'Message'
/// Exception
/// </returns>
public override string ToString() => $"[{LogLevel}] ({EventId}) {CategoryName}: '{Message}'\n\t{Exception}";
}
35 changes: 34 additions & 1 deletion Frank.PulseFlow.Logging/PulseFlowLogger.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,45 @@

namespace Frank.PulseFlow.Logging;

/// <summary>
/// Implementation of ILogger interface that logs messages using pulse flow.
/// </summary>
public class PulseFlowLogger : ILogger
{
private readonly string _categoryName;
private readonly IConduit _conduit;
private readonly IOptionsMonitor<LoggerFilterOptions> _filterOptions;

/// <summary>
/// Initializes a new instance of the PulseFlowLogger class with the specified category name, conduit, and filter options.
/// </summary>
/// <param name="categoryName">The category name of the logger.</param>
/// <param name="conduit">The conduit used for logging.</param>
/// <param name="filterOptions">The options monitor for logger filter options.</param>
public PulseFlowLogger(string categoryName, IConduit conduit, IOptionsMonitor<LoggerFilterOptions> filterOptions)
{
_categoryName = categoryName;
_conduit = conduit;
_filterOptions = filterOptions;
}

/// <summary>
/// Logs a message with the specified log level, event ID, state, exception, and formatter.
/// </summary>
/// <typeparam name="TState">The type of the state object.</typeparam>
/// <param name="logLevel">The log level.</param>
/// <param name="eventId">The event ID associated with the log entry.</param>
/// <param name="state">The state object.</param>
/// <param name="exception">The exception associated with the log entry.</param>
/// <param name="formatter">A function that formats the log message.</param>
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception? exception, Func<TState, Exception?, string> formatter)
=> _conduit.SendAsync(new LogPulse<TState>(logLevel, eventId, state, exception, formatter, _categoryName)).GetAwaiter().GetResult();
=> _conduit.SendAsync(new LogPulse(logLevel, eventId, exception, _categoryName, formatter.Invoke(state, exception))).GetAwaiter().GetResult();

/// <summary>
/// Checks if logging is enabled for the specified log level.
/// </summary>
/// <param name="logLevel">The log level to check.</param>
/// <returns>Returns true if logging is enabled for the specified log level, otherwise false.</returns>
public bool IsEnabled(LogLevel logLevel)
{
// If LogLevel is None, logging is disabled.
Expand All @@ -39,5 +62,15 @@ public bool IsEnabled(LogLevel logLevel)
return logLevel >= filterOptions.MinLevel;
}

/// <summary>
/// Begins a new log scope with the specified state.
/// </summary>
/// <typeparam name="TState">The type of the state.</typeparam>
/// <param name="state">The state object for the log scope.</param>
/// <returns>An object that represents the log scope. Dispose this object to end the log scope.</returns>
/// <remarks>
/// The log scope allows grouping related log entries together.
/// </remarks>
/// <seealso cref="PulseFlowLoggerScope{TState}"/>
public IDisposable? BeginScope<TState>(TState state) where TState : notnull => new PulseFlowLoggerScope<TState>(state);
}
30 changes: 30 additions & 0 deletions Frank.PulseFlow.Logging/PulseFlowLoggerProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,50 @@

namespace Frank.PulseFlow.Logging;

/// <summary>
/// Provides instances of PulseFlowLogger.
/// </summary>
public class PulseFlowLoggerProvider : ILoggerProvider
{
private readonly IConduit _conduit;
private readonly IOptionsMonitor<LoggerFilterOptions> _filterOptions;
private readonly ConcurrentDictionary<string, PulseFlowLogger> _loggers = new();

/// <summary>
/// Represents a PulseFlowLoggerProvider object that provides logging services for PulseFlow application.
/// </summary>
/// <remarks>
/// This class is responsible for initializing and configuring the PulseFlow logger provider. It takes an IConduit object and an IOptionsMonitor{LoggerFilterOptions} object as input
/// parameters.
/// </remarks>
/// <param name="conduit">An IConduit object that represents the conduit for transmitting logs.</param>
/// <param name="filterOptions">An IOptionsMonitor{LoggerFilterOptions} object that represents the various options for filtering logs.</param>
/// <exception cref="ArgumentNullException">Thrown when either conduit or filterOptions is null.</exception>
/// <example>
/// <code>
/// IConduit conduit = new MyConduit();
/// IOptionsMonitor{LoggerFilterOptions} filterOptions = new MyFilterOptions();
/// PulseFlowLoggerProvider loggerProvider = new PulseFlowLoggerProvider(conduit, filterOptions);
/// </code>
/// </example>
public PulseFlowLoggerProvider(IConduit conduit, IOptionsMonitor<LoggerFilterOptions> filterOptions)
{
_conduit = conduit;
_filterOptions = filterOptions;
}

/// <summary>
/// Disposes the resources used by the object and clears all the loggers.
/// </summary>
public void Dispose() => _loggers.Clear();

/// <summary>
/// Creates a new instance of ILogger for the specified category name.
/// </summary>
/// <param name="categoryName">The name of the category to create the logger for.</param>
/// <returns>
/// The ILogger instance for the specified category name.
/// </returns>
public ILogger CreateLogger(string categoryName) =>
// ReSharper disable once HeapView.CanAvoidClosure
_loggers.GetOrAdd(categoryName, name => new PulseFlowLogger(name, _conduit, _filterOptions));
Expand Down
16 changes: 16 additions & 0 deletions Frank.PulseFlow.Logging/PulseFlowLoggerScope.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,26 @@
namespace Frank.PulseFlow.Logging;

/// <summary>
/// Represents a logger scope that can pulse flow and logs a state of type <typeparamref name="TState"/>.
/// </summary>
/// <typeparam name="TState">The type of the state to be logged.</typeparam>
public class PulseFlowLoggerScope<TState> : IDisposable
{
/// <summary>
/// Gets or sets the state of the object.
/// </summary>
/// <typeparam name="TState">The type of the state.</typeparam>

Check warning on line 12 in Frank.PulseFlow.Logging/PulseFlowLoggerScope.cs

View workflow job for this annotation

GitHub Actions / Merge Job / Publish Preview Job

XML comment has a typeparam tag for 'TState', but there is no type parameter by that name

Check warning on line 12 in Frank.PulseFlow.Logging/PulseFlowLoggerScope.cs

View workflow job for this annotation

GitHub Actions / Merge Job / Publish Preview Job

XML comment has a typeparam tag for 'TState', but there is no type parameter by that name

Check warning on line 12 in Frank.PulseFlow.Logging/PulseFlowLoggerScope.cs

View workflow job for this annotation

GitHub Actions / Release Job / Release Job

XML comment has a typeparam tag for 'TState', but there is no type parameter by that name

Check warning on line 12 in Frank.PulseFlow.Logging/PulseFlowLoggerScope.cs

View workflow job for this annotation

GitHub Actions / Release Job / Release Job

XML comment has a typeparam tag for 'TState', but there is no type parameter by that name
/// <returns>The current state of the object.</returns>
public TState? State { get; private set; }

/// <summary>
/// Initializes a new instance of the <see cref="PulseFlowLoggerScope{TState}"/> class with the specified state.
/// </summary>
/// <param name="state">The state to assign to the logger scope.</param>
public PulseFlowLoggerScope(TState state) => State = state;

/// <summary>
/// Performs application-defined tasks associated with freeing, releasing, or resetting resources.
/// </summary>
public void Dispose() => State = default;
}
1 change: 1 addition & 0 deletions Frank.PulseFlow.Logging/ServiceCollectionExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ public static class LoggingBuilderExtensions
public static ILoggingBuilder AddPulseFlow(this ILoggingBuilder builder)
{
builder.Services.AddSingleton<ILoggerProvider, PulseFlowLoggerProvider>();

return builder;
}
}
Loading

0 comments on commit 3237dc5

Please sign in to comment.