LittyLogs.Tool
0.2.3
dotnet tool install --global LittyLogs.Tool --version 0.2.3
dotnet new tool-manifest
dotnet tool install --local LittyLogs.Tool --version 0.2.3
#tool dotnet:?package=LittyLogs.Tool&version=0.2.3
nuke :add-package LittyLogs.Tool --version 0.2.3
litty-logs ๐ฅ
yo your .NET logs are giving corporate dystopia energy rn and thats not it bestie. litty-logs fully rewrites all them boring built-in framework messages into gen alpha slang while also blessing your terminal with emojis and ANSI colors no cap
before (deadass boring) ๐
info: Microsoft.Hosting.Lifetime[14]
Now listening on: http://localhost:5000
info: Microsoft.Hosting.Lifetime[0]
Application started. Press Ctrl+C to shut down.
info: Microsoft.Hosting.Lifetime[0]
Content root path: /app
after (absolutely bussin) ๐ฅ
[๐ฅ info] [2026-02-18T21:45:00.420Z] [Lifetime] we vibing on http://localhost:5000 fr fr ๐ง
[๐ฅ info] [2026-02-18T21:45:00.421Z] [Lifetime] app is bussin and ready to slay bestie ๐
yeet Ctrl+C to dip out no cap
[๐ฅ info] [2026-02-18T21:45:00.421Z] [Lifetime] content root living at /app bestie ๐
installation
dotnet add package LittyLogs
# for xUnit test output (optional, separate package)
dotnet add package LittyLogs.Xunit
# for file sink with rotation and gzip compression (optional, separate package)
dotnet add package LittyLogs.File
# for webhook sink โ yeet logs to Matrix, Teams, etc (optional, separate package)
dotnet add package LittyLogs.Webhooks
# for the CLI tool that litty-fies build, test, publish, pack, and clean output
dotnet tool install --global LittyLogs.Tool
usage โ one line thats it thats the tweet
web api
using LittyLogs;
var builder = WebApplication.CreateBuilder(args);
builder.Logging.AddLittyLogs(); // thats it bestie ๐ฅ
var app = builder.Build();
app.Run();
hosted service / background worker
using LittyLogs;
var host = Host.CreateDefaultBuilder(args)
.ConfigureLogging(logging => logging.AddLittyLogs())
.ConfigureServices(services => services.AddHostedService<MyService>())
.Build();
await host.RunAsync();
console script (the ten-liner speedrun)
using LittyLogs;
using Microsoft.Extensions.Logging;
using var factory = LoggerFactory.Create(logging =>
{
logging.SetMinimumLevel(LogLevel.Trace);
logging.AddLittyLogs();
});
var logger = factory.CreateLogger("MyScript");
logger.LogInformation("we in here bestie ๐ฅ");
xUnit tests
using LittyLogs.Xunit;
using Xunit;
using Xunit.Abstractions;
public class MyTests
{
private readonly ILogger<MyTests> _logger;
public MyTests(ITestOutputHelper output)
{
// one line to litty-fy your test output bestie ๐
_logger = output.CreateLittyLogger<MyTests>();
}
[Fact]
public void MyTest()
{
_logger.LogInformation("this shows up litty-fied in test output ๐ฅ");
}
}
JSON structured logging โ for when machines need to eat too ๐ฝ๏ธ
same litty rewrites and emojis, but as valid JSON. your log aggregator is gonna love this no cap
using LittyLogs;
var builder = WebApplication.CreateBuilder(args);
builder.Logging.AddLittyJsonLogs(); // structured JSON with emojis bestie ๐ฅ
var app = builder.Build();
app.Run();
output:
{"timestamp":"2026-02-19T10:45:00.420Z","level":"info","emoji":"๐ฅ","category":"Lifetime","message":"app is bussin and ready to slay bestie ๐
yeet Ctrl+C to dip out no cap"}
emojis in JSON? absolutely bussin โ JSON is UTF-8 native so every parser on earth handles it perfectly ๐
file sink โ yeet logs to disk with rotation and compression ๐
using LittyLogs.File;
var builder = WebApplication.CreateBuilder(args);
builder.Logging.AddLittyFileLogs(opts =>
{
opts.FilePath = "logs/app.log";
opts.OutputFormat = LittyFileOutputFormat.Text; // or Json for structured output
opts.RollingInterval = LittyRollingInterval.Daily;
opts.MaxFileSizeBytes = 10 * 1024 * 1024; // 10MB then rotate
opts.CompressionMode = LittyCompressionMode.Gzip; // compress rotated files ๐๏ธ
});
var app = builder.Build();
app.Run();
features that go hard:
- async I/O โ
Channel<string>based, your app thread never blocks on disk writes ๐ - text or JSON โ human-readable or machine-parseable, your choice bestie
- size + time rotation โ daily, hourly, or size-based. rotated files get timestamps in the name
- gzip compression โ old rotated files auto-compress to
.gz, active file stays uncompressed - startup safeguard โ never auto-rotates on startup, only rotates before writing the next entry ๐
- no ANSI codes โ files never get terminal escape chars, thats cursed ๐
webhook sink โ yeet logs to Matrix and Teams chat ๐ช
critical error hits? your group chat knows about it instantly, formatted all nice with emojis
using LittyLogs.Webhooks;
var builder = WebApplication.CreateBuilder(args);
builder.Logging.AddLittyMatrixLogs("https://hookshot.example.com/webhook/abc123"); // one liner bestie ๐ฃ
var app = builder.Build();
app.Run();
with full options:
builder.Logging.AddLittyMatrixLogs("https://hookshot.example.com/webhook/abc123", opts =>
{
opts.MinimumLevel = LogLevel.Warning; // only Warning+ goes to chat (default)
opts.Username = "LittyLogs"; // bot display name in chat
opts.BatchSize = 10; // max messages per batch
opts.BatchInterval = TimeSpan.FromSeconds(2); // flush interval
});
features that go hard:
- async batching โ
Channel<T>based, groups messages by interval (2s) or count (10), your app thread never blocks ๐ - Polly resilience โ retry with exponential backoff, circuit breaker, per-request timeout via
Microsoft.Extensions.Http.Resilience๐ - best-effort โ if the webhook is bricked after retries, we drop the batch and keep vibing. never crashes your app no cap
- min level filtering โ default
Warningso your chat dont get spammed with trace logs ๐ - IHttpClientFactory โ proper socket management, named client
"LittyWebhooks"for custom config - Matrix hookshot format โ markdown messages with emojis, exceptions in code blocks
Teams Adaptive Cards ๐ฆ
builder.Logging.AddLittyTeamsLogs("https://your-org.webhook.office.com/webhook/..."); // one liner bestie ๐ฆ
with full options:
builder.Logging.AddLittyTeamsLogs("https://your-org.webhook.office.com/webhook/...", opts =>
{
opts.MinimumLevel = LogLevel.Warning; // only Warning+ goes to chat (default)
opts.Username = "LittyLogs"; // shows in the card header
opts.BatchSize = 10; // max messages per batch
opts.BatchInterval = TimeSpan.FromSeconds(2); // flush interval
});
Teams-specific features that go hard:
- Adaptive Card v1.5 โ proper card format, not just plain text messages ๐
- severity-colored containers โ green (info), yellow (warning), red (error/critical), neutral (trace/debug) ๐จ
- monospace TextBlocks โ log lines render in monospace for that dashboard energy
- exception blocks โ subtle monospace blocks underneath the log line, dont overpower the message
- same batching + resilience โ Channel<T> batching, Polly retry, circuit breaker, best-effort delivery
what gets litty-fied
all the boring framework messages you see every dotnet run:
| boring version ๐ | litty version ๐ฅ |
|---|---|
| Application started. Press Ctrl+C to shut down. | app is bussin and ready to slay bestie ๐ yeet Ctrl+C to dip out no cap |
| Now listening on: {url} | we vibing on {url} fr fr ๐ง |
| Content root path: {path} | content root living at {path} bestie ๐ |
| Hosting environment: {env} | we in our {env} era rn โจ |
| Application is shutting down... | app said aight imma head out ๐ |
| Request starting {details} | yo a request just slid in: {details} ๐ |
| Request finished {details} | request finished cooking: {details} ๐ณ |
plus hosting lifecycle, endpoint routing, and more fr fr
log level emojis
| level | emoji | vibe |
|---|---|---|
| Trace | ๐ | lowkey peeking |
| Debug | ๐ | investigating bestie |
| Information | ๐ฅ | bussin as usual |
| Warning | ๐ค | not it |
| Error | ๐ | big L |
| Critical | โ ๏ธ | its giving death |
options โ configure the vibe
builder.Logging.AddLittyLogs(options =>
{
options.RewriteMessages = true; // rewrite framework messages (default: true, thats the whole point)
options.UseColors = true; // ANSI colors (default: true)
options.ShortenCategories = true; // yeet namespace bloat (default: true)
options.UseUtcTimestamp = true; // UTC timestamps (default: true, international rizz)
options.TimestampFormat = "yyyy-MM-ddTHH:mm:ss.fffK"; // ISO 8601 with milliseconds (default)
options.TimestampFirst = false; // false = RFC 5424 (level first), true = observability style (timestamp first)
});
dotnet litty CLI tool โ litty-fy your build, test, publish, pack, and clean output ๐งช
your app logs are litty but dotnet build, dotnet test, dotnet publish, dotnet pack, and dotnet clean output is still giving corporate energy? install the tool and never look at boring terminal output again no cap
# install the tool
dotnet tool install --global LittyLogs.Tool
# litty-fy your test output (auto-shows ITestOutputHelper output too)
dotnet litty test
# litty-fy your build output
dotnet litty build
# litty-fy your publish output
dotnet litty publish
# litty-fy your pack output โ nupkgs go brrr ๐ฆ
dotnet litty pack
# litty-fy your clean output โ watch artifacts get yeeted in style ๐๏ธ
dotnet litty clean
# all args pass through to the underlying dotnet command
dotnet litty test --filter "FullyQualifiedName~MyTests"
dotnet litty build -c Release
dotnet litty publish -c Release --self-contained
dotnet litty pack -c Release
dotnet litty clean -c Release
before (boring test output) ๐
Passed! - Failed: 0, Passed: 66, Skipped: 0, Total: 66, Duration: 80 ms - LittyLogs.Tests.dll (net10.0)
after (bussin test output) ๐ฅ
[xUnit.net] scouting for tests in LittyLogs.Tests ๐
[xUnit.net] found the squad in LittyLogs.Tests ๐
[xUnit.net] lets gooo LittyLogs.Tests is cooking ๐ฅ
โ
LittyLogs.Tests.MyTest.SomeTest [26 ms]
[xUnit.net] LittyLogs.Tests absolutely ate no crumbs ๐
all tests ate and left no crumbs ๐
total vibes checked: 66
ate: 66 โ
cooked in 0.5 Seconds โฑ๏ธ
your own logs stay untouched
litty-logs only rewrites known framework messages. your custom log messages pass through with the bussin formatting (emojis, colors, short categories) but the actual message text stays exactly how you wrote it no cap
logger.LogInformation("my custom message stays exactly like this");
// output: [๐ฅ info] [2026-02-18T21:45:00.420Z] [MyService] my custom message stays exactly like this
examples
seven example projects in examples/ so you can see litty-logs in every scenario:
| example | what it shows | run it |
|---|---|---|
WebApi |
startup demo with level-first โ timestamp-first โ JSON, then server runs | just example web |
HostedService |
startup demo with both timestamp modes, then background service vibes | just example hosted |
Console |
side-by-side text + JSON output comparison | just example console |
Xunit |
litty-fied xUnit test output with all log levels + TimestampFirst test | just example xunit |
Json |
structured JSON logging with both timestamp configs | just example json |
FileSink |
file sink with level-first โ timestamp-first โ JSON, reads em all back | just example filesink |
Webhooks |
dual webhook sink (Matrix + Teams) with mock listeners or live endpoints | just example webhooks |
every example auto-showcases ALL the modes when you run it โ no hidden flags, no secret handshakes. you run it, you see everything ๐
the webhooks example runs three demos: Matrix-only, Teams-only, and dual mode (both firing simultaneously). set HOOKSHOT_URL and/or TEAMS_WEBHOOK_URL in .env to go live โ any sink without a URL falls back to a local mock listener so it always works bestie ๐ช๐ฅ
development โ for the contributing besties ๐ ๏ธ
just recipes
this project uses just as the task runner. here are the vibes:
| recipe | what it does |
|---|---|
just build |
build the whole solution with litty-fied output ๐๏ธ๐ฅ |
just test |
run all tests with litty-fied output ๐งช๐ฅ |
just publish |
publish with litty-fied output ๐ค๐ฅ |
just pack |
pack all five NuGet packages with litty-fied output ๐ฆ๐ฅ |
just clean |
yeet all build artifacts with litty-fied output ๐๏ธ๐ฅ |
just bump patch |
bump the patch version (also: minor, major) |
just bump-pre dev.1 |
slap a pre-release label on (e.g. 0.1.0-dev.1) |
just release patch |
full gitflow release โ bump, branch, finish, push ๐ |
just release-current |
gitflow release without bumping (for first release etc.) |
just re-release |
nuke old releases + tags everywhere, re-do the current version ๐ |
just release-dev patch |
dev/pre-release โ bump + label + ship (e.g. 0.1.1-dev) ๐งช |
just hotfix patch |
start a gitflow hotfix branch off main ๐ |
just finish |
finish whatever gitflow branch youre on (hotfix/release/support) + push ๐ |
just nuget-push |
manually push packages to nuget.org |
just example <name> |
run an example โ web, hosted, console, xunit, json, filesink, webhooks ๐ฅ |
just setup-completions |
install shell tab-completions for just example <tab> |
shell completions
tab-complete just example <tab> to see all available examples. works with zsh and bash:
# auto-install to your shell rc file
just setup-completions
# or source manually
source completions/just.zsh # zsh
source completions/just.bash # bash
versioning
version lives in one place: Directory.Build.props. all five packages inherit from it. we use gitflow via the git flow CLI โ main is production, develop is the integration branch, releases and hotfixes get their own branches ๐ฅ
release flow (gitflow)
# from develop โ full gitflow ceremony (bump, branch, finish, push โ all in one command)
just release patch # 0.1.0 โ 0.1.1, pushes everything, pipeline goes brrr
just release minor # 0.1.0 โ 0.2.0
just release major # 0.1.0 โ 1.0.0
# dev/pre-release for testing the pipeline
just release-dev patch # 0.1.0 โ 0.1.1-dev
just release-dev minor beta.1 # 0.1.0 โ 0.2.0-beta.1
# release the current version without bumping (e.g. first release)
just release-current
all release commands auto-push develop + main + tag to origin when done. no manual git push needed fr fr ๐ฅ
hotfix flow
# from main โ start a hotfix when something is bricked in prod
just hotfix patch
# make your fix, commit it, then finish + push
just finish
just finish auto-detects if youre on a hotfix, release, or support branch, does git flow finish, and pushes everything. one command to rule them all ๐
CI/CD โ triple release pipeline ๐
forgejo actions on a self-hosted runner handles the whole squad:
- CI (
ci.yml) โ builds, tests (with litty output ๐ฅ), and packs on every push/PR todevelopandmain. if this fails your code is bricked and you should not merge no cap - Release (
release.yml) โ triggered byv*tags. the full pipeline hits THREE destinations:- nuget.org โ all five
.nupkgfiles with--skip-duplicateso retries dont catch Ls - forgejo releases โ via Gitea API with
.nupkgassets attached ๐ - github mirror releases โ via
ghCLI with.nupkgassets on the mirror repo ๐
- nuget.org โ all five
pipeline features that go hard:
- fully retryable โ every step checks if work is already done before doing it again. re-run from the forgejo UI all day, zero errors ๐
- pre-release auto-detection โ versions with
-(like0.1.0-dev,1.0.0-beta.1) auto-flag as pre-release on both platforms ๐งช - changelog extraction โ release notes auto-pulled from
CHANGELOG.mdfor that professional rizz ๐ - version sanity check โ tag must match
Directory.Build.propsor the pipeline tells you its not it ๐
see docs/runner-setup.md for runner setup and required secrets no cap
manifesting these features ๐ง โจ
stuff that would go absolutely crazy but aint started yet. vibes only rn no cap
- ๐ฌ Slack webhook sink โ Block Kit formatter for the Slack besties
- ๐ฃ Matrix Client-Server API โ direct room messages for power users who want full HTML control instead of hookshot
- ๐จ custom webhook templates โ user-defined message format strings so you can make it look however you want
- ๐๏ธ zstd compression โ for file sink rotation (gzip is cool but zstd is faster and smaller fr fr)
- ๐ structured log enrichment โ auto-attach machine name, environment, correlation IDs to webhook messages
wanna see one of these happen? PRs are open bestie, or just vibe in the issues ๐
security ๐
litty-logs takes security seriously even though we dont take ourselves seriously no cap. heres the tldr:
- webhook URL validation โ SSRF prevention, only
http/httpsschemes allowed - log injection prevention โ newlines in messages get sanitized to spaces in text output
- content injection prevention โ webhook messages get HTML-encoded (Matrix) or rendered as plain text (Teams Adaptive Cards), no tracking pixels or phishing links in your chat
- HTTP category filtering โ prevents infinite recursion AND accidental webhook URL token exposure
full details in docs/security.md
found a vulnerability? dont yeet it in a public issue โ open a security advisory instead bestie ๐
license
MIT โ share the vibes bestie โ๏ธ
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | 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. |
This package has no dependencies.