Kanject.Core.Logs.Abstractions 3.6.0

Prefix Reserved
There is a newer version of this package available.
See the version list below for details.
dotnet add package Kanject.Core.Logs.Abstractions --version 3.6.0
                    
NuGet\Install-Package Kanject.Core.Logs.Abstractions -Version 3.6.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Kanject.Core.Logs.Abstractions" Version="3.6.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Kanject.Core.Logs.Abstractions" Version="3.6.0" />
                    
Directory.Packages.props
<PackageReference Include="Kanject.Core.Logs.Abstractions" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Kanject.Core.Logs.Abstractions --version 3.6.0
                    
#r "nuget: Kanject.Core.Logs.Abstractions, 3.6.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Kanject.Core.Logs.Abstractions@3.6.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Kanject.Core.Logs.Abstractions&version=3.6.0
                    
Install as a Cake Addin
#tool nuget:?package=Kanject.Core.Logs.Abstractions&version=3.6.0
                    
Install as a Cake Tool

Kanject.Core.Logs.Abstractions

Contracts for an application-level log store — write named log entries, page back through them by group and date range — plus a small distributed-lock contract. Application code depends on ILogManager and IDbLockRepository<TEntity>; a provider package supplies the storage (the Kanject provider targets Amazon DynamoDB).

This is for durable, queryable business or audit logs that your application reads back, not a replacement for Microsoft.Extensions.Logging.

Installation

dotnet add package Kanject.Core.Logs.Abstractions

Targets .NET 8, .NET 9 and .NET 10. Depends on Kanject.Core.Api.Abstractions, which provides the PaginatedQueryModel request base and the PayloadMetadata paging result.

Quick start

using Kanject.Core.Logs.Abstractions.Interfaces;
using Kanject.Core.Logs.Abstractions.Models;

public sealed class PaymentAudit(ILogManager logs)
{
    private const string Group = "payments";

    public Task<LogResponse> RecordAsync(string paymentId, string message) =>
        logs.LogAsync(new LogRequest { LogGroup = Group, Log = $"{paymentId}: {message}" });

    public async Task<(IReadOnlyList<GetLogsResponse> Entries, string? NextPageToken)> ReadAsync(
        DateTime fromUtc, DateTime toUtc, string? pageToken)
    {
        var (payload, metadata) = await logs.GetLogsAsync(new GetSystemLogsRequest
        {
            LogGroup = Group,
            StartDate = fromUtc,
            EndDate = toUtc,
            PageSize = 50,
            PageToken = pageToken
        });

        return (payload.ToList(), metadata.HasNextPage ? metadata.PageToken : null);
    }
}

With the DynamoDB provider, AddLogStore(...) from Kanject.Core.Logs.Provider.DynamoDb registers ILogManager (scoped), along with a scoped unit of work and repositories of its own; it leaves your application's shared NoSQL IUnitOfWork and IRepository<TEntity> registrations alone, whichever order you register the providers in. That provider indexes entries by log group and calendar month (UTC) and matches group names case-insensitively. It throws ApiValidationException when a GetLogsAsync request has no LogGroup, when EndDate is before StartDate, or when the two fall in different calendar months — query each month separately.

In that provider, Query keeps the entries whose log text contains it, case-sensitively, against the text exactly as it was logged: Query = "FAILED" matches "Payment FAILED" but not "payment failed". Search in the case your application writes its log text.

The log contract

Member Purpose
ILogManager.LogAsync(LogRequest) Append an entry (LogGroup, Log); returns LogResponse with the assigned Id and CreatedOn
ILogManager.GetLogsAsync(GetSystemLogsRequest) Page through entries; returns (IEnumerable<GetLogsResponse> payload, PayloadMetadata metadata)

GetSystemLogsRequest extends PaginatedQueryModel (PageSize, PageToken) and adds LogGroup, Id, Query, StartDate and EndDate filters. Continue paging by passing metadata.PageToken back while metadata.HasNextPage is true.

ILogEntity (LogGroup, CreatedOn) is the minimal shape a provider's stored log entity implements.

A hand-written implementation for tests

ILogManager is small enough to fake without a mocking library:

using System.Collections.Concurrent;
using Kanject.Core.Api.Abstractions.Models;
using Kanject.Core.Logs.Abstractions.Interfaces;
using Kanject.Core.Logs.Abstractions.Models;

public sealed class InMemoryLogManager : ILogManager
{
    private readonly ConcurrentQueue<LogResponse> _entries = new();

    public Task<LogResponse> LogAsync(LogRequest model)
    {
        var entry = new LogResponse
        {
            Id = Guid.NewGuid(),
            LogGroup = model.LogGroup,
            Log = model.Log,
            CreatedOn = DateTime.UtcNow
        };
        _entries.Enqueue(entry);
        return Task.FromResult(entry);
    }

    public Task<(IEnumerable<GetLogsResponse> payload, PayloadMetadata metadata)> GetLogsAsync(
        GetSystemLogsRequest model)
    {
        var page = _entries
            .Where(e => e.LogGroup == model.LogGroup)
            .Where(e => model.StartDate is null || e.CreatedOn >= model.StartDate)
            .Where(e => model.EndDate is null || e.CreatedOn <= model.EndDate)
            .OrderByDescending(e => e.CreatedOn)
            .Take(model.PageSize > 0 ? model.PageSize : 50)
            .Select(e => new GetLogsResponse
            {
                Id = e.Id, LogGroup = e.LogGroup, Log = e.Log, CreatedOn = e.CreatedOn
            })
            .ToList();

        (IEnumerable<GetLogsResponse> payload, PayloadMetadata metadata) result =
            (page, new PayloadMetadata(model.PageSize, pageItemCount: page.Count));
        return Task.FromResult(result);
    }
}

Register it in place of a provider: services.AddSingleton<ILogManager, InMemoryLogManager>();.

Distributed locks

IDbLockRepository<TEntity> guards work that must not run concurrently across instances — a scheduled job, a one-time migration:

using Kanject.Core.Logs.Abstractions.Repositories;

// JobLock is your lock entity; it implements IDbLockEntity (see below).
public sealed class NightlyReportJob(IDbLockRepository<JobLock> locks)
{
    private const string LockId = "nightly-report";

    public async Task RunAsync()
    {
        await locks.AcquireLockAsync(LockId, DateTime.UtcNow.AddMinutes(10), comment: "report run");
        try
        {
            // ... do the work ...
        }
        finally
        {
            await locks.ReleaseLockAsync(LockId);
        }
    }
}

The lock entity implements IDbLockEntity (LockId, Log, InvokeCount, Ttl, plus ILogEntity's LogGroup and CreatedOn); a provider adds its own entity interfaces on top. In the DynamoDB provider, the DateTime passed to AcquireLockAsync is the lock's expiry time, not a length of time; acquiring a lock that is still held and unexpired throws ApiServiceException, and an expired lock is taken over.

Trimming and Native AOT

The package is built with the .NET trim and AOT analyzers enabled (IsAotCompatible). ILogManager carries no trimming annotations. The IDbLockRepository<TEntity> members are annotated [RequiresUnreferencedCode] and [RequiresDynamicCode], so calls to them report IL2026 / IL3050 in a trimmed or Native AOT publish.

Package Role Availability
Kanject.Core.Api.Abstractions PaginatedQueryModel, PayloadMetadata and ApiServiceException nuget.org
Kanject.Core.Logs.Provider.DynamoDb Amazon DynamoDB log store; AddLogStore(...) registers ILogManager and IDbLockRepository<TEntity> Commercial license (not on nuget.org)
Kanject.Core.Logs.Provider.DynamoDb.Abstractions DynamoDB log and lock entities, the lock repository, and the log database context used by that provider Commercial license (not on nuget.org)

License

Licensed under the Kanject Code Libraries License Agreement (KCLLA); the full text ships in this package as LICENSE.md. Organizations whose trailing-twelve-month gross revenue and total funding raised are each below US$250,000 may use it at no cost under the Free Tier. At or above either threshold a commercial license is required — contact commercial@kanjectbusiness.com.

Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 is compatible.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
3.8.0 0 10/5/2026
3.7.0 45 10/2/2026
3.6.1 109 9/27/2026
3.6.0 85 9/27/2026
3.5.7 91 9/26/2026
3.5.6 122 9/7/2026
3.5.5 105 8/27/2026
3.5.4 113 8/22/2026
3.5.3 125 8/10/2026
3.5.2 107 8/9/2026
3.5.1 119 8/5/2026
3.5.0 126 8/5/2026
3.4.0 118 8/3/2026
3.3.8 133 7/30/2026
3.3.7 130 7/18/2026
3.3.6 136 7/13/2026
3.3.5 125 7/11/2026
3.3.4 129 7/11/2026
3.3.3 132 7/9/2026
3.3.2 119 7/9/2026