feat: add structured logging, Shouldly assertions, CPM, and project documentation
- Add Microsoft.Extensions.Logging + Serilog to NatsServer and NatsClient - Convert all test assertions from xUnit Assert to Shouldly - Add NSubstitute package for future mocking needs - Introduce Central Package Management via Directory.Packages.props - Add documentation_rules.md with style guide, generation/update rules, component map - Generate 10 documentation files across 5 component folders (GettingStarted, Protocol, Subscriptions, Server, Configuration/Operations) - Update CLAUDE.md with logging, testing, porting, agent model, CPM, and documentation guidance
This commit is contained in:
183
Documentation/GettingStarted/Setup.md
Normal file
183
Documentation/GettingStarted/Setup.md
Normal file
@@ -0,0 +1,183 @@
|
||||
# Setup
|
||||
|
||||
This guide covers prerequisites, building, running, and testing the NATS .NET server.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
### .NET 10 SDK
|
||||
|
||||
The project targets `net10.0` with `LangVersion preview` (configured in `Directory.Build.props`). Install the .NET 10 preview SDK from https://dotnet.microsoft.com/download.
|
||||
|
||||
Verify your installation:
|
||||
|
||||
```bash
|
||||
dotnet --version
|
||||
# Expected: 10.0.x
|
||||
```
|
||||
|
||||
### Go Toolchain (optional)
|
||||
|
||||
The Go toolchain is only needed if you want to run the reference server from `golang/nats-server/` or execute Go test suites for cross-validation. It is not required for building or testing the .NET port.
|
||||
|
||||
```bash
|
||||
go version
|
||||
# Expected: go1.22 or later
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Building
|
||||
|
||||
The solution file uses the `.slnx` format (not `.sln`). Pass it explicitly if your tooling requires it.
|
||||
|
||||
```bash
|
||||
# Build all projects
|
||||
dotnet build
|
||||
|
||||
# Clean and rebuild
|
||||
dotnet clean && dotnet build
|
||||
```
|
||||
|
||||
The solution contains three projects:
|
||||
|
||||
| Project | Path |
|
||||
|---------|------|
|
||||
| `NATS.Server` | `src/NATS.Server/` |
|
||||
| `NATS.Server.Host` | `src/NATS.Server.Host/` |
|
||||
| `NATS.Server.Tests` | `tests/NATS.Server.Tests/` |
|
||||
|
||||
All projects share settings from `Directory.Build.props`: `net10.0` target framework, nullable reference types enabled, warnings treated as errors.
|
||||
|
||||
---
|
||||
|
||||
## Running
|
||||
|
||||
The server executable is `NATS.Server.Host`. With no arguments it binds to `0.0.0.0:4222`.
|
||||
|
||||
```bash
|
||||
dotnet run --project src/NATS.Server.Host
|
||||
```
|
||||
|
||||
### CLI Arguments
|
||||
|
||||
| Flag | Alias | Type | Default | Description |
|
||||
|------|-------|------|---------|-------------|
|
||||
| `-p` | `--port` | `int` | `4222` | TCP port to listen on |
|
||||
| `-a` | `--addr` | `string` | `0.0.0.0` | Bind address |
|
||||
| `-n` | `--name` | `string` | `nats-dotnet-<hostname>` | Server name reported in INFO |
|
||||
|
||||
```bash
|
||||
# Custom port
|
||||
dotnet run --project src/NATS.Server.Host -- -p 14222
|
||||
|
||||
# Custom address and name
|
||||
dotnet run --project src/NATS.Server.Host -- -a 127.0.0.1 -p 4222 -n dev-server
|
||||
```
|
||||
|
||||
The `--` separator is required to pass arguments through `dotnet run` to the application.
|
||||
|
||||
Startup log output (Serilog console sink):
|
||||
|
||||
```
|
||||
[12:00:00 INF] Listening on 0.0.0.0:4222
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Testing
|
||||
|
||||
```bash
|
||||
# Run all tests
|
||||
dotnet test
|
||||
|
||||
# Run tests with verbose output
|
||||
dotnet test -v normal
|
||||
|
||||
# Run a single test project
|
||||
dotnet test tests/NATS.Server.Tests
|
||||
|
||||
# Run a specific test by name
|
||||
dotnet test tests/NATS.Server.Tests --filter "FullyQualifiedName~SubListTests"
|
||||
```
|
||||
|
||||
### Test Stack
|
||||
|
||||
| Package | Version | Purpose |
|
||||
|---------|---------|---------|
|
||||
| `xunit` | 2.9.3 | Test framework |
|
||||
| `xunit.runner.visualstudio` | 3.1.4 | VS/Rider test runner integration |
|
||||
| `Shouldly` | 4.3.0 | Assertion library |
|
||||
| `NSubstitute` | 5.3.0 | Mocking |
|
||||
| `NATS.Client.Core` | 2.7.2 | Official NATS .NET client for integration tests |
|
||||
| `coverlet.collector` | 6.0.4 | Code coverage |
|
||||
|
||||
Do not use FluentAssertions or Moq — the project uses Shouldly and NSubstitute exclusively.
|
||||
|
||||
### Test Files
|
||||
|
||||
| File | Covers |
|
||||
|------|--------|
|
||||
| `ParserTests.cs` | `NatsParser.TryParse` for each command type |
|
||||
| `SubjectMatchTests.cs` | `SubjectMatch` validation and wildcard matching |
|
||||
| `SubListTests.cs` | `SubList` trie insert, remove, match, and cache behaviour |
|
||||
| `ClientTests.cs` | `NatsClient` command dispatch and subscription tracking |
|
||||
| `ServerTests.cs` | `NatsServer` pub/sub, wildcards, queue groups |
|
||||
| `IntegrationTests.cs` | End-to-end tests using `NATS.Client.Core` against a live server |
|
||||
|
||||
---
|
||||
|
||||
## NuGet: Central Package Management
|
||||
|
||||
Package versions are defined centrally in `Directory.Packages.props`. Individual `.csproj` files reference packages without a `Version` attribute:
|
||||
|
||||
```xml
|
||||
<!-- Directory.Packages.props -->
|
||||
<PackageVersion Include="Shouldly" Version="4.3.0" />
|
||||
<PackageVersion Include="NSubstitute" Version="5.3.0" />
|
||||
```
|
||||
|
||||
```xml
|
||||
<!-- NATS.Server.Tests.csproj -->
|
||||
<PackageReference Include="Shouldly" />
|
||||
<PackageReference Include="NSubstitute" />
|
||||
```
|
||||
|
||||
To add a new dependency: add a `<PackageVersion>` entry in `Directory.Packages.props`, then add a `<PackageReference>` (without `Version`) in the relevant `.csproj`.
|
||||
|
||||
---
|
||||
|
||||
## Logging
|
||||
|
||||
The host configures Serilog via `Microsoft.Extensions.Logging` in `Program.cs`:
|
||||
|
||||
```csharp
|
||||
Log.Logger = new LoggerConfiguration()
|
||||
.MinimumLevel.Debug()
|
||||
.Enrich.FromLogContext()
|
||||
.WriteTo.Console(outputTemplate: "[{Timestamp:HH:mm:ss} {Level:u3}] {Message:lj}{NewLine}{Exception}")
|
||||
.CreateLogger();
|
||||
|
||||
using var loggerFactory = new Serilog.Extensions.Logging.SerilogLoggerFactory(Log.Logger);
|
||||
var server = new NatsServer(options, loggerFactory);
|
||||
```
|
||||
|
||||
`NatsServer` and `NatsClient` receive `ILoggerFactory` and `ILogger` respectively via constructor injection. The core library (`NATS.Server`) depends only on `Microsoft.Extensions.Logging.Abstractions` — it has no direct Serilog dependency. The Serilog packages are wired in `NATS.Server.Host`.
|
||||
|
||||
Per-client loggers are created with a scoped category name that includes the client ID:
|
||||
|
||||
```csharp
|
||||
var clientLogger = _loggerFactory.CreateLogger($"NATS.Server.NatsClient[{clientId}]");
|
||||
```
|
||||
|
||||
To adjust log levels at runtime, modify the `LoggerConfiguration` in `Program.cs`.
|
||||
|
||||
---
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- [Architecture](./Architecture.md)
|
||||
- [Configuration Overview](../Configuration/Overview.md)
|
||||
- [Protocol Overview](../Protocol/Overview.md)
|
||||
- [Server Overview](../Server/Overview.md)
|
||||
|
||||
<!-- Last verified against codebase: 2026-02-22 -->
|
||||
Reference in New Issue
Block a user