Prometheus-compatible metrics exporter for Rust servers with extensible plugin API.
RustExporter is a Carbon plugin that exposes server metrics via an HTTP endpoint in Prometheus format. It provides comprehensive built-in server metrics and a powerful API for other plugins to register and track custom metrics. Perfect for building monitoring dashboards, alerting systems, and gaining deep insights into your Rust server's performance and player activity.
- π Server FPS - Real-time frames per second
- πΎ Memory Usage - Total memory consumption in bytes
- π₯ Player Count - Active players on the server
- π€ Bot Count - NPCs and AI entities
- π§ Entity Count - Total server entities
- β±οΈ Uptime - Server runtime in seconds
- π Client Ping Statistics - Comprehensive ping metrics (average, percentiles, min/max, std dev, buckets)
- π Histograms - Track distributions (request durations, response sizes, etc.)
- π’ Gauges - Monitor values that go up and down (memory, connections, queue sizes)
- β Counters - Track cumulative values (total requests, errors, events)
- π·οΈ Label Support - Add dimensions to metrics for powerful filtering and aggregation
- π Auto-Registration - Metrics automatically register on first use
- π§΅ Thread-Safe - Safe for concurrent access from multiple plugins
- π‘ Prometheus Format - Industry-standard exposition format (text/plain)
- π HTTP Endpoint - Simple
/metricsendpoint for scraping - π Grafana Compatible - Build beautiful dashboards
- π Alert Manager Ready - Configure alerts based on your metrics
- π Server Identity Labels - Automatic server identification for multi-server setups
- Download
RustExporter.csand place it in yourcarbon/pluginsfolder - Edit the generated config at
carbon/configs/RustExporter.json - Set your desired port (default: 28066) and bind address (default: localhost)
- For external Prometheus access, set
BindAddressto"*" - Reload the plugin:
c.reload RustExporter
{
"Port": 28066,
"BindAddress": "localhost"
}| Option | Description | Default |
|---|---|---|
| Port | HTTP port for metrics endpoint | 28066 |
| BindAddress | IP address to bind to. Use "localhost" for local access only, "*" to bind to all interfaces (public access) |
"localhost" |
After loading, the plugin will be accessible at:
http://your-server-ip:28066/metrics
β οΈ Security Note: The defaultBindAddressof"localhost"means the metrics endpoint is only accessible from the server itself. To allow external access (e.g., from Prometheus), setBindAddressto"*". Consider using firewall rules to restrict access to trusted IPs.
All built-in metrics include an identity label with your server's identity (from server.identity or hostname).
| Metric Name | Type | Description |
|---|---|---|
rust_server_fps |
gauge | Current server FPS |
rust_server_memory_usage_bytes |
gauge | Memory usage in bytes |
rust_server_pop |
gauge | Active player count |
rust_server_bots |
gauge | Bot/NPC count |
rust_server_entities |
gauge | Total entity count |
rust_server_uptime |
counter | Server uptime in seconds |
rust_client_ping_average_ms |
gauge | Average client ping in milliseconds |
rust_client_ping_p50_ms |
gauge | Median (50th percentile) client ping |
rust_client_ping_p75_ms |
gauge | 75th percentile client ping |
rust_client_ping_p90_ms |
gauge | 90th percentile client ping |
rust_client_ping_p95_ms |
gauge | 95th percentile client ping |
rust_client_ping_p99_ms |
gauge | 99th percentile client ping |
rust_client_ping_min_ms |
gauge | Minimum client ping |
rust_client_ping_max_ms |
gauge | Maximum client ping |
rust_client_ping_stddev_ms |
gauge | Standard deviation of client ping |
rust_client_ping_bucket |
gauge | Players by ping range (with range label) |
# HELP rust_server_fps Current server FPS
# TYPE rust_server_fps gauge
rust_server_fps{identity="my-rust-server"} 60.5
# HELP rust_server_memory_usage_bytes Current memory usage in bytes
# TYPE rust_server_memory_usage_bytes gauge
rust_server_memory_usage_bytes{identity="my-rust-server"} 4294967296
# HELP rust_server_pop Current player count
# TYPE rust_server_pop gauge
rust_server_pop{identity="my-rust-server"} 42
# HELP rust_server_uptime Server uptime in seconds
# TYPE rust_server_uptime counter
rust_server_uptime{identity="my-rust-server"} 86400.12345
# HELP rust_client_ping_average_ms Average client ping in milliseconds
# TYPE rust_client_ping_average_ms gauge
rust_client_ping_average_ms{identity="my-rust-server"} 65
# HELP rust_client_ping_p95_ms 95th percentile client ping in milliseconds
# TYPE rust_client_ping_p95_ms gauge
rust_client_ping_p95_ms{identity="my-rust-server"} 120
# HELP rust_client_ping_bucket Players by ping range
# TYPE rust_client_ping_bucket gauge
rust_client_ping_bucket{identity="my-rust-server",range="0-50"} 15
rust_client_ping_bucket{identity="my-rust-server",range="50-100"} 20
rust_client_ping_bucket{identity="my-rust-server",range="100-150"} 5
rust_client_ping_bucket{identity="my-rust-server",range="150-200"} 2
rust_client_ping_bucket{identity="my-rust-server",range="200+"} 0
RustExporter provides hook methods that other plugins can call to register and update custom metrics.
| Method | Purpose | Auto-Registers |
|---|---|---|
RegisterHistogram |
Create a histogram metric | No |
RegisterGauge |
Create a gauge metric | No |
RegisterCounter |
Create a counter metric | No |
ObserveHistogram |
Record histogram value | Yes |
SetGauge |
Set gauge value | Yes |
IncCounter |
Increment counter | Yes |
DecCounter |
Decrement counter | Yes |
Track the distribution of values. Perfect for measuring request durations, response sizes, or any value where you care about percentiles and averages.
Default Buckets: [0.5, 1, 5, 10, 30, 60, 300, 500, 900, +Inf]
Use Cases:
- API request duration
- Command execution time
- Event processing latency
- Item craft durations
Represent values that can go up or down. Snapshot of current state.
Use Cases:
- Active connections
- Queue sizes
- Current temperature
- Available resources
- Cache size
Monotonically increasing values (can decrement with DecCounter). Track cumulative totals.
Use Cases:
- Total HTTP requests
- Total errors
- Items crafted
- Players joined (all-time)
- Events triggered
[PluginReference]
private Plugin RustExporter;
private void OnPlayerConnected(BasePlayer player)
{
// Increment player join counter
RustExporter?.Call("IncCounter", "total_player_joins");
}[PluginReference]
private Plugin RustExporter;
private void UpdateQueueSize(string queueType, int size)
{
var labels = new Dictionary<string, string>
{
["queue_type"] = queueType,
["priority"] = "high"
};
RustExporter?.Call("SetGauge", "queue_size", (double)size, labels);
}
// Usage:
UpdateQueueSize("crafting", 15);
UpdateQueueSize("respawn", 3);Resulting metrics:
queue_size{identity="my-server",queue_type="crafting",priority="high"} 15
queue_size{identity="my-server",queue_type="respawn",priority="high"} 3
[PluginReference]
private Plugin RustExporter;
private void Init()
{
// Register histogram with custom buckets for command execution time
var buckets = new double[] { 0.001, 0.005, 0.01, 0.05, 0.1, 0.5, 1.0 };
var labels = new Dictionary<string, string>
{
["command_type"] = "admin"
};
RustExporter?.Call("RegisterHistogram", "command_duration_seconds", buckets, labels);
}
private void OnCommandExecuted(string command, float duration)
{
var labels = new Dictionary<string, string>
{
["command_type"] = "admin"
};
RustExporter?.Call("ObserveHistogram", "command_duration_seconds", (double)duration, labels);
}[Info("MyAwesomePlugin", "YourName", "1.0.0")]
public class MyAwesomePlugin : CarbonPlugin
{
[PluginReference]
private Plugin RustExporter;
private void Init()
{
// Register metrics on plugin load
RustExporter?.Call("RegisterCounter", "myplug_events_processed", 0L);
RustExporter?.Call("RegisterGauge", "myplug_active_sessions", 0.0);
}
private void OnEventProcessed(string eventType)
{
var labels = new Dictionary<string, string>
{
["event_type"] = eventType
};
RustExporter?.Call("IncCounter", "myplug_events_processed", 1L, labels);
}
private void UpdateActiveSessions(int count)
{
RustExporter?.Call("SetGauge", "myplug_active_sessions", (double)count);
}
}[PluginReference]
private Plugin RustExporter;
private void OnResourceGathered()
{
// Increment total gathered
RustExporter?.Call("IncCounter", "resources_gathered");
}
private void OnResourceConsumed()
{
// Decrement available resources (counter won't go below 0)
RustExporter?.Call("DecCounter", "resources_available");
}Labels add dimensions to your metrics, allowing you to filter and aggregate in Prometheus/Grafana.
Best Practices:
- Keep label cardinality reasonable (avoid unique player IDs as labels)
- Use consistent label names across metrics
- Common label examples:
type,status,method,outcome,category - The
identitylabel is automatically added to all metrics
Example with multiple labels:
var labels = new Dictionary<string, string>
{
["plugin_name"] = "MyPlugin",
["action_type"] = "purchase",
["item_category"] = "weapon",
["outcome"] = "success"
};
RustExporter?.Call("IncCounter", "plugin_actions_total", 1L, labels);Resulting metric:
plugin_actions_total{identity="my-server",plugin_name="MyPlugin",action_type="purchase",item_category="weapon",outcome="success"} 156
Add this to your prometheus.yml:
scrape_configs:
- job_name: 'rust-servers'
static_configs:
- targets: ['your-server-ip:28066']
labels:
environment: 'production'
region: 'us-west'# Average FPS across all servers
avg(rust_server_fps)
# Player count by server
sum by (identity) (rust_server_pop)
# Memory usage in GB
rust_server_memory_usage_bytes / 1024 / 1024 / 1024
# Rate of player joins per minute
rate(total_player_joins[1m]) * 60
# 95th percentile command execution time
histogram_quantile(0.95, rate(command_duration_seconds_bucket[5m]))
# Servers with low FPS (below 30)
rust_server_fps < 30
# Average client ping across all servers
avg(rust_client_ping_average_ms)
# Servers with high ping (95th percentile > 150ms)
rust_client_ping_p95_ms > 150
# Count of players with good ping (< 50ms)
sum by (identity) (rust_client_ping_bucket{range="0-50"})
# Percentage of players with poor ping (> 150ms)
(rust_client_ping_bucket{range="150-200"} + rust_client_ping_bucket{range="200+"}) / rust_server_pop * 100
- FPS graph (line chart)
- Memory usage (line chart with threshold alerts)
- Entity count trends
- Uptime counter
- Active player count (gauge visualization)
- Player joins/leaves rate (stat panel)
- Geographic distribution (if tracking via labels)
- Peak hours heatmap
- Average ping over time (line chart)
- Ping percentiles (P50, P95, P99) multi-line chart
- Players by ping bucket (bar chart/stacked bar chart)
- Ping standard deviation trend
- High ping alerts (P95 > threshold)
- Custom event rates
- Error counters
- Queue sizes
- Processing latencies (histogram percentiles)
You don't need to register metrics before using them. Just call the observe/set/increment methods directly:
// This automatically registers the counter if it doesn't exist
RustExporter?.Call("IncCounter", "my_new_metric");All metric operations are thread-safe and can be called from any plugin at any time without coordination.
The identity label is automatically added to all metrics using:
server.identityConVar (if set)server.hostname(if identity not set)"rust-server"(fallback)
This allows you to run multiple servers and distinguish them in Prometheus.
Default buckets are optimized for duration measurements in seconds:
[0.5, 1, 5, 10, 30, 60, 300, 500, 900, +Inf]
For different use cases, provide custom buckets:
// For millisecond-level response times
var buckets = new double[] { 0.001, 0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0 };
// For item counts/quantities
var buckets = new double[] { 1, 5, 10, 25, 50, 100, 500, 1000, 5000, 10000 };
RustExporter?.Call("RegisterHistogram", "my_metric", buckets);- β Carbon Mod installed and running
- β Network access to the configured port
- β Prometheus/Grafana (optional, for visualization)
No, but it's recommended. The plugin exposes metrics via HTTP that any tool can consume. You can even just browse to http://your-server:28066/metrics to see the raw data.
Minimal impact. The HTTP server runs on a separate thread, and metric updates are simple in-memory operations. Scraping the metrics endpoint is a lightweight operation.
β
Yes! The identity label automatically distinguishes servers. Configure Prometheus to scrape all your servers.
β Automatic registration! The observe/set/increment methods will automatically register metrics with default settings.
No. Counters are meant to be monotonically increasing. If you need resetable values, use a gauge instead.
Not supported. Metrics persist for the lifetime of the plugin. If you need temporary metrics, use unique label combinations instead.
- Counter: Tracks totals that only go up (e.g., total requests, total errors). Can be decremented with
DecCounter. - Gauge: Tracks current values that fluctuate (e.g., current players, memory usage, queue size).
Thousands. Each unique combination of metric name and labels creates a new time series. Keep label cardinality reasonable to avoid excessive memory usage.
No. Metrics are write-only from plugins. Only the /metrics HTTP endpoint exposes them, and only Prometheus (or similar tools) read them.
- Monitor server health (FPS, memory, entities)
- Track player counts and trends
- Set up alerts for low FPS or high memory usage
- Compare performance across multiple servers
- Track plugin-specific events and metrics
- Measure command execution times
- Monitor queue sizes and processing rates
- Debug performance issues with histogram percentiles
- A/B test features by tracking success rates
- Display live server stats on websites
- Create public dashboards for players
- Track and display server uptime
- Monitor and optimize server performance
Made with β€οΈ by mainloot | Join our Discord
