From 34fb17360a6d641a34f5321b1496bf4c790579ed Mon Sep 17 00:00:00 2001 From: Valina Li Date: Mon, 6 Feb 2023 10:26:18 -0800 Subject: [PATCH] feat!: [SDK] Remove old metrics collection and REST /metrics endpoint (#1287) * feat!: [SDK] Remove old metrics collection and REST /metrics endpoint BREAKING CHANGE: /metrics endpoint no longer available for any service Closes: #1281 Signed-off-by: Valina Li --- app-service-template/Attribution.txt | 3 - app-service-template/go.mod | 1 - app-service-template/go.sum | 2 - go.mod | 1 - go.sum | 2 - internal/app/service.go | 2 - internal/bootstrap/handlers/telemetry.go | 51 ------------ internal/controller/rest/controller.go | 19 ----- internal/controller/rest/controller_test.go | 35 -------- internal/telemetry/linux_cpu.go | 54 ------------ internal/telemetry/telemetry.go | 92 --------------------- internal/telemetry/unimplemented_cpu.go | 40 --------- internal/telemetry/windows_cpu.go | 79 ------------------ internal/webserver/server.go | 1 - openapi/v2/app-functions-sdk.yaml | 56 ------------- 15 files changed, 438 deletions(-) delete mode 100644 internal/bootstrap/handlers/telemetry.go delete mode 100644 internal/telemetry/linux_cpu.go delete mode 100644 internal/telemetry/telemetry.go delete mode 100644 internal/telemetry/unimplemented_cpu.go delete mode 100644 internal/telemetry/windows_cpu.go diff --git a/app-service-template/Attribution.txt b/app-service-template/Attribution.txt index b90a87cc5..485300768 100644 --- a/app-service-template/Attribution.txt +++ b/app-service-template/Attribution.txt @@ -1,8 +1,5 @@ The following open source projects are referenced by app-service-configurable: -bertimus9/systemstat (MIT) https://bitbucket.org/bertimus9/systemstat -https://bitbucket.org/bertimus9/systemstat/src/master/LICENSE - armon/go-metrics (MIT) https://github.com/armon/go-metrics https://github.com/armon/go-metrics/blob/master/LICENSE diff --git a/app-service-template/go.mod b/app-service-template/go.mod index 1e5e21fce..280a60e28 100644 --- a/app-service-template/go.mod +++ b/app-service-template/go.mod @@ -17,7 +17,6 @@ require ( ) require ( - bitbucket.org/bertimus9/systemstat v0.5.0 // indirect github.com/Microsoft/go-winio v0.6.0 // indirect github.com/armon/go-metrics v0.3.10 // indirect github.com/cenkalti/backoff v2.2.1+incompatible // indirect diff --git a/app-service-template/go.sum b/app-service-template/go.sum index 4f5af966a..8aa19697d 100644 --- a/app-service-template/go.sum +++ b/app-service-template/go.sum @@ -1,5 +1,3 @@ -bitbucket.org/bertimus9/systemstat v0.5.0 h1:n0aLnh2Jo4nBUBym9cE5PJDG8GT6g+4VuS2Ya2jYYpA= -bitbucket.org/bertimus9/systemstat v0.5.0/go.mod h1:EkUWPp8lKFPMXP8vnbpT5JDI0W/sTiLZAvN8ONWErHY= github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= github.com/Microsoft/go-winio v0.6.0 h1:slsWYD/zyx7lCXoZVlvQrj0hPTM1HI4+v1sIda2yDvg= github.com/Microsoft/go-winio v0.6.0/go.mod h1:cTAf44im0RAYeL23bpB+fzCyDH2MJiz2BO69KH/soAE= diff --git a/go.mod b/go.mod index 2848f05e0..83b5f41e6 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,6 @@ module github.com/edgexfoundry/app-functions-sdk-go/v3 go 1.18 require ( - bitbucket.org/bertimus9/systemstat v0.5.0 github.com/diegoholiveira/jsonlogic/v3 v3.2.6 github.com/eclipse/paho.mqtt.golang v1.4.2 github.com/edgexfoundry/go-mod-bootstrap/v3 v3.0.0-dev.11 diff --git a/go.sum b/go.sum index 63da10845..d399b5362 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,3 @@ -bitbucket.org/bertimus9/systemstat v0.5.0 h1:n0aLnh2Jo4nBUBym9cE5PJDG8GT6g+4VuS2Ya2jYYpA= -bitbucket.org/bertimus9/systemstat v0.5.0/go.mod h1:EkUWPp8lKFPMXP8vnbpT5JDI0W/sTiLZAvN8ONWErHY= github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= github.com/Microsoft/go-winio v0.6.0 h1:slsWYD/zyx7lCXoZVlvQrj0hPTM1HI4+v1sIda2yDvg= github.com/Microsoft/go-winio v0.6.0/go.mod h1:cTAf44im0RAYeL23bpB+fzCyDH2MJiz2BO69KH/soAE= diff --git a/internal/app/service.go b/internal/app/service.go index 2cf47dd27..4f6b14753 100644 --- a/internal/app/service.go +++ b/internal/app/service.go @@ -116,7 +116,6 @@ type contextGroup struct { func (svc *Service) AddRoute(route string, handler func(nethttp.ResponseWriter, *nethttp.Request), methods ...string) error { if route == commonConstants.ApiPingRoute || route == commonConstants.ApiConfigRoute || - route == commonConstants.ApiMetricsRoute || route == commonConstants.ApiVersionRoute || route == internal.ApiTriggerRoute { return errors.New("route is reserved") @@ -507,7 +506,6 @@ func (svc *Service) Initialize() error { []bootstrapInterfaces.BootstrapHandler{ bootstrapHandlers.MessagingBootstrapHandler, bootstrapHandlers.NewClientsBootstrap().BootstrapHandler, - handlers.NewTelemetry().BootstrapHandler, handlers.NewVersionValidator(svc.commandLine.skipVersionCheck, internal.SDKVersion).BootstrapHandler, bootstrapHandlers.NewServiceMetrics(svc.serviceKey).BootstrapHandler, }, diff --git a/internal/bootstrap/handlers/telemetry.go b/internal/bootstrap/handlers/telemetry.go deleted file mode 100644 index 4804bcb2f..000000000 --- a/internal/bootstrap/handlers/telemetry.go +++ /dev/null @@ -1,51 +0,0 @@ -// -// Copyright (c) 2021 Intel Corporation -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package handlers - -import ( - "context" - "sync" - - "github.com/edgexfoundry/go-mod-bootstrap/v3/bootstrap/container" - "github.com/edgexfoundry/go-mod-bootstrap/v3/bootstrap/startup" - "github.com/edgexfoundry/go-mod-bootstrap/v3/di" - - "github.com/edgexfoundry/app-functions-sdk-go/v3/internal/telemetry" -) - -// Telemetry contains references to dependencies required by the Telemetry bootstrap implementation. -type Telemetry struct { -} - -// New Telemetry create a new instance of Telemetry -func NewTelemetry() *Telemetry { - return &Telemetry{} -} - -// BootstrapHandler starts the telemetry collection -func (_ *Telemetry) BootstrapHandler( - ctx context.Context, - wg *sync.WaitGroup, - _ startup.Timer, - dic *di.Container) bool { - - logger := container.LoggingClientFrom(dic.Get) - - wg.Add(1) - go telemetry.StartCpuUsageAverage(wg, ctx, logger) - - return true -} diff --git a/internal/controller/rest/controller.go b/internal/controller/rest/controller.go index d4ff5e5c6..56345b188 100644 --- a/internal/controller/rest/controller.go +++ b/internal/controller/rest/controller.go @@ -28,7 +28,6 @@ import ( "github.com/edgexfoundry/app-functions-sdk-go/v3/internal" "github.com/edgexfoundry/app-functions-sdk-go/v3/internal/bootstrap/container" sdkCommon "github.com/edgexfoundry/app-functions-sdk-go/v3/internal/common" - "github.com/edgexfoundry/app-functions-sdk-go/v3/internal/telemetry" "github.com/edgexfoundry/app-functions-sdk-go/v3/pkg/interfaces" bootstrapInterfaces "github.com/edgexfoundry/go-mod-bootstrap/v3/bootstrap/interfaces" @@ -102,24 +101,6 @@ func (c *Controller) Config(writer http.ResponseWriter, request *http.Request) { c.sendResponse(writer, request, common.ApiVersionRoute, response, http.StatusOK) } -// Metrics handles the request to the /metrics endpoint, memory and cpu utilization stats -// It returns a response as specified by the V2 API swagger in openapi/v2 -func (c *Controller) Metrics(writer http.ResponseWriter, request *http.Request) { - t := telemetry.NewSystemUsage() - metrics := commonDtos.Metrics{ - MemAlloc: t.Memory.Alloc, - MemFrees: t.Memory.Frees, - MemLiveObjects: t.Memory.LiveObjects, - MemMallocs: t.Memory.Mallocs, - MemSys: t.Memory.Sys, - MemTotalAlloc: t.Memory.TotalAlloc, - CpuBusyAvg: uint8(t.CpuBusyAvg), - } - - response := commonDtos.NewMetricsResponse(metrics, c.serviceName) - c.sendResponse(writer, request, common.ApiMetricsRoute, response, http.StatusOK) -} - // AddSecret handles the request to add App Service exclusive secret to the Secret Store // It returns a response as specified by the V2 API swagger in openapi/v2 func (c *Controller) AddSecret(writer http.ResponseWriter, request *http.Request) { diff --git a/internal/controller/rest/controller_test.go b/internal/controller/rest/controller_test.go index 38448b93e..4ea8e030b 100644 --- a/internal/controller/rest/controller_test.go +++ b/internal/controller/rest/controller_test.go @@ -20,7 +20,6 @@ import ( "encoding/json" "errors" "io" - "math" "net/http" "net/http/httptest" "os" @@ -107,40 +106,6 @@ func TestVersionRequest(t *testing.T) { assert.Equal(t, serviceName, actual.ServiceName) } -func TestMetricsRequest(t *testing.T) { - serviceName := uuid.NewString() - - target := NewController(nil, dic, serviceName) - - recorder := doRequest(t, http.MethodGet, common.ApiMetricsRoute, target.Metrics, nil) - - actual := commonDtos.MetricsResponse{ - Metrics: commonDtos.Metrics{ - MemAlloc: math.MaxUint64, - MemFrees: math.MaxUint64, - MemLiveObjects: math.MaxUint64, - MemMallocs: math.MaxUint64, - MemSys: math.MaxUint64, - MemTotalAlloc: math.MaxUint64, - CpuBusyAvg: 0, - }, - } - err := json.Unmarshal(recorder.Body.Bytes(), &actual) - require.NoError(t, err) - - assert.Equal(t, common.ApiVersion, actual.ApiVersion) - assert.Equal(t, serviceName, actual.ServiceName) - - // Since when -race flag is use some values may come back as 0 we need to use the max value to detect change - assert.NotEqual(t, uint64(math.MaxUint64), actual.Metrics.MemAlloc) - assert.NotEqual(t, uint64(math.MaxUint64), actual.Metrics.MemFrees) - assert.NotEqual(t, uint64(math.MaxUint64), actual.Metrics.MemLiveObjects) - assert.NotEqual(t, uint64(math.MaxUint64), actual.Metrics.MemMallocs) - assert.NotEqual(t, uint64(math.MaxUint64), actual.Metrics.MemSys) - assert.NotEqual(t, uint64(math.MaxUint64), actual.Metrics.MemTotalAlloc) - assert.NotEqual(t, 0, actual.Metrics.CpuBusyAvg) -} - func TestConfigRequest(t *testing.T) { serviceName := uuid.NewString() diff --git a/internal/telemetry/linux_cpu.go b/internal/telemetry/linux_cpu.go deleted file mode 100644 index 4ebd917ea..000000000 --- a/internal/telemetry/linux_cpu.go +++ /dev/null @@ -1,54 +0,0 @@ -//go:build linux -// +build linux - -/******************************************************************************* - * Copyright 2019 Dell Inc., Intel Corporation - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except - * in compliance with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the License - * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express - * or implied. See the License for the specific language governing permissions and limitations under - * the License. - *******************************************************************************/ - -package telemetry - -import ( - "math" - - "bitbucket.org/bertimus9/systemstat" -) - -func PollCpu() (cpuSnapshot CpuUsage) { - linuxSample := systemstat.GetCPUSample() - return CpuUsage{ - Busy: linuxSample.Nice + linuxSample.User, - Idle: linuxSample.Idle, - Total: linuxSample.Total, - } -} - -func AvgCpuUsage(init, final CpuUsage) (avg float64) { - // SimpleAverage only uses idle and total, so only copy those - linuxInit := systemstat.CPUSample{ - Idle: init.Idle, - Total: init.Total, - } - - linuxFinal := systemstat.CPUSample{ - Idle: final.Idle, - Total: final.Total, - } - - avg = systemstat.GetSimpleCPUAverage(linuxInit, linuxFinal).BusyPct - - if avg < .000001 || math.IsNaN(avg) { - return 0.0 - } - - return avg -} diff --git a/internal/telemetry/telemetry.go b/internal/telemetry/telemetry.go deleted file mode 100644 index b2b180dd6..000000000 --- a/internal/telemetry/telemetry.go +++ /dev/null @@ -1,92 +0,0 @@ -/******************************************************************************* - * Copyright 2021 Dell Inc., Intel Corporation - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except - * in compliance with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the License - * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express - * or implied. See the License for the specific language governing permissions and limitations under - * the License. - *******************************************************************************/ - -package telemetry - -import ( - "context" - "runtime" - "sync" - "time" - - "github.com/edgexfoundry/go-mod-core-contracts/v3/clients/logger" -) - -// SystemUsage -// swagger:model -type SystemUsage struct { - Memory memoryUsage - CpuBusyAvg float64 -} - -// swagger:model -type memoryUsage struct { - Alloc uint64 - TotalAlloc uint64 - Sys uint64 - Mallocs uint64 - Frees uint64 - LiveObjects uint64 -} - -type CpuUsage struct { - Busy, // time used by all processes. this ideally does not include system processes. - Idle, // time used by the idle process - Total uint64 // reported sum total of all usage -} - -var lastSample CpuUsage -var usageAvg float64 - -func NewSystemUsage() (s SystemUsage) { - // The micro-service is to be considered the System Of Record (SOR) in terms of accurate information. - // Fetch metrics for the metadata service. - var rtm runtime.MemStats - - // Read full memory stats - runtime.ReadMemStats(&rtm) - - // Miscellaneous memory stats - s.Memory.Alloc = rtm.Alloc - s.Memory.TotalAlloc = rtm.TotalAlloc - s.Memory.Sys = rtm.Sys - s.Memory.Mallocs = rtm.Mallocs - s.Memory.Frees = rtm.Frees - - // Live objects = Mallocs - Frees - s.Memory.LiveObjects = s.Memory.Mallocs - s.Memory.Frees - - s.CpuBusyAvg = usageAvg - - return s -} - -func StartCpuUsageAverage(appWg *sync.WaitGroup, appCtx context.Context, logger logger.LoggingClient) { - defer appWg.Done() - - logger.Info("Starting CPU Usage Average loop") - - for { - select { - case <-appCtx.Done(): - logger.Info("Exiting CPU Usage Average loop") - return - - case <-time.After(time.Second * 10): - nextUsage := PollCpu() - usageAvg = AvgCpuUsage(lastSample, nextUsage) - lastSample = nextUsage - } - } -} diff --git a/internal/telemetry/unimplemented_cpu.go b/internal/telemetry/unimplemented_cpu.go deleted file mode 100644 index c18c1b1ee..000000000 --- a/internal/telemetry/unimplemented_cpu.go +++ /dev/null @@ -1,40 +0,0 @@ -//go:build !linux && !windows -// +build !linux,!windows - -/******************************************************************************* - * Copyright 2019 Dell Inc., Intel Corporation - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except - * in compliance with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the License - * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express - * or implied. See the License for the specific language governing permissions and limitations under - * the License. - *******************************************************************************/ - -package telemetry - -import ( - "github.com/edgexfoundry/go-mod-core-contracts/v3/clients/logger" -) - -var LoggingClient logger.LoggingClient - -func PollCpu() (cpuSnapshot CpuUsage) { - if LoggingClient != nil { - LoggingClient.Debug("Could not poll CPU usage", "reason", "OS not compatible with metrics service") - } - - return cpuSnapshot -} - -func AvgCpuUsage(init, final CpuUsage) (avg float64) { - if LoggingClient != nil { - LoggingClient.Debug("Could not average CPU usage", "reason", "OS not compatible with metrics service") - } - - return -1 -} diff --git a/internal/telemetry/windows_cpu.go b/internal/telemetry/windows_cpu.go deleted file mode 100644 index 5d610b09a..000000000 --- a/internal/telemetry/windows_cpu.go +++ /dev/null @@ -1,79 +0,0 @@ -//go:build windows -// +build windows - -// -// Copyright (c) 2021 Intel Corporation -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -package telemetry - -import ( - "math" - "syscall" - "unsafe" -) - -var ( - modKernel32 = syscall.NewLazyDLL("kernel32.dll") - procGetSystemTimes = modKernel32.NewProc("GetSystemTimes") -) - -func PollCpu() (cpuSnapshot CpuUsage) { - var idle, kernel, user FileTime - - getSystemTimes(&idle, &kernel, &user) - idleFirst := idle.LowDateTime | (idle.HighDateTime << 32) - kernelFirst := kernel.LowDateTime | (kernel.HighDateTime << 32) - userFirst := user.LowDateTime | (user.HighDateTime << 32) - - return CpuUsage{ - Busy: uint64(userFirst), // linuxSample.Nice + linuxSample.User, - Idle: uint64(idleFirst), //linuxSample.Idle, - Total: uint64(kernelFirst + userFirst), // linuxSample.Total, - } - -} - -func AvgCpuUsage(init, final CpuUsage) (avg float64) { - - idle := float64(final.Idle - init.Idle) - total := float64(final.Total - init.Total) - - avg = (total - idle) * 100 / total - - if avg < .000001 || math.IsNaN(avg) { - return 0.0 - } - - return avg -} - -// getSystemTimes makes the system call to windows to get the system data -func getSystemTimes(idleTime, kernelTime, userTime *FileTime) bool { - ret, _, _ := procGetSystemTimes.Call( - uintptr(unsafe.Pointer(idleTime)), - uintptr(unsafe.Pointer(kernelTime)), - uintptr(unsafe.Pointer(userTime))) - - return ret != 0 -} - -// FileTime Struct from: http://msdn.microsoft.com/en-us/library/windows/desktop/ms724284.aspx -type FileTime struct { - // DwLowDateTime from Windows API - LowDateTime uint32 - // DwHighDateTime from Windows API - HighDateTime uint32 -} diff --git a/internal/webserver/server.go b/internal/webserver/server.go index 36798c5f3..c77c11780 100644 --- a/internal/webserver/server.go +++ b/internal/webserver/server.go @@ -87,7 +87,6 @@ func (webserver *WebServer) ConfigureStandardRoutes() { router.HandleFunc(common.ApiPingRoute, controller.Ping).Methods(http.MethodGet) router.HandleFunc(common.ApiVersionRoute, controller.Version).Methods(http.MethodGet) - router.HandleFunc(common.ApiMetricsRoute, controller.Metrics).Methods(http.MethodGet) router.HandleFunc(common.ApiConfigRoute, controller.Config).Methods(http.MethodGet) router.HandleFunc(internal.ApiAddSecretRoute, controller.AddSecret).Methods(http.MethodPost) diff --git a/openapi/v2/app-functions-sdk.yaml b/openapi/v2/app-functions-sdk.yaml index 387f04baf..769b9407a 100644 --- a/openapi/v2/app-functions-sdk.yaml +++ b/openapi/v2/app-functions-sdk.yaml @@ -59,40 +59,6 @@ components: serviceName: description: "Outputs the name of the service the response is from" type: string - MetricsResponse: - description: "A response from the /metrics endpoint providing memory and cpu utilization stats." - type: object - properties: - apiVersion: - description: "A version number shows the API version in DTOs." - type: string - serviceName: - description: "Outputs the name of the service the response is from" - type: string - metrics: - type: object - properties: - memAlloc: - description: "Alloc is bytes of allocated heap objects which is a uint64 type integer." - type: integer - memFrees: - description: "Frees is the cumulative count of heap objects freed which is a uint64 type integer." - type: integer - memLiveObjects: - description: "The uint64 type integer of live objects is Mallocs - Frees." - type: integer - memMallocs: - description: "The cumulative count of heap objects allocated which is a uint64 type integer." - type: integer - memSys: - description: "The total bytes of memory obtained from the OS which is a uint64 type integer." - type: integer - memTotalAlloc: - description: "Cumulative bytes allocated for heap objects which is a uint64 type integer." - type: integer - cpuBusyAvg: - description: "A uint8 type integer indicates the average level of CPU utilization" - type: number PingResponse: description: "A response from the /ping endpoint indicating that the service is functioning." type: object @@ -206,28 +172,6 @@ paths: application/json: schema: $ref: '#/components/schemas/ErrorResponse' - /metrics: - get: - summary: "An endpoint that can be used to obtain CPU/Memory usage stats for a given service." - responses: - '200': - description: "OK" - headers: - X-Correlation-ID: - $ref: '#/components/headers/correlatedResponseHeader' - content: - application/json: - schema: - $ref: '#/components/schemas/MetricsResponse' - '500': - description: "Interval Server Error" - headers: - X-Correlation-ID: - $ref: '#/components/headers/correlatedResponseHeader' - content: - application/json: - schema: - $ref: '#/components/schemas/ErrorResponse' /ping: get: summary: "A simple 'ping' endpoint that can be used as a service healthcheck"