diff --git a/CHANGELOG.md b/CHANGELOG.md index c47b5c40d709e7..56402b4467004c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,11 @@ **Merged pull requests:** +- Regenerate integrations docs [\#19265](https://github.com/netdata/netdata/pull/19265) ([netdatabot](https://github.com/netdatabot)) +- improvement\(go.d/nats\): add routez metrics [\#19264](https://github.com/netdata/netdata/pull/19264) ([ilyam8](https://github.com/ilyam8)) +- Regenerate integrations docs [\#19263](https://github.com/netdata/netdata/pull/19263) ([netdatabot](https://github.com/netdatabot)) +- improvement\(go.d/nats\): add accstatz metrics [\#19262](https://github.com/netdata/netdata/pull/19262) ([ilyam8](https://github.com/ilyam8)) +- HELP and TYPE in prometheus fix [\#19261](https://github.com/netdata/netdata/pull/19261) ([ktsaou](https://github.com/ktsaou)) - Add an alert guide for reboot required [\#19260](https://github.com/netdata/netdata/pull/19260) ([ralphm](https://github.com/ralphm)) - fix crash when the DRM file does not contain the right information [\#19258](https://github.com/netdata/netdata/pull/19258) ([ktsaou](https://github.com/ktsaou)) - docs: change "node-membership-rules" filename/title [\#19257](https://github.com/netdata/netdata/pull/19257) ([ilyam8](https://github.com/ilyam8)) @@ -455,10 +460,6 @@ - Delay child disconnect update [\#18712](https://github.com/netdata/netdata/pull/18712) ([stelfrag](https://github.com/stelfrag)) - Windows installer \(Change descriptions add helping\) [\#18711](https://github.com/netdata/netdata/pull/18711) ([thiagoftsm](https://github.com/thiagoftsm)) - add instructions to configure SCIM integration in Okta [\#18710](https://github.com/netdata/netdata/pull/18710) ([juacker](https://github.com/juacker)) -- fix wrong config file name in go.d/oracledb meta [\#18709](https://github.com/netdata/netdata/pull/18709) ([ilyam8](https://github.com/ilyam8)) -- Regenerate integrations.js [\#18708](https://github.com/netdata/netdata/pull/18708) ([netdatabot](https://github.com/netdatabot)) -- feat\(go.d/sensors\): add a config option to update/add sensor label value [\#18707](https://github.com/netdata/netdata/pull/18707) ([ilyam8](https://github.com/ilyam8)) -- improve apps.plugin readme [\#18705](https://github.com/netdata/netdata/pull/18705) ([ilyam8](https://github.com/ilyam8)) ## [v1.47.5](https://github.com/netdata/netdata/tree/v1.47.5) (2024-10-24) diff --git a/packaging/version b/packaging/version index bc4a6d25b388e3..640f5c80d84ff0 100644 --- a/packaging/version +++ b/packaging/version @@ -1 +1 @@ -v2.1.0-9-nightly +v2.1.0-15-nightly diff --git a/src/go/plugin/go.d/collector/nats/charts.go b/src/go/plugin/go.d/collector/nats/charts.go index 68674e3312f34b..3e751b8fe8856f 100644 --- a/src/go/plugin/go.d/collector/nats/charts.go +++ b/src/go/plugin/go.d/collector/nats/charts.go @@ -4,6 +4,8 @@ package nats import ( "fmt" + "strconv" + "strings" "github.com/netdata/netdata/go/plugins/plugin/go.d/agent/module" ) @@ -11,13 +13,25 @@ import ( const ( prioServerTraffic = module.Priority + iota prioServerMessages - prioServerConnectionsCurrent + prioServerConnections prioServerConnectionsRate prioHttpEndpointRequests prioServerHealthProbeStatus prioServerCpuUsage prioServerMemoryUsage prioServerUptime + + prioAccountTraffic + prioAccountMessages + prioAccountConnections + prioAccountConnectionsRate + prioAccountSubscriptions + prioAccountSlowConsumers + prioAccountLeafNodes + + prioRouteTraffic + prioRouteMessages + prioRouteSubscriptions ) var serverCharts = func() module.Charts { @@ -31,7 +45,7 @@ var serverCharts = func() module.Charts { chartServerMemUsage.Copy(), chartServerUptime.Copy(), } - charts = append(charts, httpEndpointCharts()...) + charts = append(charts, httpEndpointsCharts()...) return charts }() @@ -45,8 +59,8 @@ var ( Priority: prioServerTraffic, Type: module.Area, Dims: module.Dims{ - {ID: "in_bytes", Name: "in", Algo: module.Incremental}, - {ID: "out_bytes", Name: "out", Mul: -1, Algo: module.Incremental}, + {ID: "varz_srv_in_bytes", Name: "received", Algo: module.Incremental}, + {ID: "varz_srv_out_bytes", Name: "sent", Mul: -1, Algo: module.Incremental}, }, } chartServerMessages = module.Chart{ @@ -57,19 +71,19 @@ var ( Ctx: "nats.server_messages", Priority: prioServerMessages, Dims: module.Dims{ - {ID: "in_msgs", Name: "in", Algo: module.Incremental}, - {ID: "out_msgs", Name: "out", Mul: -1, Algo: module.Incremental}, + {ID: "varz_srv_in_msgs", Name: "received", Algo: module.Incremental}, + {ID: "varz_srv_out_msgs", Name: "sent", Mul: -1, Algo: module.Incremental}, }, } chartServerConnectionsCurrent = module.Chart{ - ID: "server_connections_current", - Title: "Server Current Connections", + ID: "server_connections", + Title: "Server Active Connections", Units: "connections", Fam: "connections", - Ctx: "nats.server_connections_current", - Priority: prioServerConnectionsCurrent, + Ctx: "nats.server_connections", + Priority: prioServerConnections, Dims: module.Dims{ - {ID: "connections", Name: "active"}, + {ID: "varz_srv_connections", Name: "active"}, }, } chartServerConnectionsRate = module.Chart{ @@ -80,7 +94,7 @@ var ( Ctx: "nats.server_connections_rate", Priority: prioServerConnectionsRate, Dims: module.Dims{ - {ID: "total_connections", Name: "connections", Algo: module.Incremental}, + {ID: "varz_srv_total_connections", Name: "connections", Algo: module.Incremental}, }, } chartServerHealthProbeStatus = module.Chart{ @@ -91,8 +105,8 @@ var ( Ctx: "nats.server_health_probe_status", Priority: prioServerHealthProbeStatus, Dims: module.Dims{ - {ID: "healthz_status_ok", Name: "ok"}, - {ID: "healthz_status_error", Name: "error"}, + {ID: "varz_srv_healthz_status_ok", Name: "ok"}, + {ID: "varz_srv_healthz_status_error", Name: "error"}, }, } chartServerCpuUsage = module.Chart{ @@ -104,7 +118,7 @@ var ( Priority: prioServerCpuUsage, Type: module.Area, Dims: module.Dims{ - {ID: "cpu", Name: "used"}, + {ID: "varz_srv_cpu", Name: "used"}, }, } chartServerMemUsage = module.Chart{ @@ -116,7 +130,7 @@ var ( Priority: prioServerMemoryUsage, Type: module.Area, Dims: module.Dims{ - {ID: "mem", Name: "used"}, + {ID: "varz_srv_mem", Name: "used"}, }, } chartServerUptime = module.Chart{ @@ -127,15 +141,17 @@ var ( Ctx: "nats.server_uptime", Priority: prioServerUptime, Dims: module.Dims{ - {ID: "uptime", Name: "uptime"}, + {ID: "varz_srv_uptime", Name: "uptime"}, }, } ) -func httpEndpointCharts() module.Charts { +func httpEndpointsCharts() module.Charts { var charts module.Charts + for _, path := range httpEndpoints { chart := httpEndpointRequestsChartTmpl.Copy() + chart.ID = fmt.Sprintf(chart.ID, path) chart.Labels = []module.Label{ {Key: "http_endpoint", Value: path}, @@ -145,6 +161,7 @@ func httpEndpointCharts() module.Charts { } charts = append(charts, chart) } + return charts } @@ -156,6 +173,209 @@ var httpEndpointRequestsChartTmpl = module.Chart{ Ctx: "nats.http_endpoint_requests", Priority: prioHttpEndpointRequests, Dims: module.Dims{ - {ID: "http_endpoint_%s_req", Name: "requests", Algo: module.Incremental}, + {ID: "varz_http_endpoint_%s_req", Name: "requests", Algo: module.Incremental}, }, } + +var accountChartsTmpl = module.Charts{ + accountTrafficTmpl.Copy(), + accountMessagesTmpl.Copy(), + accountConnectionsCurrentTmpl.Copy(), + accountConnectionsRateTmpl.Copy(), + accountSubscriptionsTmpl.Copy(), + accountSlowConsumersTmpl.Copy(), + accountLeadNodesTmpl.Copy(), +} + +var ( + accountTrafficTmpl = module.Chart{ + ID: "account_%s_traffic", + Title: "Account Traffic", + Units: "bytes/s", + Fam: "acc traffic", + Ctx: "nats.account_traffic", + Priority: prioAccountTraffic, + Type: module.Area, + Dims: module.Dims{ + {ID: "accstatz_acc_%s_received_bytes", Name: "received", Algo: module.Incremental}, + {ID: "accstatz_acc_%s_sent_bytes", Name: "sent", Mul: -1, Algo: module.Incremental}, + }, + } + accountMessagesTmpl = module.Chart{ + ID: "account_%s_messages", + Title: "Account Messages", + Units: "messages/s", + Fam: "acc traffic", + Ctx: "nats.account_messages", + Priority: prioAccountMessages, + Type: module.Line, + Dims: module.Dims{ + {ID: "accstatz_acc_%s_received_msgs", Name: "received", Algo: module.Incremental}, + {ID: "accstatz_acc_%s_sent_msgs", Name: "sent", Mul: -1, Algo: module.Incremental}, + }, + } + accountConnectionsCurrentTmpl = module.Chart{ + ID: "account_%s_connections", + Title: "Account Active Connections", + Units: "connections", + Fam: "acc connections", + Ctx: "nats.account_connections", + Priority: prioAccountConnections, + Type: module.Line, + Dims: module.Dims{ + {ID: "accstatz_acc_%s_conns", Name: "active"}, + }, + } + accountConnectionsRateTmpl = module.Chart{ + ID: "account_%s_connections_rate", + Title: "Account Connections", + Units: "connections/s", + Fam: "acc connections", + Ctx: "nats.account_connections_rate", + Priority: prioAccountConnectionsRate, + Type: module.Line, + Dims: module.Dims{ + {ID: "accstatz_acc_%s_total_conns", Name: "connections", Algo: module.Incremental}, + }, + } + accountSubscriptionsTmpl = module.Chart{ + ID: "account_%s_subscriptions", + Title: "Account Active Subscriptions", + Units: "subscriptions", + Fam: "acc subscriptions", + Ctx: "nats.account_subscriptions", + Priority: prioAccountSubscriptions, + Type: module.Line, + Dims: module.Dims{ + {ID: "accstatz_acc_%s_num_subs", Name: "active"}, + }, + } + accountSlowConsumersTmpl = module.Chart{ + ID: "account_%s_slow_consumers", + Title: "Account Slow Consumers", + Units: "consumers/s", + Fam: "acc consumers", + Ctx: "nats.account_slow_consumers", + Priority: prioAccountSlowConsumers, + Type: module.Line, + Dims: module.Dims{ + {ID: "accstatz_acc_%s_slow_consumers", Name: "slow", Algo: module.Incremental}, + }, + } + accountLeadNodesTmpl = module.Chart{ + ID: "account_%s_leaf_nodes", + Title: "Account Leaf Nodes", + Units: "servers", + Fam: "acc leaf nodes", + Ctx: "nats.account_leaf_nodes", + Priority: prioAccountLeafNodes, + Type: module.Line, + Dims: module.Dims{ + {ID: "accstatz_acc_%s_leaf_nodes", Name: "leafnode"}, + }, + } +) + +func (c *Collector) addAccountCharts(acc string) { + charts := accountChartsTmpl.Copy() + + for _, chart := range *charts { + chart.ID = fmt.Sprintf(chart.ID, acc) + chart.Labels = []module.Label{ + {Key: "account", Value: acc}, + } + for _, dim := range chart.Dims { + dim.ID = fmt.Sprintf(dim.ID, acc) + } + } + + if err := c.Charts().Add(*charts...); err != nil { + c.Warningf("failed to add charts for account %s: %s", acc, err) + } +} + +func (c *Collector) removeAccountCharts(acc string) { + px := fmt.Sprintf("account_%s_", acc) + c.removeCharts(px) +} + +var routeChartsTmpl = module.Charts{ + routeTrafficTmpl.Copy(), + routeMessagesTmpl.Copy(), + routeSubscriptionsTmpl.Copy(), +} + +var ( + routeTrafficTmpl = module.Chart{ + ID: "route_%d_traffic", + Title: "Route Traffic", + Units: "bytes/s", + Fam: "route traffic", + Ctx: "nats.route_traffic", + Priority: prioRouteTraffic, + Type: module.Area, + Dims: module.Dims{ + {ID: "routez_route_id_%d_in_bytes", Name: "in", Algo: module.Incremental}, + {ID: "routez_route_id_%d_out_bytes", Name: "out", Mul: -1, Algo: module.Incremental}, + }, + } + routeMessagesTmpl = module.Chart{ + ID: "route_%d_messages", + Title: "Route Messages", + Units: "messages/s", + Fam: "route traffic", + Ctx: "nats.route_messages", + Priority: prioRouteMessages, + Type: module.Line, + Dims: module.Dims{ + {ID: "routez_route_id_%d_in_msgs", Name: "in", Algo: module.Incremental}, + {ID: "routez_route_id_%d_out_msgs", Name: "out", Mul: -1, Algo: module.Incremental}, + }, + } + routeSubscriptionsTmpl = module.Chart{ + ID: "route_%d_subscriptions", + Title: "Route Active Subscriptions", + Units: "subscriptions", + Fam: "route subscriptions", + Ctx: "nats.route_subscriptions", + Priority: prioRouteSubscriptions, + Type: module.Line, + Dims: module.Dims{ + {ID: "routez_route_id_%d_num_subs", Name: "active"}, + }, + } +) + +func (c *Collector) addRouteCharts(rid uint64, remoteId string) { + charts := routeChartsTmpl.Copy() + + for _, chart := range *charts { + chart.ID = fmt.Sprintf(chart.ID, rid) + chart.Labels = []module.Label{ + {Key: "route_id", Value: strconv.FormatUint(rid, 10)}, + {Key: "remote_id", Value: remoteId}, + } + for _, dim := range chart.Dims { + dim.ID = fmt.Sprintf(dim.ID, rid) + } + } + + if err := c.Charts().Add(*charts...); err != nil { + c.Warningf("failed to add charts for route id %d: %s", rid, err) + } + +} + +func (c *Collector) removeRouteCharts(rid uint64) { + px := fmt.Sprintf("route_%d_", rid) + c.removeCharts(px) +} + +func (c *Collector) removeCharts(prefix string) { + for _, chart := range *c.Charts() { + if strings.HasPrefix(chart.ID, prefix) { + chart.MarkRemove() + chart.MarkNotCreated() + } + } +} diff --git a/src/go/plugin/go.d/collector/nats/collect.go b/src/go/plugin/go.d/collector/nats/collect.go index d14b2e74e49f3b..3af9a5a499b931 100644 --- a/src/go/plugin/go.d/collector/nats/collect.go +++ b/src/go/plugin/go.d/collector/nats/collect.go @@ -10,26 +10,54 @@ import ( "github.com/netdata/netdata/go/plugins/plugin/go.d/pkg/web" ) -const ( - urlPathVarz = "/varz" - urlPathHealthz = "/healthz" -) - func (c *Collector) collect() (map[string]int64, error) { mx := make(map[string]int64) - if err := c.collectVarz(mx); err != nil { - return nil, err - } if err := c.collectHealthz(mx); err != nil { return nil, err } + if err := c.collectVarz(mx); err != nil { + return mx, err + } + if err := c.collectAccstatz(mx); err != nil { + return mx, err + } + if err := c.collectRoutez(mx); err != nil { + return mx, err + } return mx, nil } +func (c *Collector) collectHealthz(mx map[string]int64) error { + req, err := web.NewHTTPRequestWithPath(c.RequestConfig, urlPathHealthz) + if err != nil { + return err + } + + switch c.HealthzCheck { + case "js-enabled-only": + req.URL.Scheme = urlQueryHealthzJsEnabledOnly + case "js-server-only": + req.URL.Scheme = urlQueryHealthzJsServerOnly + } + + var resp healthzResponse + client := web.DoHTTP(c.httpClient).OnNokCode(func(resp *http.Response) (bool, error) { return true, nil }) + if err := client.RequestJSON(req, &resp); err != nil { + return err + } + if resp.Status == nil { + return fmt.Errorf("healthz response missing status") + } + + mx["varz_srv_healthz_status_ok"] = metrix.Bool(*resp.Status == "ok") + mx["varz_srv_healthz_status_error"] = metrix.Bool(*resp.Status != "ok") + + return nil +} + func (c *Collector) collectVarz(mx map[string]int64) error { - // https://docs.nats.io/running-a-nats-service/nats_admin/monitoring#general-information req, err := web.NewHTTPRequestWithPath(c.RequestConfig, urlPathVarz) if err != nil { return err @@ -40,46 +68,114 @@ func (c *Collector) collectVarz(mx map[string]int64) error { return err } - mx["uptime"] = int64(resp.Now.Sub(resp.Start).Seconds()) - mx["in_msgs"] = resp.InMsgs - mx["out_msgs"] = resp.OutMsgs - mx["in_bytes"] = resp.InBytes - mx["out_bytes"] = resp.OutBytes - mx["slow_consumers"] = resp.SlowConsumers - mx["subscriptions"] = int64(resp.Subscriptions) - mx["connections"] = int64(resp.Connections) - mx["total_connections"] = int64(resp.TotalConnections) - mx["routes"] = int64(resp.Routes) - mx["remotes"] = int64(resp.Remotes) - mx["cpu"] = int64(resp.CPU) - mx["mem"] = resp.Mem + mx["varz_srv_uptime"] = int64(resp.Now.Sub(resp.Start).Seconds()) + mx["varz_srv_in_msgs"] = resp.InMsgs + mx["varz_srv_out_msgs"] = resp.OutMsgs + mx["varz_srv_in_bytes"] = resp.InBytes + mx["varz_srv_out_bytes"] = resp.OutBytes + mx["varz_srv_slow_consumers"] = resp.SlowConsumers + mx["varz_srv_subscriptions"] = int64(resp.Subscriptions) + mx["varz_srv_connections"] = int64(resp.Connections) + mx["varz_srv_total_connections"] = int64(resp.TotalConnections) + mx["varz_srv_routes"] = int64(resp.Routes) + mx["varz_srv_remotes"] = int64(resp.Remotes) + mx["varz_srv_cpu"] = int64(resp.CPU) + mx["varz_srv_mem"] = resp.Mem for _, path := range httpEndpoints { v := resp.HTTPReqStats[path] - mx[fmt.Sprintf("http_endpoint_%s_req", path)] = int64(v) + mx[fmt.Sprintf("varz_http_endpoint_%s_req", path)] = int64(v) } return nil } -func (c *Collector) collectHealthz(mx map[string]int64) error { - // https://docs.nats.io/running-a-nats-service/nats_admin/monitoring#health - req, err := web.NewHTTPRequestWithPath(c.RequestConfig, urlPathHealthz) +func (c *Collector) collectAccstatz(mx map[string]int64) error { + req, err := web.NewHTTPRequestWithPath(c.RequestConfig, urlPathAccstatz) if err != nil { return err } - var resp healthzResponse - client := web.DoHTTP(c.httpClient).OnNokCode(func(resp *http.Response) (bool, error) { return true, nil }) - if err := client.RequestJSON(req, &resp); err != nil { + req.URL.RawQuery = urlQueryAccstatz + + var resp accstatzResponse + if err := web.DoHTTP(c.httpClient).RequestJSON(req, &resp); err != nil { return err } - if resp.Status == nil { - return fmt.Errorf("healthz response missing status") + + seen := make(map[string]bool) + + for _, acc := range resp.AccStats { + if acc.Account == "" { + continue + } + + seen[acc.Account] = true + + px := fmt.Sprintf("accstatz_acc_%s_", acc.Account) + + mx[px+"conns"] = int64(acc.Conns) + mx[px+"total_conns"] = int64(acc.TotalConns) + mx[px+"num_subs"] = int64(acc.NumSubs) + mx[px+"leaf_nodes"] = int64(acc.LeafNodes) + mx[px+"slow_consumers"] = acc.SlowConsumers + mx[px+"received_bytes"] = acc.Received.Bytes + mx[px+"received_msgs"] = acc.Received.Msgs + mx[px+"sent_bytes"] = acc.Sent.Bytes + mx[px+"sent_msgs"] = acc.Sent.Msgs + } + + for acc := range seen { + if !c.seenAccounts[acc] { + c.seenAccounts[acc] = true + c.addAccountCharts(acc) + } + } + for acc := range c.seenAccounts { + if !seen[acc] { + delete(c.seenAccounts, acc) + c.removeAccountCharts(acc) + } + } + + return nil +} + +func (c *Collector) collectRoutez(mx map[string]int64) error { + req, err := web.NewHTTPRequestWithPath(c.RequestConfig, urlPathRoutez) + if err != nil { + return err + } + + var resp routezResponse + if err := web.DoHTTP(c.httpClient).RequestJSON(req, &resp); err != nil { + return err + } + + seen := make(map[uint64]bool) + + for _, route := range resp.Routes { + seen[route.Rid] = true + if !c.seenRoutes[route.Rid] { + c.seenRoutes[route.Rid] = true + c.addRouteCharts(route.Rid, route.RemoteID) + } + + px := fmt.Sprintf("routez_route_id_%d_", route.Rid) + + mx[px+"in_bytes"] = route.InBytes + mx[px+"out_bytes"] = route.OutBytes + mx[px+"in_msgs"] = route.InMsgs + mx[px+"out_msgs"] = route.OutMsgs + mx[px+"num_subs"] = int64(route.NumSubs) } - mx["healthz_status_ok"] = metrix.Bool(*resp.Status == "ok") - mx["healthz_status_error"] = metrix.Bool(*resp.Status != "ok") + for rid := range c.seenRoutes { + if !seen[rid] { + delete(c.seenRoutes, rid) + c.removeRouteCharts(rid) + } + } return nil } diff --git a/src/go/plugin/go.d/collector/nats/collector.go b/src/go/plugin/go.d/collector/nats/collector.go index 847163f8aa9c78..78eb8523e16b79 100644 --- a/src/go/plugin/go.d/collector/nats/collector.go +++ b/src/go/plugin/go.d/collector/nats/collector.go @@ -37,14 +37,18 @@ func New() *Collector { Timeout: confopt.Duration(time.Second), }, }, + HealthzCheck: "default", }, - charts: serverCharts.Copy(), + charts: serverCharts.Copy(), + seenAccounts: make(map[string]bool), + seenRoutes: make(map[uint64]bool), } } type Config struct { Vnode string `yaml:"vnode,omitempty" json:"vnode"` UpdateEvery int `yaml:"update_every,omitempty" json:"update_every"` + HealthzCheck string `yaml:"healthz_check,omitempty" json:"healthz_check"` web.HTTPConfig `yaml:",inline" json:""` } @@ -55,6 +59,9 @@ type Collector struct { charts *module.Charts httpClient *http.Client + + seenAccounts map[string]bool + seenRoutes map[uint64]bool } func (c *Collector) Configuration() any { diff --git a/src/go/plugin/go.d/collector/nats/collector_test.go b/src/go/plugin/go.d/collector/nats/collector_test.go index c49f6f56bdf109..cd165ad50f9832 100644 --- a/src/go/plugin/go.d/collector/nats/collector_test.go +++ b/src/go/plugin/go.d/collector/nats/collector_test.go @@ -20,16 +20,20 @@ var ( dataConfigJSON, _ = os.ReadFile("testdata/config.json") dataConfigYAML, _ = os.ReadFile("testdata/config.yaml") - dataVer210Varz, _ = os.ReadFile("testdata/v2.10.24/varz.json") dataVer210HealthzOk, _ = os.ReadFile("testdata/v2.10.24/healthz-ok.json") + dataVer210Varz, _ = os.ReadFile("testdata/v2.10.24/varz.json") + dataVer210Accstatz, _ = os.ReadFile("testdata/v2.10.24/accstatz.json") + dataVer210Routez, _ = os.ReadFile("testdata/v2.10.24/routez.json") ) func Test_testDataIsValid(t *testing.T) { for name, data := range map[string][]byte{ "dataConfigJSON": dataConfigJSON, "dataConfigYAML": dataConfigYAML, - "dataVer210Varz": dataVer210Varz, "dataVer210HealthzOk": dataVer210HealthzOk, + "dataVer210Varz": dataVer210Varz, + "dataVer210Accstatz": dataVer210Accstatz, + "dataVer210Routez": dataVer210Routez, } { require.NotNil(t, data, name) } @@ -124,38 +128,72 @@ func TestCollector_Collect(t *testing.T) { wantMetrics map[string]int64 }{ "success on valid response": { - prepare: caseOk, - wantNumOfCharts: len(serverCharts), + prepare: caseOk, + wantNumOfCharts: len(serverCharts) + + len(accountChartsTmpl)*3 + + len(routeChartsTmpl)*1, wantMetrics: map[string]int64{ - "connections": 0, - "cpu": 0, - "healthz_status_error": 0, - "healthz_status_ok": 1, - "http_endpoint_/_req": 3, - "http_endpoint_/accountz_req": 2, - "http_endpoint_/accstatz_req": 2, - "http_endpoint_/connz_req": 2, - "http_endpoint_/gatewayz_req": 2, - "http_endpoint_/healthz_req": 2017, - "http_endpoint_/ipqueuesz_req": 0, - "http_endpoint_/jsz_req": 3, - "http_endpoint_/leafz_req": 2, - "http_endpoint_/raftz_req": 0, - "http_endpoint_/routez_req": 2, - "http_endpoint_/stacksz_req": 0, - "http_endpoint_/subsz_req": 1, - "http_endpoint_/varz_req": 3750, - "in_bytes": 0, - "in_msgs": 0, - "mem": 21725184, - "out_bytes": 0, - "out_msgs": 0, - "remotes": 0, - "routes": 0, - "slow_consumers": 0, - "subscriptions": 57, - "total_connections": 0, - "uptime": 27513, + "accstatz_acc_$G_conns": 0, + "accstatz_acc_$G_leaf_nodes": 0, + "accstatz_acc_$G_num_subs": 5, + "accstatz_acc_$G_received_bytes": 0, + "accstatz_acc_$G_received_msgs": 0, + "accstatz_acc_$G_sent_bytes": 0, + "accstatz_acc_$G_sent_msgs": 0, + "accstatz_acc_$G_slow_consumers": 0, + "accstatz_acc_$G_total_conns": 0, + "accstatz_acc_$SYS_conns": 0, + "accstatz_acc_$SYS_leaf_nodes": 0, + "accstatz_acc_$SYS_num_subs": 220, + "accstatz_acc_$SYS_received_bytes": 0, + "accstatz_acc_$SYS_received_msgs": 0, + "accstatz_acc_$SYS_sent_bytes": 0, + "accstatz_acc_$SYS_sent_msgs": 0, + "accstatz_acc_$SYS_slow_consumers": 0, + "accstatz_acc_$SYS_total_conns": 0, + "accstatz_acc_default_conns": 44, + "accstatz_acc_default_leaf_nodes": 0, + "accstatz_acc_default_num_subs": 1133, + "accstatz_acc_default_received_bytes": 62023455, + "accstatz_acc_default_received_msgs": 916392, + "accstatz_acc_default_sent_bytes": 529749990, + "accstatz_acc_default_sent_msgs": 2546732, + "accstatz_acc_default_slow_consumers": 1, + "accstatz_acc_default_total_conns": 44, + "routez_route_id_1_in_bytes": 4, + "routez_route_id_1_in_msgs": 1, + "routez_route_id_1_num_subs": 1, + "routez_route_id_1_out_bytes": 4, + "routez_route_id_1_out_msgs": 1, + "varz_http_endpoint_/_req": 5710, + "varz_http_endpoint_/accountz_req": 2201, + "varz_http_endpoint_/accstatz_req": 6, + "varz_http_endpoint_/connz_req": 3649, + "varz_http_endpoint_/gatewayz_req": 2204, + "varz_http_endpoint_/healthz_req": 3430, + "varz_http_endpoint_/ipqueuesz_req": 0, + "varz_http_endpoint_/jsz_req": 2958, + "varz_http_endpoint_/leafz_req": 9, + "varz_http_endpoint_/raftz_req": 0, + "varz_http_endpoint_/routez_req": 2202, + "varz_http_endpoint_/stacksz_req": 0, + "varz_http_endpoint_/subsz_req": 4412, + "varz_http_endpoint_/varz_req": 7114, + "varz_srv_connections": 44, + "varz_srv_cpu": 10, + "varz_srv_healthz_status_error": 0, + "varz_srv_healthz_status_ok": 1, + "varz_srv_in_bytes": 62024985, + "varz_srv_in_msgs": 916475, + "varz_srv_mem": 95731712, + "varz_srv_out_bytes": 529775656, + "varz_srv_out_msgs": 2546840, + "varz_srv_remotes": 0, + "varz_srv_routes": 0, + "varz_srv_slow_consumers": 1, + "varz_srv_subscriptions": 1358, + "varz_srv_total_connections": 74932, + "varz_srv_uptime": 339394, }, }, "fail on unexpected JSON response": { @@ -201,10 +239,18 @@ func caseOk(t *testing.T) (*Collector, func()) { srv := httptest.NewServer(http.HandlerFunc( func(w http.ResponseWriter, r *http.Request) { switch r.URL.Path { - case urlPathVarz: - _, _ = w.Write(dataVer210Varz) case urlPathHealthz: _, _ = w.Write(dataVer210HealthzOk) + case urlPathVarz: + _, _ = w.Write(dataVer210Varz) + case urlPathAccstatz: + if r.URL.RawQuery != urlQueryAccstatz { + w.WriteHeader(http.StatusNotFound) + return + } + _, _ = w.Write(dataVer210Accstatz) + case urlPathRoutez: + _, _ = w.Write(dataVer210Routez) default: w.WriteHeader(http.StatusNotFound) } diff --git a/src/go/plugin/go.d/collector/nats/config_schema.json b/src/go/plugin/go.d/collector/nats/config_schema.json index 1cc4d7ac028f01..c3e3114d78e44d 100644 --- a/src/go/plugin/go.d/collector/nats/config_schema.json +++ b/src/go/plugin/go.d/collector/nats/config_schema.json @@ -30,6 +30,17 @@ "description": "If set, the client will not follow HTTP redirects automatically.", "type": "boolean" }, + "healthz_check": { + "title": "Health Check Mode", + "description": "Controls the behavior of the `/healthz` endpoint [health check](https://docs.nats.io/running-a-nats-service/nats_admin/monitoring#health).", + "type": "string", + "enum": [ + "default", + "js-enabled-only", + "js-server-only" + ], + "default": "default" + }, "vnode": { "title": "Vnode", "description": "Associates this data collection job with a [Virtual Node](https://learn.netdata.cloud/docs/netdata-agent/configuration/organize-systems-metrics-and-alerts#virtual-nodes).", @@ -127,6 +138,9 @@ "vnode": { "ui:placeholder": "To use this option, first create a Virtual Node and then reference its name here." }, + "healthz_check": { + "ui:help": "`default` performs a full health check, ensuring the server can accept connections and that JetStream is functional, including checking accounts, streams, and consumers. `js-enabled-only` returns an error if JetStream is disabled. `js-server-only` checks if the server can accept connections and that JetStream is enabled, but skips health checks of accounts, streams, and consumers." + }, "timeout": { "ui:help": "Accepts decimals for precise control (e.g., type 1.5 for 1.5 seconds)." }, @@ -152,6 +166,7 @@ "url", "timeout", "not_follow_redirects", + "healthz_check", "vnode" ] }, diff --git a/src/go/plugin/go.d/collector/nats/integrations/nats.md b/src/go/plugin/go.d/collector/nats/integrations/nats.md index 69de918156cbf5..1500e3e2eb7c2d 100644 --- a/src/go/plugin/go.d/collector/nats/integrations/nats.md +++ b/src/go/plugin/go.d/collector/nats/integrations/nats.md @@ -69,15 +69,56 @@ Metrics: | Metric | Dimensions | Unit | |:------|:----------|:----| -| nats.server_traffic | in, out | bytes/s | -| nats.server_messages | in, out | messages/s | -| nats.server_connections_current | active | connections | +| nats.server_traffic | received, sent | bytes/s | +| nats.server_messages | received, sent | messages/s | +| nats.server_connections | active | connections | | nats.server_connections_rate | connections | connections/s | | nats.server_health_probe_status | ok, error | status | | nats.server_cpu_usage | used | percent | | nats.server_mem_usage | used | bytes | | nats.server_uptime | uptime | seconds | +### Per account + +These metrics refer to [Accounts](https://docs.nats.io/running-a-nats-service/nats_admin/monitoring#account-statistics). + +Labels: + +| Label | Description | +|:-----------|:----------------| +| account | Account name. | + +Metrics: + +| Metric | Dimensions | Unit | +|:------|:----------|:----| +| nats.account_traffic | received, sent | bytes/s | +| nats.account_messages | received, sent | messages/s | +| nats.account_connections | active | connections | +| nats.account_connections_rate | connections | connections/s | +| nats.account_subscriptions | active | subscriptions | +| nats.account_slow_consumers | slow | consumers/s | +| nats.account_leaf_nodes | leafnode | servers | + +### Per route + +These metrics refer to [Routes](https://docs.nats.io/running-a-nats-service/nats_admin/monitoring#route-information). + +Labels: + +| Label | Description | +|:-----------|:----------------| +| route_id | A unique identifier for a route within the NATS cluster. | +| remote_id | he unique identifier of the remote server connected via the route. | + +Metrics: + +| Metric | Dimensions | Unit | +|:------|:----------|:----| +| nats.route_traffic | in, out | bytes/s | +| nats.route_messages | in, out | messages/s | +| nats.route_subscriptions | active | subscriptions | + ### Per http endpoint These metrics refer to HTTP endpoints. @@ -138,6 +179,7 @@ The following options can be defined globally: update_every, autodetection_retry | autodetection_retry | Recheck interval in seconds. Zero means no recheck will be scheduled. | 0 | no | | url | Server URL. | http://127.0.0.1:8222 | yes | | timeout | HTTP request timeout. | 1 | no | +| healthz_check | Controls the behavior of the `/healthz` endpoint [health check](https://docs.nats.io/running-a-nats-service/nats_admin/monitoring#health). | default | no | | username | Username for basic HTTP authentication. | | no | | password | Password for basic HTTP authentication. | | no | | proxy_url | Proxy URL. | | no | diff --git a/src/go/plugin/go.d/collector/nats/metadata.yaml b/src/go/plugin/go.d/collector/nats/metadata.yaml index 1cd392fda44390..79b9853426cbcf 100644 --- a/src/go/plugin/go.d/collector/nats/metadata.yaml +++ b/src/go/plugin/go.d/collector/nats/metadata.yaml @@ -76,6 +76,10 @@ modules: description: HTTP request timeout. default_value: 1 required: false + - name: healthz_check + description: "Controls the behavior of the `/healthz` endpoint [health check](https://docs.nats.io/running-a-nats-service/nats_admin/monitoring#health)." + default_value: "default" + required: false - name: username description: Username for basic HTTP authentication. default_value: "" @@ -188,17 +192,17 @@ modules: unit: bytes/s chart_type: area dimensions: - - name: in - - name: out + - name: received + - name: sent - name: nats.server_messages description: Server Messages unit: messages/s chart_type: line dimensions: - - name: in - - name: out - - name: nats.server_connections_current - description: Server Current Connections + - name: received + - name: sent + - name: nats.server_connections + description: Server Active Connections unit: connections chart_type: line dimensions: @@ -234,6 +238,84 @@ modules: chart_type: line dimensions: - name: uptime + - name: account + description: These metrics refer to [Accounts](https://docs.nats.io/running-a-nats-service/nats_admin/monitoring#account-statistics). + labels: + - name: account + description: "Account name." + metrics: + - name: nats.account_traffic + description: Account Traffic + unit: bytes/s + chart_type: area + dimensions: + - name: received + - name: sent + - name: nats.account_messages + description: Account Messages + unit: messages/s + chart_type: line + dimensions: + - name: received + - name: sent + - name: nats.account_connections + description: Account Active Connections + unit: connections + chart_type: line + dimensions: + - name: active + - name: nats.account_connections_rate + description: Account Connections + unit: connections/s + chart_type: line + dimensions: + - name: connections + - name: nats.account_subscriptions + description: Account Active Subscriptions + unit: subscriptions + chart_type: line + dimensions: + - name: active + - name: nats.account_slow_consumers + description: Account Slow Consumers + unit: consumers/s + chart_type: line + dimensions: + - name: slow + - name: nats.account_leaf_nodes + description: Account Leaf Nodes + unit: servers + chart_type: line + dimensions: + - name: leafnode + - name: route + description: These metrics refer to [Routes](https://docs.nats.io/running-a-nats-service/nats_admin/monitoring#route-information). + labels: + - name: route_id + description: "A unique identifier for a route within the NATS cluster." + - name: remote_id + description: "he unique identifier of the remote server connected via the route." + metrics: + - name: nats.route_traffic + description: Route Traffic + unit: bytes/s + chart_type: area + dimensions: + - name: in + - name: out + - name: nats.route_messages + description: Route Messages + unit: messages/s + chart_type: line + dimensions: + - name: in + - name: out + - name: nats.route_subscriptions + description: Route Active Subscriptions + unit: subscriptions + chart_type: line + dimensions: + - name: active - name: http endpoint description: These metrics refer to HTTP endpoints. labels: diff --git a/src/go/plugin/go.d/collector/nats/restapi.go b/src/go/plugin/go.d/collector/nats/restapi.go index 94043602e2e20c..14e9d6e3511fc6 100644 --- a/src/go/plugin/go.d/collector/nats/restapi.go +++ b/src/go/plugin/go.d/collector/nats/restapi.go @@ -4,10 +4,52 @@ package nats import ( "time" + + "github.com/netdata/netdata/go/plugins/plugin/go.d/pkg/web" ) // https://docs.nats.io/running-a-nats-service/nats_admin/monitoring +const ( + // https://docs.nats.io/running-a-nats-service/nats_admin/monitoring#general-information + urlPathVarz = "/varz" + // https://docs.nats.io/running-a-nats-service/nats_admin/monitoring#health + urlPathHealthz = "/healthz" + // https://docs.nats.io/running-a-nats-service/nats_admin/monitoring#account-statistics + urlPathAccstatz = "/accstatz" + // https://docs.nats.io/running-a-nats-service/nats_admin/monitoring#route-information + urlPathRoutez = "/routez" +) + +var ( + urlQueryHealthzJsEnabledOnly = web.URLQuery("js-enabled-only", "true") + urlQueryHealthzJsServerOnly = web.URLQuery("js-server-only", "true") + urlQueryAccstatz = web.URLQuery("unused", "1") +) + +// //https://github.com/nats-io/nats-server/blob/v2.10.24/server/server.go#L2851 +var httpEndpoints = []string{ + "/", + "/varz", + "/connz", + "/routez", + "/gatewayz", + "/leafz", + "/subsz", + "/stacksz", + "/accountz", + "/accstatz", + "/jsz", + "/healthz", + "/ipqueuesz", + "/raftz", +} + +// https://github.com/nats-io/nats-server/blob/v2.10.24/server/monitor.go#L3125 +type healthzResponse struct { + Status *string `json:"status"` +} + // https://github.com/nats-io/nats-server/blob/v2.10.24/server/monitor.go#L1164 type varzResponse struct { ID string `json:"server_id"` @@ -19,24 +61,9 @@ type varzResponse struct { IP string `json:"ip,omitempty"` MaxConn int `json:"max_connections"` MaxSubs int `json:"max_subscriptions,omitempty"` - PingInterval time.Duration `json:"ping_interval"` - MaxPingsOut int `json:"ping_max"` - HTTPHost string `json:"http_host"` - HTTPPort int `json:"http_port"` - HTTPBasePath string `json:"http_base_path"` - HTTPSPort int `json:"https_port"` - AuthTimeout float64 `json:"auth_timeout"` - MaxControlLine int32 `json:"max_control_line"` - MaxPayload int `json:"max_payload"` - MaxPending int64 `json:"max_pending"` - TLSTimeout float64 `json:"tls_timeout"` - WriteDeadline time.Duration `json:"write_deadline"` Start time.Time `json:"start"` Now time.Time `json:"now"` - Uptime string `json:"uptime"` Mem int64 `json:"mem"` - Cores int `json:"cores"` - MaxProcs int `json:"gomaxprocs"` CPU float64 `json:"cpu"` Connections int `json:"connections"` TotalConnections uint64 `json:"total_connections"` @@ -52,25 +79,35 @@ type varzResponse struct { HTTPReqStats map[string]uint64 `json:"http_req_stats"` } -// //https://github.com/nats-io/nats-server/blob/v2.10.24/server/server.go#L2851 -var httpEndpoints = []string{ - "/", - "/varz", - "/connz", - "/routez", - "/gatewayz", - "/leafz", - "/subsz", - "/stacksz", - "/accountz", - "/accstatz", - "/jsz", - "/healthz", - "/ipqueuesz", - "/raftz", +// https://github.com/nats-io/nats-server/blob/v2.10.24/server/monitor.go#L2279 +type accstatzResponse struct { + AccStats []struct { + Account string `json:"acc"` + Conns int `json:"conns"` + TotalConns int `json:"total_conns"` + LeafNodes int `json:"leafnodes"` + NumSubs uint32 `json:"num_subscriptions"` + Sent struct { + Msgs int64 `json:"msgs"` + Bytes int64 `json:"bytes"` + } `json:"sent"` + Received struct { + Msgs int64 `json:"msgs"` + Bytes int64 `json:"bytes"` + } `json:"received"` + SlowConsumers int64 `json:"slow_consumers"` + } `json:"account_statz"` } -// https://github.com/nats-io/nats-server/blob/v2.10.24/server/monitor.go#L3125 -type healthzResponse struct { - Status *string `json:"status"` +// https://github.com/nats-io/nats-server/blob/v2.10.24/server/monitor.go#L752 +type routezResponse struct { + Routes []struct { + Rid uint64 `json:"rid"` + RemoteID string `json:"remote_id"` + InMsgs int64 `json:"in_msgs"` + OutMsgs int64 `json:"out_msgs"` + InBytes int64 `json:"in_bytes"` + OutBytes int64 `json:"out_bytes"` + NumSubs uint32 `json:"subscriptions"` + } `json:"routes"` } diff --git a/src/go/plugin/go.d/collector/nats/testdata/config.json b/src/go/plugin/go.d/collector/nats/testdata/config.json index dee7e030c9dec2..a2f96cbfa29964 100644 --- a/src/go/plugin/go.d/collector/nats/testdata/config.json +++ b/src/go/plugin/go.d/collector/nats/testdata/config.json @@ -1,6 +1,7 @@ { "vnode": "ok", "update_every": 123, + "healthz_check": "ok", "url": "ok", "body": "ok", "method": "ok", diff --git a/src/go/plugin/go.d/collector/nats/testdata/config.yaml b/src/go/plugin/go.d/collector/nats/testdata/config.yaml index d74c39ba07579b..e7a409b49cd837 100644 --- a/src/go/plugin/go.d/collector/nats/testdata/config.yaml +++ b/src/go/plugin/go.d/collector/nats/testdata/config.yaml @@ -1,5 +1,6 @@ vnode: "ok" update_every: 123 +healthz_check: "ok" url: "ok" body: "ok" method: "ok" diff --git a/src/go/plugin/go.d/collector/nats/testdata/v2.10.24/accstatz.json b/src/go/plugin/go.d/collector/nats/testdata/v2.10.24/accstatz.json new file mode 100644 index 00000000000000..62e60c62646fe2 --- /dev/null +++ b/src/go/plugin/go.d/collector/nats/testdata/v2.10.24/accstatz.json @@ -0,0 +1,54 @@ +{ + "server_id": "NDR5FR76SWSTAP5LSKUNYG7ADXPFLXXWNC7ALU3WGX6WLFMMCIDQAD4J", + "now": "2024-12-21T15:43:05.910221284Z", + "account_statz": [ + { + "acc": "$SYS", + "conns": 0, + "leafnodes": 0, + "total_conns": 0, + "num_subscriptions": 220, + "sent": { + "msgs": 0, + "bytes": 0 + }, + "received": { + "msgs": 0, + "bytes": 0 + }, + "slow_consumers": 0 + }, + { + "acc": "$G", + "conns": 0, + "leafnodes": 0, + "total_conns": 0, + "num_subscriptions": 5, + "sent": { + "msgs": 0, + "bytes": 0 + }, + "received": { + "msgs": 0, + "bytes": 0 + }, + "slow_consumers": 0 + }, + { + "acc": "default", + "conns": 44, + "leafnodes": 0, + "total_conns": 44, + "num_subscriptions": 1133, + "sent": { + "msgs": 2546732, + "bytes": 529749990 + }, + "received": { + "msgs": 916392, + "bytes": 62023455 + }, + "slow_consumers": 1 + } + ] +} diff --git a/src/go/plugin/go.d/collector/nats/testdata/v2.10.24/routez.json b/src/go/plugin/go.d/collector/nats/testdata/v2.10.24/routez.json new file mode 100644 index 00000000000000..c0e7cb6c0e677c --- /dev/null +++ b/src/go/plugin/go.d/collector/nats/testdata/v2.10.24/routez.json @@ -0,0 +1,20 @@ +{ + "server_id": "NACDVKFBUW4C4XA24OOT6L4MDP56MW76J5RJDFXG7HLABSB46DCMWCOW", + "now": "2019-06-24T14:29:16.046656-07:00", + "num_routes": 1, + "routes": [ + { + "rid": 1, + "remote_id": "de475c0041418afc799bccf0fdd61b47", + "did_solicit": true, + "ip": "127.0.0.1", + "port": 61791, + "pending_size": 0, + "in_msgs": 1, + "out_msgs": 1, + "in_bytes": 4, + "out_bytes": 4, + "subscriptions": 1 + } + ] +} diff --git a/src/go/plugin/go.d/collector/nats/testdata/v2.10.24/varz.json b/src/go/plugin/go.d/collector/nats/testdata/v2.10.24/varz.json index 8d31549b67e61d..5b644c2d26e254 100644 --- a/src/go/plugin/go.d/collector/nats/testdata/v2.10.24/varz.json +++ b/src/go/plugin/go.d/collector/nats/testdata/v2.10.24/varz.json @@ -1,73 +1,107 @@ { - "server_id": "NASZPQXJ3BIJOGQHV5ZEWGI6EH3YRQPI2Z5GJRA4AZ47TC4PX4OJGY63", - "server_name": "NASZPQXJ3BIJOGQHV5ZEWGI6EH3YRQPI2Z5GJRA4AZ47TC4PX4OJGY63", + "server_id": "NDR5FR76SWSTAP5LSKUNYG7ADXPFLXXWNC7ALU3WGX6WLFMMCIDQAD4J", + "server_name": "us-south-nats-demo", "version": "2.10.24", "proto": 1, "git_commit": "1d6f7ea", "go": "go1.23.4", "host": "0.0.0.0", "port": 4222, - "max_connections": 65536, + "auth_required": true, + "max_connections": 250000, + "max_subscriptions": 200000, "ping_interval": 120000000000, "ping_max": 2, "http_host": "0.0.0.0", - "http_port": 8222, + "http_port": 0, "http_base_path": "", - "https_port": 0, - "auth_timeout": 2, + "https_port": 8222, + "auth_timeout": 6, "max_control_line": 4096, "max_payload": 1048576, "max_pending": 67108864, - "cluster": { - "name": "my_cluster", - "addr": "0.0.0.0", - "cluster_port": 6222, - "auth_timeout": 2, - "tls_timeout": 2, - "pool_size": 3 - }, + "cluster": {}, "gateway": {}, - "leaf": {}, - "mqtt": {}, - "websocket": {}, - "jetstream": {}, - "tls_timeout": 2, + "leaf": { + "host": "0.0.0.0", + "port": 7422, + "auth_timeout": 6, + "tls_timeout": 5, + "tls_required": true + }, + "mqtt": { + "host": "0.0.0.0", + "port": 1883, + "no_auth_user": "demo-user", + "tls_timeout": 5, + "ack_wait": 60000000000, + "max_ack_pending": 1024 + }, + "websocket": { + "host": "0.0.0.0", + "port": 8443, + "no_auth_user": "demo-user", + "handshake_timeout": 5000000000, + "compression": true + }, + "jetstream": { + "config": { + "max_memory": 10737418240, + "max_storage": 440234147840, + "store_dir": "/var/jetstream/jetstream", + "sync_interval": 120000000000, + "compress_ok": true + }, + "stats": { + "memory": 0, + "storage": 1819021225, + "reserved_memory": 0, + "reserved_storage": 1620615736, + "accounts": 1, + "ha_assets": 0, + "api": { + "total": 324897, + "errors": 323 + } + } + }, + "tls_timeout": 5, "write_deadline": 10000000000, - "start": "2024-12-19T11:51:48.038140697Z", - "now": "2024-12-19T19:30:21.110744698Z", - "uptime": "7h38m33s", - "mem": 21725184, + "start": "2024-12-17T17:27:05.96540148Z", + "now": "2024-12-21T15:43:40.410706574Z", + "uptime": "3d22h16m34s", + "mem": 95731712, "cores": 16, "gomaxprocs": 16, - "cpu": 0, - "connections": 0, - "total_connections": 0, + "cpu": 10, + "connections": 44, + "total_connections": 74932, "routes": 0, "remotes": 0, "leafnodes": 0, - "in_msgs": 0, - "out_msgs": 0, - "in_bytes": 0, - "out_bytes": 0, - "slow_consumers": 0, - "subscriptions": 57, + "in_msgs": 916475, + "out_msgs": 2546840, + "in_bytes": 62024985, + "out_bytes": 529775656, + "slow_consumers": 1, + "subscriptions": 1358, "http_req_stats": { - "/": 3, - "/accountz": 2, - "/accstatz": 2, - "/connz": 2, - "/gatewayz": 2, - "/healthz": 2017, - "/jsz": 3, - "/leafz": 2, - "/routez": 2, - "/subsz": 1, - "/varz": 3750 + "/": 5710, + "/accountz": 2201, + "/accstatz": 6, + "/connz": 3649, + "/gatewayz": 2204, + "/healthz": 3430, + "/jsz": 2958, + "/leafz": 9, + "/routez": 2202, + "/subsz": 4412, + "/varz": 7114 }, - "config_load_time": "2024-12-19T11:51:48.038140697Z", + "config_load_time": "2024-12-17T17:27:05.96540148Z", "system_account": "$SYS", "slow_consumer_stats": { - "clients": 0, + "clients": 1, "routes": 0, "gateways": 0, "leafs": 0 diff --git a/src/go/plugin/go.d/pkg/web/request_config.go b/src/go/plugin/go.d/pkg/web/request_config.go index ca96eca082f7fe..3abb9be3e035b6 100644 --- a/src/go/plugin/go.d/pkg/web/request_config.go +++ b/src/go/plugin/go.d/pkg/web/request_config.go @@ -103,3 +103,7 @@ func NewHTTPRequestWithPath(cfg RequestConfig, urlPath string) (*http.Request, e return NewHTTPRequest(cfg) } + +func URLQuery(key, value string) string { + return url.Values{key: []string{value}}.Encode() +}