Add option to emit metrics and logs when players connect to the router (#391)
This commit is contained in:
@@ -78,6 +78,8 @@ Routes Minecraft client connections to backend servers based upon the requested
|
||||
Indicates if the webhook will only be called if a user is connecting rather than just server list/ping (env WEBHOOK_REQUIRE_USER)
|
||||
-webhook-url string
|
||||
If set, a POST request that contains connection status notifications will be sent to this HTTP address (env WEBHOOK_URL)
|
||||
-record-logins
|
||||
Log and generate metrics on player logins. Metrics only supported with influxdb or prometheus backend
|
||||
```
|
||||
|
||||
## Docker Multi-Architecture Image
|
||||
|
||||
@@ -54,6 +54,7 @@ type Config struct {
|
||||
UseProxyProtocol bool `default:"false" usage:"Send PROXY protocol to backend servers"`
|
||||
ReceiveProxyProtocol bool `default:"false" usage:"Receive PROXY protocol from backend servers, by default trusts every proxy header that it receives, combine with -trusted-proxies to specify a list of trusted proxies"`
|
||||
TrustedProxies []string `usage:"Comma delimited list of CIDR notation IP blocks to trust when receiving PROXY protocol"`
|
||||
RecordLogins bool `default:"false" usage:"Log and generate metrics on player logins. Metrics only supported with influxdb or prometheus backend"`
|
||||
MetricsBackendConfig MetricsBackendConfig
|
||||
RoutesConfig string `usage:"Name or full path to routes config file"`
|
||||
NgrokToken string `usage:"If set, an ngrok tunnel will be established. It is HIGHLY recommended to pass as an environment variable."`
|
||||
@@ -142,7 +143,7 @@ func main() {
|
||||
trustedIpNets = append(trustedIpNets, ipNet)
|
||||
}
|
||||
|
||||
connector := server.NewConnector(metricsBuilder.BuildConnectorMetrics(), config.UseProxyProtocol, config.ReceiveProxyProtocol, trustedIpNets)
|
||||
connector := server.NewConnector(metricsBuilder.BuildConnectorMetrics(), config.UseProxyProtocol, config.ReceiveProxyProtocol, trustedIpNets, config.RecordLogins)
|
||||
|
||||
clientFilter, err := server.NewClientFilter(config.ClientsToAllow, config.ClientsToDeny)
|
||||
if err != nil {
|
||||
|
||||
@@ -65,6 +65,8 @@ func (b expvarMetricsBuilder) BuildConnectorMetrics() *server.ConnectorMetrics {
|
||||
ConnectionsFrontend: c,
|
||||
ConnectionsBackend: c,
|
||||
ActiveConnections: expvarMetrics.NewGauge("active_connections"),
|
||||
ServerActivePlayer: expvarMetrics.NewGauge("server_active_player"),
|
||||
ServerLogins: expvarMetrics.NewCounter("server_logins"),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -83,6 +85,8 @@ func (b discardMetricsBuilder) BuildConnectorMetrics() *server.ConnectorMetrics
|
||||
ConnectionsFrontend: discardMetrics.NewCounter(),
|
||||
ConnectionsBackend: discardMetrics.NewCounter(),
|
||||
ActiveConnections: discardMetrics.NewGauge(),
|
||||
ServerActivePlayer: discardMetrics.NewGauge(),
|
||||
ServerLogins: discardMetrics.NewCounter(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -132,6 +136,8 @@ func (b *influxMetricsBuilder) BuildConnectorMetrics() *server.ConnectorMetrics
|
||||
ConnectionsFrontend: c.With("side", "frontend"),
|
||||
ConnectionsBackend: c.With("side", "backend"),
|
||||
ActiveConnections: metrics.NewGauge("mc_router_connections_active"),
|
||||
ServerActivePlayer: metrics.NewGauge("mc_router_server_player_active"),
|
||||
ServerLogins: metrics.NewCounter("mc_router_server_logins"),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -178,5 +184,15 @@ func (b prometheusMetricsBuilder) BuildConnectorMetrics() *server.ConnectorMetri
|
||||
Name: "active_connections",
|
||||
Help: "The number of active connections",
|
||||
}, nil)),
|
||||
ServerActivePlayer: prometheusMetrics.NewGauge(promauto.NewGaugeVec(prometheus.GaugeOpts{
|
||||
Namespace: "mc_router",
|
||||
Name: "server_active_player",
|
||||
Help: "Player is active on server",
|
||||
}, []string{"player_name", "player_uuid", "server_address"})),
|
||||
ServerLogins: prometheusMetrics.NewCounter(promauto.NewCounterVec(prometheus.CounterOpts{
|
||||
Namespace: "mc_router",
|
||||
Name: "server_logins",
|
||||
Help: "The total number of player logins",
|
||||
}, []string{"player_name", "player_uuid", "server_address"})),
|
||||
}
|
||||
}
|
||||
|
||||
+2
-1
@@ -45,7 +45,8 @@ func ReadPacket(reader *bufio.Reader, addr net.Addr, state State) (*Packet, erro
|
||||
return nil, err
|
||||
}
|
||||
|
||||
packet := &Packet{Length: frame.Length}
|
||||
// Packet length is frame length (bytes for packetID and data) plus bytes used to store the frame length data
|
||||
packet := &Packet{Length: frame.Length + PacketLengthFieldBytes}
|
||||
|
||||
remainder := bytes.NewBuffer(frame.Payload)
|
||||
|
||||
|
||||
@@ -80,3 +80,7 @@ type LegacyServerListPing struct {
|
||||
type ByteReader interface {
|
||||
ReadByte() (byte, error)
|
||||
}
|
||||
|
||||
const (
|
||||
PacketLengthFieldBytes = 1
|
||||
)
|
||||
|
||||
+33
-1
@@ -34,6 +34,8 @@ type ConnectorMetrics struct {
|
||||
ConnectionsFrontend metrics.Counter
|
||||
ConnectionsBackend metrics.Counter
|
||||
ActiveConnections metrics.Gauge
|
||||
ServerActivePlayer metrics.Gauge
|
||||
ServerLogins metrics.Counter
|
||||
}
|
||||
|
||||
type ClientInfo struct {
|
||||
@@ -57,13 +59,14 @@ type PlayerInfo struct {
|
||||
Uuid uuid.UUID `json:"uuid"`
|
||||
}
|
||||
|
||||
func NewConnector(metrics *ConnectorMetrics, sendProxyProto bool, receiveProxyProto bool, trustedProxyNets []*net.IPNet) *Connector {
|
||||
func NewConnector(metrics *ConnectorMetrics, sendProxyProto bool, receiveProxyProto bool, trustedProxyNets []*net.IPNet, recordLogins bool) *Connector {
|
||||
return &Connector{
|
||||
metrics: metrics,
|
||||
sendProxyProto: sendProxyProto,
|
||||
connectionsCond: sync.NewCond(&sync.Mutex{}),
|
||||
receiveProxyProto: receiveProxyProto,
|
||||
trustedProxyNets: trustedProxyNets,
|
||||
recordLogins: recordLogins,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,6 +75,7 @@ type Connector struct {
|
||||
metrics *ConnectorMetrics
|
||||
sendProxyProto bool
|
||||
receiveProxyProto bool
|
||||
recordLogins bool
|
||||
trustedProxyNets []*net.IPNet
|
||||
|
||||
activeConnections int32
|
||||
@@ -383,9 +387,37 @@ func (c *Connector) findAndConnectBackend(ctx context.Context, frontendConn net.
|
||||
|
||||
c.metrics.ActiveConnections.Set(float64(
|
||||
atomic.AddInt32(&c.activeConnections, 1)))
|
||||
if c.recordLogins && userInfo != nil {
|
||||
logrus.
|
||||
WithField("client", clientAddr).
|
||||
WithField("playerName", userInfo.Name).
|
||||
WithField("playerUUID", userInfo.Uuid).
|
||||
WithField("serverAddress", serverAddress).
|
||||
Info("Player attempted to login to server")
|
||||
|
||||
c.metrics.ServerActivePlayer.
|
||||
With("player_name", userInfo.Name).
|
||||
With("player_uuid", userInfo.Uuid.String()).
|
||||
With("server_address", serverAddress).
|
||||
Set(1)
|
||||
|
||||
c.metrics.ServerLogins.
|
||||
With("player_name", userInfo.Name).
|
||||
With("player_uuid", userInfo.Uuid.String()).
|
||||
With("server_address", serverAddress).
|
||||
Add(1)
|
||||
}
|
||||
|
||||
defer func() {
|
||||
c.metrics.ActiveConnections.Set(float64(
|
||||
atomic.AddInt32(&c.activeConnections, -1)))
|
||||
if c.recordLogins && userInfo != nil {
|
||||
c.metrics.ServerActivePlayer.
|
||||
With("player_name", userInfo.Name).
|
||||
With("player_uuid", userInfo.Uuid.String()).
|
||||
With("server_address", serverAddress).
|
||||
Set(0)
|
||||
}
|
||||
c.connectionsCond.Signal()
|
||||
}()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user