Skip to content

Commit

Permalink
feat: Initial functionality (#4)
Browse files Browse the repository at this point in the history
* feat: Initial functionality

* fix(deps): Added missing PackageVersion

* fix(deps): More packages

* ci: Enabled SonarQube

* chore(tests): Added unit tests
  • Loading branch information
samtrion authored May 17, 2024
1 parent 1341cdb commit f895a12
Show file tree
Hide file tree
Showing 13 changed files with 263 additions and 3 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/cicd.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ jobs:
name: Build & Tests
uses: dailydevops/pipelines/.github/workflows/[email protected]
with:
disablePublish: true
enableSonarQube: true
dotnet-logging: ${{ inputs.dotnet-logging }}
dotnet-version: |
8.x
Expand Down
5 changes: 5 additions & 0 deletions Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,9 @@
<Import Project="$(DirEngineeringSettings)src.build.props" Condition=" '$(IsTestableProject)' != 'true' " />
<Import Project="$(DirEngineeringSettings)tests.build.props" Condition=" '$(IsTestableProject)' == 'true' " />

<PropertyGroup>
<ProjectTargetFrameworks>net8.0;netstandard2.0</ProjectTargetFrameworks>
<TestTargetFrameworks>net8.0</TestTargetFrameworks>
</PropertyGroup>

</Project>
10 changes: 10 additions & 0 deletions Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,14 @@
<GlobalPackageReference Include="SonarAnalyzer.CSharp" Version="9.16.0.82469" Condition=" '$(BuildingInsideVisualStudio)' == 'true' " />
</ItemGroup>

<ItemGroup>
<PackageVersion Include="coverlet.collector" Version="6.0.2" />
<PackageVersion Include="coverlet.msbuild" Version="6.0.2" />
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.9.0" />
<PackageVersion Include="Microsoft.Extensions.Logging.Abstractions" Version="8.0.1" />
<PackageVersion Include="NetEvolve.Extensions.XUnit" Version="2.0.13" />
<PackageVersion Include="xunit" Version="2.7.0" />
<PackageVersion Include="xunit.runner.visualstudio" Version="2.5.6" />
</ItemGroup>

</Project>
22 changes: 22 additions & 0 deletions Logging.Abstractions.sln
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,14 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
update-solution.ps1 = update-solution.ps1
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{C155CC82-19F5-4362-9DF0-3C376BF5587B}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NetEvolve.Logging.Abstractions", "src\NetEvolve.Logging.Abstractions\NetEvolve.Logging.Abstractions.csproj", "{69640616-9CA3-4200-BEB0-CCA07C343E2B}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{AE17327A-3F21-42F0-B3F0-2B7D147BBA42}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NetEvolve.Logging.Abstractions.Tests.Unit", "tests\NetEvolve.Logging.Abstractions.Tests.Unit\NetEvolve.Logging.Abstractions.Tests.Unit.csproj", "{766B8D41-B637-4572-A259-66FB4550F89C}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand All @@ -30,4 +38,18 @@ Global
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{69640616-9CA3-4200-BEB0-CCA07C343E2B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{69640616-9CA3-4200-BEB0-CCA07C343E2B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{69640616-9CA3-4200-BEB0-CCA07C343E2B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{69640616-9CA3-4200-BEB0-CCA07C343E2B}.Release|Any CPU.Build.0 = Release|Any CPU
{766B8D41-B637-4572-A259-66FB4550F89C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{766B8D41-B637-4572-A259-66FB4550F89C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{766B8D41-B637-4572-A259-66FB4550F89C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{766B8D41-B637-4572-A259-66FB4550F89C}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{69640616-9CA3-4200-BEB0-CCA07C343E2B} = {C155CC82-19F5-4362-9DF0-3C376BF5587B}
{766B8D41-B637-4572-A259-66FB4550F89C} = {AE17327A-3F21-42F0-B3F0-2B7D147BBA42}
EndGlobalSection
EndGlobal
11 changes: 9 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,9 @@
# template-dotnet
.NET template for repositories
# NetEvolve.Logging.Abstractions

This library provides some extensions to the `Microsoft.Extensions.Logging` library. It is intended to be used in conjunction further libraries that provide more specific logging implementations.

## Provided Types & Extensions

- `LoggedMessage` - A simple class that represents a message that has been logged. It contains the message, the log level, and the exception that was thrown (if any).
- `NullExternalScopeProvider` - An implementation of `IExternalScopeProvider` that does nothing.
- `NullScope` - An implementation of `IDisposable` that does nothing.
16 changes: 16 additions & 0 deletions src/NetEvolve.Logging.Abstractions/IsExternalInit.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// <auto-generated />

#if NETSTANDARD2_0
namespace System.Runtime.CompilerServices
{
using global::System.Diagnostics;
using global::System.Diagnostics.CodeAnalysis;

/// <summary>
/// Reserved to be used by the compiler for tracking metadata.
/// This class should not be used by developers in source code.
/// </summary>
[ExcludeFromCodeCoverage, DebuggerNonUserCode]
internal static class IsExternalInit { }
}
#endif
23 changes: 23 additions & 0 deletions src/NetEvolve.Logging.Abstractions/LoggedMessage.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
namespace NetEvolve.Logging.Abstractions;

using System;
using System.Collections.Generic;
using Microsoft.Extensions.Logging;

/// <summary>
/// Represents a logged message, including the timestamp, log level, event ID, message, exception, and scopes.
/// </summary>
/// <param name="Timestamp">Timestamp of the logged message.</param>
/// <param name="LogLevel">LogLevel of the logged message.</param>
/// <param name="EventId">EventId of the logged message.</param>
/// <param name="Message">Logged message.</param>
/// <param name="Exception">Logged exception. (optional)</param>
/// <param name="Scopes">Logged scopes.</param>
public readonly record struct LoggedMessage(
DateTimeOffset Timestamp,
LogLevel LogLevel,
EventId EventId,
string Message,
Exception? Exception = null,
IReadOnlyCollection<object?>? Scopes = null
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFrameworks>$(ProjectTargetFrameworks)</TargetFrameworks>
</PropertyGroup>

<PropertyGroup>
<Title>$(MSBuildProjectName)</Title>
<Description>
Contains several abstractions for logging, based on the nuget package `Microsoft.Extensions.Logging.Abstractions`.

- `LoggedMessage` represents a message that was logged.
- `NullExternalScopeProvider` is a `IExternalScopeProvider` that does nothing.
- `NullScope` is a `IDisposable` that does nothing.
</Description>

<PackageTags>$(PackageTags);logging;abstractions</PackageTags>
<PackageProjectUrl>https://github.com/dailydevops/logging.abstractions.git</PackageProjectUrl>
<RepositoryUrl>https://github.com/dailydevops/logging.abstractions.git</RepositoryUrl>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" />
</ItemGroup>

</Project>
26 changes: 26 additions & 0 deletions src/NetEvolve.Logging.Abstractions/NullExternalScopeProvider.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
namespace NetEvolve.Logging.Abstractions;

using System;
using Microsoft.Extensions.Logging;

/// <summary>
/// Scope provider that does nothing, used when no scope provider is available.
/// </summary>
public sealed class NullExternalScopeProvider : IExternalScopeProvider
{
private static readonly Lazy<IExternalScopeProvider> _instance =
new(() => new NullExternalScopeProvider());

private NullExternalScopeProvider() { }

/// <summary>
/// Returns a cached instance of <see cref="NullExternalScopeProvider"/>.
/// </summary>
public static IExternalScopeProvider Instance => _instance.Value;

/// <inheritdoc cref="IExternalScopeProvider.ForEachScope{TState}(Action{object?, TState}, TState)" />
public void ForEachScope<TState>(Action<object?, TState> callback, TState state) { }

/// <inheritdoc cref="IExternalScopeProvider.Push(object?)" />
public IDisposable Push(object? state) => NullScope.Instance;
}
21 changes: 21 additions & 0 deletions src/NetEvolve.Logging.Abstractions/NullScope.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
namespace NetEvolve.Logging.Abstractions;

using System;

/// <summary>
/// Scope that does nothing.
/// </summary>
public sealed class NullScope : IDisposable
{
private static readonly Lazy<IDisposable> _instance = new(() => new NullScope());

/// <summary>
/// Returns a cached instance of <see cref="NullScope"/>.
/// </summary>
public static IDisposable Instance => _instance.Value;

private NullScope() { }

/// <inheritdoc cref="IDisposable.Dispose" />
public void Dispose() { }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
namespace NetEvolve.Logging.Abstractions.Tests.Unit;

using System;
using Microsoft.Extensions.Logging;
using Xunit;

public class LoggedMessageTests
{
[Fact]
public void Constructor_WithoutScopes_Expected()
{
// Arrange
var timestamp = DateTimeOffset.Now;
var logLevel = LogLevel.Information;
var message = "Hello World!";
var eventId = new EventId(1, nameof(Constructor_WithoutScopes_Expected));

// Act
var loggedMessage = new LoggedMessage(timestamp, logLevel, eventId, message);

// Assert
Assert.Equal(timestamp, loggedMessage.Timestamp);
Assert.Equal(logLevel, loggedMessage.LogLevel);
Assert.Equal(eventId, loggedMessage.EventId);
Assert.Equal(message, loggedMessage.Message);
Assert.Null(loggedMessage.Exception);
Assert.Null(loggedMessage.Scopes);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFrameworks>$(TestTargetFrameworks)</TargetFrameworks>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="coverlet.collector" />
<PackageReference Include="coverlet.msbuild" />
<PackageReference Include="Microsoft.NET.Test.Sdk" />
<PackageReference Include="NetEvolve.Extensions.XUnit" />
<PackageReference Include="xunit" />
<PackageReference Include="xunit.runner.visualstudio" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\..\src\NetEvolve.Logging.Abstractions\NetEvolve.Logging.Abstractions.csproj" />
</ItemGroup>

<ItemGroup>
<AssemblyAttribute Include="NetEvolve.Extensions.XUnit.UnitTestAttribute" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
namespace NetEvolve.Logging.Abstractions.Tests.Unit;

using System.Collections.Generic;
using Xunit;

public class NullExternalScopeProviderTests
{
[Fact]
public void Instance_ReturnsSameInstance_Expected()
{
// Arrange
var instance1 = NullExternalScopeProvider.Instance;
var instance2 = NullExternalScopeProvider.Instance;

// Assert
Assert.Same(instance1, instance2);
}

[Fact]
public void ForEachScope_DoNothing_NoExceptionIsThrown()
{
// Arrange
var provider = NullExternalScopeProvider.Instance;
var state = new Dictionary<string, object?> { { "Hello World!", null } };

// Act
var ex = Record.Exception(() => provider.ForEachScope((_, _) => { }, state));

// Assert
Assert.Null(ex);
}

[Fact]
public void Push_ReturnsNullScope_Expected()
{
// Arrange
var provider = NullExternalScopeProvider.Instance;

// Act
var ex = Record.Exception(() =>
{
using var scope = provider.Push(null);

Assert.NotNull(scope);
_ = Assert.IsType<NullScope>(scope);
});

// Assert
Assert.Null(ex);
}
}

0 comments on commit f895a12

Please sign in to comment.