From c144da2524fc705cb20f23c4a4ce36c2ff45525e Mon Sep 17 00:00:00 2001
From: Francois Tur <ftur@infoblox.com>
Date: Fri, 29 Mar 2019 02:37:17 -0400
Subject: [PATCH] plugin/pprof - add option to enable block profiling (#2729)

* - add an option for block profiling to plugin pprof

* - move option block into nested block
---
 plugin/pprof/README.md     | 16 ++++++++++++----
 plugin/pprof/pprof.go      | 10 +++++++---
 plugin/pprof/setup.go      | 26 +++++++++++++++++++++++---
 plugin/pprof/setup_test.go | 12 +++++++++++-
 4 files changed, 53 insertions(+), 11 deletions(-)

diff --git a/plugin/pprof/README.md b/plugin/pprof/README.md
index 27d64aee7..4ff6c6e38 100644
--- a/plugin/pprof/README.md
+++ b/plugin/pprof/README.md
@@ -17,10 +17,16 @@ This plugin can only be used once per Server Block.
 ## Syntax
 
 ~~~
-pprof [ADDRESS]
+pprof [ADDRESS] {
+   block [RATE]
+}
 ~~~
 
-If not specified, ADDRESS defaults to localhost:6053.
+- If not specified, **ADDRESS** defaults to localhost:6053.
+
+- `block` option allow to enable the `block` profiling. see [Diagnostics, chapter profiling](https://golang.org/doc/diagnostics.html).
+if you need to use `block` profile, set a positive value to **RATE**. See [runtime.SetBlockProfileRate](https://golang.org/pkg/runtime/#SetBlockProfileRate).
+ if not specified, **RATE** default's to 1. if `block` option is not specified the `block` profiling is disabled.
 
 ## Examples
 
@@ -42,11 +48,13 @@ Listen on an alternate address:
 }
 ~~~
 
-Listen on an all addresses on port 6060:
+Listen on an all addresses on port 6060: and enable block profiling
 
 ~~~ txt
 . {
-    pprof :6060
+    pprof :6060 {
+       block
+    }
 }
 ~~~
 
diff --git a/plugin/pprof/pprof.go b/plugin/pprof/pprof.go
index 6cfaa5490..8367a3071 100644
--- a/plugin/pprof/pprof.go
+++ b/plugin/pprof/pprof.go
@@ -6,12 +6,14 @@ import (
 	"net"
 	"net/http"
 	pp "net/http/pprof"
+	"runtime"
 )
 
 type handler struct {
-	addr string
-	ln   net.Listener
-	mux  *http.ServeMux
+	addr     string
+	rateBloc int
+	ln       net.Listener
+	mux      *http.ServeMux
 }
 
 func (h *handler) Startup() error {
@@ -30,6 +32,8 @@ func (h *handler) Startup() error {
 	h.mux.HandleFunc(path+"/symbol", pp.Symbol)
 	h.mux.HandleFunc(path+"/trace", pp.Trace)
 
+	runtime.SetBlockProfileRate(h.rateBloc)
+
 	go func() {
 		http.Serve(h.ln, h.mux)
 	}()
diff --git a/plugin/pprof/setup.go b/plugin/pprof/setup.go
index cdc346374..66c147e78 100644
--- a/plugin/pprof/setup.go
+++ b/plugin/pprof/setup.go
@@ -2,6 +2,7 @@ package pprof
 
 import (
 	"net"
+	"strconv"
 	"sync"
 
 	"github.com/coredns/coredns/plugin"
@@ -36,15 +37,34 @@ func setup(c *caddy.Controller) error {
 			h.addr = args[0]
 			_, _, e := net.SplitHostPort(h.addr)
 			if e != nil {
-				return e
+				return plugin.Error("pprof", c.Errf("%v", e))
 			}
 		}
+
 		if len(args) > 1 {
 			return plugin.Error("pprof", c.ArgErr())
 		}
-		if c.NextBlock() {
-			return plugin.Error("pprof", c.ArgErr())
+
+		for c.NextBlock() {
+			switch c.Val() {
+			case "block":
+				args := c.RemainingArgs()
+				if len(args) > 1 {
+					return plugin.Error("pprof", c.ArgErr())
+				}
+				h.rateBloc = 1
+				if len(args) > 0 {
+					t, err := strconv.Atoi(args[0])
+					if err != nil {
+						return plugin.Error("pprof", c.Errf("property '%s' invalid integer value '%v'", "block", args[0]))
+					}
+					h.rateBloc = t
+				}
+			default:
+				return plugin.Error("pprof", c.Errf("unknown property '%s'", c.Val()))
+			}
 		}
+
 	}
 
 	pprofOnce.Do(func() {
diff --git a/plugin/pprof/setup_test.go b/plugin/pprof/setup_test.go
index eaa4cb37e..276229379 100644
--- a/plugin/pprof/setup_test.go
+++ b/plugin/pprof/setup_test.go
@@ -14,11 +14,21 @@ func TestPProf(t *testing.T) {
 		{`pprof`, false},
 		{`pprof 1.2.3.4:1234`, false},
 		{`pprof :1234`, false},
-		{`pprof {}`, true},
+		{`pprof :1234 -1`, true},
+		{`pprof {
+                }`, false},
 		{`pprof /foo`, true},
 		{`pprof {
             a b
         }`, true},
+		{`pprof { block
+                }`, false},
+		{`pprof :1234 { 
+                   block 20
+                }`, false},
+		{`pprof { 
+                   block 20 30
+                }`, true},
 		{`pprof
           pprof`, true},
 	}