From 4fc6d9c2361236d5f84dbf54bd5bb716f8f56d23 Mon Sep 17 00:00:00 2001 From: Colstuwjx Date: Wed, 13 Sep 2017 20:49:01 +0800 Subject: [PATCH] Enable gin pprof. --- main.go | 16 +-- vendor/github.com/gin-contrib/pprof/LICENSE | 21 ++++ vendor/github.com/gin-contrib/pprof/README.md | 83 +++++++++++++ vendor/github.com/gin-contrib/pprof/pprof.go | 42 +++++++ vendor/github.com/gin-contrib/sse/LICENSE | 21 ++++ vendor/github.com/gin-contrib/sse/README.md | 58 +++++++++ .../github.com/gin-contrib/sse/sse-decoder.go | 116 ++++++++++++++++++ .../github.com/gin-contrib/sse/sse-encoder.go | 110 +++++++++++++++++ vendor/github.com/gin-contrib/sse/writer.go | 24 ++++ vendor/github.com/gin-gonic/gin/json/json.go | 17 +++ .../github.com/gin-gonic/gin/json/jsoniter.go | 18 +++ vendor/vendor.json | 18 +++ 12 files changed, 537 insertions(+), 7 deletions(-) create mode 100644 vendor/github.com/gin-contrib/pprof/LICENSE create mode 100644 vendor/github.com/gin-contrib/pprof/README.md create mode 100644 vendor/github.com/gin-contrib/pprof/pprof.go create mode 100644 vendor/github.com/gin-contrib/sse/LICENSE create mode 100644 vendor/github.com/gin-contrib/sse/README.md create mode 100644 vendor/github.com/gin-contrib/sse/sse-decoder.go create mode 100644 vendor/github.com/gin-contrib/sse/sse-encoder.go create mode 100644 vendor/github.com/gin-contrib/sse/writer.go create mode 100644 vendor/github.com/gin-gonic/gin/json/json.go create mode 100644 vendor/github.com/gin-gonic/gin/json/jsoniter.go diff --git a/main.go b/main.go index e9a8c4a..35d1910 100644 --- a/main.go +++ b/main.go @@ -1,13 +1,14 @@ package main import ( - "github.com/yunlzheng/prometheus-pusher/scrape" + "flag" + "fmt" + "github.com/gin-contrib/pprof" "github.com/gin-gonic/gin" + "github.com/prometheus/prometheus/config" "github.com/prometheus/prometheus/retrieval" "github.com/prometheus/prometheus/storage" - "github.com/prometheus/prometheus/config" - "fmt" - "flag" + "github.com/yunlzheng/prometheus-pusher/scrape" "strings" ) @@ -40,8 +41,8 @@ func main() { var ( sampleAppender = storage.Fanout{} - targetManager = retrieval.NewTargetManager(sampleAppender) - jobTargets = scrape.NewJobTargets(targetManager) + targetManager = retrieval.NewTargetManager(sampleAppender) + jobTargets = scrape.NewJobTargets(targetManager) ) fmt.Println("Loading prometheus config file: " + cfg.configFile) @@ -76,6 +77,8 @@ func main() { defer scrapeManager.Stop() r := gin.Default() + pprof.Register(r, nil) // NOQA + r.GET("/ping", func(c *gin.Context) { c.JSON(200, gin.H{ "message": "pong", @@ -87,4 +90,3 @@ func main() { r.Run() } - diff --git a/vendor/github.com/gin-contrib/pprof/LICENSE b/vendor/github.com/gin-contrib/pprof/LICENSE new file mode 100644 index 0000000..4e2cfb0 --- /dev/null +++ b/vendor/github.com/gin-contrib/pprof/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2016 Gin-Gonic + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/github.com/gin-contrib/pprof/README.md b/vendor/github.com/gin-contrib/pprof/README.md new file mode 100644 index 0000000..e65e9be --- /dev/null +++ b/vendor/github.com/gin-contrib/pprof/README.md @@ -0,0 +1,83 @@ +# pprof + +[![Build Status](https://travis-ci.org/gin-contrib/pprof.svg)](https://travis-ci.org/gin-contrib/pprof) +[![codecov](https://codecov.io/gh/gin-contrib/pprof/branch/master/graph/badge.svg)](https://codecov.io/gh/gin-contrib/pprof) +[![Go Report Card](https://goreportcard.com/badge/github.com/gin-contrib/pprof)](https://goreportcard.com/report/github.com/gin-contrib/pprof) +[![GoDoc](https://godoc.org/github.com/gin-contrib/pprof?status.svg)](https://godoc.org/github.com/gin-contrib/pprof) +[![Join the chat at https://gitter.im/gin-gonic/gin](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/gin-gonic/gin) + +gin pprof middleware + +> Package pprof serves via its HTTP server runtime profiling data in the format expected by the pprof visualization tool. + +## Usage + +### Start using it + +Download and install it: + +```bash +$ go get github.com/gin-contrib/pprof +``` + +Import it in your code: + +```go +import "github.com/gin-contrib/pprof" +``` + +### Example: + +```go +package main + +import ( + "github.com/gin-contrib/pprof" + "github.com/gin-gonic/gin" +) + +func main() { + router := gin.Default() + pprof.Register(router, nil) + router.Run(":8080") +} +``` + +### change default path prefix: + +```go +func main() { + router := gin.Default() + pprof.Register(router, &pprof.Options{ + // default is "debug/pprof" + RoutePrefix: "debug/pprof", + }) + router.Run(":8080") +} +``` + +### Use the pprof tool + +Then use the pprof tool to look at the heap profile: + +```bash +go tool pprof http://localhost:8080/debug/pprof/heap +``` + +Or to look at a 30-second CPU profile: + +```bash +go tool pprof http://localhost:8080/debug/pprof/profile +``` + +Or to look at the goroutine blocking profile, after calling runtime.SetBlockProfileRate in your program: + +```bash +go tool pprof http://localhost:8080/debug/pprof/block +``` + +Or to collect a 5-second execution trace: + +```bash +wget http://localhost:8080/debug/pprof/trace?seconds=5 +``` diff --git a/vendor/github.com/gin-contrib/pprof/pprof.go b/vendor/github.com/gin-contrib/pprof/pprof.go new file mode 100644 index 0000000..c04e631 --- /dev/null +++ b/vendor/github.com/gin-contrib/pprof/pprof.go @@ -0,0 +1,42 @@ +package pprof + +import ( + "net/http" + "net/http/pprof" + + "github.com/gin-gonic/gin" +) + +// Options provides potential route registration configuration options +type Options struct { + // RoutePrefix is an optional path prefix. If left unspecified, `/debug/pprof` + // is used as the default path prefix. + RoutePrefix string +} + +// Register the standard HandlerFuncs from the net/http/pprof package with +// the provided gin.Engine. opts is a optional. If a `nil` value is passed, +// the default path prefix is used. +func Register(r *gin.Engine, opts *Options) { + prefix := routePrefix(opts) + r.GET(prefix+"/block", pprofHandler(pprof.Index)) + r.GET(prefix+"/heap", pprofHandler(pprof.Index)) + r.GET(prefix+"/profile", pprofHandler(pprof.Profile)) + r.POST(prefix+"/symbol", pprofHandler(pprof.Symbol)) + r.GET(prefix+"/symbol", pprofHandler(pprof.Symbol)) + r.GET(prefix+"/trace", pprofHandler(pprof.Trace)) +} + +func pprofHandler(h http.HandlerFunc) gin.HandlerFunc { + handler := http.HandlerFunc(h) + return func(c *gin.Context) { + handler.ServeHTTP(c.Writer, c.Request) + } +} + +func routePrefix(opts *Options) string { + if opts == nil { + return "/debug/pprof" + } + return opts.RoutePrefix +} diff --git a/vendor/github.com/gin-contrib/sse/LICENSE b/vendor/github.com/gin-contrib/sse/LICENSE new file mode 100644 index 0000000..1ff7f37 --- /dev/null +++ b/vendor/github.com/gin-contrib/sse/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2014 Manuel Martínez-Almeida + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/vendor/github.com/gin-contrib/sse/README.md b/vendor/github.com/gin-contrib/sse/README.md new file mode 100644 index 0000000..c9c49cf --- /dev/null +++ b/vendor/github.com/gin-contrib/sse/README.md @@ -0,0 +1,58 @@ +# Server-Sent Events + +[![GoDoc](https://godoc.org/github.com/gin-contrib/sse?status.svg)](https://godoc.org/github.com/gin-contrib/sse) +[![Build Status](https://travis-ci.org/gin-contrib/sse.svg)](https://travis-ci.org/gin-contrib/sse) +[![codecov](https://codecov.io/gh/gin-contrib/sse/branch/master/graph/badge.svg)](https://codecov.io/gh/gin-contrib/sse) +[![Go Report Card](https://goreportcard.com/badge/github.com/gin-contrib/sse)](https://goreportcard.com/report/github.com/gin-contrib/sse) + +Server-sent events (SSE) is a technology where a browser receives automatic updates from a server via HTTP connection. The Server-Sent Events EventSource API is [standardized as part of HTML5[1] by the W3C](http://www.w3.org/TR/2009/WD-eventsource-20091029/). + +- [Read this great SSE introduction by the HTML5Rocks guys](http://www.html5rocks.com/en/tutorials/eventsource/basics/) +- [Browser support](http://caniuse.com/#feat=eventsource) + +## Sample code + +```go +import "github.com/gin-contrib/sse" + +func httpHandler(w http.ResponseWriter, req *http.Request) { + // data can be a primitive like a string, an integer or a float + sse.Encode(w, sse.Event{ + Event: "message", + Data: "some data\nmore data", + }) + + // also a complex type, like a map, a struct or a slice + sse.Encode(w, sse.Event{ + Id: "124", + Event: "message", + Data: map[string]interface{}{ + "user": "manu", + "date": time.Now().Unix(), + "content": "hi!", + }, + }) +} +``` +``` +event: message +data: some data\\nmore data + +id: 124 +event: message +data: {"content":"hi!","date":1431540810,"user":"manu"} + +``` + +## Content-Type + +```go +fmt.Println(sse.ContentType) +``` +``` +text/event-stream +``` + +## Decoding support + +There is a client-side implementation of SSE coming soon. diff --git a/vendor/github.com/gin-contrib/sse/sse-decoder.go b/vendor/github.com/gin-contrib/sse/sse-decoder.go new file mode 100644 index 0000000..fd49b9c --- /dev/null +++ b/vendor/github.com/gin-contrib/sse/sse-decoder.go @@ -0,0 +1,116 @@ +// Copyright 2014 Manu Martinez-Almeida. All rights reserved. +// Use of this source code is governed by a MIT style +// license that can be found in the LICENSE file. + +package sse + +import ( + "bytes" + "io" + "io/ioutil" +) + +type decoder struct { + events []Event +} + +func Decode(r io.Reader) ([]Event, error) { + var dec decoder + return dec.decode(r) +} + +func (d *decoder) dispatchEvent(event Event, data string) { + dataLength := len(data) + if dataLength > 0 { + //If the data buffer's last character is a U+000A LINE FEED (LF) character, then remove the last character from the data buffer. + data = data[:dataLength-1] + dataLength-- + } + if dataLength == 0 && event.Event == "" { + return + } + if event.Event == "" { + event.Event = "message" + } + event.Data = data + d.events = append(d.events, event) +} + +func (d *decoder) decode(r io.Reader) ([]Event, error) { + buf, err := ioutil.ReadAll(r) + if err != nil { + return nil, err + } + + var currentEvent Event + var dataBuffer *bytes.Buffer = new(bytes.Buffer) + // TODO (and unit tests) + // Lines must be separated by either a U+000D CARRIAGE RETURN U+000A LINE FEED (CRLF) character pair, + // a single U+000A LINE FEED (LF) character, + // or a single U+000D CARRIAGE RETURN (CR) character. + lines := bytes.Split(buf, []byte{'\n'}) + for _, line := range lines { + if len(line) == 0 { + // If the line is empty (a blank line). Dispatch the event. + d.dispatchEvent(currentEvent, dataBuffer.String()) + + // reset current event and data buffer + currentEvent = Event{} + dataBuffer.Reset() + continue + } + if line[0] == byte(':') { + // If the line starts with a U+003A COLON character (:), ignore the line. + continue + } + + var field, value []byte + colonIndex := bytes.IndexRune(line, ':') + if colonIndex != -1 { + // If the line contains a U+003A COLON character character (:) + // Collect the characters on the line before the first U+003A COLON character (:), + // and let field be that string. + field = line[:colonIndex] + // Collect the characters on the line after the first U+003A COLON character (:), + // and let value be that string. + value = line[colonIndex+1:] + // If value starts with a single U+0020 SPACE character, remove it from value. + if len(value) > 0 && value[0] == ' ' { + value = value[1:] + } + } else { + // Otherwise, the string is not empty but does not contain a U+003A COLON character character (:) + // Use the whole line as the field name, and the empty string as the field value. + field = line + value = []byte{} + } + // The steps to process the field given a field name and a field value depend on the field name, + // as given in the following list. Field names must be compared literally, + // with no case folding performed. + switch string(field) { + case "event": + // Set the event name buffer to field value. + currentEvent.Event = string(value) + case "id": + // Set the event stream's last event ID to the field value. + currentEvent.Id = string(value) + case "retry": + // If the field value consists of only characters in the range U+0030 DIGIT ZERO (0) to U+0039 DIGIT NINE (9), + // then interpret the field value as an integer in base ten, and set the event stream's reconnection time to that integer. + // Otherwise, ignore the field. + currentEvent.Id = string(value) + case "data": + // Append the field value to the data buffer, + dataBuffer.Write(value) + // then append a single U+000A LINE FEED (LF) character to the data buffer. + dataBuffer.WriteString("\n") + default: + //Otherwise. The field is ignored. + continue + } + } + // Once the end of the file is reached, the user agent must dispatch the event one final time. + d.dispatchEvent(currentEvent, dataBuffer.String()) + + return d.events, nil +} diff --git a/vendor/github.com/gin-contrib/sse/sse-encoder.go b/vendor/github.com/gin-contrib/sse/sse-encoder.go new file mode 100644 index 0000000..f9c8087 --- /dev/null +++ b/vendor/github.com/gin-contrib/sse/sse-encoder.go @@ -0,0 +1,110 @@ +// Copyright 2014 Manu Martinez-Almeida. All rights reserved. +// Use of this source code is governed by a MIT style +// license that can be found in the LICENSE file. + +package sse + +import ( + "encoding/json" + "fmt" + "io" + "net/http" + "reflect" + "strconv" + "strings" +) + +// Server-Sent Events +// W3C Working Draft 29 October 2009 +// http://www.w3.org/TR/2009/WD-eventsource-20091029/ + +const ContentType = "text/event-stream" + +var contentType = []string{ContentType} +var noCache = []string{"no-cache"} + +var fieldReplacer = strings.NewReplacer( + "\n", "\\n", + "\r", "\\r") + +var dataReplacer = strings.NewReplacer( + "\n", "\ndata:", + "\r", "\\r") + +type Event struct { + Event string + Id string + Retry uint + Data interface{} +} + +func Encode(writer io.Writer, event Event) error { + w := checkWriter(writer) + writeId(w, event.Id) + writeEvent(w, event.Event) + writeRetry(w, event.Retry) + return writeData(w, event.Data) +} + +func writeId(w stringWriter, id string) { + if len(id) > 0 { + w.WriteString("id:") + fieldReplacer.WriteString(w, id) + w.WriteString("\n") + } +} + +func writeEvent(w stringWriter, event string) { + if len(event) > 0 { + w.WriteString("event:") + fieldReplacer.WriteString(w, event) + w.WriteString("\n") + } +} + +func writeRetry(w stringWriter, retry uint) { + if retry > 0 { + w.WriteString("retry:") + w.WriteString(strconv.FormatUint(uint64(retry), 10)) + w.WriteString("\n") + } +} + +func writeData(w stringWriter, data interface{}) error { + w.WriteString("data:") + switch kindOfData(data) { + case reflect.Struct, reflect.Slice, reflect.Map: + err := json.NewEncoder(w).Encode(data) + if err != nil { + return err + } + w.WriteString("\n") + default: + dataReplacer.WriteString(w, fmt.Sprint(data)) + w.WriteString("\n\n") + } + return nil +} + +func (r Event) Render(w http.ResponseWriter) error { + r.WriteContentType(w) + return Encode(w, r) +} + +func (r Event) WriteContentType(w http.ResponseWriter) { + header := w.Header() + header["Content-Type"] = contentType + + if _, exist := header["Cache-Control"]; !exist { + header["Cache-Control"] = noCache + } +} + +func kindOfData(data interface{}) reflect.Kind { + value := reflect.ValueOf(data) + valueType := value.Kind() + if valueType == reflect.Ptr { + valueType = value.Elem().Kind() + } + return valueType +} diff --git a/vendor/github.com/gin-contrib/sse/writer.go b/vendor/github.com/gin-contrib/sse/writer.go new file mode 100644 index 0000000..6f9806c --- /dev/null +++ b/vendor/github.com/gin-contrib/sse/writer.go @@ -0,0 +1,24 @@ +package sse + +import "io" + +type stringWriter interface { + io.Writer + WriteString(string) (int, error) +} + +type stringWrapper struct { + io.Writer +} + +func (w stringWrapper) WriteString(str string) (int, error) { + return w.Writer.Write([]byte(str)) +} + +func checkWriter(writer io.Writer) stringWriter { + if w, ok := writer.(stringWriter); ok { + return w + } else { + return stringWrapper{writer} + } +} diff --git a/vendor/github.com/gin-gonic/gin/json/json.go b/vendor/github.com/gin-gonic/gin/json/json.go new file mode 100644 index 0000000..d2d0f8b --- /dev/null +++ b/vendor/github.com/gin-gonic/gin/json/json.go @@ -0,0 +1,17 @@ +// Copyright 2017 Bo-Yi Wu. All rights reserved. +// Use of this source code is governed by a MIT style +// license that can be found in the LICENSE file. + +// +build !jsoniter + +package json + +import ( + "encoding/json" +) + +var ( + Marshal = json.Marshal + MarshalIndent = json.MarshalIndent + NewDecoder = json.NewDecoder +) diff --git a/vendor/github.com/gin-gonic/gin/json/jsoniter.go b/vendor/github.com/gin-gonic/gin/json/jsoniter.go new file mode 100644 index 0000000..65deee5 --- /dev/null +++ b/vendor/github.com/gin-gonic/gin/json/jsoniter.go @@ -0,0 +1,18 @@ +// Copyright 2017 Bo-Yi Wu. All rights reserved. +// Use of this source code is governed by a MIT style +// license that can be found in the LICENSE file. + +// +build jsoniter + +package json + +import ( + "github.com/json-iterator/go" +) + +var ( + json = jsoniter.ConfigCompatibleWithStandardLibrary + Marshal = json.Marshal + MarshalIndent = json.MarshalIndent + NewDecoder = json.NewDecoder +) diff --git a/vendor/vendor.json b/vendor/vendor.json index 3b987d7..39834a0 100644 --- a/vendor/vendor.json +++ b/vendor/vendor.json @@ -373,6 +373,18 @@ "revision": "aaaec6431e60c5d0088a77a161752b6368b834b1", "revisionTime": "2017-05-04T05:36:21Z" }, + { + "checksumSHA1": "WcN6IfR2xIp07+SMWuh+teN2zhk=", + "path": "github.com/gin-contrib/pprof", + "revision": "7ac49c4f3351f9542e0270b0f78802b987902596", + "revisionTime": "2017-08-26T17:00:44Z" + }, + { + "checksumSHA1": "QeKwBtN2df+j+4stw3bQJ6yO4EY=", + "path": "github.com/gin-contrib/sse", + "revision": "22d885f9ecc78bf4ee5d72b937e4bbcdc58e8cae", + "revisionTime": "2017-01-09T09:34:21Z" + }, { "checksumSHA1": "RsNwOto8G8aXIiRrlFn4dtU9q/g=", "path": "github.com/gin-gonic/gin", @@ -385,6 +397,12 @@ "revision": "e2212d40c62a98b388a5eb48ecbdcf88534688ba", "revisionTime": "2016-12-04T22:13:08Z" }, + { + "checksumSHA1": "YOwO5bkv3ei+GTVZqeEVB30kXDM=", + "path": "github.com/gin-gonic/gin/json", + "revision": "5afc5b19730118c9b8324fe9dd995d44ec65c81a", + "revisionTime": "2017-09-11T14:33:19Z" + }, { "checksumSHA1": "PHv9FNb7YavJWtAHcY6ZgXmkmHs=", "path": "github.com/gin-gonic/gin/render",