Enforce Runtime Logging Governance in .NET 8 with Cerbi.MEL.Governance
Thomas Nelson

Thomas Nelson @zeroshi

Joined:
Apr 9, 2025

Enforce Runtime Logging Governance in .NET 8 with Cerbi.MEL.Governance

Publish Date: Jun 5
0 0

Ever wished you could automatically catch missing PII fields or forbidden values in your .NET 8 logs, without rewriting your entire logging setup? With Cerbi.MEL.Governance, you can now plug governance checks directly into any Microsoft.Extensions.Logging pipeline. It always emits your original log line—and only emits a second JSON payload when a violation occurs.

In this post, we’ll cover:

  1. Why runtime logging governance matters
  2. How to install Cerbi.MEL.Governance
  3. Configuring your governance JSON (cerbi_governance.json)
  4. A quick‐start code example (3 lines to enable)
  5. A live demo with console output
  6. Advanced tips: Relaxed mode, multiple profiles, performance notes

Let’s dive in!


1. Why Runtime Logging Governance Matters

When you log structured messages in production—especially with user data or payment information—you want to make sure:

  • Required fields (e.g., userId, email) are never missing.
  • Forbidden fields (e.g., password, creditCardNumber) never appear.
  • You can enforce these rules at runtime, without having to manually audit logs later.

Most teams adopt Serilog or other libraries for structured logging. But if you’re already using .NET’s built‐in MEL (Microsoft.Extensions.Logging), there wasn’t a turnkey way to enforce governance rules—until now.

With Cerbi.MEL.Governance, you can:

  • Validate structured fields at runtime against a governance profile.
  • Always emit the original log line (so downstream parsers/alerts work unchanged).
  • Emit a secondary JSON payload only if a violation exists (no extra noise when everything is valid).
  • Support “Relaxed mode” (if you want to temporarily bypass some rules) by passing { Relax } = true.
  • Plug into any MEL-compatible sink: Console, File, Seq, Application Insights, etc.

2. Installation (NuGet)

Install the latest version via CLI:

# Installs the most recent version of Cerbi.MEL.Governance
dotnet add package Cerbi.MEL.Governance
Enter fullscreen mode Exit fullscreen mode

Note: Cerbi.MEL.Governance targets .NET 8.0 or higher.


3. Governance Configuration (cerbi_governance.json)

Create a file named cerbi_governance.json in your project root (or anywhere you like, just point ConfigPath to it). Here’s a sample:

{
  "EnforcementMode": "Strict",
  "LoggingProfiles": {
    "Orders": {
      "FieldSeverities": {
        "userId": "Required",
        "email": "Required",
        "password": "Forbidden"
      },
      "AllowRelax": true,
      "RequireTopic": true,
      "AllowedTopics": ["Orders"]
    },
    "Payments": {
      "FieldSeverities": {
        "accountNumber": "Required",
        "amount": "Required"
      },
      "AllowRelax": false,
      "RequireTopic": true,
      "AllowedTopics": ["Payments"]
    }
  }
}
Enter fullscreen mode Exit fullscreen mode
  • EnforcementMode

    • "Strict": Any missing required field or forbidden field triggers a violation.
  • LoggingProfiles

    • Each top‐level key (e.g., "Orders", "Payments") is a profile name or topic.
    • FieldSeverities: map each field name to "Required" or "Forbidden".
    • AllowRelax (boolean): if true, passing { Relax } = true in your log call will suppress violations and mark "GovernanceRelaxed": true.
    • RequireTopic: if true, logs without a matching [CerbiTopic] attribute or fallback Profile key will be skipped/flagged.
    • AllowedTopics: list of topics allowed for this profile (helps prevent cross‐pollination).

4. Quick‐Start Code Example (3 Lines!)

In most .NET 8 console or worker‐service apps, you have something like:

using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Cerbi; // Cerbi.MEL.Governance’s namespace

var builder = Host.CreateDefaultBuilder(args)
    .ConfigureLogging(logging =>
    {
        logging.ClearProviders();
        logging.AddSimpleConsole(options =>
        {
            options.IncludeScopes = true;
            options.SingleLine = true;
            options.TimestampFormat = "HH:mm:ss ";
        });

        // ← 3 lines to enable governance:
        logging.AddCerbiGovernance(options =>
        {
            options.Profile    = "Orders";                   // fallback topic if no [CerbiTopic] found
            options.ConfigPath = "cerbi_governance.json";    // path to your JSON profile
            options.Enabled    = true;                         // toggle enforcement on/off
        });
    })
    .ConfigureServices(services =>
    {
        services.AddTransient<OrderService>();
        services.AddTransient<PaymentService>();
    })
    .Build();
Enter fullscreen mode Exit fullscreen mode
  • using Cerbi; is mandatory because the AddCerbiGovernance(...) extension lives there.
  • You can replace logging.AddSimpleConsole(...) with any other MEL sink (e.g., logging.AddConsole(), logging.AddApplicationInsights(), etc.).
  • options.Profile is the default fallback topic if no [CerbiTopic("…")] is found on the call stack. You can still override via [CerbiTopic] on a class or method.

5. Live Demo & Output

OrderService.cs (example)

using Cerbi;  // for [CerbiTopic]
using Microsoft.Extensions.Logging;

[CerbiTopic("Orders")]
public class OrderService
{
    private readonly ILogger<OrderService> _logger;

    public OrderService(ILogger<OrderService> logger)
    {
        _logger = logger;
    }

    public void ProcessOrder(string userId, string email)
    {
        // Example 1: Valid log (both userId and email provided)
        _logger.LogInformation("Valid order: {userId} {email}", userId, email);

        // Example 2: Missing userId → violation
        _logger.LogInformation("Missing userId, only email: {email}", email);

        // Example 3: Forbidden field (password) → violation
        _logger.LogInformation(
            "Leaking password: {userId} {email} {password}",
            userId, email, "supersecret"
        );

        // Example 4: Relaxed mode (AllowRelax = true in JSON; pass {Relax} = true)
        _logger.LogInformation(
            "Email-only (relaxed): {email} {Relax}",
            email, true
        );
    }
}
Enter fullscreen mode Exit fullscreen mode

Assuming you call:

var service = host.Services.GetRequiredService<OrderService>();
service.ProcessOrder("abc123", "user@example.com");
Enter fullscreen mode Exit fullscreen mode

You’ll see console output like this:

[12:34:56 INF] Valid order: abc123 user@example.com
[12:34:56 INF] {"userId":"abc123","email":"user@example.com","CerbiTopic":"Orders","GovernanceProfileUsed":"Orders","GovernanceEnforced":true,"GovernanceMode":"Strict"}

[12:34:56 INF] Missing userId, only email: user@example.com
[12:34:56 INF] {"email":"user@example.com","CerbiTopic":"Orders","GovernanceViolations":["MissingField:userId"],"GovernanceRelaxed":false,"GovernanceProfileUsed":"Orders"}

[12:34:56 INF] Leaking password: abc123 user@example.com supersecret
[12:34:56 INF] {"userId":"abc123","email":"user@example.com","password":"supersecret","CerbiTopic":"Orders","GovernanceViolations":["ForbiddenField:password"],"GovernanceRelaxed":false,"GovernanceProfileUsed":"Orders"}

[12:34:56 INF] Email-only (relaxed): user@example.com True
[12:34:56 INF] {"email":"user@example.com","CerbiTopic":"Orders","GovernanceRelaxed":true,"GovernanceProfileUsed":"Orders"}
Enter fullscreen mode Exit fullscreen mode
  • First log: both fields present → governance enforced in “Strict” mode (JSON payload shows "GovernanceEnforced": true).
  • Second log: missing userId → JSON payload includes "GovernanceViolations": ["MissingField:userId"].
  • Third log: forbidden password → JSON payload includes "ForbiddenField:password".
  • Fourth log: relaxed (because { Relax } = true and AllowRelax:true in JSON) → JSON payload shows "GovernanceRelaxed": true.

Notice that your original log line always appears first, unchanged. Only when a rule is violated (or relaxed) do you see that second JSON‐only line. Downstream log processors (Seq, Kibana, Splunk) still parse your structured fields from the first line as usual.


6. Advanced Tips & Best Practices

  1. Multiple Profiles / Topics
  • If your solution has multiple domains (e.g., “Orders,” “Payments,” “Users”), define each profile in the JSON.
  • Use [CerbiTopic("Payments")] on your PaymentService class. If no attribute is found, options.Profile kicks in as a fallback.
  1. Turning Enforcement On/Off
  • Set options.Enabled = false (or toggle via an environment variable) for development or quick debugging.
  • You can programmatically reload the JSON file if it changes at runtime by restarting your host. A future version may support hot‐reloading.
  1. Relaxed Mode
  • In JSON: "AllowRelax": true
  • In code: _logger.LogInformation("… {Relax}", true)
  • Violations are suppressed; JSON payload simply shows "GovernanceRelaxed": true, "GovernanceProfileUsed": "Orders".
  1. EA / Compliance-Driven Use Cases
  • If you’re a Lead Enterprise Architect responsible for compliance, embed your EA roadmap decisions into your governance JSON.
  • Use field‐severity rules to detect days when migrations aren’t passing compliance checks (e.g., new microservices missing required context fields).
  1. Performance Considerations
  • On a warm VM startup, the JSON validator is built once in memory. Per‐log overhead is minimal (milliseconds) unless you have hundreds of structured fields.
  • Benchmarks show < 1 ms overhead on typical log calls when no violations occur. Always measure under your app’s load profile if you have extremely high‐frequency logging.

7. Next Steps & Roadmap

  • Relax() Helper Extension
    Coming soon: a fluent logger.Relax() API so you don’t have to manually pass { Relax } = true each time.

  • Support for Additional EA Tools
    Future releases will integrate directly with LeanIX, Alfabet, and MEGA’s REST APIs to sync governance profiles automatically.

  • Custom Violation Formatting
    Want more context in the JSON payload? We plan to add hooks so you can control the violation‐code format (e.g., prepend environment name or correlation‐ID).

  • Community Contributions
    We welcome issues and pull requests! If you have a scenario we haven’t covered (e.g., Azure Functions scope issues), please open an issue or PR on GitHub.


8. Links & Resources


TL;DR

Cerbi.MEL.Governance gives you runtime enforcement of required/forbidden fields in any MEL pipeline. Install one NuGet package, configure a simple JSON file, and enforce PII/compliance rules automatically. Visit the repo for a full demo; join the conversation via issues or PRs if you need help or want to contribute!

Happy logging!

Comments 0 total

    Add comment