Skip to content

Commit 919495d

Browse files
committed
adding support for monitoring path
Signed-off-by: Chengxuan Xing <chengxuan.xing@kaleido.io>
1 parent 611834d commit 919495d

File tree

8 files changed

+142
-63
lines changed

8 files changed

+142
-63
lines changed

doc-site/docs/reference/config.md

Lines changed: 44 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -407,30 +407,70 @@ title: Configuration Reference
407407

408408
## metrics
409409

410+
|Key|Description|Type|Default Value|
411+
|---|-----------|----|-------------|
412+
|address|Deprecated - use monitoring.address instead|`int`|`127.0.0.1`
413+
|enabled|Deprecated - use monitoring.enabled instead|`boolean`|`true`
414+
|path|Deprecated - use monitoring.metricsPath instead|`string`|`/metrics`
415+
|port|Deprecated - use monitoring.port instead|`int`|`6000`
416+
|publicURL|Deprecated - use monitoring.publicURL instead|URL `string`|`<nil>`
417+
|readTimeout|Deprecated - use monitoring.readTimeout instead|[`time.Duration`](https://pkg.go.dev/time#Duration)|`15s`
418+
|shutdownTimeout|The maximum amount of time to wait for any open HTTP requests to finish before shutting down the HTTP server|[`time.Duration`](https://pkg.go.dev/time#Duration)|`10s`
419+
|writeTimeout|Deprecated - use monitoring.writeTimeout instead|[`time.Duration`](https://pkg.go.dev/time#Duration)|`15s`
420+
421+
## metrics.auth
422+
423+
|Key|Description|Type|Default Value|
424+
|---|-----------|----|-------------|
425+
|type|The auth plugin to use for server side authentication of requests|`string`|`<nil>`
426+
427+
## metrics.auth.basic
428+
429+
|Key|Description|Type|Default Value|
430+
|---|-----------|----|-------------|
431+
|passwordfile|The path to a .htpasswd file to use for authenticating requests. Passwords should be hashed with bcrypt.|`string`|`<nil>`
432+
433+
## metrics.tls
434+
435+
|Key|Description|Type|Default Value|
436+
|---|-----------|----|-------------|
437+
|ca|The TLS certificate authority in PEM format (this option is ignored if caFile is also set)|`string`|`<nil>`
438+
|caFile|The path to the CA file for TLS on this API|`string`|`<nil>`
439+
|cert|The TLS certificate in PEM format (this option is ignored if certFile is also set)|`string`|`<nil>`
440+
|certFile|The path to the certificate file for TLS on this API|`string`|`<nil>`
441+
|clientAuth|Enables or disables client auth for TLS on this API|`string`|`<nil>`
442+
|enabled|Enables or disables TLS on this API|`boolean`|`false`
443+
|insecureSkipHostVerify|When to true in unit test development environments to disable TLS verification. Use with extreme caution|`boolean`|`<nil>`
444+
|key|The TLS certificate key in PEM format (this option is ignored if keyFile is also set)|`string`|`<nil>`
445+
|keyFile|The path to the private key file for TLS on this API|`string`|`<nil>`
446+
|requiredDNAttributes|A set of required subject DN attributes. Each entry is a regular expression, and the subject certificate must have a matching attribute of the specified type (CN, C, O, OU, ST, L, STREET, POSTALCODE, SERIALNUMBER are valid attributes)|`map[string]string`|`<nil>`
447+
448+
## monitoring
449+
410450
|Key|Description|Type|Default Value|
411451
|---|-----------|----|-------------|
412452
|address|The IP address on which the metrics HTTP API should listen|`int`|`127.0.0.1`
413453
|enabled|Enables the metrics API|`boolean`|`true`
414-
|path|The path from which to serve the Prometheus metrics|`string`|`/metrics`
454+
|metricsPath|The path from which to serve the Prometheus metrics|`string`|`/metrics`
415455
|port|The port on which the metrics HTTP API should listen|`int`|`6000`
416456
|publicURL|The fully qualified public URL for the metrics API. This is used for building URLs in HTTP responses and in OpenAPI Spec generation|URL `string`|`<nil>`
417457
|readTimeout|The maximum time to wait when reading from an HTTP connection|[`time.Duration`](https://pkg.go.dev/time#Duration)|`15s`
418458
|shutdownTimeout|The maximum amount of time to wait for any open HTTP requests to finish before shutting down the HTTP server|[`time.Duration`](https://pkg.go.dev/time#Duration)|`10s`
419459
|writeTimeout|The maximum time to wait when writing to an HTTP connection|[`time.Duration`](https://pkg.go.dev/time#Duration)|`15s`
420460

421-
## metrics.auth
461+
## monitoring.auth
422462

423463
|Key|Description|Type|Default Value|
424464
|---|-----------|----|-------------|
425465
|type|The auth plugin to use for server side authentication of requests|`string`|`<nil>`
426466

427-
## metrics.auth.basic
467+
## monitoring.auth.basic
428468

429469
|Key|Description|Type|Default Value|
430470
|---|-----------|----|-------------|
431471
|passwordfile|The path to a .htpasswd file to use for authenticating requests. Passwords should be hashed with bcrypt.|`string`|`<nil>`
432472

433-
## metrics.tls
473+
## monitoring.tls
434474

435475
|Key|Description|Type|Default Value|
436476
|---|-----------|----|-------------|

internal/apiserver/metrics_server.go

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright © 2022 Kaleido, Inc.
1+
// Copyright © 2025 Kaleido, Inc.
22
//
33
// SPDX-License-Identifier: Apache-2.0
44
//
@@ -21,11 +21,17 @@ import (
2121
)
2222

2323
const (
24-
MetricsEnabled = "enabled"
25-
MetricsPath = "path"
24+
Enabled = "enabled"
25+
DeprecatedMetricsPath = "path"
26+
MetricsPath = "metricsPath"
2627
)
2728

28-
func initMetricsConfig(config config.Section) {
29-
config.AddKnownKey(MetricsEnabled, true)
29+
func initDeprecatedMetricsConfig(config config.Section) {
30+
config.AddKnownKey(Enabled, true)
31+
config.AddKnownKey(DeprecatedMetricsPath, "/metrics")
32+
}
33+
34+
func initMonitoringConfig(config config.Section) {
35+
config.AddKnownKey(Enabled, true)
3036
config.AddKnownKey(MetricsPath, "/metrics")
3137
}

internal/apiserver/server.go

Lines changed: 54 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright © 2024 Kaleido, Inc.
1+
// Copyright © 2025 Kaleido, Inc.
22
//
33
// SPDX-License-Identifier: Apache-2.0
44
//
@@ -42,10 +42,11 @@ import (
4242
)
4343

4444
var (
45-
spiConfig = config.RootSection("spi")
46-
apiConfig = config.RootSection("http")
47-
metricsConfig = config.RootSection("metrics")
48-
corsConfig = config.RootSection("cors")
45+
spiConfig = config.RootSection("spi")
46+
apiConfig = config.RootSection("http")
47+
deprecatedMetricsConfig = config.RootSection("metrics")
48+
monitoringConfig = config.RootSection("monitoring")
49+
corsConfig = config.RootSection("cors")
4950
)
5051

5152
// Server is the external interface for the API Server
@@ -55,31 +56,35 @@ type Server interface {
5556

5657
type apiServer struct {
5758
// Defaults set with config
58-
apiTimeout time.Duration
59-
apiMaxTimeout time.Duration
60-
metricsEnabled bool
61-
ffiSwaggerGen FFISwaggerGen
62-
apiPublicURL string
63-
dynamicPublicURLHeader string
64-
defaultNamespace string
59+
apiTimeout time.Duration
60+
apiMaxTimeout time.Duration
61+
deprecatedMetricsEnabled bool
62+
monitoringEnabled bool
63+
ffiSwaggerGen FFISwaggerGen
64+
apiPublicURL string
65+
dynamicPublicURLHeader string
66+
defaultNamespace string
6567
}
6668

6769
func InitConfig() {
6870
httpserver.InitHTTPConfig(apiConfig, 5000)
6971
httpserver.InitHTTPConfig(spiConfig, 5001)
70-
httpserver.InitHTTPConfig(metricsConfig, 6000)
72+
httpserver.InitHTTPConfig(deprecatedMetricsConfig, 6000)
73+
httpserver.InitHTTPConfig(monitoringConfig, 6000)
7174
httpserver.InitCORSConfig(corsConfig)
72-
initMetricsConfig(metricsConfig)
75+
initDeprecatedMetricsConfig(deprecatedMetricsConfig)
76+
initMonitoringConfig(monitoringConfig)
7377
}
7478

7579
func NewAPIServer() Server {
7680
as := &apiServer{
77-
apiTimeout: config.GetDuration(coreconfig.APIRequestTimeout),
78-
apiMaxTimeout: config.GetDuration(coreconfig.APIRequestMaxTimeout),
79-
dynamicPublicURLHeader: config.GetString(coreconfig.APIDynamicPublicURLHeader),
80-
defaultNamespace: config.GetString(coreconfig.NamespacesDefault),
81-
metricsEnabled: config.GetBool(coreconfig.MetricsEnabled),
82-
ffiSwaggerGen: &ffiSwaggerGen{},
81+
apiTimeout: config.GetDuration(coreconfig.APIRequestTimeout),
82+
apiMaxTimeout: config.GetDuration(coreconfig.APIRequestMaxTimeout),
83+
dynamicPublicURLHeader: config.GetString(coreconfig.APIDynamicPublicURLHeader),
84+
defaultNamespace: config.GetString(coreconfig.NamespacesDefault),
85+
deprecatedMetricsEnabled: config.GetBool(coreconfig.DeprecatedMetricsEnabled),
86+
monitoringEnabled: config.GetBool(coreconfig.MonitoringEnabled),
87+
ffiSwaggerGen: &ffiSwaggerGen{},
8388
}
8489
as.apiPublicURL = as.getPublicURL(apiConfig, "")
8590
return as
@@ -110,16 +115,20 @@ func (as *apiServer) Serve(ctx context.Context, mgr namespace.Manager) (err erro
110115
} else if config.GetBool(coreconfig.LegacyAdminEnabled) {
111116
log.L(ctx).Warnf("Your config includes an 'admin' section, which should be renamed to 'spi' - SPI server will not be enabled until this is corrected")
112117
}
113-
114-
if as.metricsEnabled {
115-
metricsHTTPServer, err := httpserver.NewHTTPServer(ctx, "metrics", as.createMetricsMuxRouter(), metricsErrChan, metricsConfig, corsConfig, &httpserver.ServerOptions{
118+
var monitoringServer httpserver.HTTPServer
119+
if as.monitoringEnabled {
120+
monitoringServer, err = httpserver.NewHTTPServer(ctx, "monitoring", as.createMonitoringMuxRouter(), metricsErrChan, monitoringConfig, corsConfig, &httpserver.ServerOptions{
121+
MaximumRequestTimeout: as.apiMaxTimeout,
122+
})
123+
} else if as.deprecatedMetricsEnabled {
124+
monitoringServer, err = httpserver.NewHTTPServer(ctx, "metrics", as.createMonitoringMuxRouter(), metricsErrChan, deprecatedMetricsConfig, corsConfig, &httpserver.ServerOptions{
116125
MaximumRequestTimeout: as.apiMaxTimeout,
117126
})
118-
if err != nil {
119-
return err
120-
}
121-
go metricsHTTPServer.ServeHTTP(ctx)
122127
}
128+
if err != nil {
129+
return err
130+
}
131+
go monitoringServer.ServeHTTP(ctx)
123132

124133
return as.waitForServerStop(httpErrChan, spiErrChan, metricsErrChan)
125134
}
@@ -345,7 +354,7 @@ func (as *apiServer) createMuxRouter(ctx context.Context, mgr namespace.Manager)
345354
r := mux.NewRouter()
346355
hf := as.handlerFactory()
347356

348-
if as.metricsEnabled {
357+
if as.deprecatedMetricsEnabled || as.monitoringEnabled {
349358
r.Use(metrics.GetRestServerInstrumentation().Middleware)
350359
}
351360

@@ -433,7 +442,7 @@ func (as *apiServer) spiWSHandler(mgr namespace.Manager) http.HandlerFunc {
433442

434443
func (as *apiServer) createAdminMuxRouter(mgr namespace.Manager) *mux.Router {
435444
r := mux.NewRouter()
436-
if as.metricsEnabled {
445+
if as.deprecatedMetricsEnabled || as.monitoringEnabled {
437446
r.Use(metrics.GetAdminServerInstrumentation().Middleware)
438447
}
439448
hf := as.handlerFactory()
@@ -468,12 +477,24 @@ func (as *apiServer) createAdminMuxRouter(mgr namespace.Manager) *mux.Router {
468477
return r
469478
}
470479

471-
func (as *apiServer) createMetricsMuxRouter() *mux.Router {
480+
func (as *apiServer) createMonitoringMuxRouter() *mux.Router {
472481
r := mux.NewRouter()
473482

474-
r.Path(config.GetString(coreconfig.MetricsPath)).Handler(promhttp.InstrumentMetricHandler(metrics.Registry(),
475-
promhttp.HandlerFor(metrics.Registry(), promhttp.HandlerOpts{})))
476-
483+
if as.monitoringEnabled {
484+
r.Path(config.GetString(coreconfig.MonitoringMetricsPath)).Handler(promhttp.InstrumentMetricHandler(metrics.Registry(),
485+
promhttp.HandlerFor(metrics.Registry(), promhttp.HandlerOpts{})))
486+
} else if as.deprecatedMetricsEnabled {
487+
r.Path(config.GetString(coreconfig.DeprecatedMetricsPath)).Handler(promhttp.InstrumentMetricHandler(metrics.Registry(),
488+
promhttp.HandlerFor(metrics.Registry(), promhttp.HandlerOpts{})))
489+
}
490+
hf := ffapi.HandlerFactory{}
491+
r.HandleFunc("/livez", hf.APIWrapper(func(res http.ResponseWriter, req *http.Request) (status int, err error) {
492+
// a simple liveness check
493+
return http.StatusOK, nil
494+
}))
495+
r.NotFoundHandler = hf.APIWrapper(func(_ http.ResponseWriter, req *http.Request) (status int, err error) {
496+
return 404, i18n.NewError(req.Context(), i18n.Msg404NotFound)
497+
})
477498
return r
478499
}
479500

internal/apiserver/server_test.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright © 2021 Kaleido, Inc.
1+
// Copyright © 2025 Kaleido, Inc.
22
//
33
// SPDX-License-Identifier: Apache-2.0
44
//
@@ -86,7 +86,7 @@ func TestStartStopServer(t *testing.T) {
8686
InitConfig()
8787
apiConfig.Set(httpserver.HTTPConfPort, 0)
8888
spiConfig.Set(httpserver.HTTPConfPort, 0)
89-
metricsConfig.Set(httpserver.HTTPConfPort, 0)
89+
monitoringConfig.Set(httpserver.HTTPConfPort, 0)
9090
config.Set(coreconfig.UIPath, "test")
9191
config.Set(coreconfig.SPIEnabled, true)
9292
ctx, cancel := context.WithCancel(context.Background())
@@ -105,7 +105,7 @@ func TestStartLegacyAdminConfig(t *testing.T) {
105105
InitConfig()
106106
apiConfig.Set(httpserver.HTTPConfPort, 0)
107107
spiConfig.Set(httpserver.HTTPConfPort, 0)
108-
metricsConfig.Set(httpserver.HTTPConfPort, 0)
108+
monitoringConfig.Set(httpserver.HTTPConfPort, 0)
109109
config.Set(coreconfig.UIPath, "test")
110110
config.Set(coreconfig.LegacyAdminEnabled, true)
111111
ctx, cancel := context.WithCancel(context.Background())
@@ -170,8 +170,8 @@ func TestStartMetricsFail(t *testing.T) {
170170
coreconfig.Reset()
171171
metrics.Clear()
172172
InitConfig()
173-
metricsConfig.Set(httpserver.HTTPConfAddress, "...://")
174-
config.Set(coreconfig.MetricsEnabled, true)
173+
monitoringConfig.Set(httpserver.HTTPConfAddress, "...://")
174+
config.Set(coreconfig.MonitoringEnabled, true)
175175
ctx, cancel := context.WithCancel(context.Background())
176176
cancel() // server will immediately shut down
177177
as := NewAPIServer()

internal/coreconfig/coreconfig.go

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright © 2024 Kaleido, Inc.
1+
// Copyright © 2025 Kaleido, Inc.
22
//
33
// SPDX-License-Identifier: Apache-2.0
44
//
@@ -287,10 +287,14 @@ var (
287287
MessageWriterBatchTimeout = ffc("message.writer.batchTimeout")
288288
// MessageWriterBatchMaxInserts
289289
MessageWriterBatchMaxInserts = ffc("message.writer.batchMaxInserts")
290-
// MetricsEnabled determines whether metrics will be instrumented and if the metrics server will be enabled or not
291-
MetricsEnabled = ffc("metrics.enabled")
290+
// MetricsEnabled - deprecated, use monitoring.enabled
291+
DeprecatedMetricsEnabled = ffc("metrics.enabled")
292+
// MetricsPath - deprecated, use monitoring.metricsPath
293+
DeprecatedMetricsPath = ffc("metrics.path")
294+
// Monitoring determines whether monitoring routes will be enabled, which contains metrics instruments
295+
MonitoringEnabled = ffc("monitoring.enabled")
292296
// MetricsPath determines what path to serve the Prometheus metrics from
293-
MetricsPath = ffc("metrics.path")
297+
MonitoringMetricsPath = ffc("monitoring.metricsPath")
294298
// NamespacesDefault is the default namespace - must be in the predefines list
295299
NamespacesDefault = ffc("namespaces.default")
296300
// NamespacesPredefined is a list of namespaces to ensure exists, without requiring a broadcast from the network

internal/coremsgs/en_config_descriptions.go

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright © 2024 Kaleido, Inc.
1+
// Copyright © 2025 Kaleido, Inc.
22
//
33
// SPDX-License-Identifier: Apache-2.0
44
//
@@ -320,13 +320,21 @@ var (
320320
ConfigTransactionWriterBatchTimeout = ffc("config.transaction.writer.batchTimeout", "How long to wait for more transactions to arrive before flushing the batch", i18n.TimeDurationType)
321321
ConfigTransactionWriterCount = ffc("config.transaction.writer.count", "The number of message writer workers", i18n.IntType)
322322

323-
ConfigMetricsAddress = ffc("config.metrics.address", "The IP address on which the metrics HTTP API should listen", i18n.IntType)
324-
ConfigMetricsEnabled = ffc("config.metrics.enabled", "Enables the metrics API", i18n.BooleanType)
325-
ConfigMetricsPath = ffc("config.metrics.path", "The path from which to serve the Prometheus metrics", i18n.StringType)
326-
ConfigMetricsPort = ffc("config.metrics.port", "The port on which the metrics HTTP API should listen", i18n.IntType)
327-
ConfigMetricsPublicURL = ffc("config.metrics.publicURL", "The fully qualified public URL for the metrics API. This is used for building URLs in HTTP responses and in OpenAPI Spec generation", urlStringType)
328-
ConfigMetricsReadTimeout = ffc("config.metrics.readTimeout", "The maximum time to wait when reading from an HTTP connection", i18n.TimeDurationType)
329-
ConfigMetricsWriteTimeout = ffc("config.metrics.writeTimeout", "The maximum time to wait when writing to an HTTP connection", i18n.TimeDurationType)
323+
DeprecatedConfigMetricsAddress = ffc("config.metrics.address", "Deprecated - use monitoring.address instead", i18n.IntType)
324+
DeprecatedConfigMetricsEnabled = ffc("config.metrics.enabled", "Deprecated - use monitoring.enabled instead", i18n.BooleanType)
325+
DeprecatedConfigMetricsPath = ffc("config.metrics.path", "Deprecated - use monitoring.metricsPath instead", i18n.StringType)
326+
DeprecatedConfigMetricsPort = ffc("config.metrics.port", "Deprecated - use monitoring.port instead", i18n.IntType)
327+
DeprecatedConfigMetricsPublicURL = ffc("config.metrics.publicURL", "Deprecated - use monitoring.publicURL instead", urlStringType)
328+
DeprecatedConfigMetricsReadTimeout = ffc("config.metrics.readTimeout", "Deprecated - use monitoring.readTimeout instead", i18n.TimeDurationType)
329+
DeprecatedConfigMetricsWriteTimeout = ffc("config.metrics.writeTimeout", "Deprecated - use monitoring.writeTimeout instead", i18n.TimeDurationType)
330+
331+
ConfigMetricsAddress = ffc("config.monitoring.address", "The IP address on which the metrics HTTP API should listen", i18n.IntType)
332+
ConfigMetricsEnabled = ffc("config.monitoring.enabled", "Enables the metrics API", i18n.BooleanType)
333+
ConfigMetricsPath = ffc("config.monitoring.metricsPath", "The path from which to serve the Prometheus metrics", i18n.StringType)
334+
ConfigMetricsPort = ffc("config.monitoring.port", "The port on which the metrics HTTP API should listen", i18n.IntType)
335+
ConfigMetricsPublicURL = ffc("config.monitoring.publicURL", "The fully qualified public URL for the metrics API. This is used for building URLs in HTTP responses and in OpenAPI Spec generation", urlStringType)
336+
ConfigMetricsReadTimeout = ffc("config.monitoring.readTimeout", "The maximum time to wait when reading from an HTTP connection", i18n.TimeDurationType)
337+
ConfigMetricsWriteTimeout = ffc("config.monitoring.writeTimeout", "The maximum time to wait when writing to an HTTP connection", i18n.TimeDurationType)
330338

331339
ConfigNamespacesDefault = ffc("config.namespaces.default", "The default namespace - must be in the predefined list", i18n.StringType)
332340
ConfigNamespacesPredefined = ffc("config.namespaces.predefined", "A list of namespaces to ensure exists, without requiring a broadcast from the network", "List "+i18n.StringType)

internal/metrics/metrics.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright © 2024 Kaleido, Inc.
1+
// Copyright © 2025 Kaleido, Inc.
22
//
33
// SPDX-License-Identifier: Apache-2.0
44
//
@@ -54,7 +54,7 @@ type metricsManager struct {
5454
func NewMetricsManager(ctx context.Context) Manager {
5555
mm := &metricsManager{
5656
ctx: ctx,
57-
metricsEnabled: config.GetBool(coreconfig.MetricsEnabled),
57+
metricsEnabled: config.GetBool(coreconfig.DeprecatedMetricsEnabled) || config.GetBool(coreconfig.MonitoringEnabled),
5858
timeMap: make(map[string]time.Time),
5959
}
6060

internal/namespace/manager.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright © 2024 Kaleido, Inc.
1+
// Copyright © 2025 Kaleido, Inc.
22
//
33
// SPDX-License-Identifier: Apache-2.0
44
//
@@ -161,7 +161,7 @@ func stringSlicesEqual(a, b []string) bool {
161161
func NewNamespaceManager() Manager {
162162
nm := &namespaceManager{
163163
namespaces: make(map[string]*namespace),
164-
metricsEnabled: config.GetBool(coreconfig.MetricsEnabled),
164+
metricsEnabled: config.GetBool(coreconfig.DeprecatedMetricsEnabled) || config.GetBool(coreconfig.MonitoringEnabled),
165165
tokenBroadcastNames: make(map[string]string),
166166
watchConfig: viper.WatchConfig,
167167

0 commit comments

Comments
 (0)