Zetian.HealthCheck
1.0.0
Prefix Reserved
See the version list below for details.
dotnet add package Zetian.HealthCheck --version 1.0.0
NuGet\Install-Package Zetian.HealthCheck -Version 1.0.0
<PackageReference Include="Zetian.HealthCheck" Version="1.0.0" />
<PackageVersion Include="Zetian.HealthCheck" Version="1.0.0" />
<PackageReference Include="Zetian.HealthCheck" />
paket add Zetian.HealthCheck --version 1.0.0
#r "nuget: Zetian.HealthCheck, 1.0.0"
#:package Zetian.HealthCheck@1.0.0
#addin nuget:?package=Zetian.HealthCheck&version=1.0.0
#tool nuget:?package=Zetian.HealthCheck&version=1.0.0
Zetian.HealthCheck - Health Monitoring for SMTP
A lightweight health monitoring extension for Zetian SMTP Server, providing HTTP endpoints for health checks, liveness probes, readiness checks, and custom health metrics. Perfect for Kubernetes, Docker Swarm, load balancers, and monitoring systems.
β‘ Features
- π Multiple Endpoints -
/health/,/health/livez,/health/readyz - π Detailed Metrics - Server uptime, active sessions, memory usage, utilization
- π― Custom Checks - Add your own health checks (database, disk, services)
- π Flexible Binding - Support for localhost, specific IPs, hostnames, IPv6
- βΈοΈ Kubernetes Ready - Built for K8s liveness and readiness probes
- π Real-time Status - Live server health monitoring
- π JSON Response - Structured health data for monitoring tools
- π Zero Dependencies - Lightweight, uses only .NET built-in HttpListener
π¦ Installation
# Install Zetian SMTP Server (required)
dotnet add package Zetian
# Install Health Check Extension
dotnet add package Zetian.HealthCheck
π Quick Start
Basic Health Check
using Zetian;
using Zetian.HealthCheck.Extensions;
// Create and start SMTP server
var server = SmtpServerBuilder.CreateBasic();
await server.StartAsync();
// Enable health check on port 8080
var healthCheck = server.EnableHealthCheck(8080);
await healthCheck.StartAsync();
// Health check now available at:
// http://localhost:8080/health/
// http://localhost:8080/health/livez
// http://localhost:8080/health/readyz
Start Server with Health Check
// Start both SMTP and health check together
var healthCheck = await server.StartWithHealthCheckAsync(8080);
π οΈ Advanced Configuration
Custom Port and Path
// Custom port
var healthCheck = server.EnableHealthCheck(9090);
// Custom path (must end with /)
var healthCheck = server.EnableHealthCheck(8080, "/status/");
IP/Hostname Binding
// Bind to specific IP
var healthCheck = server.EnableHealthCheck(IPAddress.Parse("192.168.1.100"), 8080);
// Bind to hostname
var healthCheck = server.EnableHealthCheck("myserver.local", 8080);
// Bind to all interfaces (accessible externally)
var healthCheck = server.EnableHealthCheck("0.0.0.0", 8080);
// IPv6 support
var healthCheck = server.EnableHealthCheck(IPAddress.IPv6Loopback, 8080);
Custom Health Checks
var healthCheck = server.EnableHealthCheck(8080);
// Add database check
healthCheck.AddHealthCheck("database", async (ct) =>
{
try
{
var isConnected = await CheckDatabaseAsync();
return isConnected
? HealthCheckResult.Healthy("Database connected")
: HealthCheckResult.Unhealthy("Database connection failed");
}
catch (Exception ex)
{
return HealthCheckResult.Unhealthy("Database error", ex);
}
});
// Add disk space check
healthCheck.AddHealthCheck("disk_space", async (ct) =>
{
var drive = new DriveInfo("C:\\");
var freePercent = (double)drive.AvailableFreeSpace / drive.TotalSize * 100;
var data = new Dictionary<string, object>
{
["freeSpaceGB"] = drive.AvailableFreeSpace / (1024 * 1024 * 1024),
["totalSpaceGB"] = drive.TotalSize / (1024 * 1024 * 1024),
["freePercent"] = Math.Round(freePercent, 2)
};
if (freePercent < 10)
return HealthCheckResult.Unhealthy($"Critical: {freePercent:F2}% free", data: data);
if (freePercent < 20)
return HealthCheckResult.Degraded($"Low space: {freePercent:F2}% free", data: data);
return HealthCheckResult.Healthy($"Disk space OK: {freePercent:F2}% free", data: data);
});
await healthCheck.StartAsync();
Advanced Options
// Custom thresholds for SMTP health
var smtpOptions = new SmtpHealthCheckOptions
{
DegradedThresholdPercent = 60, // Degraded at 60% utilization
UnhealthyThresholdPercent = 85, // Unhealthy at 85% utilization
CheckMemoryUsage = true // Include memory metrics
};
// Custom service options
var serviceOptions = new HealthCheckServiceOptions
{
Prefixes = new() { "http://+:8080/health/" }, // Listen on all interfaces
DegradedStatusCode = 218 // Custom HTTP status for degraded (default: 200)
};
var healthCheck = server.EnableHealthCheck(serviceOptions, smtpOptions);
await healthCheck.StartAsync();
π Response Format
Healthy Response (HTTP 200)
{
"status": "Healthy",
"timestamp": "2024-10-22T16:30:00Z",
"checks": {
"smtp_server": {
"status": "Healthy",
"description": "SMTP server is healthy",
"data": {
"status": "running",
"uptime": "2d 3h 15m 42s",
"activeSessions": 5,
"maxSessions": 50,
"utilizationPercent": 10.0,
"memoryUsageMB": 45.2
}
},
"database": {
"status": "Healthy",
"description": "Database connected"
},
"disk_space": {
"status": "Healthy",
"description": "Disk space OK: 65.3% free",
"data": {
"freeSpaceGB": 250,
"totalSpaceGB": 500,
"freePercent": 50.0
}
}
}
}
Degraded Response (HTTP 200 or custom)
{
"status": "Degraded",
"timestamp": "2024-10-22T16:30:00Z",
"checks": {
"smtp_server": {
"status": "Degraded",
"description": "SMTP server utilization is high",
"data": {
"activeSessions": 35,
"maxSessions": 50,
"utilizationPercent": 70.0
}
}
}
}
Unhealthy Response (HTTP 503)
{
"status": "Unhealthy",
"timestamp": "2024-10-22T16:30:00Z",
"checks": {
"smtp_server": {
"status": "Unhealthy",
"description": "SMTP server is not running"
}
}
}
βΈοΈ Kubernetes Integration
Deployment Configuration
apiVersion: apps/v1
kind: Deployment
metadata:
name: smtp-server
spec:
replicas: 3
selector:
matchLabels:
app: smtp-server
template:
metadata:
labels:
app: smtp-server
spec:
containers:
- name: smtp-server
image: myregistry/smtp-server:latest
ports:
- containerPort: 25 # SMTP port
- containerPort: 8080 # Health check port
livenessProbe:
httpGet:
path: /health/livez
port: 8080
initialDelaySeconds: 30
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3
readinessProbe:
httpGet:
path: /health/readyz
port: 8080
initialDelaySeconds: 10
periodSeconds: 5
timeoutSeconds: 3
failureThreshold: 2
Service Configuration
apiVersion: v1
kind: Service
metadata:
name: smtp-service
spec:
selector:
app: smtp-server
ports:
- name: smtp
port: 25
targetPort: 25
- name: health
port: 8080
targetPort: 8080
π³ Docker Integration
Dockerfile Example
FROM mcr.microsoft.com/dotnet/runtime:8.0
WORKDIR /app
COPY . .
EXPOSE 25 8080
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD curl -f http://localhost:8080/health/ || exit 1
ENTRYPOINT ["dotnet", "MySmtpServer.dll"]
Docker Compose
version: '3.8'
services:
smtp:
image: mysmtp:latest
ports:
- "25:25"
- "8080:8080"
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/health/"]
interval: 30s
timeout: 3s
retries: 3
start_period: 40s
π― Monitoring Integration
Prometheus Metrics
// Add custom metrics check for Prometheus
healthCheck.AddHealthCheck("metrics", async (ct) =>
{
var data = new Dictionary<string, object>
{
["smtp_connections_active"] = server.SessionCount,
["smtp_connections_total"] = server.TotalConnectionsCount,
["smtp_messages_received"] = server.MessagesReceivedCount,
["smtp_uptime_seconds"] = server.UptimeSeconds
};
return HealthCheckResult.Healthy("Metrics collected", data: data);
});
Grafana/Datadog
Use the JSON endpoints to collect metrics:
# Collect health data
curl http://localhost:8080/health/ | jq '.checks.smtp_server.data'
# Check liveness
curl -f http://localhost:8080/health/livez
# Check readiness
curl -f http://localhost:8080/health/readyz
π API Reference
Extension Methods
| Method | Description |
|---|---|
EnableHealthCheck(port) |
Enable health check on localhost |
EnableHealthCheck(hostname, port) |
Enable on specific hostname |
EnableHealthCheck(IPAddress, port) |
Enable on specific IP |
EnableHealthCheck(options, healthOptions) |
Advanced configuration |
StartWithHealthCheckAsync(port) |
Start server and health check |
AddHealthCheck(name, checkFunc) |
Add custom health check |
Health Check Results
| Status | HTTP Code | Description |
|---|---|---|
| Healthy | 200 | Everything is working |
| Degraded | 200/218 | Working but with issues |
| Unhealthy | 503 | Critical problems detected |
π§ Troubleshooting
Common Issues
Port Already in Use
// Check if port is available before starting
var listener = new HttpListener();
try
{
listener.Prefixes.Add("http://localhost:8080/");
listener.Start();
listener.Stop();
// Port is available
}
catch (HttpListenerException)
{
// Port is in use
}
Access Denied on Non-Localhost
# Windows: Run as administrator or add URL ACL
netsh http add urlacl url=http://+:8080/health/ user=Everyone
# Linux: Use authbind or run as root
sudo setcap cap_net_bind_service=+ep /usr/bin/dotnet
IPv6 Issues
// Check IPv6 support
if (Socket.OSSupportsIPv6)
{
var healthCheck = server.EnableHealthCheck(IPAddress.IPv6Any, 8080);
}
else
{
var healthCheck = server.EnableHealthCheck("0.0.0.0", 8080);
}
π Requirements
- Windows, Linux, or macOS
- Zetian SMTP Server package
- .NET 6.0, 7.0, 8.0, 9.0, or 10.0
- Administrator privileges for non-localhost binding (Windows)
π Documentation & Support
- Issues: GitHub Issues
- Examples: GitHub Examples
- Discussions: GitHub Discussions
- Documentation: Zetian Documentation
π Acknowledgments
- Community feedback and contributions
- Inspired by ASP.NET Core Health Checks
- Built on top of Zetian SMTP Server
π Security
Best Practices:
- Configure rate limiting
- Keep the library updated
- Implement proper authentication
- Always use TLS/SSL in production
Report Security Issues: taiizor@vegalya.com
π License
MIT License - see LICENSE
Built with β€οΈ for the .NET community
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net6.0 is compatible. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 is compatible. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 is compatible. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. 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. |
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
All changes are detailed at https://zetian.soferity.com/changelog.