Repository: gofr-dev/gofr

Issue:
Pprof endpoints should not be availible at an Exposed Endpoint
When we give APP_ENV=DEBUG, the profiling should be availible at an internal port, rather than an exposed endpoint.

Hints from issue comments:

Solution patch:
diff --git a/docs/advanced-guide/debugging/page.md b/docs/advanced-guide/debugging/page.md
new file mode 100644
index 00000000..fde6fe96
--- /dev/null
+++ b/docs/advanced-guide/debugging/page.md
@@ -0,0 +1,162 @@
+# Using `pprof` in GoFr Applications
+
+In GoFr applications, `pprof` profiling is automatically enabled. The profiling endpoints are served on the `METRICS_PORT`, which defaults to `2121` if not specified.
+
+This guide explains how to enable and use `pprof` in GoFr applications.
+
+---
+
+## Enabling `pprof` in GoFr
+
+### Prerequisites
+Ensure the `METRICS_PORT` is set (default is `2121`):
+   ```bash
+   METRICS_PORT=2121
+   ```
+
+GoFr automatically registers the following `pprof` routes:
+- `/debug/pprof/cmdline`
+- `/debug/pprof/profile`
+- `/debug/pprof/symbol`
+- `/debug/pprof/trace`
+- `/debug/pprof/` (index)
+
+---
+
+## Accessing `pprof` Endpoints
+
+Once `pprof` is enabled, you can access the profiling endpoints at `http://localhost:<METRICS_PORT>/debug/pprof/`. For example, if `METRICS_PORT` is `2121`, the endpoints will be available at:
+- `http://localhost:2121/debug/pprof/`
+
+### Available Endpoints
+1. **`/debug/pprof/cmdline`**:
+    - Returns the command-line arguments of the running application.
+
+2. **`/debug/pprof/profile`**:
+    - Generates a CPU profile for the application.
+
+3. **`/debug/pprof/symbol`**:
+    - Resolves program counters into function names.
+
+4. **`/debug/pprof/trace`**:
+    - Captures an execution trace of the application.
+
+5. **`/debug/pprof/` (index)**:
+    - Provides an index page with links to all available profiling endpoints, including memory, goroutine, and blocking profiles.
+
+---
+
+## Collecting Profiling Data
+
+### 1. **CPU Profiling**
+To collect a CPU profile:
+```bash
+curl -o cpu.pprof http://localhost:2121/debug/pprof/profile
+```
+
+### 2. **Memory Profiling**
+To collect a memory profile:
+```bash
+curl -o mem.pprof http://localhost:2121/debug/pprof/heap
+```
+
+### 3. **Goroutine Profiling**
+To collect information about running goroutines:
+```bash
+curl -o goroutine.pprof http://localhost:2121/debug/pprof/goroutine
+```
+
+### 4. **Execution Trace**
+To collect an execution trace:
+```bash
+curl -o trace.out http://localhost:2121/debug/pprof/trace
+```
+
+---
+
+## Analyzing Profiling Data
+
+### Using `go tool pprof`
+To analyze CPU, memory, or goroutine profiles:
+```bash
+go tool pprof <profile_file>
+```
+
+#### **`top`**
+Shows the functions consuming the most resources (e.g., CPU or memory).
+```bash
+go tool pprof cpu.pprof
+(pprof) top
+```
+
+#### **`list`**
+Displays the source code of a specific function, along with resource usage.
+```bash
+(pprof) list <function_name>
+```
+Example:
+```bash
+(pprof) list main.myFunction
+```
+
+#### **`web`**
+Generates a visual representation of the profile in your browser. This requires Graphviz to be installed.
+```bash
+(pprof) web
+```
+
+
+### Using `go tool trace`
+To analyze execution traces:
+```bash
+go tool trace trace.out
+```
+
+---
+
+## Example Workflow
+
+1. **Set Environment Variables**:
+   ```bash
+   METRICS_PORT=2121
+   ```
+
+2. **Run Your GoFr Application**:
+   ```bash
+   go run main.go
+   ```
+
+3. **Collect Profiling Data**:
+    - Collect a CPU profile:
+      ```bash
+      curl -o cpu.pprof http://localhost:2121/debug/pprof/profile
+      ```
+    - Collect a memory profile:
+      ```bash
+      curl -o mem.pprof http://localhost:2121/debug/pprof/heap
+      ```
+
+
+4. **Analyze the Data**:
+    - Analyze the CPU profile:
+      ```bash
+      go tool pprof cpu.pprof
+      (pprof) top
+      (pprof) list main.myFunction
+      (pprof) web
+      ```
+    - Analyze the memory profile:
+      ```bash
+      go tool pprof mem.pprof
+      (pprof) top
+      (pprof) list main.myFunction
+      (pprof) web
+      ```
+
+---
+
+## References
+- [Go `pprof` Documentation](https://pkg.go.dev/net/http/pprof)
+- [Profiling Go Programs](https://blog.golang.org/profiling-go-programs)
+- [Go Execution Tracer](https://golang.org/doc/diagnostics.html#tracing)
+```
\ No newline at end of file
diff --git a/docs/navigation.js b/docs/navigation.js
index b8e7244d..dc74962c 100644
--- a/docs/navigation.js
+++ b/docs/navigation.js
@@ -45,7 +45,7 @@ export const navigation = [
             {
                 title: 'Overriding Default',
                 href: '/docs/advanced-guide/overriding-default',
-                desc: "Understand how to override default configurations and behaviors in GoFR to tailor framework to your specific needs."
+                desc: "Understand how to override default configurations and behaviors in GoFr to tailor framework to your specific needs."
             },
             {
                 title: 'Remote Log Level Change',
@@ -70,12 +70,12 @@ export const navigation = [
             {
                 title: 'Adding Custom Middleware',
                 href: '/docs/advanced-guide/middlewares',
-                desc: "Learn how to add custom middleware to your GoFR application for enhanced functionality and request processing."
+                desc: "Learn how to add custom middleware to your GoFr application for enhanced functionality and request processing."
             },
             {
                 title: 'HTTP Communication',
                 href: '/docs/advanced-guide/http-communication',
-                desc: "Get familiar with making HTTP requests and handling responses within your GoFR application to facilitate seamless communication."
+                desc: "Get familiar with making HTTP requests and handling responses within your GoFr application to facilitate seamless communication."
             },
             {
                 title: 'HTTP Authentication',
@@ -95,52 +95,57 @@ export const navigation = [
             {
                 title: 'Handling Data Migrations',
                 href: '/docs/advanced-guide/handling-data-migrations',
-                desc: "Explore strategies for managing data migrations within your GoFR application to ensure smooth transitions and data integrity."
+                desc: "Explore strategies for managing data migrations within your GoFr application to ensure smooth transitions and data integrity."
             },
             {
                 title: 'Writing gRPC Server/Client',
                 href: '/docs/advanced-guide/grpc',
-                desc: "Step-by-step guide on writing a gRPC server in GoFR to facilitate efficient communication between services."
+                desc: "Step-by-step guide on writing a gRPC server in GoFr to facilitate efficient communication between services."
             },
             {
                 title: 'Using Pub/Sub',
                 href: '/docs/advanced-guide/using-publisher-subscriber',
-                desc: "Discover how to gofr seamlessly allows to integrate different Pub/Sub systems in your application for effective messaging and event-driven architectures."
+                desc: "Discover how to GoFr seamlessly allows to integrate different Pub/Sub systems in your application for effective messaging and event-driven architectures."
             },
             {
                 title: 'Key Value Store',
                 href: '/docs/advanced-guide/key-value-store',
-                desc: "Explore how to implement and manage a key-value store in your GoFR application for fast and efficient data retrieval."
+                desc: "Explore how to implement and manage a key-value store in your GoFr application for fast and efficient data retrieval."
             },
             {
                 title: 'Dealing with SQL',
                 href: '/docs/advanced-guide/dealing-with-sql',
-                desc: "Get insights into best practices for working with SQL databases in GoFR, including query optimization and error handling."
+                desc: "Get insights into best practices for working with SQL databases in GoFr, including query optimization and error handling."
             },
             {
                 title: 'Automatic SwaggerUI Rendering',
                 href: '/docs/advanced-guide/swagger-documentation',
-                desc: "Learn how to automatically render SwaggerUI documentation for your GoFR APIs, improving discoverability and usability."
+                desc: "Learn how to automatically render SwaggerUI documentation for your GoFr APIs, improving discoverability and usability."
             },
             {
                 title: 'Error Handling',
                 href: '/docs/advanced-guide/gofr-errors',
-                desc: "Understand error handling mechanisms in GoFR to ensure robust applications and improved user experience."
+                desc: "Understand error handling mechanisms in GoFr to ensure robust applications and improved user experience."
             },
             {
                 title: 'Handling File',
                 href: '/docs/advanced-guide/handling-file',
-                desc: "Explore how GoFR enables efficient file handling by abstracting remote and local filestore providers in your Go application. Learn to manage file uploads, downloads, and storage seamlessly, enhancing your application's capability to work with diverse data sources."
+                desc: "Explore how GoFr enables efficient file handling by abstracting remote and local filestore providers in your Go application. Learn to manage file uploads, downloads, and storage seamlessly, enhancing your application's capability to work with diverse data sources."
             },
             {
                 title: 'WebSockets',
                 href: '/docs/advanced-guide/websocket',
-                desc: "Explore how gofr eases the process of WebSocket communication in your Golang application for real-time data exchange."
+                desc: "Explore how GoFr eases the process of WebSocket communication in your Golang application for real-time data exchange."
             },
             {
                 title: 'Serving-Static Files',
                 href: '/docs/advanced-guide/serving-static-files',
                 desc: "Know how GoFr automatically serves static content from a static folder in the application directory."
+            },
+            {
+                title: 'Profiling in GoFr Applications',
+                href: '/docs/advanced-guide/debugging',
+                desc: "Discover GoFr auto-enables pprof profiling by leveraging its built-in configurations."
             }
         ],
     },
diff --git a/pkg/gofr/factory.go b/pkg/gofr/factory.go
index 550af14d..3c509a55 100644
--- a/pkg/gofr/factory.go
+++ b/pkg/gofr/factory.go
@@ -50,10 +50,6 @@ func New() *App {
 
 	app.checkAndAddOpenAPIDocumentation()
 
-	if app.Config.Get("APP_ENV") == "DEBUG" {
-		app.httpServer.RegisterProfilingRoutes()
-	}
-
 	// gRPC Server
 	port, err = strconv.Atoi(app.Config.Get("GRPC_PORT"))
 	if err != nil || port <= 0 {
diff --git a/pkg/gofr/http_server.go b/pkg/gofr/http_server.go
index ed7d491a..2489bbaa 100644
--- a/pkg/gofr/http_server.go
+++ b/pkg/gofr/http_server.go
@@ -5,7 +5,6 @@ import (
 	"errors"
 	"fmt"
 	"net/http"
-	"net/http/pprof"
 	"os"
 	"time"
 
@@ -48,28 +47,6 @@ func newHTTPServer(c *container.Container, port int, middlewareConfigs map[strin
 	}
 }
 
-// RegisterProfilingRoutes registers pprof endpoints on the HTTP server.
-//
-// This method adds the following routes to the server's router:
-//
-//   - /debug/pprof/cmdline
-//   - /debug/pprof/profile
-//   - /debug/pprof/symbol
-//   - /debug/pprof/trace
-//   - /debug/pprof/ (index)
-//
-// These endpoints provide various profiling information for the application,
-// such as command-line arguments, memory profiles, symbol information, and
-// execution traces.
-func (s *httpServer) RegisterProfilingRoutes() {
-	s.router.HandleFunc("/debug/pprof/cmdline", pprof.Cmdline)
-	s.router.HandleFunc("/debug/pprof/profile", pprof.Profile)
-	s.router.HandleFunc("/debug/pprof/symbol", pprof.Symbol)
-	s.router.HandleFunc("/debug/pprof/trace", pprof.Trace)
-
-	s.router.NewRoute().Methods(http.MethodGet).PathPrefix("/debug/pprof/").HandlerFunc(pprof.Index)
-}
-
 func (s *httpServer) run(c *container.Container) {
 	// Developer Note:
 	//	WebSocket connections do not inherently support authentication mechanisms.
diff --git a/pkg/gofr/metrics/handler.go b/pkg/gofr/metrics/handler.go
index 492eb56d..3511b97b 100644
--- a/pkg/gofr/metrics/handler.go
+++ b/pkg/gofr/metrics/handler.go
@@ -2,6 +2,7 @@ package metrics
 
 import (
 	"net/http"
+	"net/http/pprof"
 	"runtime"
 
 	"github.com/gorilla/mux"
@@ -15,6 +16,22 @@ func GetHandler(m Manager) http.Handler {
 	// Prometheus
 	router.NewRoute().Methods(http.MethodGet).Path("/metrics").Handler(systemMetricsHandler(m, promhttp.Handler()))
 
+	//   - /debug/pprof/cmdline
+	//   - /debug/pprof/profile
+	//   - /debug/pprof/symbol
+	//   - /debug/pprof/trace
+	//   - /debug/pprof/ (index)
+	//
+	// These endpoints provide various profiling information for the application,
+	// such as command-line arguments, memory profiles, symbol information, and
+	// execution traces.
+	router.HandleFunc("/debug/pprof/cmdline", pprof.Cmdline)
+	router.HandleFunc("/debug/pprof/profile", pprof.Profile)
+	router.HandleFunc("/debug/pprof/symbol", pprof.Symbol)
+	router.HandleFunc("/debug/pprof/trace", pprof.Trace)
+
+	router.NewRoute().Methods(http.MethodGet).PathPrefix("/debug/pprof/").HandlerFunc(pprof.Index)
+
 	return router
 }
 



Test patch:
diff --git a/pkg/gofr/http_server_test.go b/pkg/gofr/http_server_test.go
index 28d82020..236b044d 100644
--- a/pkg/gofr/http_server_test.go
+++ b/pkg/gofr/http_server_test.go
@@ -4,9 +4,7 @@ import (
 	"context"
 	"fmt"
 	"net/http"
-	"net/http/httptest"
 	"os"
-	"strconv"
 	"testing"
 	"time"
 
@@ -89,40 +87,6 @@ func getConfigs(t *testing.T) config.Config {
 	return config.NewEnvFile(configLocation, logging.NewLogger(logging.INFO))
 }
 
-func TestRegisterProfillingRoutes(t *testing.T) {
-	port := testutil.GetFreePort(t)
-
-	c := &container.Container{
-		Logger: logging.NewLogger(logging.INFO),
-	}
-
-	server := &httpServer{
-		router: gofrHTTP.NewRouter(),
-		port:   port,
-	}
-
-	server.RegisterProfilingRoutes()
-
-	go server.run(c)
-
-	// Test if the expected handlers are registered for the pprof endpoints
-	expectedRoutes := []string{
-		"/debug/pprof/",
-		"/debug/pprof/cmdline",
-		"/debug/pprof/symbol",
-	}
-
-	serverURL := "http://localhost:" + strconv.Itoa(8000)
-
-	for _, route := range expectedRoutes {
-		r := httptest.NewRequest(http.MethodGet, serverURL+route, http.NoBody)
-		rr := httptest.NewRecorder()
-		server.router.ServeHTTP(rr, r)
-
-		assert.Equal(t, http.StatusOK, rr.Code)
-	}
-}
-
 func TestShutdown_ServerStopsListening(t *testing.T) {
 	// Create a mock router and add a new route
 	router := &gofrHTTP.Router{}
diff --git a/pkg/gofr/metrics/handler_test.go b/pkg/gofr/metrics/handler_test.go
index af6793a6..5d236d5e 100644
--- a/pkg/gofr/metrics/handler_test.go
+++ b/pkg/gofr/metrics/handler_test.go
@@ -77,3 +77,37 @@ func Test_MetricsGetHandler_SystemMetricsRegistered(t *testing.T) {
 	assert.Contains(t, bodyString, `app_sys_total_alloc{otel_scope_name="test-app",otel_scope_version="v1.0.0"}`)
 	assert.Contains(t, bodyString, `app_go_numGC{otel_scope_name="test-app",otel_scope_version="v1.0.0"}`)
 }
+
+func Test_MetricsGetHandler_RegisteredProfilingRoutes(t *testing.T) {
+	manager := NewMetricsManager(exporters.Prometheus("test-app", "v1.0.0"),
+		logging.NewMockLogger(logging.INFO))
+
+	// Registering the metrics because the values are being set in the GetHandler function.
+	manager.NewGauge("app_go_routines", "Number of Go routines running.")
+	manager.NewGauge("app_sys_memory_alloc", "Number of bytes allocated for heap objects.")
+	manager.NewGauge("app_sys_total_alloc", "Number of cumulative bytes allocated for heap objects.")
+	manager.NewGauge("app_go_numGC", "Number of completed Garbage Collector cycles.")
+	manager.NewGauge("app_go_sys", "Number of total bytes of memory.")
+
+	handler := GetHandler(manager)
+
+	server := httptest.NewServer(handler)
+
+	// Test if the expected handlers are registered for the pprof endpoints
+	expectedRoutes := []string{
+		"/debug/pprof/",
+		"/debug/pprof/cmdline",
+		"/debug/pprof/symbol",
+	}
+
+	for _, route := range expectedRoutes {
+		req, _ := http.NewRequestWithContext(context.Background(), http.MethodGet, server.URL+route, http.NoBody)
+		resp, err := server.Client().Do(req)
+
+		require.NotNil(t, resp)
+		require.Equal(t, http.StatusOK, resp.StatusCode)
+		require.NoError(t, err)
+
+		resp.Body.Close()
+	}
+}