mirror of
https://github.com/gogrlx/nats-server.git
synced 2026-04-02 11:48:43 -07:00
Merge pull request #103 from cmfatih/master
Add JSONP support for monitoring routes
This commit is contained in:
13
README.md
13
README.md
@@ -236,6 +236,19 @@ You can also report detailed subscription information on a per connection basis
|
||||
}
|
||||
```
|
||||
|
||||
Monitoring endpoints support JSONP for CORS so you can easily create single page
|
||||
web applications for monitoring. Simply pass `callback` query parameter to any
|
||||
endpoint. For example; `http://localhost:8222/connz?callback=cb`
|
||||
|
||||
```javascript
|
||||
// JQuery example
|
||||
|
||||
$.getJSON('http://localhost:8222/connz?callback=?', function(data) {
|
||||
console.log(data);
|
||||
});
|
||||
|
||||
```
|
||||
|
||||
## Building
|
||||
|
||||
This code currently requires at _least_ version 1.1 of Go, but we encourage
|
||||
|
||||
@@ -140,8 +140,9 @@ func (s *Server) HandleConnz(w http.ResponseWriter, r *http.Request) {
|
||||
if err != nil {
|
||||
Errorf("Error marshalling response to /connz request: %v", err)
|
||||
}
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.Write(b)
|
||||
|
||||
// Handle response
|
||||
ResponseHandler(w, r, b)
|
||||
}
|
||||
|
||||
func castToSliceString(input []interface{}) []string {
|
||||
@@ -220,8 +221,9 @@ func (s *Server) HandleRoutez(w http.ResponseWriter, r *http.Request) {
|
||||
if err != nil {
|
||||
Errorf("Error marshalling response to /routez request: %v", err)
|
||||
}
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.Write(b)
|
||||
|
||||
// Handle response
|
||||
ResponseHandler(w, r, b)
|
||||
}
|
||||
|
||||
// HandleStats process HTTP requests for subjects stats.
|
||||
@@ -232,8 +234,9 @@ func (s *Server) HandleSubsz(w http.ResponseWriter, r *http.Request) {
|
||||
if err != nil {
|
||||
Errorf("Error marshalling response to /subscriptionsz request: %v", err)
|
||||
}
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.Write(b)
|
||||
|
||||
// Handle response
|
||||
ResponseHandler(w, r, b)
|
||||
}
|
||||
|
||||
// Varz will output server information on the monitoring port at /varz.
|
||||
@@ -287,16 +290,16 @@ func myUptime(d time.Duration) string {
|
||||
|
||||
// HandleRoot will show basic info and links to others handlers.
|
||||
func (s *Server) HandleRoot(w http.ResponseWriter, r *http.Request) {
|
||||
fmt.Fprint(w, "<html lang=\"en\">gnatsd monitoring<br/><br/>")
|
||||
vlink := fmt.Sprintf("http://%s/varz", r.Host)
|
||||
fmt.Fprintf(w, "<a href=%s>%s</a><br/>", vlink, vlink)
|
||||
clink := fmt.Sprintf("http://%s/connz", r.Host)
|
||||
fmt.Fprintf(w, "<a href=%s>%s</a><br/>", clink, clink)
|
||||
rlink := fmt.Sprintf("http://%s/routez", r.Host)
|
||||
fmt.Fprintf(w, "<a href=%s>%s</a><br/>", rlink, rlink)
|
||||
slink := fmt.Sprintf("http://%s/subscriptionsz", r.Host)
|
||||
fmt.Fprintf(w, "<a href=%s>%s</a><br/>", slink, slink)
|
||||
fmt.Fprint(w, "</html>")
|
||||
fmt.Fprintf(w, `<html lang="en">
|
||||
<body>
|
||||
gnatsd monitoring
|
||||
<br/><br/>
|
||||
<a href=http://%s/varz>http://%s/varz</a><br/>
|
||||
<a href=http://%s/connz>http://%s/connz</a><br/>
|
||||
<a href=http://%s/routez>http://%s/routez</a><br/>
|
||||
<a href=http://%s/subscriptionsz>http://%s/subscriptionsz</a><br/>
|
||||
</body>
|
||||
</html>`, r.Host, r.Host, r.Host, r.Host, r.Host, r.Host, r.Host, r.Host)
|
||||
}
|
||||
|
||||
// HandleVarz will process HTTP requests for server information.
|
||||
@@ -322,8 +325,9 @@ func (s *Server) HandleVarz(w http.ResponseWriter, r *http.Request) {
|
||||
if err != nil {
|
||||
Errorf("Error marshalling response to /varz request: %v", err)
|
||||
}
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.Write(b)
|
||||
|
||||
// Handle response
|
||||
ResponseHandler(w, r, b)
|
||||
}
|
||||
|
||||
// Grab RSS and PCPU
|
||||
@@ -337,3 +341,19 @@ func updateUsage(v *Varz) {
|
||||
v.CPU = pcpu
|
||||
v.Cores = numCores
|
||||
}
|
||||
|
||||
// ResponseHandler handles responses for monitoring routes
|
||||
func ResponseHandler(w http.ResponseWriter, r *http.Request, data []byte) {
|
||||
// Get callback from request
|
||||
callback := r.URL.Query().Get("callback")
|
||||
// If callback is not empty then
|
||||
if callback != "" {
|
||||
// Response for JSONP
|
||||
w.Header().Set("Content-Type", "application/javascript")
|
||||
fmt.Fprintf(w, "%s(%s)", callback, data)
|
||||
} else {
|
||||
// Otherwise JSON
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.Write(data)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
@@ -99,6 +100,10 @@ func TestVarz(t *testing.T) {
|
||||
if resp.StatusCode != 200 {
|
||||
t.Fatalf("Expected a 200 response, got %d\n", resp.StatusCode)
|
||||
}
|
||||
ct := resp.Header.Get("Content-Type")
|
||||
if ct != "application/json" {
|
||||
t.Fatalf("Expected application/json content-type, got %s\n", ct)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
@@ -151,6 +156,17 @@ func TestVarz(t *testing.T) {
|
||||
if v.OutBytes != 5 {
|
||||
t.Fatalf("Expected OutBytes of 5, got %v\n", v.OutBytes)
|
||||
}
|
||||
|
||||
// Test JSONP
|
||||
respj, errj := http.Get(fmt.Sprintf("http://localhost:%d/", DEFAULT_HTTP_PORT) + "varz?callback=callback")
|
||||
if errj != nil {
|
||||
t.Fatalf("Expected no error: Got %v\n", err)
|
||||
}
|
||||
ct = respj.Header.Get("Content-Type")
|
||||
if ct != "application/javascript" {
|
||||
t.Fatalf("Expected application/javascript content-type, got %s\n", ct)
|
||||
}
|
||||
defer respj.Body.Close()
|
||||
}
|
||||
|
||||
func TestConnz(t *testing.T) {
|
||||
@@ -165,6 +181,10 @@ func TestConnz(t *testing.T) {
|
||||
if resp.StatusCode != 200 {
|
||||
t.Fatalf("Expected a 200 response, got %d\n", resp.StatusCode)
|
||||
}
|
||||
ct := resp.Header.Get("Content-Type")
|
||||
if ct != "application/json" {
|
||||
t.Fatalf("Expected application/json content-type, got %s\n", ct)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
@@ -249,6 +269,17 @@ func TestConnz(t *testing.T) {
|
||||
if ci.OutBytes != 5 {
|
||||
t.Fatalf("Expected OutBytes of 1, got %v\n", ci.OutBytes)
|
||||
}
|
||||
|
||||
// Test JSONP
|
||||
respj, errj := http.Get(fmt.Sprintf("http://localhost:%d/", DEFAULT_HTTP_PORT) + "connz?callback=callback")
|
||||
if errj != nil {
|
||||
t.Fatalf("Expected no error: Got %v\n", err)
|
||||
}
|
||||
ct = respj.Header.Get("Content-Type")
|
||||
if ct != "application/javascript" {
|
||||
t.Fatalf("Expected application/javascript content-type, got %s\n", ct)
|
||||
}
|
||||
defer respj.Body.Close()
|
||||
}
|
||||
|
||||
func TestConnzWithSubs(t *testing.T) {
|
||||
@@ -629,6 +660,10 @@ func TestConnzWithRoutes(t *testing.T) {
|
||||
if resp.StatusCode != 200 {
|
||||
t.Fatalf("Expected a 200 response, got %d\n", resp.StatusCode)
|
||||
}
|
||||
ct := resp.Header.Get("Content-Type")
|
||||
if ct != "application/json" {
|
||||
t.Fatalf("Expected application/json content-type, got %s\n", ct)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
@@ -682,6 +717,17 @@ func TestConnzWithRoutes(t *testing.T) {
|
||||
if route.DidSolicit != false {
|
||||
t.Fatalf("Expected unsolicited route, got %v\n", route.DidSolicit)
|
||||
}
|
||||
|
||||
// Test JSONP
|
||||
respj, errj := http.Get(fmt.Sprintf("http://localhost:%d/", DEFAULT_HTTP_PORT) + "routez?callback=callback")
|
||||
if errj != nil {
|
||||
t.Fatalf("Expected no error: Got %v\n", err)
|
||||
}
|
||||
ct = respj.Header.Get("Content-Type")
|
||||
if ct != "application/javascript" {
|
||||
t.Fatalf("Expected application/javascript content-type, got %s\n", ct)
|
||||
}
|
||||
defer respj.Body.Close()
|
||||
}
|
||||
|
||||
func TestSubsz(t *testing.T) {
|
||||
@@ -699,6 +745,10 @@ func TestSubsz(t *testing.T) {
|
||||
if resp.StatusCode != 200 {
|
||||
t.Fatalf("Expected a 200 response, got %d\n", resp.StatusCode)
|
||||
}
|
||||
ct := resp.Header.Get("Content-Type")
|
||||
if ct != "application/json" {
|
||||
t.Fatalf("Expected application/json content-type, got %s\n", ct)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
@@ -719,6 +769,38 @@ func TestSubsz(t *testing.T) {
|
||||
t.Fatalf("Expected NumMatches of 1, got %d\n", sl.NumMatches)
|
||||
}
|
||||
|
||||
// Test JSONP
|
||||
respj, errj := http.Get(fmt.Sprintf("http://localhost:%d/", DEFAULT_HTTP_PORT) + "subscriptionsz?callback=callback")
|
||||
ct = respj.Header.Get("Content-Type")
|
||||
if errj != nil {
|
||||
t.Fatalf("Expected no error: Got %v\n", err)
|
||||
}
|
||||
if ct != "application/javascript" {
|
||||
t.Fatalf("Expected application/javascript content-type, got %s\n", ct)
|
||||
}
|
||||
defer respj.Body.Close()
|
||||
}
|
||||
|
||||
// Tests handle root
|
||||
func TestHandleRoot(t *testing.T) {
|
||||
s := runMonitorServer(DEFAULT_HTTP_PORT)
|
||||
defer s.Shutdown()
|
||||
|
||||
nc := createClientConnSubscribeAndPublish(t)
|
||||
defer nc.Close()
|
||||
|
||||
resp, err := http.Get(fmt.Sprintf("http://localhost:%d/", DEFAULT_HTTP_PORT))
|
||||
if err != nil {
|
||||
t.Fatalf("Expected no error: Got %v\n", err)
|
||||
}
|
||||
if resp.StatusCode != 200 {
|
||||
t.Fatalf("Expected a 200 response, got %d\n", resp.StatusCode)
|
||||
}
|
||||
ct := resp.Header.Get("Content-Type")
|
||||
if !strings.Contains(ct, "text/html") {
|
||||
t.Fatalf("Expected text/html response, got %s\n", ct)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
}
|
||||
|
||||
// Create a connection to test ConnInfo
|
||||
|
||||
Reference in New Issue
Block a user