A cross-platform .NET CLI (logc) for compressing log files. Built for unattended scheduled jobs on servers โ point it at a log directory, optionally filter by age, and it produces archives and removes the originals.
- Two compression modes:
logc compress <path>โ produces one archive per source file (each log gets its own.zip/.tar.gz/.tar.br)logc bundle <path>โ produces one archive containing many files (good for end-of-month rollups)
- Three formats: ZIP (default), GZip (
.tar.gz), Brotli (.tar.br) - Filtering:
-r|--recurseโ descend into subdirectories--older-than <days>โ only files modified N+ calendar days ago--min-datetime/--max-datetimeโ explicit date-range window (mutually exclusive with--older-than)
- Safe by default โ original is deleted only after the archive is written successfully
- Self-contained single-file executable โ no .NET runtime required on the target server
- Response-file support โ pass arguments via a config file for repeatable scheduled jobs
- Structured logging via Serilog (console + file sinks); records what was compressed, skipped, errors, before/after sizes
Status: v0.1.0 โ first release. Download a prebuilt archive from Releases, or build from source below.
Each release attaches one self-contained archive per platform. Download the one for your OS (these links always resolve to the latest release):
| Platform | Download |
|---|---|
| Windows (x64) | logc-win-x64.zip |
| Linux (x64) | logc-linux-x64.tar.gz |
| macOS (Intel, x64) | logc-osx-x64.tar.gz |
Or browse every release on the Releases page.
Each archive contains the logc executable and its AppSettings.json โ keep the two together in the same folder (logc reads AppSettings.json from beside itself at startup).
Linux / macOS
# Download + extract (Linux x64 shown; swap in osx-x64 for macOS):
curl -L -o logc-linux-x64.tar.gz \
https://github.com/Chris-Wolfgang/Log-Compressor/releases/latest/download/logc-linux-x64.tar.gz
mkdir -p ~/logc && tar -xzf logc-linux-x64.tar.gz -C ~/logc
cd ~/logc
chmod +x logc # first run only
./logc compress /var/log/myapp --recurse --older-than 7macOS may quarantine a downloaded binary. If you see "cannot be opened because the developer cannot be verified," run
xattr -d com.apple.quarantine ./logconce.
Windows (PowerShell)
# Download + extract:
Invoke-WebRequest -Uri https://github.com/Chris-Wolfgang/Log-Compressor/releases/latest/download/logc-win-x64.zip -OutFile logc-win-x64.zip
Expand-Archive logc-win-x64.zip -DestinationPath C:\Tools\logc
cd C:\Tools\logc
.\logc.exe compress C:\Logs\myapp --recurse --older-than 7Put the folder on your PATH to call logc from anywhere.
git clone https://github.com/Chris-Wolfgang/Log-Compressor.git
cd Log-Compressor
git checkout v0.1.0
dotnet restore
dotnet build --configuration Release
dotnet testlogc compress /var/log/myapp/app.log
# Produces: /var/log/myapp/app-2026-05-04_10-15-30.zip
# Then deletes: /var/log/myapp/app.loglogc compress /var/log/myapp --recurse --older-than 7logc bundle /var/log/myapp --recurse --min-datetime 2026-04-01 --max-datetime 2026-04-30 --format gz
# Produces: /var/log/myapp/myapp-2026-04-01 to 2026-04-30.tar.gz| Mode | Pattern |
|---|---|
compress |
{filename}-{lastModified yyyy-MM-dd_HH-mm-ss}.{ext} |
bundle |
{foldername}-{minModified} to {maxModified}.{ext} |
| Flag | Purpose | Default |
|---|---|---|
-r, --recurse |
Recurse subdirectories | false |
-o, --output <dir> |
Output directory | source directory |
--older-than <days> |
Only files modified N+ days ago | (no filter) |
--min-datetime <dt> |
Inclusive lower bound on last-modified date | (no filter) |
--max-datetime <dt> |
Inclusive upper bound on last-modified date | (no filter) |
-f, --format <fmt> |
zip | gz | brotli |
zip |
--older-than is mutually exclusive with --min-datetime / --max-datetime. DateTime values are parsed using the local culture.
McMaster CommandLineUtils response-file support is enabled. Pass @path/to/args.txt and the file's lines become arguments โ useful for scheduled tasks where the command-line is awkward to express.
# example.rsp
compress
/var/log/myapp
--recurse
--older-than
7
--format
gz
--output
/archive/myapp
logc @example.rspThree layers, all internal and exposed to the test project via InternalsVisibleTo:
| Layer | Examples |
|---|---|
| Command | SharedOptions, Compress, Bundle (McMaster CommandLineUtils) |
| Service | CompressService, BundleService, FileFilterService, FileNamingService, compression strategies |
| Abstraction | IFileSystem, ICompressionStrategy, IFileFilter, IFileNamer |
Compression strategies (ZipStrategy, GZipStrategy, BrotliStrategy) are dispatched via CompressionStrategyFactory. GZip and Brotli bundles use System.Formats.Tar.TarWriter to wrap many files into a single tar before compressing โ .tar.gz and .tar.br respectively.
- TFM:
net10.0 - Distribution: self-contained, per-platform archive attached to each GitHub Release (no .NET runtime required on the target)
- Runtimes:
win-x64,linux-x64,osx-x64 - Not on NuGet:
logcis an application, not a library, so it is not published as a NuGet package.
Releases are produced by the publish-binaries job in .github/workflows/release.yaml, which cross-compiles all three runtimes and uploads one archive each (.zip for Windows, .tar.gz for Linux/macOS).
Each archive contains two files:
| File | Purpose |
|---|---|
logc (logc.exe on Windows) |
the self-contained single-file executable |
AppSettings.json |
runtime configuration (logging sinks/levels) โ loaded from beside the executable at startup; required |
To build the same artifact locally for one runtime:
dotnet publish src/Wolfgang.LogCompressor -c Release -r linux-x64 --self-contained -p:PublishSingleFile=trueThe output lands in bin/Release/net10.0/linux-x64/publish/ as logc alongside AppSettings.json โ copy both to your server (keep them together) and run ./logc.
| Metric | Value |
|---|---|
| Unit tests (xunit 2.9.3, NSubstitute) | 183 |
| Integration tests (real file system, all OSes) | 14 |
| Code coverage | 100% line, 95% branch; 90% per-module gate in CI |
| Benchmarks | BenchmarkDotNet (compression-format throughput) |
- GitHub Repository: https://github.com/Chris-Wolfgang/Log-Compressor
- Contributing Guide: CONTRIBUTING.md
- Code of Conduct: CODE_OF_CONDUCT.md
- Security Policy: SECURITY.md
Items deferred from v0.1.0:
decompresssub-command- Compressed-timestamp naming mode (
{name}-{now}instead of{name}-{lastModified}) - Custom name prefix (
--name) - Glob-pattern input (
*.log,app-*.log) - Mid-batch error-handling strategies (currently: skip & continue for
compress, fail-fast forbundle)
Contributions welcome. The architecture is built around interfaces (ICompressionStrategy, IFileSystem, etc.) so adding a new compression format or filter is a single-file change plus tests. See CONTRIBUTING.md for code style and PR guidelines.
This project is licensed under the MIT License. See the LICENSE file for details.