Comprehensive monitoring and metrics collection for Zetian SMTP Server. Features include real-time metrics, Prometheus/Grafana integration, OpenTelemetry support, command-level statistics, and performance monitoring.
$ dotnet add package Zetian.MonitoringComprehensive monitoring and observability solution for Zetian SMTP Server with Prometheus, OpenTelemetry, and real-time metrics collection.
# Install Zetian SMTP Server (required)
dotnet add package Zetian
# Install Monitoring Extension
dotnet add package Zetian.Monitoring
using Zetian.Server;
using Zetian.Monitoring.Extensions;
// Create and start SMTP server
var server = SmtpServerBuilder.CreateBasic();
// Enable monitoring with default settings
server.EnableMonitoring();
await server.StartAsync();
// Get statistics
var stats = server.GetStatistics();
Console.WriteLine($"Active Sessions: {stats?.ActiveSessions}");
Console.WriteLine($"Messages/sec: {stats?.CurrentThroughput?.MessagesPerSecond}");
// Enable Prometheus exporter on port 9090 (default host: localhost)
server.EnablePrometheus(9090);
// With custom host (use "+" for all interfaces - requires admin rights)
server.EnablePrometheus("0.0.0.0", 9090); // Listen on all IPv4
server.EnablePrometheus("localhost", 9090); // Listen on localhost only (default)
server.EnablePrometheus("+", 9090); // Listen on all interfaces (requires admin)
// Or with builder pattern
server.EnableMonitoring(builder => builder
.EnablePrometheus(9090) // Uses default host: localhost
.WithUpdateInterval(TimeSpan.FromSeconds(5)));
// With custom host in builder
server.EnableMonitoring(builder => builder
.EnablePrometheus("0.0.0.0", 9090)
.WithPrometheusHost("0.0.0.0") // Alternative way
.WithUpdateInterval(TimeSpan.FromSeconds(5)));
// Metrics available at http://localhost:9090/metrics (or your configured host)
server.EnableMonitoring(builder => builder
.EnablePrometheus(9090)
.EnableOpenTelemetry("http://localhost:4317")
.WithServiceName("smtp-production")
.WithServiceVersion("1.0.0")
.EnableDetailedMetrics()
.EnableCommandMetrics()
.EnableThroughputMetrics()
.EnableHistograms()
.WithUpdateInterval(TimeSpan.FromSeconds(10))
.WithLabels(
("environment", "production"),
("region", "us-east-1"),
("instance", "smtp-01"))
.WithCommandDurationBuckets(1, 5, 10, 25, 50, 100, 250, 500, 1000)
.WithMessageSizeBuckets(1024, 10240, 102400, 1048576, 10485760));
| Metric | Type | Description |
|---|---|---|
zetian_sessions_total | Counter | Total SMTP sessions |
zetian_messages_total{status} | Counter | Total messages (delivered/rejected) |
zetian_bytes_total{direction} | Counter | Total bytes (in/out) |
zetian_errors_total{type} | Counter | Total errors by type |
zetian_commands_total{command,status} | Counter | SMTP commands executed |
zetian_authentications_total{mechanism,status} | Counter | Authentication attempts |
zetian_connections_total{status} | Counter | Connection attempts |
zetian_tls_upgrades_total{status} | Counter | TLS upgrades |
zetian_rejections_total{reason} | Counter | Message rejections |
zetian_active_sessions | Gauge | Current active sessions |
zetian_uptime_seconds | Gauge | Server uptime |
zetian_memory_bytes | Gauge | Memory usage |
zetian_throughput_messages_per_second | Gauge | Current message throughput |
zetian_throughput_bytes_per_second | Gauge | Current bytes throughput |
zetian_command_duration_milliseconds{command} | Histogram | Command execution time |
zetian_message_size_bytes | Histogram | Message size distribution |
zetian_session_duration_seconds | Summary | Session duration statistics |
// Get comprehensive statistics
var stats = server.GetStatistics();
// Basic metrics
Console.WriteLine($"Uptime: {stats.Uptime}");
Console.WriteLine($"Total Sessions: {stats.TotalSessions}");
Console.WriteLine($"Active Sessions: {stats.ActiveSessions}");
Console.WriteLine($"Total Messages: {stats.TotalMessagesReceived}");
Console.WriteLine($"Delivery Rate: {stats.DeliveryRate}%");
Console.WriteLine($"Rejection Rate: {stats.RejectionRate}%");
// Connection metrics
Console.WriteLine($"Connections Accepted: {stats.ConnectionMetrics.AcceptedCount}");
Console.WriteLine($"TLS Usage: {stats.ConnectionMetrics.TlsUsageRate}%");
Console.WriteLine($"Peak Concurrent: {stats.ConnectionMetrics.PeakConcurrentConnections}");
// Authentication metrics
Console.WriteLine($"Auth Success Rate: {stats.AuthenticationMetrics.SuccessRate}%");
Console.WriteLine($"Unique Users: {stats.AuthenticationMetrics.UniqueUsers}");
// Command metrics
foreach (var cmd in stats.CommandMetrics)
{
Console.WriteLine($"{cmd.Key}: {cmd.Value.AverageDurationMs}ms avg, " +
$"{cmd.Value.SuccessRate}% success");
}
// Throughput
var throughput = stats.CurrentThroughput;
Console.WriteLine($"Messages/sec: {throughput.MessagesPerSecond}");
Console.WriteLine($"Bytes/sec: {throughput.BytesPerSecond}");
Console.WriteLine($"Commands/sec: {throughput.CommandsPerSecond}");
// Record custom command metrics
server.RecordMetric("CUSTOM_CMD", success: true, durationMs: 42.5);
// Access metrics collector directly
var collector = server.GetMetricsCollector();
collector.RecordCommand("XCUSTOM", true, 15.3);
collector.RecordAuthentication(true, "CUSTOM_AUTH");
collector.RecordRejection("Custom rejection reason");
using Zetian.Server;
using Zetian.Monitoring.Extensions;
// Create SMTP server
var server = SmtpServerBuilder.CreateBasic();
// Enable monitoring with OpenTelemetry (automatic tracing & metrics)
server.EnableMonitoring(builder => builder
.EnableOpenTelemetry("http://localhost:4317") // OTLP endpoint
.WithServiceName("smtp-production")
.WithServiceVersion("1.0.0"));
await server.StartAsync();
server.EnableMonitoring(builder => builder
.EnablePrometheus(9090) // Prometheus on port 9090
.EnableOpenTelemetry("http://localhost:4317") // OpenTelemetry OTLP
.WithServiceName("smtp-server")
.WithServiceVersion("1.0.0")
.EnableDetailedMetrics()
.EnableCommandMetrics()
.WithLabels(
("environment", "production"),
("region", "us-east-1")));
// Start a custom activity (span) for your operations
using (var activity = server.StartActivity("custom.operation"))
{
activity?.SetTag("operation.type", "batch_process");
activity?.SetTag("batch.size", 100);
// Your custom logic here
ProcessBatch();
activity?.SetTag("result", "success");
}
// Trace message processing with custom attributes
server.MessageReceived += (sender, e) =>
{
using var activity = server.StartActivity("message.custom_processing");
activity?.SetTag("message.size", e.Message.Size);
activity?.SetTag("sender.host", e.Message.From?.Host);
activity?.SetTag("sender.address", e.Message.From?.Address);
// Custom processing logic
if (e.Message.Size > 10_000_000)
{
activity?.AddEvent(new ActivityEvent("large_message_detected"));
}
};
public class MonitoringConfiguration
{
// Prometheus settings
public bool EnablePrometheus { get; set; }
public int? PrometheusPort { get; set; }
// OpenTelemetry settings
public bool EnableOpenTelemetry { get; set; }
public string? OpenTelemetryEndpoint { get; set; }
// Update settings
public TimeSpan UpdateInterval { get; set; } = TimeSpan.FromSeconds(10);
// Feature toggles
public bool EnableDetailedMetrics { get; set; } = true;
public bool EnableCommandMetrics { get; set; } = true;
public bool EnableThroughputMetrics { get; set; } = true;
public bool EnableHistograms { get; set; } = true;
// Service identification
public string ServiceName { get; set; } = "Zetian.SMTP";
public string ServiceVersion { get; set; } = "1.0.0";
// Custom labels for all metrics
public Dictionary<string, string> CustomLabels { get; }
}
FROM mcr.microsoft.com/dotnet/runtime:9.0
EXPOSE 25 9090
# SMTP on 25, Metrics on 9090
apiVersion: v1
kind: Service
metadata:
name: smtp-server
annotations:
prometheus.io/scrape: "true"
prometheus.io/port: "9090"
prometheus.io/path: "/metrics"
services:
smtp:
image: zetian/smtp:latest
ports:
- "25:25"
- "9090:9090"
prometheus:
image: prom/prometheus
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml
grafana:
image: grafana/grafana
ports:
- "3000:3000"
MIT License - see LICENSE
Built with ❤️ for the .NET community