Coject.Core.Logging 1.0.0

dotnet add package Coject.Core.Logging --version 1.0.0
                    
NuGet\Install-Package Coject.Core.Logging -Version 1.0.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="Coject.Core.Logging" Version="1.0.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Coject.Core.Logging" Version="1.0.0" />
                    
Directory.Packages.props
<PackageReference Include="Coject.Core.Logging" />
                    
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 Coject.Core.Logging --version 1.0.0
                    
#r "nuget: Coject.Core.Logging, 1.0.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 Coject.Core.Logging@1.0.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=Coject.Core.Logging&version=1.0.0
                    
Install as a Cake Addin
#tool nuget:?package=Coject.Core.Logging&version=1.0.0
                    
Install as a Cake Tool

Coject Core Logging

Coject.Core.Logging is the provider-neutral runtime pipeline for Coject Contracts 3.0 logging and auditing. It accepts typed records, captures trusted server context, redacts sensitive values before ownership, writes application and audit JSONL locally, and optionally fans records out to a provider registered by another package.

This package owns the Core pipeline. The optional CSCC HTTP destination is in Coject.Core.Logging.Cscc. The package does not depend on CojectCore.Controller and does not register MVC controllers, routes, authentication, or database access.

Package and support

  • Package: Coject.Core.Logging version 1.0.0
  • Target framework: net8.0
  • Wire contract: Coject Contracts 3.0 from Coject.Core.Logging.Contracts 3.0.0
  • Repository: https://github.com/coject/CojectCore
  • The package contains portable symbols (.snupkg) and the packaged README.md, license, and icon.

Installation

<PackageReference Include="Coject.Core.Logging" Version="1.0.0" />

The package declares a dependency on Coject.Core.Logging.Contracts 3.0.0 plus the required Microsoft.Extensions abstraction packages. Add Coject.Core.Logging.Cscc separately when CSCC delivery is required.

Registration

The normal host-level boundary is AddCojectLogging. It is idempotent and registers the typed logger, local application and audit providers, durable fallback, health services, and coordinated shutdown.

using Coject.Core.Logging;

var builder = Host.CreateApplicationBuilder(args);
builder.AddCojectLogging();

using var host = builder.Build();
await host.RunAsync();

For an ASP.NET Core application:

using Coject.Core.Logging;

var builder = WebApplication.CreateBuilder(args);
builder.AddCojectLogging();

var app = builder.Build();
app.MapGet("/", () => Results.Ok("running"));
app.Run();

AddCojectLogging() replaces existing ILoggerProvider registrations by default so framework records have one ownership path. During a deliberate coexistence migration only, use:

builder.AddCojectLogging(options =>
    options.ReplaceExistingFrameworkProviders = false);

AddCojectLoggingConfiguration(IServiceCollection, IConfiguration) is the lower-level boundary for hosts that need to compose registration manually. Prefer the host-builder method unless the application owns that composition explicitly.

Complete appsettings.json tree

The following is the complete bindable CojectLogging graph. The API key is a placeholder only; do not commit a real key. The CSCC section can remain disabled for a local-only deployment.

{
  "CojectLogging": {
    "Environment": "Production",
    "TrustedContext": {
      "KnownProxies": [],
      "KnownNetworks": [],
      "ForwardLimit": 1,
      "PresentationTimeZoneId": "Asia/Riyadh"
    },
    "Local": {
      "RootPath": "logs",
      "Application": {
        "Enabled": true,
        "RetentionDays": 30,
        "MaxSegmentSizeBytes": 104857600,
        "BatchSize": 100,
        "FlushIntervalMilliseconds": 1000
      },
      "Audit": {
        "Enabled": true,
        "RetentionDays": 365,
        "MaxSegmentSizeBytes": 104857600,
        "BatchSize": 20,
        "FlushIntervalMilliseconds": 500
      }
    },
    "Cscc": {
      "Enabled": false,
      "AppId": "sample-service",
      "Endpoint": "https://cscc.example.invalid",
      "ApiKey": "<YOUR_CSCC_API_KEY>",
      "ContractVersion": "3.0",
      "Scopes": [
        "logging.write",
        "audit.write"
      ],
      "Delivery": {
        "LogConcurrency": 4,
        "AuditConcurrency": 2,
        "AttemptTimeoutSeconds": 10
      },
      "CircuitBreaker": {
        "FailureThreshold": 5,
        "InitialCooldownSeconds": 30,
        "MaxCooldownSeconds": 300,
        "JitterRatio": 0.2,
        "RateLimitPauseMinimumSeconds": 1,
        "RateLimitPauseMaximumSeconds": 3600
      }
    },
    "Queues": {
      "Memory": {
        "Logs": {
          "MaxRecords": 10000,
          "MaxBytes": 134217728
        },
        "Audits": {
          "MaxRecords": 1000,
          "MaxBytes": 268435456
        }
      },
      "Overflow": {
        "Logs": {
          "MaxRecords": 25000,
          "MaxBytes": 536870912
        },
        "Audits": {
          "MaxRecords": 5000,
          "MaxBytes": 1073741824
        },
        "HighSeverityReservationPercent": 25
      },
      "HighSeverityBurstLimit": 8,
      "EnqueueTimeoutMs": 25,
      "HandoffRetryInitialDelaySeconds": 1,
      "HandoffRetryMaxDelaySeconds": 60,
      "ShutdownDrainTimeoutSeconds": 10
    },
    "Outbox": {
      "Retry": {
        "InitialDelaySeconds": 2,
        "Multiplier": 2,
        "MaxDelaySeconds": 300,
        "RetryAfterMinimumSeconds": 1,
        "RetryAfterMaximumSeconds": 3600
      },
      "Logs": {
        "MaxRecords": 100000,
        "MaxBytes": 2147483648,
        "HighSeverityReservationPercent": 25,
        "QuarantineRetentionDays": 90
      },
      "Audits": {
        "MaxRecords": 20000,
        "MaxBytes": 4294967296,
        "HighSeverityReservationPercent": 25,
        "QuarantineRetentionDays": 365
      }
    },
    "Redaction": {
      "AdditionalSensitiveFields": []
    },
    "Health": {
      "EmergencyDiagnosticMinimumIntervalSeconds": 60,
      "Disk": {
        "WarningFreeSpacePercent": 10,
        "WarningFreeSpaceBytes": 2147483648,
        "CriticalFreeSpacePercent": 5,
        "CriticalFreeSpaceBytes": 536870912,
        "CheckIntervalSeconds": 30
      }
    },
    "Framework": {
      "Enabled": true,
      "MinimumLevel": "Information"
    }
  }
}

Property behavior and limits

  • Environment defaults to Production; it must contain 1–64 printable characters.
  • TrustedContext.KnownProxies contains canonical proxy IPs; KnownNetworks contains aligned CIDR networks. Each list has at most 100 unique entries. ForwardLimit is 1–8. PresentationTimeZoneId defaults to Asia/Riyadh and is display-only.
  • Local.RootPath is required, is resolved relative to the process working directory when relative, and cannot contain control characters, wildcards, or a .. path segment. Application and audit JSONL sinks are mandatory in the configuration binding boundary. In this release, a missing or Enabled: false sink binding is normalized to its enabled default; keep both values true and control global disablement by not registering the package rather than relying on a local sink flag.
  • Local RetentionDays is 1–3650, MaxSegmentSizeBytes is 1–1073741824, BatchSize is 1–1000, and FlushIntervalMilliseconds is 50–5000.
  • Cscc.Enabled controls only the optional provider destination. When false, Core remains local-only and does not require valid endpoint, key, or scopes. When true, AppId is a non-empty identifier of at most 128 characters, Endpoint is an absolute HTTPS URI without user information, ApiKey is one scalar value of 32–512 non-whitespace characters, ContractVersion is exactly 3.0, and scopes are unique supported values containing logging.write. Supported scopes are logging.write and audit.write.
  • Cscc.Delivery.LogConcurrency and AuditConcurrency are 1–32 with a combined maximum of 64. AttemptTimeoutSeconds is 1–60.
  • Cscc.CircuitBreaker.FailureThreshold is positive; cooldown and rate-limit values must be positive finite numbers, maximum cooldown must not be below initial cooldown, maximum rate-limit pause must not be below minimum, and JitterRatio is greater than zero and at most 1.
  • Memory queue capacities are 1–1000000 records and 1–4294967296 bytes. HighSeverityBurstLimit is 1–100, EnqueueTimeoutMs is 1–250, handoff retry delays are 1–60 and 1–300 seconds with maximum not below initial, and shutdown drain is 1–30 seconds.
  • Queues.Overflow.HighSeverityReservationPercent is fixed at 25 in v1. Outbox lane reservation percentages are also fixed at 25.
  • Outbox capacities are 1–10000000 records and 1–17179869184 bytes. Quarantine retention is 1–3650 days. Retry delays and Retry-After bounds are positive finite values no greater than 3600 seconds; multiplier is 1–10; maximums cannot be below minimums.
  • Redaction.AdditionalSensitiveFields accepts at most 100 non-empty printable field names, each at most 128 characters. Names are normalized for matching.
  • Health diagnostic interval is 1–3600 seconds. Disk warning/critical percentages are positive and at most 100, critical must be below warning, byte thresholds are positive with critical below warning, and the disk check interval is 5–300 seconds.
  • Framework.Enabled controls the compatibility ILoggerProvider adapter only. Framework.MinimumLevel must be a defined Microsoft.Extensions.Logging level and does not filter explicit ICojectLogger calls.

Typed logging and auditing

Resolve ICojectLogger from DI. The facade prepares immutable Contracts records, validates them, redacts them, and attempts bounded Core ownership. An accepted record is independent of the caller after the ownership result returns.

using Coject.Core.Logging.Contracts;
using Coject.Core.Logging.Contracts.Payloads;

var logger = host.Services.GetRequiredService<ICojectLogger>();
var result = await logger.LogAsync(
    CojectEvents.SystemExecution(new SystemExecutionPayload(stepName: "startup")),
    CojectLogLevel.Info,
    "Coject logging verification");

Console.WriteLine($"{result.Status}: {result.Reason}");

Audits use closed event/action factories from Contracts. A mutation audit must carry committed-state snapshots and a context provider must supply Module, Resource, and Operation.

using Coject.Core.Logging.Contracts;
using Coject.Core.Logging.Contracts.Payloads;

CojectAuditAction<DataCreationPayload> action =
    CojectAuditActions.DataCreation(
        new DataCreationPayload(newValues: persistedSnapshot));
var result = await logger.AuditAsync(action);

persistedSnapshot above is an application-created CojectSnapshot; do not pass request DTOs as a substitute for committed state. The Core audit validator rejects missing required context, incomplete snapshots, invalid event/action pairs, and no-change modifications.

Local JSONL and audit behavior

The local providers are always installed by Core. Each service instance gets separate application and audit lanes. With the default RootPath, the layout is:

<working-directory>/logs/<service>/<environment>/<instance>/local/application/
  application-<service>-<environment>-<instance>-00000001.jsonl
<working-directory>/logs/<service>/<environment>/<instance>/local/audit/
  audit-<service>-<environment>-<instance>-00000001.jsonl

The service segment is derived from the entry assembly, environment is the configured value, and the instance segment is generated by Core. Each lane has a .writer.lock, rotates at MaxSegmentSizeBytes, batches writes, flushes on its interval, and removes files outside retention. Invalid managed records are isolated under that lane’s quarantine directory instead of being mixed into active JSONL.

Application records are operational/framework logs. Audit records are typed Contracts 3.0 records. Their canonical body is a nested envelope plus payload object; no provider-specific routing metadata is added to the body.

Failure, retry, and durable fallback

The enqueue path is intentionally bounded by Queues.EnqueueTimeoutMs. Memory capacity is independent for logs and audits. When a record cannot remain in memory, Core uses its protected overflow spool under the instance root:

<instance-root>/spool/logs/
<instance-root>/spool/audits/

The spool uses ownership and capability checks, preserves canonical bytes, recovers in the background, and quarantines malformed or unsafe entries. Provider outbox state is separate from the Core spool. CSCC delivery (when installed) has independent log/audit queues, concurrency, retry, quota, and quarantine settings.

Transient transport failures, timeouts, HTTP 408/425/429, and HTTP 5xx responses are eligible for bounded retry. A valid Retry-After on HTTP 429 is honored within the configured limits. HTTP 401 and 403 are classified as authentication/scope failures. HTTP 400, 404, 405, 413, 415, 422, and other ordinary 4xx responses are permanent provider failures; they do not open the circuit and are not blindly retried. Uncertain outcomes such as an ingestion conflict are retained for reconciliation rather than treated as confirmed.

On shutdown, the coordinated shutdown service closes intake, drains within ShutdownDrainTimeoutSeconds, and spills unresolved ownership. Application code should still await host.StopAsync() during graceful shutdown.

Redaction and security

  • Never put API keys, bearer tokens, passwords, cookies, connection strings, or raw authorization headers in records or README/configuration committed to source control.
  • Contracts redaction runs before local persistence and provider handoff. Redaction.AdditionalSensitiveFields adds normalized field names to the built-in sensitive set; it does not disable built-in redaction.
  • Keep Cscc.ApiKey in a secret provider or environment-variable override. The configuration binder requires one scalar value and the validator rejects whitespace/control characters.
  • Use HTTPS endpoints only. The CSCC adapter sends the key in X-API-Key, sends X-Correlation-ID, and does not copy credentials into canonical records or health snapshots.
  • Keep KnownProxies and KnownNetworks narrow. Forwarded IP values are accepted only when rebuilt by a trusted edge and the connection matches a configured proxy or network.
  • System actors do not carry an actor IP. User and anonymous actors may carry a trusted normalized originating IP. Do not accept arbitrary client-supplied actor identity as trusted context.

Correlation, actor, and IP behavior

The capture boundary prefers a validated X-Correlation-ID, then an envelope correlation ID, and otherwise generates a safe correlation ID. If both header and envelope values exist they must match; valid IDs are 8–64 ASCII letters, digits, ., _, or -. Canonical occurrence time is UTC at millisecond precision. PresentationTimeZoneId affects display text only.

The trusted context model supports user, system, and anonymous actors. User/system actors require stable IDs; display names are bounded and sanitized. Request context fields are closed to correlationId, module, resource, operation, entityId, and statusCode. Business identifiers are bounded safe values, and status codes must be 100–599.

Minimal verification

  1. Start the host with CojectLogging configured and Cscc.Enabled set to false.
  2. Resolve ICojectLogger and run the SystemExecution example above.
  3. Confirm an application-*.jsonl file appears under the configured local path and contains a Contracts 3.0 record.
  4. For an audit integration, supply a trusted context provider with module/resource/operation, submit a closed CojectAuditActions action after the database commit, and confirm an audit-*.jsonl file appears.
  5. Check ICojectLoggingHealth for local queue, spool, disk, and lifecycle state rather than parsing credentials or provider response bodies.

Troubleshooting

Symptom Check
Host fails during startup Read the safe options validation message. Check HTTPS endpoint, scalar key shape, exact 3.0 contract version, queue bounds, and disk thresholds.
No local file Check the process working directory, safe Local.RootPath, write permissions, disk health, and whether the host was started long enough for the writer loop to flush.
Audit is rejected Confirm the action is from a closed Contracts factory, snapshots represent committed state, and the context contains module, resource, and operation.
Framework logs are missing Check Framework.Enabled and Framework.MinimumLevel; explicit typed records are independent of this filter.
CSCC is not called Install/register Coject.Core.Logging.Cscc, set Cscc.Enabled to true, and verify the validated endpoint and key are supplied through secrets.
CSCC returns 401/403 Verify the API key and the required logging.write/audit.write scope for the lane.
CSCC returns 422 Treat it as a permanent persistence-validation failure. Inspect the provider’s contract validation and the safe diagnostic code; do not add blind retries.
Files accumulate in spool/outbox Check provider reachability, circuit-breaker state, disk capacity, quota limits, and quarantine files. Reconcile only after confirming the provider’s acknowledgement semantics.

Controller dependency decision

CojectCore.Controller is intentionally not referenced. Core logging is a hosting/infrastructure library and its public contracts do not use Controller types. Applications that use both libraries may reference both independently; adding a Controller dependency here would expand the runtime graph without providing logging functionality.

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 was computed.  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 was computed.  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 (1)

Showing the top 1 NuGet packages that depend on Coject.Core.Logging:

Package Downloads
Coject.Core.Logging.Cscc

Optional CSCC destination adapter for the provider-neutral Coject Core Logging pipeline, with separate log and audit HTTP lanes, Contracts 3.0 transport, bounded delivery, retry, and circuit-breaker behavior.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.0.0 47 8/15/2026

Initial publishable Coject Core Logging package. Includes the stable IHostApplicationBuilder.AddCojectLogging registration boundary, local JSONL application and audit sinks, durable fallback, and Contracts 3.0.0 support.