diff --git a/README.md b/README.md index 4f13ad3a..68e69a23 100644 --- a/README.md +++ b/README.md @@ -38,6 +38,8 @@ docker build . * `NSM_FORWARDER_NETWORK_SERVICE_NAME` - the default service name for forwarder discovering (default: "forwarder") * `NSM_OPEN_TELEMETRY_ENDPOINT` - OpenTelemetry Collector Endpoint (default: "otel-collector.observability.svc.cluster.local:4317") * `NSM_METRICS_EXPORT_INTERVAL` - interval between mertics exports (default: "10s") +* `NSM_ENABLE_PROFILER` - Enable pprof package HTTP server for profiling runtime data. +* `NSM_PROFILER_HTTP_PORT` - Profiling server HTTP port providing data in the format expected by the pprof visualization tool. # Testing diff --git a/internal/config/config.go b/internal/config/config.go index 3a0e8c32..c8f9129f 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -37,4 +37,6 @@ type Config struct { ForwarderNetworkServiceName string `default:"forwarder" desc:"the default service name for forwarder discovering" split_words:"true"` OpenTelemetryEndpoint string `default:"otel-collector.observability.svc.cluster.local:4317" desc:"OpenTelemetry Collector Endpoint" split_words:"true"` MetricsExportInterval time.Duration `default:"10s" desc:"interval between mertics exports" split_words:"true"` + EnableProfiler bool `default:"false" desc:"Enable pprof package HTTP server for profiling runtime data. The handled paths all begin with /debug/pprof/." split_words:"true"` + ProfilerHTTPPort uint16 `default:"6060" desc:"Profiling server HTTP port providing data in the format expected by the pprof visualization tool." split_words:"true"` } diff --git a/internal/imports/imports_linux.go b/internal/imports/imports_linux.go index 7aedaeb5..ffc6889b 100644 --- a/internal/imports/imports_linux.go +++ b/internal/imports/imports_linux.go @@ -55,6 +55,8 @@ import ( _ "google.golang.org/grpc/health/grpc_health_v1" _ "google.golang.org/grpc/peer" _ "net" + _ "net/http" + _ "net/http/pprof" _ "net/url" _ "os" _ "os/signal" diff --git a/main.go b/main.go index 7e945672..ef8f16c3 100644 --- a/main.go +++ b/main.go @@ -2,6 +2,8 @@ // // Copyright (c) 2021-2023 Doc.ai and/or its affiliates. // +// Copyright (c) 2024 Pragmagic Inc. and/or its affiliates. +// // SPDX-License-Identifier: Apache-2.0 // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -20,6 +22,7 @@ package main import ( "context" + "fmt" "os" "os/signal" "syscall" @@ -33,6 +36,9 @@ import ( "github.com/networkservicemesh/sdk/pkg/tools/log" "github.com/networkservicemesh/sdk/pkg/tools/log/logruslogger" "github.com/networkservicemesh/sdk/pkg/tools/opentelemetry" + + "net/http" + _ "net/http/pprof" // #nosec ) func main() { @@ -75,6 +81,19 @@ func main() { logrus.SetLevel(level) log.EnableTracing(true) + // Enable profiling server + if cfg.EnableProfiler { + go func() { + log.FromContext(ctx).Infof("Profiler is enabled. Starting HTTP server on %d", cfg.ProfilerHTTPPort) + + address := fmt.Sprintf("localhost:%d", cfg.ProfilerHTTPPort) + // nolint:gosec + if err = http.ListenAndServe(address, nil); err != nil { + log.FromContext(ctx).Errorf("Failed to start profiler: %s", err.Error()) + } + }() + } + // Configure Open Telemetry if opentelemetry.IsEnabled() { collectorAddress := cfg.OpenTelemetryEndpoint