# Configuration Overview `NatsOptions` is the single configuration object passed to `NatsServer` at construction time. The host application (`Program.cs`) also reads CLI arguments to populate it before server startup. Go reference: `golang/nats-server/server/opts.go` --- ## NatsOptions Class `NatsOptions` is a plain mutable class with no validation logic — values are consumed directly by `NatsServer` and `NatsClient`. ```csharp namespace NATS.Server; public sealed class NatsOptions { public string Host { get; set; } = "0.0.0.0"; public int Port { get; set; } = 4222; public string? ServerName { get; set; } public int MaxPayload { get; set; } = 1024 * 1024; // 1MB public int MaxControlLine { get; set; } = 4096; public int MaxConnections { get; set; } = 65536; public TimeSpan PingInterval { get; set; } = TimeSpan.FromMinutes(2); public int MaxPingsOut { get; set; } = 2; } ``` ### Option reference | Option | Type | Default | Description | |--------|------|---------|-------------| | `Host` | `string` | `"0.0.0.0"` | Bind address for the TCP listener. Use `"127.0.0.1"` to restrict to loopback. | | `Port` | `int` | `4222` | Client listen port. Standard NATS client port. | | `ServerName` | `string?` | `null` (auto: `nats-dotnet-{MachineName}`) | Server name sent in the `INFO` message. When `null`, the server constructs a name from `Environment.MachineName`. | | `MaxPayload` | `int` | `1048576` (1 MB) | Maximum allowed message payload in bytes. Clients that publish larger payloads are rejected. | | `MaxControlLine` | `int` | `4096` | Maximum protocol control line size in bytes. Matches the Go server default. | | `MaxConnections` | `int` | `65536` | Maximum concurrent client connections the server will accept. | | `PingInterval` | `TimeSpan` | `2 minutes` | Interval between server-initiated `PING` messages to connected clients. | | `MaxPingsOut` | `int` | `2` | Number of outstanding `PING`s without a `PONG` response before the server disconnects a client. | ### How ServerName is resolved `NatsServer` constructs the `ServerInfo` sent to each client at connection time. If `ServerName` is `null`, it uses `nats-dotnet-{Environment.MachineName}`: ```csharp _serverInfo = new ServerInfo { ServerId = Guid.NewGuid().ToString("N")[..20].ToUpperInvariant(), ServerName = options.ServerName ?? $"nats-dotnet-{Environment.MachineName}", Version = NatsProtocol.Version, Host = options.Host, Port = options.Port, MaxPayload = options.MaxPayload, }; ``` --- ## CLI Arguments `Program.cs` parses command-line arguments before creating `NatsServer`. The three supported flags map directly to `NatsOptions` fields: | Flag | Alias | Field | Example | |------|-------|-------|---------| | `-p` | `--port` | `Port` | `-p 14222` | | `-a` | `--addr` | `Host` | `-a 127.0.0.1` | | `-n` | `--name` | `ServerName` | `-n my-server` | ```csharp for (int i = 0; i < args.Length; i++) { switch (args[i]) { case "-p" or "--port" when i + 1 < args.Length: options.Port = int.Parse(args[++i]); break; case "-a" or "--addr" when i + 1 < args.Length: options.Host = args[++i]; break; case "-n" or "--name" when i + 1 < args.Length: options.ServerName = args[++i]; break; } } ``` Unrecognized flags are silently ignored. There is no `--help` output. --- ## Protocol Constants `NatsProtocol` defines wire-level constants that mirror the Go server's defaults. These values are used by the parser and the `INFO` response: | Constant | Value | Description | |----------|-------|-------------| | `MaxControlLineSize` | `4096` | Maximum bytes in a protocol control line | | `MaxPayloadSize` | `1048576` | Maximum message payload in bytes (1 MB) | | `DefaultPort` | `4222` | Standard NATS client port | | `Version` | `"0.1.0"` | Server version string sent in `INFO` | | `ProtoVersion` | `1` | NATS protocol version number sent in `INFO` | ```csharp public static class NatsProtocol { public const int MaxControlLineSize = 4096; public const int MaxPayloadSize = 1024 * 1024; // 1MB public const int DefaultPort = 4222; public const string Version = "0.1.0"; public const int ProtoVersion = 1; } ``` `MaxControlLine` in `NatsOptions` and `MaxControlLineSize` in `NatsProtocol` carry the same value. `NatsOptions.MaxPayload` is used as the per-server runtime limit passed into `NatsParser`; `NatsProtocol.MaxPayloadSize` is the compile-time default. --- ## Logging Configuration ### Serilog setup Logging uses [Serilog](https://serilog.net/) with the console sink, configured in `Program.cs` before any other code runs: ```csharp Log.Logger = new LoggerConfiguration() .MinimumLevel.Debug() .Enrich.FromLogContext() .WriteTo.Console(outputTemplate: "[{Timestamp:HH:mm:ss} {Level:u3}] {Message:lj}{NewLine}{Exception}") .CreateLogger(); ``` The output template produces lines like: ``` [14:32:01 INF] Listening on 0.0.0.0:4222 [14:32:01 DBG] Client 1 connected from 127.0.0.1:54321 ``` ### ILoggerFactory injection `Program.cs` wraps the Serilog logger in a `SerilogLoggerFactory` and passes it to `NatsServer`: ```csharp using var loggerFactory = new Serilog.Extensions.Logging.SerilogLoggerFactory(Log.Logger); var server = new NatsServer(options, loggerFactory); ``` `NatsServer` stores the factory and uses it to create two kinds of loggers: - **`ILogger`** — obtained via `loggerFactory.CreateLogger()`, used for server-level events (listening, client connect/disconnect). - **`ILogger` with named category** — obtained via `loggerFactory.CreateLogger($"NATS.Server.NatsClient[{clientId}]")`, created per connection. This gives each client a distinct category in log output so messages can be correlated by client ID without structured log properties. ```csharp // In NatsServer.StartAsync — one logger per accepted connection var clientLogger = _loggerFactory.CreateLogger($"NATS.Server.NatsClient[{clientId}]"); var client = new NatsClient(clientId, socket, _options, _serverInfo, clientLogger); ``` `NatsClient` takes `ILogger` (not `ILogger`) so it can accept the pre-named logger instance rather than deriving its category from its own type. ### Log flushing `Log.CloseAndFlush()` runs in the `finally` block of `Program.cs` after the server stops, ensuring buffered log entries are written before the process exits: ```csharp try { await server.StartAsync(cts.Token); } catch (OperationCanceledException) { } finally { Log.CloseAndFlush(); } ``` --- ## Related Documentation - [Operations Overview](../Operations/Overview.md) - [Server Overview](../Server/Overview.md)