├── .gitignore ├── Dockerfile ├── Makefile ├── README.md ├── docker-compose.yml ├── docs └── diagram.png ├── src └── github.com │ └── nickschuch │ └── marco │ ├── balancer.go │ ├── balancer_test.go │ ├── main.go │ ├── util.go │ └── util_test.go └── vendor ├── manifest └── src ├── github.com ├── Sirupsen │ └── logrus │ │ ├── CHANGELOG.md │ │ ├── LICENSE │ │ ├── README.md │ │ ├── doc.go │ │ ├── entry.go │ │ ├── entry_test.go │ │ ├── examples │ │ ├── basic │ │ │ └── basic.go │ │ └── hook │ │ │ └── hook.go │ │ ├── exported.go │ │ ├── formatter.go │ │ ├── formatter_bench_test.go │ │ ├── formatters │ │ └── logstash │ │ │ ├── logstash.go │ │ │ └── logstash_test.go │ │ ├── hook_test.go │ │ ├── hooks.go │ │ ├── hooks │ │ ├── airbrake │ │ │ ├── airbrake.go │ │ │ └── airbrake_test.go │ │ ├── bugsnag │ │ │ ├── bugsnag.go │ │ │ └── bugsnag_test.go │ │ ├── papertrail │ │ │ ├── README.md │ │ │ ├── papertrail.go │ │ │ └── papertrail_test.go │ │ ├── sentry │ │ │ ├── README.md │ │ │ ├── sentry.go │ │ │ └── sentry_test.go │ │ └── syslog │ │ │ ├── README.md │ │ │ ├── syslog.go │ │ │ └── syslog_test.go │ │ ├── json_formatter.go │ │ ├── json_formatter_test.go │ │ ├── logger.go │ │ ├── logrus.go │ │ ├── logrus_test.go │ │ ├── terminal_bsd.go │ │ ├── terminal_linux.go │ │ ├── terminal_notwindows.go │ │ ├── terminal_windows.go │ │ ├── text_formatter.go │ │ ├── text_formatter_test.go │ │ └── writer.go ├── alecthomas │ ├── kingpin │ │ ├── COPYING │ │ ├── README.md │ │ ├── actions.go │ │ ├── app.go │ │ ├── app_test.go │ │ ├── args.go │ │ ├── args_test.go │ │ ├── cmd.go │ │ ├── cmd │ │ │ └── genvalues │ │ │ │ └── main.go │ │ ├── cmd_test.go │ │ ├── doc.go │ │ ├── examples │ │ │ ├── chat1 │ │ │ │ └── main.go │ │ │ ├── chat2 │ │ │ │ └── main.go │ │ │ ├── curl │ │ │ │ └── main.go │ │ │ ├── modular │ │ │ │ └── main.go │ │ │ └── ping │ │ │ │ └── main.go │ │ ├── examples_test.go │ │ ├── flags.go │ │ ├── flags_test.go │ │ ├── global.go │ │ ├── guesswidth.go │ │ ├── guesswidth_unix.go │ │ ├── model.go │ │ ├── parser.go │ │ ├── parser_test.go │ │ ├── parsers.go │ │ ├── parsers_test.go │ │ ├── templates.go │ │ ├── usage.go │ │ ├── usage_test.go │ │ ├── values.go │ │ ├── values.json │ │ ├── values_generated.go │ │ └── values_test.go │ ├── template │ │ ├── README.md │ │ ├── doc.go │ │ ├── example_test.go │ │ ├── examplefiles_test.go │ │ ├── examplefunc_test.go │ │ ├── exec.go │ │ ├── exec_test.go │ │ ├── funcs.go │ │ ├── helper.go │ │ ├── multi_test.go │ │ ├── parse │ │ │ ├── lex.go │ │ │ ├── lex_test.go │ │ │ ├── node.go │ │ │ ├── parse.go │ │ │ └── parse_test.go │ │ ├── template.go │ │ └── testdata │ │ │ ├── file1.tmpl │ │ │ ├── file2.tmpl │ │ │ ├── tmpl1.tmpl │ │ │ └── tmpl2.tmpl │ └── units │ │ ├── COPYING │ │ ├── README.md │ │ ├── bytes.go │ │ ├── bytes_test.go │ │ ├── doc.go │ │ ├── si.go │ │ └── util.go ├── bugsnag │ ├── bugsnag-go │ │ ├── CHANGELOG.md │ │ ├── CONTRIBUTING.md │ │ ├── LICENSE.txt │ │ ├── Makefile │ │ ├── README.md │ │ ├── appengine.go │ │ ├── appengine_test.go │ │ ├── bugsnag.go │ │ ├── bugsnag_test.go │ │ ├── configuration.go │ │ ├── configuration_test.go │ │ ├── doc.go │ │ ├── errors │ │ │ ├── README.md │ │ │ ├── error.go │ │ │ ├── error_test.go │ │ │ ├── parse_panic.go │ │ │ ├── parse_panic_test.go │ │ │ └── stackframe.go │ │ ├── event.go │ │ ├── examples │ │ │ ├── appengine │ │ │ │ ├── README.md │ │ │ │ ├── app.yaml │ │ │ │ ├── hello.go │ │ │ │ └── mylogs.txt │ │ │ ├── http │ │ │ │ └── main.go │ │ │ └── revelapp │ │ │ │ ├── app │ │ │ │ ├── controllers │ │ │ │ │ └── app.go │ │ │ │ ├── init.go │ │ │ │ └── views │ │ │ │ │ ├── App │ │ │ │ │ └── Index.html │ │ │ │ │ ├── debug.html │ │ │ │ │ ├── errors │ │ │ │ │ ├── 404.html │ │ │ │ │ └── 500.html │ │ │ │ │ ├── flash.html │ │ │ │ │ ├── footer.html │ │ │ │ │ └── header.html │ │ │ │ ├── conf │ │ │ │ ├── app.conf │ │ │ │ └── routes │ │ │ │ ├── messages │ │ │ │ └── sample.en │ │ │ │ ├── public │ │ │ │ ├── css │ │ │ │ │ └── bootstrap.css │ │ │ │ ├── img │ │ │ │ │ ├── favicon.png │ │ │ │ │ ├── glyphicons-halflings-white.png │ │ │ │ │ └── glyphicons-halflings.png │ │ │ │ └── js │ │ │ │ │ └── jquery-1.9.1.min.js │ │ │ │ └── tests │ │ │ │ └── apptest.go │ │ ├── json_tags.go │ │ ├── metadata.go │ │ ├── metadata_test.go │ │ ├── middleware.go │ │ ├── middleware_test.go │ │ ├── notifier.go │ │ ├── panicwrap.go │ │ ├── panicwrap_test.go │ │ ├── payload.go │ │ └── revel │ │ │ └── bugsnagrevel.go │ ├── osext │ │ ├── LICENSE │ │ ├── osext.go │ │ ├── osext_plan9.go │ │ ├── osext_procfs.go │ │ ├── osext_sysctl.go │ │ ├── osext_test.go │ │ └── osext_windows.go │ └── panicwrap │ │ ├── LICENSE │ │ ├── README.md │ │ ├── monitor.go │ │ ├── monitor_windows.go │ │ ├── panicwrap.go │ │ └── panicwrap_test.go ├── codahale │ └── hdrhistogram │ │ ├── LICENSE │ │ ├── README.md │ │ ├── hdr.go │ │ ├── hdr_test.go │ │ ├── window.go │ │ └── window_test.go ├── getsentry │ └── raven-go │ │ ├── Dockerfile.test │ │ ├── LICENSE │ │ ├── README.md │ │ ├── client.go │ │ ├── client_test.go │ │ ├── docs │ │ ├── Makefile │ │ ├── conf.py │ │ ├── index.rst │ │ ├── make.bat │ │ └── sentry-doc-config.json │ │ ├── example │ │ └── example.go │ │ ├── examples_test.go │ │ ├── exception.go │ │ ├── exception_test.go │ │ ├── http.go │ │ ├── http_test.go │ │ ├── interfaces.go │ │ ├── runtests.sh │ │ ├── stacktrace.go │ │ ├── stacktrace_test.go │ │ └── writer.go ├── mailgun │ ├── multibuf │ │ ├── LICENSE │ │ ├── Makefile │ │ ├── README.md │ │ ├── buffer.go │ │ └── buffer_test.go │ ├── oxy │ │ ├── forward │ │ │ ├── fwd.go │ │ │ ├── fwd_test.go │ │ │ ├── headers.go │ │ │ └── rewrite.go │ │ ├── memmetrics │ │ │ ├── anomaly.go │ │ │ ├── anomaly_test.go │ │ │ ├── counter.go │ │ │ ├── counter_test.go │ │ │ ├── histogram.go │ │ │ ├── histogram_test.go │ │ │ ├── ratio.go │ │ │ ├── ratio_test.go │ │ │ ├── roundtrip.go │ │ │ └── roundtrip_test.go │ │ ├── stream │ │ │ ├── retry_test.go │ │ │ ├── stream.go │ │ │ ├── stream_test.go │ │ │ └── threshold.go │ │ ├── trace │ │ │ ├── trace.go │ │ │ └── trace_test.go │ │ └── utils │ │ │ ├── auth.go │ │ │ ├── auth_test.go │ │ │ ├── handler.go │ │ │ ├── handler_test.go │ │ │ ├── logging.go │ │ │ ├── netutils.go │ │ │ ├── netutils_test.go │ │ │ └── source.go │ ├── predicate │ │ ├── LICENSE │ │ ├── Makefile │ │ ├── README.md │ │ ├── parse.go │ │ ├── parse_test.go │ │ └── predicate.go │ └── timetools │ │ ├── LICENSE │ │ ├── README.md │ │ ├── provider.go │ │ ├── provider_test.go │ │ └── rfc2822time.go ├── nickschuch │ ├── marco-lib │ │ ├── README.md │ │ └── marco-lib.go │ └── oxy │ │ └── roundrobin │ │ ├── rebalancer.go │ │ ├── rebalancer_test.go │ │ ├── rr.go │ │ └── rr_test.go ├── stretchr │ └── testify │ │ └── assert │ │ ├── assertions.go │ │ ├── assertions_test.go │ │ ├── doc.go │ │ ├── errors.go │ │ ├── forward_assertions.go │ │ ├── forward_assertions_test.go │ │ ├── http_assertions.go │ │ └── http_assertions_test.go └── tobi │ └── airbrake-go │ ├── LICENSE │ ├── README │ ├── airbrake.go │ ├── airbrake_test.go │ └── handler.go └── gopkg.in ├── alecthomas └── kingpin.v1 │ ├── COPYING │ ├── README.md │ ├── app.go │ ├── app_test.go │ ├── args.go │ ├── args_test.go │ ├── cmd.go │ ├── cmd_test.go │ ├── doc.go │ ├── examples │ ├── curl │ │ └── curl.go │ └── ping │ │ └── ping.go │ ├── examples_test.go │ ├── flags.go │ ├── flags_test.go │ ├── global.go │ ├── guesswidth.go │ ├── guesswidth_unix.go │ ├── lexer.go │ ├── lexer_test.go │ ├── parser.go │ ├── parsers.go │ ├── parsers_test.go │ ├── usage.go │ ├── usage_test.go │ └── values.go └── mgo.v2 └── bson ├── LICENSE ├── bson.go ├── bson_test.go ├── decode.go └── encode.go /.gitignore: -------------------------------------------------------------------------------- 1 | /bin 2 | /pkg 3 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:14.04 2 | 3 | ADD https://github.com/nickschuch/marco/releases/download/2.0.0/marco-Linux-x86_64 /marco 4 | RUN chmod a+x /marco 5 | 6 | CMD ["/marco"] 7 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | #!/usr/bin/make -f 2 | 3 | GO=go 4 | GB=gb 5 | 6 | all: build 7 | 8 | build: clean test 9 | @echo "Building..." 10 | env CGO_ENABLED=0 GOOS=linux GOARCH=amd64 $(GB) build -ldflags '-w -extld ld -extldflags -static' 11 | 12 | build-all: build 13 | @echo "Building others..." 14 | env GOOS=linux GOARCH=386 $(GB) build 15 | env GOOS=darwin GOARCH=amd64 $(GB) build 16 | env GOOS=darwin GOARCH=386 $(GB) build 17 | 18 | clean: 19 | rm -fR pkg bin 20 | 21 | test: 22 | @echo "Running tests..." 23 | @$(GB) test -test.v=true 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Marco 2 | ===== 3 | 4 | An API driver load balancer for modern day application infrastructure. 5 | 6 | ![Diagram](/docs/diagram.png "Diagram") 7 | 8 | ### Balancers and backends 9 | 10 | **Balancer** 11 | 12 | * Roundrobin - We are using https://github.com/mailgun/oxy under the hood for Round Robin balancing. 13 | 14 | **Drivers** 15 | 16 | * Demo - https://github.com/nickschuch/marco-demo 17 | * AWS ECS - https://github.com/nickschuch/marco-ecs 18 | * Docker - https://github.com/nickschuch/marco-docker 19 | 20 | ### Usage 21 | 22 | #### Binary 23 | 24 | ```bash 25 | $ marco 26 | INFO[0000] Balancing connections on port 80 27 | INFO[0000] Receiving backend data on port 81 28 | ``` 29 | 30 | #### Docker 31 | 32 | ```bash 33 | $ docker run -d --name=marco -p 0.0.0.0:80:80 nickschuch/marco 34 | INFO[0000] Balancing connections on port 80 35 | INFO[0000] Receiving backend data on port 81 36 | ``` 37 | 38 | ### Libraries 39 | 40 | * https://github.com/nickschuch/marco-lib - Used for backend services to leverage for consistent code when pushing to Marco. 41 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | build: 2 | image: "nickschuch/local-go" 3 | working_dir: "/data" 4 | volumes: 5 | - ".:/data" 6 | -------------------------------------------------------------------------------- /docs/diagram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nickschuch/marco/c5e47ec70e3f3e3acc0537684ee99a9dddb5538f/docs/diagram.png -------------------------------------------------------------------------------- /src/github.com/nickschuch/marco/balancer.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "net/http" 5 | "net/url" 6 | "os" 7 | 8 | "github.com/mailgun/oxy/forward" 9 | "github.com/mailgun/oxy/trace" 10 | "github.com/nickschuch/oxy/roundrobin" 11 | ) 12 | 13 | type Balancer struct { 14 | Handler *roundrobin.RoundRobin 15 | } 16 | 17 | func NewBalancer(tag string, weight int, addresses []*url.URL) (*Balancer, error) { 18 | var b *Balancer 19 | 20 | // Forwards requests to remote location and rewrites headers. 21 | fwd, err := forward.New() 22 | if err != nil { 23 | return b, err 24 | } 25 | 26 | // Structured request and response logger. 27 | t, err := trace.New(fwd, os.Stdout) 28 | if err != nil { 29 | return b, err 30 | } 31 | 32 | // Round robin load balancer for distributing traffic. 33 | lb, err := roundrobin.New(t) 34 | if err != nil { 35 | return b, err 36 | } 37 | 38 | // Populate the balancer with a list of backends. 39 | for _, a := range addresses { 40 | lb.UpsertServer(a, roundrobin.Weight(weight), roundrobin.Tag(tag)) 41 | } 42 | 43 | b = &Balancer{ 44 | Handler: lb, 45 | } 46 | return b, nil 47 | } 48 | 49 | func (b *Balancer) Update(t string, w int, l []*url.URL) { 50 | // Get a list of servers from the balancer. 51 | existing := b.Handler.FindServersByTag(t) 52 | 53 | // Determine if new items are in the list, if not remove them. 54 | for _, e := range existing { 55 | if !Contains(l, e) { 56 | b.Handler.RemoveServer(e) 57 | } 58 | } 59 | 60 | // Add the remaining items to the servers list. 61 | for _, n := range l { 62 | if !Contains(existing, n) { 63 | b.Handler.UpsertServer(n, roundrobin.Weight(w), roundrobin.Tag(t)) 64 | } 65 | } 66 | } 67 | 68 | func (b *Balancer) ServeHTTP(w http.ResponseWriter, r *http.Request) { 69 | b.Handler.ServeHTTP(w, r) 70 | } 71 | -------------------------------------------------------------------------------- /src/github.com/nickschuch/marco/balancer_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "net/url" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/assert" 8 | ) 9 | 10 | func TestBalancer(t *testing.T) { 11 | l := []*url.URL{ 12 | &url.URL{ 13 | Host: "127.0.0.1:8080", 14 | Scheme: "http", 15 | }, 16 | } 17 | e := []*url.URL{ 18 | &url.URL{ 19 | Host: "127.0.0.1:8080", 20 | Scheme: "http", 21 | }, 22 | } 23 | 24 | // Build a new balancer with the first backend. 25 | b, err := NewBalancer("backend1", 1, l) 26 | if err != nil { 27 | assert.Fail(t, err.Error()) 28 | } 29 | assert.Equal(t, e, b.Handler.Servers(), "Added records from backend1") 30 | 31 | // Update addresses from "backend1". 32 | l = []*url.URL{ 33 | &url.URL{ 34 | Host: "127.0.0.1:8081", 35 | Scheme: "http", 36 | }, 37 | } 38 | b.Update("backend1", 1, l) 39 | e = []*url.URL{ 40 | &url.URL{ 41 | Host: "127.0.0.1:8081", 42 | Scheme: "http", 43 | }, 44 | } 45 | assert.Equal(t, e, b.Handler.Servers(), "Update records from backend1") 46 | 47 | // Add new records from "backend2". 48 | l = []*url.URL{ 49 | &url.URL{ 50 | Host: "127.0.0.1:8082", 51 | Scheme: "http", 52 | }, 53 | } 54 | b.Update("backend2", 2, l) 55 | e = []*url.URL{ 56 | &url.URL{ 57 | Host: "127.0.0.1:8081", 58 | Scheme: "http", 59 | }, 60 | &url.URL{ 61 | Host: "127.0.0.1:8082", 62 | Scheme: "http", 63 | }, 64 | } 65 | assert.Equal(t, e, b.Handler.Servers(), "Added records from backend2") 66 | 67 | // Update addresses from "backend2" 68 | l = []*url.URL{ 69 | &url.URL{ 70 | Host: "127.0.0.1:8082", 71 | Scheme: "http", 72 | }, 73 | &url.URL{ 74 | Host: "127.0.0.1:8083", 75 | Scheme: "http", 76 | }, 77 | } 78 | b.Update("backend2", 2, l) 79 | e = []*url.URL{ 80 | &url.URL{ 81 | Host: "127.0.0.1:8081", 82 | Scheme: "http", 83 | }, 84 | &url.URL{ 85 | Host: "127.0.0.1:8082", 86 | Scheme: "http", 87 | }, 88 | &url.URL{ 89 | Host: "127.0.0.1:8083", 90 | Scheme: "http", 91 | }, 92 | } 93 | assert.Equal(t, e, b.Handler.Servers(), "Added records from backend2") 94 | } 95 | -------------------------------------------------------------------------------- /src/github.com/nickschuch/marco/util.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "net/url" 5 | ) 6 | 7 | func Contains(s []*url.URL, e *url.URL) bool { 8 | for _, a := range s { 9 | if a.String() == e.String() { 10 | return true 11 | } 12 | } 13 | return false 14 | } 15 | -------------------------------------------------------------------------------- /src/github.com/nickschuch/marco/util_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "net/url" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/assert" 8 | ) 9 | 10 | func TestContains(t *testing.T) { 11 | l := []*url.URL{ 12 | &url.URL{ 13 | Host: "127.0.0.1:8082", 14 | Scheme: "http", 15 | }, 16 | &url.URL{ 17 | Host: "127.0.0.1:8083", 18 | Scheme: "http", 19 | }, 20 | } 21 | c := &url.URL{ 22 | Host: "127.0.0.1:8082", 23 | Scheme: "http", 24 | } 25 | assert.True(t, Contains(l, c), "URL list contains URL.") 26 | } 27 | -------------------------------------------------------------------------------- /vendor/src/github.com/Sirupsen/logrus/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # 0.8.7 2 | 3 | * logrus/core: fix possible race (#216) 4 | * logrus/doc: small typo fixes and doc improvements 5 | 6 | 7 | # 0.8.6 8 | 9 | * hooks/raven: allow passing an initialized client 10 | 11 | # 0.8.5 12 | 13 | * logrus/core: revert #208 14 | 15 | # 0.8.4 16 | 17 | * formatter/text: fix data race (#218) 18 | 19 | # 0.8.3 20 | 21 | * logrus/core: fix entry log level (#208) 22 | * logrus/core: improve performance of text formatter by 40% 23 | * logrus/core: expose `LevelHooks` type 24 | * logrus/core: add support for DragonflyBSD and NetBSD 25 | * formatter/text: print structs more verbosely 26 | 27 | # 0.8.2 28 | 29 | * logrus: fix more Fatal family functions 30 | 31 | # 0.8.1 32 | 33 | * logrus: fix not exiting on `Fatalf` and `Fatalln` 34 | 35 | # 0.8.0 36 | 37 | * logrus: defaults to stderr instead of stdout 38 | * hooks/sentry: add special field for `*http.Request` 39 | * formatter/text: ignore Windows for colors 40 | 41 | # 0.7.3 42 | 43 | * formatter/\*: allow configuration of timestamp layout 44 | 45 | # 0.7.2 46 | 47 | * formatter/text: Add configuration option for time format (#158) 48 | -------------------------------------------------------------------------------- /vendor/src/github.com/Sirupsen/logrus/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Simon Eskildsen 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /vendor/src/github.com/Sirupsen/logrus/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Package logrus is a structured logger for Go, completely API compatible with the standard library logger. 3 | 4 | 5 | The simplest way to use Logrus is simply the package-level exported logger: 6 | 7 | package main 8 | 9 | import ( 10 | log "github.com/Sirupsen/logrus" 11 | ) 12 | 13 | func main() { 14 | log.WithFields(log.Fields{ 15 | "animal": "walrus", 16 | "number": 1, 17 | "size": 10, 18 | }).Info("A walrus appears") 19 | } 20 | 21 | Output: 22 | time="2015-09-07T08:48:33Z" level=info msg="A walrus appears" animal=walrus number=1 size=10 23 | 24 | For a full guide visit https://github.com/Sirupsen/logrus 25 | */ 26 | package logrus 27 | -------------------------------------------------------------------------------- /vendor/src/github.com/Sirupsen/logrus/entry_test.go: -------------------------------------------------------------------------------- 1 | package logrus 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "testing" 7 | 8 | "github.com/stretchr/testify/assert" 9 | ) 10 | 11 | func TestEntryWithError(t *testing.T) { 12 | 13 | assert := assert.New(t) 14 | 15 | defer func() { 16 | ErrorKey = "error" 17 | }() 18 | 19 | err := fmt.Errorf("kaboom at layer %d", 4711) 20 | 21 | assert.Equal(err, WithError(err).Data["error"]) 22 | 23 | logger := New() 24 | logger.Out = &bytes.Buffer{} 25 | entry := NewEntry(logger) 26 | 27 | assert.Equal(err, entry.WithError(err).Data["error"]) 28 | 29 | ErrorKey = "err" 30 | 31 | assert.Equal(err, entry.WithError(err).Data["err"]) 32 | 33 | } 34 | 35 | func TestEntryPanicln(t *testing.T) { 36 | errBoom := fmt.Errorf("boom time") 37 | 38 | defer func() { 39 | p := recover() 40 | assert.NotNil(t, p) 41 | 42 | switch pVal := p.(type) { 43 | case *Entry: 44 | assert.Equal(t, "kaboom", pVal.Message) 45 | assert.Equal(t, errBoom, pVal.Data["err"]) 46 | default: 47 | t.Fatalf("want type *Entry, got %T: %#v", pVal, pVal) 48 | } 49 | }() 50 | 51 | logger := New() 52 | logger.Out = &bytes.Buffer{} 53 | entry := NewEntry(logger) 54 | entry.WithField("err", errBoom).Panicln("kaboom") 55 | } 56 | 57 | func TestEntryPanicf(t *testing.T) { 58 | errBoom := fmt.Errorf("boom again") 59 | 60 | defer func() { 61 | p := recover() 62 | assert.NotNil(t, p) 63 | 64 | switch pVal := p.(type) { 65 | case *Entry: 66 | assert.Equal(t, "kaboom true", pVal.Message) 67 | assert.Equal(t, errBoom, pVal.Data["err"]) 68 | default: 69 | t.Fatalf("want type *Entry, got %T: %#v", pVal, pVal) 70 | } 71 | }() 72 | 73 | logger := New() 74 | logger.Out = &bytes.Buffer{} 75 | entry := NewEntry(logger) 76 | entry.WithField("err", errBoom).Panicf("kaboom %v", true) 77 | } 78 | -------------------------------------------------------------------------------- /vendor/src/github.com/Sirupsen/logrus/examples/basic/basic.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/Sirupsen/logrus" 5 | ) 6 | 7 | var log = logrus.New() 8 | 9 | func init() { 10 | log.Formatter = new(logrus.JSONFormatter) 11 | log.Formatter = new(logrus.TextFormatter) // default 12 | log.Level = logrus.DebugLevel 13 | } 14 | 15 | func main() { 16 | defer func() { 17 | err := recover() 18 | if err != nil { 19 | log.WithFields(logrus.Fields{ 20 | "omg": true, 21 | "err": err, 22 | "number": 100, 23 | }).Fatal("The ice breaks!") 24 | } 25 | }() 26 | 27 | log.WithFields(logrus.Fields{ 28 | "animal": "walrus", 29 | "number": 8, 30 | }).Debug("Started observing beach") 31 | 32 | log.WithFields(logrus.Fields{ 33 | "animal": "walrus", 34 | "size": 10, 35 | }).Info("A group of walrus emerges from the ocean") 36 | 37 | log.WithFields(logrus.Fields{ 38 | "omg": true, 39 | "number": 122, 40 | }).Warn("The group's number increased tremendously!") 41 | 42 | log.WithFields(logrus.Fields{ 43 | "temperature": -4, 44 | }).Debug("Temperature changes") 45 | 46 | log.WithFields(logrus.Fields{ 47 | "animal": "orca", 48 | "size": 9009, 49 | }).Panic("It's over 9000!") 50 | } 51 | -------------------------------------------------------------------------------- /vendor/src/github.com/Sirupsen/logrus/examples/hook/hook.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/Sirupsen/logrus" 5 | "github.com/Sirupsen/logrus/hooks/airbrake" 6 | ) 7 | 8 | var log = logrus.New() 9 | 10 | func init() { 11 | log.Formatter = new(logrus.TextFormatter) // default 12 | log.Hooks.Add(airbrake.NewHook("https://example.com", "xyz", "development")) 13 | } 14 | 15 | func main() { 16 | log.WithFields(logrus.Fields{ 17 | "animal": "walrus", 18 | "size": 10, 19 | }).Info("A group of walrus emerges from the ocean") 20 | 21 | log.WithFields(logrus.Fields{ 22 | "omg": true, 23 | "number": 122, 24 | }).Warn("The group's number increased tremendously!") 25 | 26 | log.WithFields(logrus.Fields{ 27 | "omg": true, 28 | "number": 100, 29 | }).Fatal("The ice breaks!") 30 | } 31 | -------------------------------------------------------------------------------- /vendor/src/github.com/Sirupsen/logrus/formatter.go: -------------------------------------------------------------------------------- 1 | package logrus 2 | 3 | import "time" 4 | 5 | const DefaultTimestampFormat = time.RFC3339 6 | 7 | // The Formatter interface is used to implement a custom Formatter. It takes an 8 | // `Entry`. It exposes all the fields, including the default ones: 9 | // 10 | // * `entry.Data["msg"]`. The message passed from Info, Warn, Error .. 11 | // * `entry.Data["time"]`. The timestamp. 12 | // * `entry.Data["level"]. The level the entry was logged at. 13 | // 14 | // Any additional fields added with `WithField` or `WithFields` are also in 15 | // `entry.Data`. Format is expected to return an array of bytes which are then 16 | // logged to `logger.Out`. 17 | type Formatter interface { 18 | Format(*Entry) ([]byte, error) 19 | } 20 | 21 | // This is to not silently overwrite `time`, `msg` and `level` fields when 22 | // dumping it. If this code wasn't there doing: 23 | // 24 | // logrus.WithField("level", 1).Info("hello") 25 | // 26 | // Would just silently drop the user provided level. Instead with this code 27 | // it'll logged as: 28 | // 29 | // {"level": "info", "fields.level": 1, "msg": "hello", "time": "..."} 30 | // 31 | // It's not exported because it's still using Data in an opinionated way. It's to 32 | // avoid code duplication between the two default formatters. 33 | func prefixFieldClashes(data Fields) { 34 | _, ok := data["time"] 35 | if ok { 36 | data["fields.time"] = data["time"] 37 | } 38 | 39 | _, ok = data["msg"] 40 | if ok { 41 | data["fields.msg"] = data["msg"] 42 | } 43 | 44 | _, ok = data["level"] 45 | if ok { 46 | data["fields.level"] = data["level"] 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /vendor/src/github.com/Sirupsen/logrus/formatter_bench_test.go: -------------------------------------------------------------------------------- 1 | package logrus 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | "time" 7 | ) 8 | 9 | // smallFields is a small size data set for benchmarking 10 | var smallFields = Fields{ 11 | "foo": "bar", 12 | "baz": "qux", 13 | "one": "two", 14 | "three": "four", 15 | } 16 | 17 | // largeFields is a large size data set for benchmarking 18 | var largeFields = Fields{ 19 | "foo": "bar", 20 | "baz": "qux", 21 | "one": "two", 22 | "three": "four", 23 | "five": "six", 24 | "seven": "eight", 25 | "nine": "ten", 26 | "eleven": "twelve", 27 | "thirteen": "fourteen", 28 | "fifteen": "sixteen", 29 | "seventeen": "eighteen", 30 | "nineteen": "twenty", 31 | "a": "b", 32 | "c": "d", 33 | "e": "f", 34 | "g": "h", 35 | "i": "j", 36 | "k": "l", 37 | "m": "n", 38 | "o": "p", 39 | "q": "r", 40 | "s": "t", 41 | "u": "v", 42 | "w": "x", 43 | "y": "z", 44 | "this": "will", 45 | "make": "thirty", 46 | "entries": "yeah", 47 | } 48 | 49 | var errorFields = Fields{ 50 | "foo": fmt.Errorf("bar"), 51 | "baz": fmt.Errorf("qux"), 52 | } 53 | 54 | func BenchmarkErrorTextFormatter(b *testing.B) { 55 | doBenchmark(b, &TextFormatter{DisableColors: true}, errorFields) 56 | } 57 | 58 | func BenchmarkSmallTextFormatter(b *testing.B) { 59 | doBenchmark(b, &TextFormatter{DisableColors: true}, smallFields) 60 | } 61 | 62 | func BenchmarkLargeTextFormatter(b *testing.B) { 63 | doBenchmark(b, &TextFormatter{DisableColors: true}, largeFields) 64 | } 65 | 66 | func BenchmarkSmallColoredTextFormatter(b *testing.B) { 67 | doBenchmark(b, &TextFormatter{ForceColors: true}, smallFields) 68 | } 69 | 70 | func BenchmarkLargeColoredTextFormatter(b *testing.B) { 71 | doBenchmark(b, &TextFormatter{ForceColors: true}, largeFields) 72 | } 73 | 74 | func BenchmarkSmallJSONFormatter(b *testing.B) { 75 | doBenchmark(b, &JSONFormatter{}, smallFields) 76 | } 77 | 78 | func BenchmarkLargeJSONFormatter(b *testing.B) { 79 | doBenchmark(b, &JSONFormatter{}, largeFields) 80 | } 81 | 82 | func doBenchmark(b *testing.B, formatter Formatter, fields Fields) { 83 | entry := &Entry{ 84 | Time: time.Time{}, 85 | Level: InfoLevel, 86 | Message: "message", 87 | Data: fields, 88 | } 89 | var d []byte 90 | var err error 91 | for i := 0; i < b.N; i++ { 92 | d, err = formatter.Format(entry) 93 | if err != nil { 94 | b.Fatal(err) 95 | } 96 | b.SetBytes(int64(len(d))) 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /vendor/src/github.com/Sirupsen/logrus/formatters/logstash/logstash.go: -------------------------------------------------------------------------------- 1 | package logstash 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | 7 | "github.com/Sirupsen/logrus" 8 | ) 9 | 10 | // Formatter generates json in logstash format. 11 | // Logstash site: http://logstash.net/ 12 | type LogstashFormatter struct { 13 | Type string // if not empty use for logstash type field. 14 | 15 | // TimestampFormat sets the format used for timestamps. 16 | TimestampFormat string 17 | } 18 | 19 | func (f *LogstashFormatter) Format(entry *logrus.Entry) ([]byte, error) { 20 | entry.Data["@version"] = 1 21 | 22 | if f.TimestampFormat == "" { 23 | f.TimestampFormat = logrus.DefaultTimestampFormat 24 | } 25 | 26 | entry.Data["@timestamp"] = entry.Time.Format(f.TimestampFormat) 27 | 28 | // set message field 29 | v, ok := entry.Data["message"] 30 | if ok { 31 | entry.Data["fields.message"] = v 32 | } 33 | entry.Data["message"] = entry.Message 34 | 35 | // set level field 36 | v, ok = entry.Data["level"] 37 | if ok { 38 | entry.Data["fields.level"] = v 39 | } 40 | entry.Data["level"] = entry.Level.String() 41 | 42 | // set type field 43 | if f.Type != "" { 44 | v, ok = entry.Data["type"] 45 | if ok { 46 | entry.Data["fields.type"] = v 47 | } 48 | entry.Data["type"] = f.Type 49 | } 50 | 51 | serialized, err := json.Marshal(entry.Data) 52 | if err != nil { 53 | return nil, fmt.Errorf("Failed to marshal fields to JSON, %v", err) 54 | } 55 | return append(serialized, '\n'), nil 56 | } 57 | -------------------------------------------------------------------------------- /vendor/src/github.com/Sirupsen/logrus/formatters/logstash/logstash_test.go: -------------------------------------------------------------------------------- 1 | package logstash 2 | 3 | import ( 4 | "bytes" 5 | "encoding/json" 6 | "github.com/Sirupsen/logrus" 7 | "github.com/stretchr/testify/assert" 8 | "testing" 9 | ) 10 | 11 | func TestLogstashFormatter(t *testing.T) { 12 | assert := assert.New(t) 13 | 14 | lf := LogstashFormatter{Type: "abc"} 15 | 16 | fields := logrus.Fields{ 17 | "message": "def", 18 | "level": "ijk", 19 | "type": "lmn", 20 | "one": 1, 21 | "pi": 3.14, 22 | "bool": true, 23 | } 24 | 25 | entry := logrus.WithFields(fields) 26 | entry.Message = "msg" 27 | entry.Level = logrus.InfoLevel 28 | 29 | b, _ := lf.Format(entry) 30 | 31 | var data map[string]interface{} 32 | dec := json.NewDecoder(bytes.NewReader(b)) 33 | dec.UseNumber() 34 | dec.Decode(&data) 35 | 36 | // base fields 37 | assert.Equal(json.Number("1"), data["@version"]) 38 | assert.NotEmpty(data["@timestamp"]) 39 | assert.Equal("abc", data["type"]) 40 | assert.Equal("msg", data["message"]) 41 | assert.Equal("info", data["level"]) 42 | 43 | // substituted fields 44 | assert.Equal("def", data["fields.message"]) 45 | assert.Equal("ijk", data["fields.level"]) 46 | assert.Equal("lmn", data["fields.type"]) 47 | 48 | // formats 49 | assert.Equal(json.Number("1"), data["one"]) 50 | assert.Equal(json.Number("3.14"), data["pi"]) 51 | assert.Equal(true, data["bool"]) 52 | } 53 | -------------------------------------------------------------------------------- /vendor/src/github.com/Sirupsen/logrus/hook_test.go: -------------------------------------------------------------------------------- 1 | package logrus 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | ) 8 | 9 | type TestHook struct { 10 | Fired bool 11 | } 12 | 13 | func (hook *TestHook) Fire(entry *Entry) error { 14 | hook.Fired = true 15 | return nil 16 | } 17 | 18 | func (hook *TestHook) Levels() []Level { 19 | return []Level{ 20 | DebugLevel, 21 | InfoLevel, 22 | WarnLevel, 23 | ErrorLevel, 24 | FatalLevel, 25 | PanicLevel, 26 | } 27 | } 28 | 29 | func TestHookFires(t *testing.T) { 30 | hook := new(TestHook) 31 | 32 | LogAndAssertJSON(t, func(log *Logger) { 33 | log.Hooks.Add(hook) 34 | assert.Equal(t, hook.Fired, false) 35 | 36 | log.Print("test") 37 | }, func(fields Fields) { 38 | assert.Equal(t, hook.Fired, true) 39 | }) 40 | } 41 | 42 | type ModifyHook struct { 43 | } 44 | 45 | func (hook *ModifyHook) Fire(entry *Entry) error { 46 | entry.Data["wow"] = "whale" 47 | return nil 48 | } 49 | 50 | func (hook *ModifyHook) Levels() []Level { 51 | return []Level{ 52 | DebugLevel, 53 | InfoLevel, 54 | WarnLevel, 55 | ErrorLevel, 56 | FatalLevel, 57 | PanicLevel, 58 | } 59 | } 60 | 61 | func TestHookCanModifyEntry(t *testing.T) { 62 | hook := new(ModifyHook) 63 | 64 | LogAndAssertJSON(t, func(log *Logger) { 65 | log.Hooks.Add(hook) 66 | log.WithField("wow", "elephant").Print("test") 67 | }, func(fields Fields) { 68 | assert.Equal(t, fields["wow"], "whale") 69 | }) 70 | } 71 | 72 | func TestCanFireMultipleHooks(t *testing.T) { 73 | hook1 := new(ModifyHook) 74 | hook2 := new(TestHook) 75 | 76 | LogAndAssertJSON(t, func(log *Logger) { 77 | log.Hooks.Add(hook1) 78 | log.Hooks.Add(hook2) 79 | 80 | log.WithField("wow", "elephant").Print("test") 81 | }, func(fields Fields) { 82 | assert.Equal(t, fields["wow"], "whale") 83 | assert.Equal(t, hook2.Fired, true) 84 | }) 85 | } 86 | 87 | type ErrorHook struct { 88 | Fired bool 89 | } 90 | 91 | func (hook *ErrorHook) Fire(entry *Entry) error { 92 | hook.Fired = true 93 | return nil 94 | } 95 | 96 | func (hook *ErrorHook) Levels() []Level { 97 | return []Level{ 98 | ErrorLevel, 99 | } 100 | } 101 | 102 | func TestErrorHookShouldntFireOnInfo(t *testing.T) { 103 | hook := new(ErrorHook) 104 | 105 | LogAndAssertJSON(t, func(log *Logger) { 106 | log.Hooks.Add(hook) 107 | log.Info("test") 108 | }, func(fields Fields) { 109 | assert.Equal(t, hook.Fired, false) 110 | }) 111 | } 112 | 113 | func TestErrorHookShouldFireOnError(t *testing.T) { 114 | hook := new(ErrorHook) 115 | 116 | LogAndAssertJSON(t, func(log *Logger) { 117 | log.Hooks.Add(hook) 118 | log.Error("test") 119 | }, func(fields Fields) { 120 | assert.Equal(t, hook.Fired, true) 121 | }) 122 | } 123 | -------------------------------------------------------------------------------- /vendor/src/github.com/Sirupsen/logrus/hooks.go: -------------------------------------------------------------------------------- 1 | package logrus 2 | 3 | // A hook to be fired when logging on the logging levels returned from 4 | // `Levels()` on your implementation of the interface. Note that this is not 5 | // fired in a goroutine or a channel with workers, you should handle such 6 | // functionality yourself if your call is non-blocking and you don't wish for 7 | // the logging calls for levels returned from `Levels()` to block. 8 | type Hook interface { 9 | Levels() []Level 10 | Fire(*Entry) error 11 | } 12 | 13 | // Internal type for storing the hooks on a logger instance. 14 | type LevelHooks map[Level][]Hook 15 | 16 | // Add a hook to an instance of logger. This is called with 17 | // `log.Hooks.Add(new(MyHook))` where `MyHook` implements the `Hook` interface. 18 | func (hooks LevelHooks) Add(hook Hook) { 19 | for _, level := range hook.Levels() { 20 | hooks[level] = append(hooks[level], hook) 21 | } 22 | } 23 | 24 | // Fire all the hooks for the passed level. Used by `entry.log` to fire 25 | // appropriate hooks for a log entry. 26 | func (hooks LevelHooks) Fire(level Level, entry *Entry) error { 27 | for _, hook := range hooks[level] { 28 | if err := hook.Fire(entry); err != nil { 29 | return err 30 | } 31 | } 32 | 33 | return nil 34 | } 35 | -------------------------------------------------------------------------------- /vendor/src/github.com/Sirupsen/logrus/hooks/airbrake/airbrake.go: -------------------------------------------------------------------------------- 1 | package airbrake 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | 7 | "github.com/Sirupsen/logrus" 8 | "github.com/tobi/airbrake-go" 9 | ) 10 | 11 | // AirbrakeHook to send exceptions to an exception-tracking service compatible 12 | // with the Airbrake API. 13 | type airbrakeHook struct { 14 | APIKey string 15 | Endpoint string 16 | Environment string 17 | } 18 | 19 | func NewHook(endpoint, apiKey, env string) *airbrakeHook { 20 | return &airbrakeHook{ 21 | APIKey: apiKey, 22 | Endpoint: endpoint, 23 | Environment: env, 24 | } 25 | } 26 | 27 | func (hook *airbrakeHook) Fire(entry *logrus.Entry) error { 28 | airbrake.ApiKey = hook.APIKey 29 | airbrake.Endpoint = hook.Endpoint 30 | airbrake.Environment = hook.Environment 31 | 32 | var notifyErr error 33 | err, ok := entry.Data["error"].(error) 34 | if ok { 35 | notifyErr = err 36 | } else { 37 | notifyErr = errors.New(entry.Message) 38 | } 39 | 40 | airErr := airbrake.Notify(notifyErr) 41 | if airErr != nil { 42 | return fmt.Errorf("Failed to send error to Airbrake: %s", airErr) 43 | } 44 | 45 | return nil 46 | } 47 | 48 | func (hook *airbrakeHook) Levels() []logrus.Level { 49 | return []logrus.Level{ 50 | logrus.ErrorLevel, 51 | logrus.FatalLevel, 52 | logrus.PanicLevel, 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /vendor/src/github.com/Sirupsen/logrus/hooks/bugsnag/bugsnag.go: -------------------------------------------------------------------------------- 1 | package logrus_bugsnag 2 | 3 | import ( 4 | "errors" 5 | 6 | "github.com/Sirupsen/logrus" 7 | "github.com/bugsnag/bugsnag-go" 8 | ) 9 | 10 | type bugsnagHook struct{} 11 | 12 | // ErrBugsnagUnconfigured is returned if NewBugsnagHook is called before 13 | // bugsnag.Configure. Bugsnag must be configured before the hook. 14 | var ErrBugsnagUnconfigured = errors.New("bugsnag must be configured before installing this logrus hook") 15 | 16 | // ErrBugsnagSendFailed indicates that the hook failed to submit an error to 17 | // bugsnag. The error was successfully generated, but `bugsnag.Notify()` 18 | // failed. 19 | type ErrBugsnagSendFailed struct { 20 | err error 21 | } 22 | 23 | func (e ErrBugsnagSendFailed) Error() string { 24 | return "failed to send error to Bugsnag: " + e.err.Error() 25 | } 26 | 27 | // NewBugsnagHook initializes a logrus hook which sends exceptions to an 28 | // exception-tracking service compatible with the Bugsnag API. Before using 29 | // this hook, you must call bugsnag.Configure(). The returned object should be 30 | // registered with a log via `AddHook()` 31 | // 32 | // Entries that trigger an Error, Fatal or Panic should now include an "error" 33 | // field to send to Bugsnag. 34 | func NewBugsnagHook() (*bugsnagHook, error) { 35 | if bugsnag.Config.APIKey == "" { 36 | return nil, ErrBugsnagUnconfigured 37 | } 38 | return &bugsnagHook{}, nil 39 | } 40 | 41 | // Fire forwards an error to Bugsnag. Given a logrus.Entry, it extracts the 42 | // "error" field (or the Message if the error isn't present) and sends it off. 43 | func (hook *bugsnagHook) Fire(entry *logrus.Entry) error { 44 | var notifyErr error 45 | err, ok := entry.Data["error"].(error) 46 | if ok { 47 | notifyErr = err 48 | } else { 49 | notifyErr = errors.New(entry.Message) 50 | } 51 | 52 | bugsnagErr := bugsnag.Notify(notifyErr) 53 | if bugsnagErr != nil { 54 | return ErrBugsnagSendFailed{bugsnagErr} 55 | } 56 | 57 | return nil 58 | } 59 | 60 | // Levels enumerates the log levels on which the error should be forwarded to 61 | // bugsnag: everything at or above the "Error" level. 62 | func (hook *bugsnagHook) Levels() []logrus.Level { 63 | return []logrus.Level{ 64 | logrus.ErrorLevel, 65 | logrus.FatalLevel, 66 | logrus.PanicLevel, 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /vendor/src/github.com/Sirupsen/logrus/hooks/bugsnag/bugsnag_test.go: -------------------------------------------------------------------------------- 1 | package logrus_bugsnag 2 | 3 | import ( 4 | "encoding/json" 5 | "errors" 6 | "io/ioutil" 7 | "net/http" 8 | "net/http/httptest" 9 | "testing" 10 | "time" 11 | 12 | "github.com/Sirupsen/logrus" 13 | "github.com/bugsnag/bugsnag-go" 14 | ) 15 | 16 | type notice struct { 17 | Events []struct { 18 | Exceptions []struct { 19 | Message string `json:"message"` 20 | } `json:"exceptions"` 21 | } `json:"events"` 22 | } 23 | 24 | func TestNoticeReceived(t *testing.T) { 25 | msg := make(chan string, 1) 26 | expectedMsg := "foo" 27 | 28 | ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 29 | var notice notice 30 | data, _ := ioutil.ReadAll(r.Body) 31 | if err := json.Unmarshal(data, ¬ice); err != nil { 32 | t.Error(err) 33 | } 34 | _ = r.Body.Close() 35 | 36 | msg <- notice.Events[0].Exceptions[0].Message 37 | })) 38 | defer ts.Close() 39 | 40 | hook := &bugsnagHook{} 41 | 42 | bugsnag.Configure(bugsnag.Configuration{ 43 | Endpoint: ts.URL, 44 | ReleaseStage: "production", 45 | APIKey: "12345678901234567890123456789012", 46 | Synchronous: true, 47 | }) 48 | 49 | log := logrus.New() 50 | log.Hooks.Add(hook) 51 | 52 | log.WithFields(logrus.Fields{ 53 | "error": errors.New(expectedMsg), 54 | }).Error("Bugsnag will not see this string") 55 | 56 | select { 57 | case received := <-msg: 58 | if received != expectedMsg { 59 | t.Errorf("Unexpected message received: %s", received) 60 | } 61 | case <-time.After(time.Second): 62 | t.Error("Timed out; no notice received by Bugsnag API") 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /vendor/src/github.com/Sirupsen/logrus/hooks/papertrail/README.md: -------------------------------------------------------------------------------- 1 | # Papertrail Hook for Logrus :walrus: 2 | 3 | [Papertrail](https://papertrailapp.com) provides hosted log management. Once stored in Papertrail, you can [group](http://help.papertrailapp.com/kb/how-it-works/groups/) your logs on various dimensions, [search](http://help.papertrailapp.com/kb/how-it-works/search-syntax) them, and trigger [alerts](http://help.papertrailapp.com/kb/how-it-works/alerts). 4 | 5 | In most deployments, you'll want to send logs to Papertrail via their [remote_syslog](http://help.papertrailapp.com/kb/configuration/configuring-centralized-logging-from-text-log-files-in-unix/) daemon, which requires no application-specific configuration. This hook is intended for relatively low-volume logging, likely in managed cloud hosting deployments where installing `remote_syslog` is not possible. 6 | 7 | ## Usage 8 | 9 | You can find your Papertrail UDP port on your [Papertrail account page](https://papertrailapp.com/account/destinations). Substitute it below for `YOUR_PAPERTRAIL_UDP_PORT`. 10 | 11 | For `YOUR_APP_NAME`, substitute a short string that will readily identify your application or service in the logs. 12 | 13 | ```go 14 | import ( 15 | "log/syslog" 16 | "github.com/Sirupsen/logrus" 17 | "github.com/Sirupsen/logrus/hooks/papertrail" 18 | ) 19 | 20 | func main() { 21 | log := logrus.New() 22 | hook, err := logrus_papertrail.NewPapertrailHook("logs.papertrailapp.com", YOUR_PAPERTRAIL_UDP_PORT, YOUR_APP_NAME) 23 | 24 | if err == nil { 25 | log.Hooks.Add(hook) 26 | } 27 | } 28 | ``` 29 | -------------------------------------------------------------------------------- /vendor/src/github.com/Sirupsen/logrus/hooks/papertrail/papertrail.go: -------------------------------------------------------------------------------- 1 | package logrus_papertrail 2 | 3 | import ( 4 | "fmt" 5 | "net" 6 | "os" 7 | "time" 8 | 9 | "github.com/Sirupsen/logrus" 10 | ) 11 | 12 | const ( 13 | format = "Jan 2 15:04:05" 14 | ) 15 | 16 | // PapertrailHook to send logs to a logging service compatible with the Papertrail API. 17 | type PapertrailHook struct { 18 | Host string 19 | Port int 20 | AppName string 21 | UDPConn net.Conn 22 | } 23 | 24 | // NewPapertrailHook creates a hook to be added to an instance of logger. 25 | func NewPapertrailHook(host string, port int, appName string) (*PapertrailHook, error) { 26 | conn, err := net.Dial("udp", fmt.Sprintf("%s:%d", host, port)) 27 | return &PapertrailHook{host, port, appName, conn}, err 28 | } 29 | 30 | // Fire is called when a log event is fired. 31 | func (hook *PapertrailHook) Fire(entry *logrus.Entry) error { 32 | date := time.Now().Format(format) 33 | msg, _ := entry.String() 34 | payload := fmt.Sprintf("<22> %s %s: %s", date, hook.AppName, msg) 35 | 36 | bytesWritten, err := hook.UDPConn.Write([]byte(payload)) 37 | if err != nil { 38 | fmt.Fprintf(os.Stderr, "Unable to send log line to Papertrail via UDP. Wrote %d bytes before error: %v", bytesWritten, err) 39 | return err 40 | } 41 | 42 | return nil 43 | } 44 | 45 | // Levels returns the available logging levels. 46 | func (hook *PapertrailHook) Levels() []logrus.Level { 47 | return []logrus.Level{ 48 | logrus.PanicLevel, 49 | logrus.FatalLevel, 50 | logrus.ErrorLevel, 51 | logrus.WarnLevel, 52 | logrus.InfoLevel, 53 | logrus.DebugLevel, 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /vendor/src/github.com/Sirupsen/logrus/hooks/papertrail/papertrail_test.go: -------------------------------------------------------------------------------- 1 | package logrus_papertrail 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | 7 | "github.com/Sirupsen/logrus" 8 | "github.com/stvp/go-udp-testing" 9 | ) 10 | 11 | func TestWritingToUDP(t *testing.T) { 12 | port := 16661 13 | udp.SetAddr(fmt.Sprintf(":%d", port)) 14 | 15 | hook, err := NewPapertrailHook("localhost", port, "test") 16 | if err != nil { 17 | t.Errorf("Unable to connect to local UDP server.") 18 | } 19 | 20 | log := logrus.New() 21 | log.Hooks.Add(hook) 22 | 23 | udp.ShouldReceive(t, "foo", func() { 24 | log.Info("foo") 25 | }) 26 | } 27 | -------------------------------------------------------------------------------- /vendor/src/github.com/Sirupsen/logrus/hooks/syslog/README.md: -------------------------------------------------------------------------------- 1 | # Syslog Hooks for Logrus :walrus: 2 | 3 | ## Usage 4 | 5 | ```go 6 | import ( 7 | "log/syslog" 8 | "github.com/Sirupsen/logrus" 9 | logrus_syslog "github.com/Sirupsen/logrus/hooks/syslog" 10 | ) 11 | 12 | func main() { 13 | log := logrus.New() 14 | hook, err := logrus_syslog.NewSyslogHook("udp", "localhost:514", syslog.LOG_INFO, "") 15 | 16 | if err == nil { 17 | log.Hooks.Add(hook) 18 | } 19 | } 20 | ``` 21 | -------------------------------------------------------------------------------- /vendor/src/github.com/Sirupsen/logrus/hooks/syslog/syslog.go: -------------------------------------------------------------------------------- 1 | package logrus_syslog 2 | 3 | import ( 4 | "fmt" 5 | "github.com/Sirupsen/logrus" 6 | "log/syslog" 7 | "os" 8 | ) 9 | 10 | // SyslogHook to send logs via syslog. 11 | type SyslogHook struct { 12 | Writer *syslog.Writer 13 | SyslogNetwork string 14 | SyslogRaddr string 15 | } 16 | 17 | // Creates a hook to be added to an instance of logger. This is called with 18 | // `hook, err := NewSyslogHook("udp", "localhost:514", syslog.LOG_DEBUG, "")` 19 | // `if err == nil { log.Hooks.Add(hook) }` 20 | func NewSyslogHook(network, raddr string, priority syslog.Priority, tag string) (*SyslogHook, error) { 21 | w, err := syslog.Dial(network, raddr, priority, tag) 22 | return &SyslogHook{w, network, raddr}, err 23 | } 24 | 25 | func (hook *SyslogHook) Fire(entry *logrus.Entry) error { 26 | line, err := entry.String() 27 | if err != nil { 28 | fmt.Fprintf(os.Stderr, "Unable to read entry, %v", err) 29 | return err 30 | } 31 | 32 | switch entry.Level { 33 | case logrus.PanicLevel: 34 | return hook.Writer.Crit(line) 35 | case logrus.FatalLevel: 36 | return hook.Writer.Crit(line) 37 | case logrus.ErrorLevel: 38 | return hook.Writer.Err(line) 39 | case logrus.WarnLevel: 40 | return hook.Writer.Warning(line) 41 | case logrus.InfoLevel: 42 | return hook.Writer.Info(line) 43 | case logrus.DebugLevel: 44 | return hook.Writer.Debug(line) 45 | default: 46 | return nil 47 | } 48 | } 49 | 50 | func (hook *SyslogHook) Levels() []logrus.Level { 51 | return []logrus.Level{ 52 | logrus.PanicLevel, 53 | logrus.FatalLevel, 54 | logrus.ErrorLevel, 55 | logrus.WarnLevel, 56 | logrus.InfoLevel, 57 | logrus.DebugLevel, 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /vendor/src/github.com/Sirupsen/logrus/hooks/syslog/syslog_test.go: -------------------------------------------------------------------------------- 1 | package logrus_syslog 2 | 3 | import ( 4 | "github.com/Sirupsen/logrus" 5 | "log/syslog" 6 | "testing" 7 | ) 8 | 9 | func TestLocalhostAddAndPrint(t *testing.T) { 10 | log := logrus.New() 11 | hook, err := NewSyslogHook("udp", "localhost:514", syslog.LOG_INFO, "") 12 | 13 | if err != nil { 14 | t.Errorf("Unable to connect to local syslog.") 15 | } 16 | 17 | log.Hooks.Add(hook) 18 | 19 | for _, level := range hook.Levels() { 20 | if len(log.Hooks[level]) != 1 { 21 | t.Errorf("SyslogHook was not added. The length of log.Hooks[%v]: %v", level, len(log.Hooks[level])) 22 | } 23 | } 24 | 25 | log.Info("Congratulations!") 26 | } 27 | -------------------------------------------------------------------------------- /vendor/src/github.com/Sirupsen/logrus/json_formatter.go: -------------------------------------------------------------------------------- 1 | package logrus 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | ) 7 | 8 | type JSONFormatter struct { 9 | // TimestampFormat sets the format used for marshaling timestamps. 10 | TimestampFormat string 11 | } 12 | 13 | func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) { 14 | data := make(Fields, len(entry.Data)+3) 15 | for k, v := range entry.Data { 16 | switch v := v.(type) { 17 | case error: 18 | // Otherwise errors are ignored by `encoding/json` 19 | // https://github.com/Sirupsen/logrus/issues/137 20 | data[k] = v.Error() 21 | default: 22 | data[k] = v 23 | } 24 | } 25 | prefixFieldClashes(data) 26 | 27 | timestampFormat := f.TimestampFormat 28 | if timestampFormat == "" { 29 | timestampFormat = DefaultTimestampFormat 30 | } 31 | 32 | data["time"] = entry.Time.Format(timestampFormat) 33 | data["msg"] = entry.Message 34 | data["level"] = entry.Level.String() 35 | 36 | serialized, err := json.Marshal(data) 37 | if err != nil { 38 | return nil, fmt.Errorf("Failed to marshal fields to JSON, %v", err) 39 | } 40 | return append(serialized, '\n'), nil 41 | } 42 | -------------------------------------------------------------------------------- /vendor/src/github.com/Sirupsen/logrus/logrus.go: -------------------------------------------------------------------------------- 1 | package logrus 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | ) 7 | 8 | // Fields type, used to pass to `WithFields`. 9 | type Fields map[string]interface{} 10 | 11 | // Level type 12 | type Level uint8 13 | 14 | // Convert the Level to a string. E.g. PanicLevel becomes "panic". 15 | func (level Level) String() string { 16 | switch level { 17 | case DebugLevel: 18 | return "debug" 19 | case InfoLevel: 20 | return "info" 21 | case WarnLevel: 22 | return "warning" 23 | case ErrorLevel: 24 | return "error" 25 | case FatalLevel: 26 | return "fatal" 27 | case PanicLevel: 28 | return "panic" 29 | } 30 | 31 | return "unknown" 32 | } 33 | 34 | // ParseLevel takes a string level and returns the Logrus log level constant. 35 | func ParseLevel(lvl string) (Level, error) { 36 | switch lvl { 37 | case "panic": 38 | return PanicLevel, nil 39 | case "fatal": 40 | return FatalLevel, nil 41 | case "error": 42 | return ErrorLevel, nil 43 | case "warn", "warning": 44 | return WarnLevel, nil 45 | case "info": 46 | return InfoLevel, nil 47 | case "debug": 48 | return DebugLevel, nil 49 | } 50 | 51 | var l Level 52 | return l, fmt.Errorf("not a valid logrus Level: %q", lvl) 53 | } 54 | 55 | // These are the different logging levels. You can set the logging level to log 56 | // on your instance of logger, obtained with `logrus.New()`. 57 | const ( 58 | // PanicLevel level, highest level of severity. Logs and then calls panic with the 59 | // message passed to Debug, Info, ... 60 | PanicLevel Level = iota 61 | // FatalLevel level. Logs and then calls `os.Exit(1)`. It will exit even if the 62 | // logging level is set to Panic. 63 | FatalLevel 64 | // ErrorLevel level. Logs. Used for errors that should definitely be noted. 65 | // Commonly used for hooks to send errors to an error tracking service. 66 | ErrorLevel 67 | // WarnLevel level. Non-critical entries that deserve eyes. 68 | WarnLevel 69 | // InfoLevel level. General operational entries about what's going on inside the 70 | // application. 71 | InfoLevel 72 | // DebugLevel level. Usually only enabled when debugging. Very verbose logging. 73 | DebugLevel 74 | ) 75 | 76 | // Won't compile if StdLogger can't be realized by a log.Logger 77 | var ( 78 | _ StdLogger = &log.Logger{} 79 | _ StdLogger = &Entry{} 80 | _ StdLogger = &Logger{} 81 | ) 82 | 83 | // StdLogger is what your logrus-enabled library should take, that way 84 | // it'll accept a stdlib logger and a logrus logger. There's no standard 85 | // interface, this is the closest we get, unfortunately. 86 | type StdLogger interface { 87 | Print(...interface{}) 88 | Printf(string, ...interface{}) 89 | Println(...interface{}) 90 | 91 | Fatal(...interface{}) 92 | Fatalf(string, ...interface{}) 93 | Fatalln(...interface{}) 94 | 95 | Panic(...interface{}) 96 | Panicf(string, ...interface{}) 97 | Panicln(...interface{}) 98 | } 99 | -------------------------------------------------------------------------------- /vendor/src/github.com/Sirupsen/logrus/terminal_bsd.go: -------------------------------------------------------------------------------- 1 | // +build darwin freebsd openbsd netbsd dragonfly 2 | 3 | package logrus 4 | 5 | import "syscall" 6 | 7 | const ioctlReadTermios = syscall.TIOCGETA 8 | 9 | type Termios syscall.Termios 10 | -------------------------------------------------------------------------------- /vendor/src/github.com/Sirupsen/logrus/terminal_linux.go: -------------------------------------------------------------------------------- 1 | // Based on ssh/terminal: 2 | // Copyright 2013 The Go Authors. All rights reserved. 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | 6 | package logrus 7 | 8 | import "syscall" 9 | 10 | const ioctlReadTermios = syscall.TCGETS 11 | 12 | type Termios syscall.Termios 13 | -------------------------------------------------------------------------------- /vendor/src/github.com/Sirupsen/logrus/terminal_notwindows.go: -------------------------------------------------------------------------------- 1 | // Based on ssh/terminal: 2 | // Copyright 2011 The Go Authors. All rights reserved. 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | 6 | // +build linux darwin freebsd openbsd netbsd dragonfly 7 | 8 | package logrus 9 | 10 | import ( 11 | "syscall" 12 | "unsafe" 13 | ) 14 | 15 | // IsTerminal returns true if the given file descriptor is a terminal. 16 | func IsTerminal() bool { 17 | fd := syscall.Stdout 18 | var termios Termios 19 | _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), ioctlReadTermios, uintptr(unsafe.Pointer(&termios)), 0, 0, 0) 20 | return err == 0 21 | } 22 | -------------------------------------------------------------------------------- /vendor/src/github.com/Sirupsen/logrus/terminal_windows.go: -------------------------------------------------------------------------------- 1 | // Based on ssh/terminal: 2 | // Copyright 2011 The Go Authors. All rights reserved. 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | 6 | // +build windows 7 | 8 | package logrus 9 | 10 | import ( 11 | "syscall" 12 | "unsafe" 13 | ) 14 | 15 | var kernel32 = syscall.NewLazyDLL("kernel32.dll") 16 | 17 | var ( 18 | procGetConsoleMode = kernel32.NewProc("GetConsoleMode") 19 | ) 20 | 21 | // IsTerminal returns true if the given file descriptor is a terminal. 22 | func IsTerminal() bool { 23 | fd := syscall.Stdout 24 | var st uint32 25 | r, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, uintptr(fd), uintptr(unsafe.Pointer(&st)), 0) 26 | return r != 0 && e == 0 27 | } 28 | -------------------------------------------------------------------------------- /vendor/src/github.com/Sirupsen/logrus/text_formatter_test.go: -------------------------------------------------------------------------------- 1 | package logrus 2 | 3 | import ( 4 | "bytes" 5 | "errors" 6 | "testing" 7 | "time" 8 | ) 9 | 10 | func TestQuoting(t *testing.T) { 11 | tf := &TextFormatter{DisableColors: true} 12 | 13 | checkQuoting := func(q bool, value interface{}) { 14 | b, _ := tf.Format(WithField("test", value)) 15 | idx := bytes.Index(b, ([]byte)("test=")) 16 | cont := bytes.Contains(b[idx+5:], []byte{'"'}) 17 | if cont != q { 18 | if q { 19 | t.Errorf("quoting expected for: %#v", value) 20 | } else { 21 | t.Errorf("quoting not expected for: %#v", value) 22 | } 23 | } 24 | } 25 | 26 | checkQuoting(false, "abcd") 27 | checkQuoting(false, "v1.0") 28 | checkQuoting(false, "1234567890") 29 | checkQuoting(true, "/foobar") 30 | checkQuoting(true, "x y") 31 | checkQuoting(true, "x,y") 32 | checkQuoting(false, errors.New("invalid")) 33 | checkQuoting(true, errors.New("invalid argument")) 34 | } 35 | 36 | func TestTimestampFormat(t *testing.T) { 37 | checkTimeStr := func(format string) { 38 | customFormatter := &TextFormatter{DisableColors: true, TimestampFormat: format} 39 | customStr, _ := customFormatter.Format(WithField("test", "test")) 40 | timeStart := bytes.Index(customStr, ([]byte)("time=")) 41 | timeEnd := bytes.Index(customStr, ([]byte)("level=")) 42 | timeStr := customStr[timeStart+5 : timeEnd-1] 43 | if timeStr[0] == '"' && timeStr[len(timeStr)-1] == '"' { 44 | timeStr = timeStr[1 : len(timeStr)-1] 45 | } 46 | if format == "" { 47 | format = time.RFC3339 48 | } 49 | _, e := time.Parse(format, (string)(timeStr)) 50 | if e != nil { 51 | t.Errorf("time string \"%s\" did not match provided time format \"%s\": %s", timeStr, format, e) 52 | } 53 | } 54 | 55 | checkTimeStr("2006-01-02T15:04:05.000000000Z07:00") 56 | checkTimeStr("Mon Jan _2 15:04:05 2006") 57 | checkTimeStr("") 58 | } 59 | 60 | // TODO add tests for sorting etc., this requires a parser for the text 61 | // formatter output. 62 | -------------------------------------------------------------------------------- /vendor/src/github.com/Sirupsen/logrus/writer.go: -------------------------------------------------------------------------------- 1 | package logrus 2 | 3 | import ( 4 | "bufio" 5 | "io" 6 | "runtime" 7 | ) 8 | 9 | func (logger *Logger) Writer() *io.PipeWriter { 10 | reader, writer := io.Pipe() 11 | 12 | go logger.writerScanner(reader) 13 | runtime.SetFinalizer(writer, writerFinalizer) 14 | 15 | return writer 16 | } 17 | 18 | func (logger *Logger) writerScanner(reader *io.PipeReader) { 19 | scanner := bufio.NewScanner(reader) 20 | for scanner.Scan() { 21 | logger.Print(scanner.Text()) 22 | } 23 | if err := scanner.Err(); err != nil { 24 | logger.Errorf("Error while reading from Writer: %s", err) 25 | } 26 | reader.Close() 27 | } 28 | 29 | func writerFinalizer(writer *io.PipeWriter) { 30 | writer.Close() 31 | } 32 | -------------------------------------------------------------------------------- /vendor/src/github.com/alecthomas/kingpin/COPYING: -------------------------------------------------------------------------------- 1 | Copyright (C) 2014 Alec Thomas 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | this software and associated documentation files (the "Software"), to deal in 5 | the Software without restriction, including without limitation the rights to 6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 7 | of the Software, and to permit persons to whom the Software is furnished to do 8 | so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | -------------------------------------------------------------------------------- /vendor/src/github.com/alecthomas/kingpin/actions.go: -------------------------------------------------------------------------------- 1 | package kingpin 2 | 3 | // Action callback executed at various stages after all values are populated. 4 | // The application, commands, arguments and flags all have corresponding 5 | // actions. 6 | type Action func(*ParseContext) error 7 | 8 | type actionMixin struct { 9 | actions []Action 10 | preActions []Action 11 | } 12 | 13 | type actionApplier interface { 14 | applyActions(*ParseContext) error 15 | applyPreActions(*ParseContext) error 16 | } 17 | 18 | func (a *actionMixin) addAction(action Action) { 19 | a.actions = append(a.actions, action) 20 | } 21 | 22 | func (a *actionMixin) addPreAction(action Action) { 23 | a.preActions = append(a.preActions, action) 24 | } 25 | 26 | func (a *actionMixin) applyActions(context *ParseContext) error { 27 | for _, action := range a.actions { 28 | if err := action(context); err != nil { 29 | return err 30 | } 31 | } 32 | return nil 33 | } 34 | 35 | func (a *actionMixin) applyPreActions(context *ParseContext) error { 36 | for _, preAction := range a.preActions { 37 | if err := preAction(context); err != nil { 38 | return err 39 | } 40 | } 41 | return nil 42 | } 43 | -------------------------------------------------------------------------------- /vendor/src/github.com/alecthomas/kingpin/args.go: -------------------------------------------------------------------------------- 1 | package kingpin 2 | 3 | import "fmt" 4 | 5 | type argGroup struct { 6 | args []*ArgClause 7 | } 8 | 9 | func newArgGroup() *argGroup { 10 | return &argGroup{} 11 | } 12 | 13 | func (a *argGroup) have() bool { 14 | return len(a.args) > 0 15 | } 16 | 17 | func (a *argGroup) Arg(name, help string) *ArgClause { 18 | arg := newArg(name, help) 19 | a.args = append(a.args, arg) 20 | return arg 21 | } 22 | 23 | func (a *argGroup) init() error { 24 | required := 0 25 | seen := map[string]struct{}{} 26 | previousArgMustBeLast := false 27 | for i, arg := range a.args { 28 | if previousArgMustBeLast { 29 | return fmt.Errorf("Args() can't be followed by another argument '%s'", arg.name) 30 | } 31 | if arg.consumesRemainder() { 32 | previousArgMustBeLast = true 33 | } 34 | if _, ok := seen[arg.name]; ok { 35 | return fmt.Errorf("duplicate argument '%s'", arg.name) 36 | } 37 | seen[arg.name] = struct{}{} 38 | if arg.required && required != i { 39 | return fmt.Errorf("required arguments found after non-required") 40 | } 41 | if arg.required { 42 | required++ 43 | } 44 | if err := arg.init(); err != nil { 45 | return err 46 | } 47 | } 48 | return nil 49 | } 50 | 51 | type ArgClause struct { 52 | actionMixin 53 | parserMixin 54 | name string 55 | help string 56 | defaultValue string 57 | required bool 58 | } 59 | 60 | func newArg(name, help string) *ArgClause { 61 | a := &ArgClause{ 62 | name: name, 63 | help: help, 64 | } 65 | return a 66 | } 67 | 68 | func (a *ArgClause) consumesRemainder() bool { 69 | if r, ok := a.value.(remainderArg); ok { 70 | return r.IsCumulative() 71 | } 72 | return false 73 | } 74 | 75 | // Required arguments must be input by the user. They can not have a Default() value provided. 76 | func (a *ArgClause) Required() *ArgClause { 77 | a.required = true 78 | return a 79 | } 80 | 81 | // Default value for this argument. It *must* be parseable by the value of the argument. 82 | func (a *ArgClause) Default(value string) *ArgClause { 83 | a.defaultValue = value 84 | return a 85 | } 86 | 87 | func (a *ArgClause) Action(action Action) *ArgClause { 88 | a.addAction(action) 89 | return a 90 | } 91 | 92 | func (a *ArgClause) PreAction(action Action) *ArgClause { 93 | a.addPreAction(action) 94 | return a 95 | } 96 | 97 | func (a *ArgClause) init() error { 98 | if a.required && a.defaultValue != "" { 99 | return fmt.Errorf("required argument '%s' with unusable default value", a.name) 100 | } 101 | if a.value == nil { 102 | return fmt.Errorf("no parser defined for arg '%s'", a.name) 103 | } 104 | return nil 105 | } 106 | -------------------------------------------------------------------------------- /vendor/src/github.com/alecthomas/kingpin/args_test.go: -------------------------------------------------------------------------------- 1 | package kingpin 2 | 3 | import ( 4 | "io/ioutil" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/assert" 8 | ) 9 | 10 | func TestArgRemainder(t *testing.T) { 11 | app := New("test", "") 12 | v := app.Arg("test", "").Strings() 13 | args := []string{"hello", "world"} 14 | _, err := app.Parse(args) 15 | assert.NoError(t, err) 16 | assert.Equal(t, args, *v) 17 | } 18 | 19 | func TestArgRemainderErrorsWhenNotLast(t *testing.T) { 20 | a := newArgGroup() 21 | a.Arg("test", "").Strings() 22 | a.Arg("test2", "").String() 23 | assert.Error(t, a.init()) 24 | } 25 | 26 | func TestArgMultipleRequired(t *testing.T) { 27 | terminated := false 28 | app := New("test", "") 29 | app.Version("0.0.0").Writer(ioutil.Discard) 30 | app.Arg("a", "").Required().String() 31 | app.Arg("b", "").Required().String() 32 | app.Terminate(func(int) { terminated = true }) 33 | 34 | _, err := app.Parse([]string{}) 35 | assert.Error(t, err) 36 | _, err = app.Parse([]string{"A"}) 37 | assert.Error(t, err) 38 | _, err = app.Parse([]string{"A", "B"}) 39 | assert.NoError(t, err) 40 | _, err = app.Parse([]string{"--version"}) 41 | assert.True(t, terminated) 42 | } 43 | 44 | func TestInvalidArgsDefaultCanBeOverridden(t *testing.T) { 45 | app := New("test", "") 46 | app.Arg("a", "").Default("invalid").Bool() 47 | _, err := app.Parse([]string{}) 48 | assert.Error(t, err) 49 | } 50 | -------------------------------------------------------------------------------- /vendor/src/github.com/alecthomas/kingpin/doc.go: -------------------------------------------------------------------------------- 1 | // Package kingpin provides command line interfaces like this: 2 | // 3 | // $ chat 4 | // usage: chat [] [] [ ...] 5 | // 6 | // Flags: 7 | // --debug enable debug mode 8 | // --help Show help. 9 | // --server=127.0.0.1 server address 10 | // 11 | // Commands: 12 | // help 13 | // Show help for a command. 14 | // 15 | // post [] 16 | // Post a message to a channel. 17 | // 18 | // register 19 | // Register a new user. 20 | // 21 | // $ chat help post 22 | // usage: chat [] post [] [] 23 | // 24 | // Post a message to a channel. 25 | // 26 | // Flags: 27 | // --image=IMAGE image to post 28 | // 29 | // Args: 30 | // channel to post to 31 | // [] text to post 32 | // $ chat post --image=~/Downloads/owls.jpg pics 33 | // 34 | // From code like this: 35 | // 36 | // package main 37 | // 38 | // import "gopkg.in/alecthomas/kingpin.v1" 39 | // 40 | // var ( 41 | // debug = kingpin.Flag("debug", "enable debug mode").Default("false").Bool() 42 | // serverIP = kingpin.Flag("server", "server address").Default("127.0.0.1").IP() 43 | // 44 | // register = kingpin.Command("register", "Register a new user.") 45 | // registerNick = register.Arg("nick", "nickname for user").Required().String() 46 | // registerName = register.Arg("name", "name of user").Required().String() 47 | // 48 | // post = kingpin.Command("post", "Post a message to a channel.") 49 | // postImage = post.Flag("image", "image to post").ExistingFile() 50 | // postChannel = post.Arg("channel", "channel to post to").Required().String() 51 | // postText = post.Arg("text", "text to post").String() 52 | // ) 53 | // 54 | // func main() { 55 | // switch kingpin.Parse() { 56 | // // Register user 57 | // case "register": 58 | // println(*registerNick) 59 | // 60 | // // Post message 61 | // case "post": 62 | // if *postImage != nil { 63 | // } 64 | // if *postText != "" { 65 | // } 66 | // } 67 | // } 68 | package kingpin 69 | -------------------------------------------------------------------------------- /vendor/src/github.com/alecthomas/kingpin/examples/chat1/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/alecthomas/kingpin" 7 | ) 8 | 9 | var ( 10 | debug = kingpin.Flag("debug", "Enable debug mode.").Bool() 11 | timeout = kingpin.Flag("timeout", "Timeout waiting for ping.").Default("5s").OverrideDefaultFromEnvar("PING_TIMEOUT").Short('t').Duration() 12 | ip = kingpin.Arg("ip", "IP address to ping.").Required().IP() 13 | count = kingpin.Arg("count", "Number of packets to send").Int() 14 | ) 15 | 16 | func main() { 17 | kingpin.Version("0.0.1") 18 | kingpin.Parse() 19 | fmt.Printf("Would ping: %s with timeout %s and count %d", *ip, *timeout, *count) 20 | } 21 | -------------------------------------------------------------------------------- /vendor/src/github.com/alecthomas/kingpin/examples/chat2/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "os" 5 | "strings" 6 | 7 | "github.com/alecthomas/kingpin" 8 | ) 9 | 10 | var ( 11 | app = kingpin.New("chat", "A command-line chat application.") 12 | debug = app.Flag("debug", "Enable debug mode.").Bool() 13 | serverIP = app.Flag("server", "Server address.").Default("127.0.0.1").IP() 14 | 15 | register = app.Command("register", "Register a new user.") 16 | registerNick = register.Arg("nick", "Nickname for user.").Required().String() 17 | registerName = register.Arg("name", "Name of user.").Required().String() 18 | 19 | post = app.Command("post", "Post a message to a channel.") 20 | postImage = post.Flag("image", "Image to post.").File() 21 | postChannel = post.Arg("channel", "Channel to post to.").Required().String() 22 | postText = post.Arg("text", "Text to post.").Strings() 23 | ) 24 | 25 | func main() { 26 | switch kingpin.MustParse(app.Parse(os.Args[1:])) { 27 | // Register user 28 | case register.FullCommand(): 29 | println(*registerNick) 30 | 31 | // Post message 32 | case post.FullCommand(): 33 | if *postImage != nil { 34 | } 35 | text := strings.Join(*postText, " ") 36 | println("Post:", text) 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /vendor/src/github.com/alecthomas/kingpin/examples/modular/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | 7 | "github.com/alecthomas/kingpin" 8 | ) 9 | 10 | // Context for "ls" command 11 | type LsCommand struct { 12 | All bool 13 | } 14 | 15 | func (l *LsCommand) run(c *kingpin.ParseContext) error { 16 | fmt.Printf("all=%v\n", l.All) 17 | return nil 18 | } 19 | 20 | func configureLsCommand(app *kingpin.Application) { 21 | c := &LsCommand{} 22 | ls := app.Command("ls", "List files.").Action(c.run) 23 | ls.Flag("all", "List all files.").Short('a').BoolVar(&c.All) 24 | } 25 | 26 | func main() { 27 | app := kingpin.New("modular", "My modular application.") 28 | configureLsCommand(app) 29 | kingpin.MustParse(app.Parse(os.Args[1:])) 30 | } 31 | -------------------------------------------------------------------------------- /vendor/src/github.com/alecthomas/kingpin/examples/ping/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/alecthomas/kingpin" 7 | ) 8 | 9 | var ( 10 | debug = kingpin.Flag("debug", "Enable debug mode.").Bool() 11 | timeout = kingpin.Flag("timeout", "Timeout waiting for ping.").OverrideDefaultFromEnvar("PING_TIMEOUT").Required().Short('t').Duration() 12 | ip = kingpin.Arg("ip", "IP address to ping.").Required().IP() 13 | count = kingpin.Arg("count", "Number of packets to send").Int() 14 | ) 15 | 16 | func main() { 17 | kingpin.Version("0.0.1") 18 | kingpin.Parse() 19 | fmt.Printf("Would ping: %s with timeout %s and count %d", *ip, *timeout, *count) 20 | } 21 | -------------------------------------------------------------------------------- /vendor/src/github.com/alecthomas/kingpin/examples_test.go: -------------------------------------------------------------------------------- 1 | package kingpin 2 | 3 | import ( 4 | "fmt" 5 | "net/http" 6 | "strings" 7 | ) 8 | 9 | type HTTPHeaderValue http.Header 10 | 11 | func (h *HTTPHeaderValue) Set(value string) error { 12 | parts := strings.SplitN(value, ":", 2) 13 | if len(parts) != 2 { 14 | return fmt.Errorf("expected HEADER:VALUE got '%s'", value) 15 | } 16 | (*http.Header)(h).Add(parts[0], parts[1]) 17 | return nil 18 | } 19 | 20 | func (h *HTTPHeaderValue) String() string { 21 | return "" 22 | } 23 | 24 | func HTTPHeader(s Settings) (target *http.Header) { 25 | target = new(http.Header) 26 | s.SetValue((*HTTPHeaderValue)(target)) 27 | return 28 | } 29 | 30 | // This example ilustrates how to define custom parsers. HTTPHeader 31 | // cumulatively parses each encountered --header flag into a http.Header struct. 32 | func ExampleValue() { 33 | var ( 34 | curl = New("curl", "transfer a URL") 35 | headers = HTTPHeader(curl.Flag("headers", "Add HTTP headers to the request.").Short('H').PlaceHolder("HEADER:VALUE")) 36 | ) 37 | 38 | curl.Parse([]string{"-H Content-Type:application/octet-stream"}) 39 | for key, value := range *headers { 40 | fmt.Printf("%s = %s\n", key, value) 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /vendor/src/github.com/alecthomas/kingpin/global.go: -------------------------------------------------------------------------------- 1 | package kingpin 2 | 3 | import ( 4 | "os" 5 | "path/filepath" 6 | ) 7 | 8 | var ( 9 | // CommandLine is the default Kingpin parser. 10 | CommandLine = New(filepath.Base(os.Args[0]), "") 11 | ) 12 | 13 | // Command adds a new command to the default parser. 14 | func Command(name, help string) *CmdClause { 15 | return CommandLine.Command(name, help) 16 | } 17 | 18 | // Flag adds a new flag to the default parser. 19 | func Flag(name, help string) *FlagClause { 20 | return CommandLine.Flag(name, help) 21 | } 22 | 23 | // Arg adds a new argument to the top-level of the default parser. 24 | func Arg(name, help string) *ArgClause { 25 | return CommandLine.Arg(name, help) 26 | } 27 | 28 | // Parse and return the selected command. Will call the termination handler if 29 | // an error is encountered. 30 | func Parse() string { 31 | selected := MustParse(CommandLine.Parse(os.Args[1:])) 32 | if selected == "" && CommandLine.cmdGroup.have() { 33 | Usage() 34 | CommandLine.terminate(0) 35 | } 36 | return selected 37 | } 38 | 39 | // Errorf prints an error message to stderr. 40 | func Errorf(format string, args ...interface{}) { 41 | CommandLine.Errorf(format, args...) 42 | } 43 | 44 | // Fatalf prints an error message to stderr and exits. 45 | func Fatalf(format string, args ...interface{}) { 46 | CommandLine.Fatalf(format, args...) 47 | } 48 | 49 | // FatalIfError prints an error and exits if err is not nil. The error is printed 50 | // with the given prefix. 51 | func FatalIfError(err error, format string, args ...interface{}) { 52 | CommandLine.FatalIfError(err, format, args...) 53 | } 54 | 55 | // FatalUsage prints an error message followed by usage information, then 56 | // exits with a non-zero status. 57 | func FatalUsage(format string, args ...interface{}) { 58 | CommandLine.FatalUsage(format, args...) 59 | } 60 | 61 | // FatalUsageContext writes a printf formatted error message to stderr, then 62 | // usage information for the given ParseContext, before exiting. 63 | func FatalUsageContext(context *ParseContext, format string, args ...interface{}) { 64 | CommandLine.FatalUsageContext(context, format, args...) 65 | } 66 | 67 | // Usage prints usage to stderr. 68 | func Usage() { 69 | CommandLine.Usage(os.Args[1:]) 70 | } 71 | 72 | // Set global usage template to use (defaults to DefaultUsageTemplate). 73 | func UsageTemplate(template string) *Application { 74 | return CommandLine.UsageTemplate(template) 75 | } 76 | 77 | // MustParse can be used with app.Parse(args) to exit with an error if parsing fails. 78 | func MustParse(command string, err error) string { 79 | if err != nil { 80 | Fatalf("%s, try --help", err) 81 | } 82 | return command 83 | } 84 | 85 | // Version adds a flag for displaying the application version number. 86 | func Version(version string) *Application { 87 | return CommandLine.Version(version) 88 | } 89 | -------------------------------------------------------------------------------- /vendor/src/github.com/alecthomas/kingpin/guesswidth.go: -------------------------------------------------------------------------------- 1 | // +build !linux,!freebsd,!darwin,!dragonfly,!netbsd,!openbsd 2 | 3 | package kingpin 4 | 5 | import "io" 6 | 7 | func guessWidth(w io.Writer) int { 8 | return 80 9 | } 10 | -------------------------------------------------------------------------------- /vendor/src/github.com/alecthomas/kingpin/guesswidth_unix.go: -------------------------------------------------------------------------------- 1 | // +build linux freebsd darwin dragonfly netbsd openbsd 2 | 3 | package kingpin 4 | 5 | import ( 6 | "io" 7 | "os" 8 | "strconv" 9 | "syscall" 10 | "unsafe" 11 | ) 12 | 13 | func guessWidth(w io.Writer) int { 14 | // check if COLUMNS env is set to comply with 15 | // http://pubs.opengroup.org/onlinepubs/009604499/basedefs/xbd_chap08.html 16 | colsStr := os.Getenv("COLUMNS") 17 | if colsStr != "" { 18 | if cols, err := strconv.Atoi(colsStr); err == nil { 19 | return cols 20 | } 21 | } 22 | 23 | if t, ok := w.(*os.File); ok { 24 | fd := t.Fd() 25 | var dimensions [4]uint16 26 | 27 | if _, _, err := syscall.Syscall6( 28 | syscall.SYS_IOCTL, 29 | uintptr(fd), 30 | uintptr(syscall.TIOCGWINSZ), 31 | uintptr(unsafe.Pointer(&dimensions)), 32 | 0, 0, 0, 33 | ); err == 0 { 34 | return int(dimensions[1]) 35 | } 36 | } 37 | return 80 38 | } 39 | -------------------------------------------------------------------------------- /vendor/src/github.com/alecthomas/kingpin/parser_test.go: -------------------------------------------------------------------------------- 1 | package kingpin 2 | 3 | import ( 4 | "io/ioutil" 5 | "os" 6 | "testing" 7 | 8 | "github.com/stretchr/testify/assert" 9 | ) 10 | 11 | func TestParserExpandFromFile(t *testing.T) { 12 | f, err := ioutil.TempFile("", "") 13 | assert.NoError(t, err) 14 | defer os.Remove(f.Name()) 15 | f.WriteString("hello\nworld\n") 16 | f.Close() 17 | 18 | app := New("test", "") 19 | arg0 := app.Arg("arg0", "").String() 20 | arg1 := app.Arg("arg1", "").String() 21 | 22 | _, err = app.Parse([]string{"@" + f.Name()}) 23 | assert.NoError(t, err) 24 | assert.Equal(t, "hello", *arg0) 25 | assert.Equal(t, "world", *arg1) 26 | } 27 | 28 | func TestParseContextPush(t *testing.T) { 29 | app := New("test", "") 30 | app.Command("foo", "").Command("bar", "") 31 | c := tokenize([]string{"foo", "bar"}) 32 | a := c.Next() 33 | assert.Equal(t, TokenArg, a.Type) 34 | b := c.Next() 35 | assert.Equal(t, TokenArg, b.Type) 36 | c.Push(b) 37 | c.Push(a) 38 | a = c.Next() 39 | assert.Equal(t, "foo", a.Value) 40 | b = c.Next() 41 | assert.Equal(t, "bar", b.Value) 42 | } 43 | -------------------------------------------------------------------------------- /vendor/src/github.com/alecthomas/kingpin/parsers_test.go: -------------------------------------------------------------------------------- 1 | package kingpin 2 | 3 | import ( 4 | "io/ioutil" 5 | "net" 6 | "net/url" 7 | "os" 8 | 9 | "github.com/stretchr/testify/assert" 10 | 11 | "testing" 12 | ) 13 | 14 | func TestParseStrings(t *testing.T) { 15 | p := parserMixin{} 16 | v := p.Strings() 17 | p.value.Set("a") 18 | p.value.Set("b") 19 | assert.Equal(t, []string{"a", "b"}, *v) 20 | } 21 | 22 | func TestStringsStringer(t *testing.T) { 23 | target := []string{} 24 | v := newAccumulator(&target, func(v interface{}) Value { return newStringValue(v.(*string)) }) 25 | v.Set("hello") 26 | v.Set("world") 27 | assert.Equal(t, "hello,world", v.String()) 28 | } 29 | 30 | func TestParseStringMap(t *testing.T) { 31 | p := parserMixin{} 32 | v := p.StringMap() 33 | p.value.Set("a:b") 34 | p.value.Set("b:c") 35 | assert.Equal(t, map[string]string{"a": "b", "b": "c"}, *v) 36 | } 37 | 38 | func TestParseIP(t *testing.T) { 39 | p := parserMixin{} 40 | v := p.IP() 41 | p.value.Set("10.1.1.2") 42 | ip := net.ParseIP("10.1.1.2") 43 | assert.Equal(t, ip, *v) 44 | } 45 | 46 | func TestParseURL(t *testing.T) { 47 | p := parserMixin{} 48 | v := p.URL() 49 | p.value.Set("http://w3.org") 50 | u, err := url.Parse("http://w3.org") 51 | assert.NoError(t, err) 52 | assert.Equal(t, *u, **v) 53 | } 54 | 55 | func TestParseExistingFile(t *testing.T) { 56 | f, err := ioutil.TempFile("", "") 57 | if err != nil { 58 | t.Fatal(err) 59 | } 60 | defer f.Close() 61 | defer os.Remove(f.Name()) 62 | 63 | p := parserMixin{} 64 | v := p.ExistingFile() 65 | err = p.value.Set(f.Name()) 66 | assert.NoError(t, err) 67 | assert.Equal(t, f.Name(), *v) 68 | err = p.value.Set("/etc/hostsDEFINITELYMISSING") 69 | assert.Error(t, err) 70 | } 71 | 72 | func TestParseTCPAddr(t *testing.T) { 73 | p := parserMixin{} 74 | v := p.TCP() 75 | err := p.value.Set("127.0.0.1:1234") 76 | assert.NoError(t, err) 77 | expected, err := net.ResolveTCPAddr("tcp", "127.0.0.1:1234") 78 | assert.NoError(t, err) 79 | assert.Equal(t, *expected, **v) 80 | } 81 | 82 | func TestParseTCPAddrList(t *testing.T) { 83 | p := parserMixin{} 84 | _ = p.TCPList() 85 | err := p.value.Set("127.0.0.1:1234") 86 | assert.NoError(t, err) 87 | err = p.value.Set("127.0.0.1:1235") 88 | assert.NoError(t, err) 89 | assert.Equal(t, "127.0.0.1:1234,127.0.0.1:1235", p.value.String()) 90 | } 91 | 92 | func TestFloat32(t *testing.T) { 93 | p := parserMixin{} 94 | v := p.Float32() 95 | err := p.value.Set("123.45") 96 | assert.NoError(t, err) 97 | assert.InEpsilon(t, 123.45, *v, 0.001) 98 | } 99 | -------------------------------------------------------------------------------- /vendor/src/github.com/alecthomas/kingpin/usage_test.go: -------------------------------------------------------------------------------- 1 | package kingpin 2 | 3 | import ( 4 | "bytes" 5 | "strings" 6 | "testing" 7 | 8 | "github.com/stretchr/testify/assert" 9 | ) 10 | 11 | func TestFormatTwoColumns(t *testing.T) { 12 | buf := bytes.NewBuffer(nil) 13 | formatTwoColumns(buf, 2, 2, 20, [][2]string{ 14 | {"--hello", "Hello world help with something that is cool."}, 15 | }) 16 | expected := ` --hello Hello 17 | world 18 | help with 19 | something 20 | that is 21 | cool. 22 | ` 23 | assert.Equal(t, expected, buf.String()) 24 | } 25 | 26 | func TestFormatTwoColumnsWide(t *testing.T) { 27 | samples := [][2]string{ 28 | {strings.Repeat("x", 29), "29 chars"}, 29 | {strings.Repeat("x", 30), "30 chars"}} 30 | buf := bytes.NewBuffer(nil) 31 | formatTwoColumns(buf, 0, 0, 200, samples) 32 | expected := `xxxxxxxxxxxxxxxxxxxxxxxxxxxxx29 chars 33 | xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 34 | 30 chars 35 | ` 36 | assert.Equal(t, expected, buf.String()) 37 | } 38 | 39 | func TestHiddenCommand(t *testing.T) { 40 | templates := []struct{ name, template string }{ 41 | {"default", DefaultUsageTemplate}, 42 | {"Compact", CompactUsageTemplate}, 43 | {"Long", LongHelpTemplate}, 44 | {"Man", ManPageTemplate}, 45 | } 46 | 47 | var buf bytes.Buffer 48 | t.Log("1") 49 | 50 | a := New("test", "Test").Writer(&buf).Terminate(nil) 51 | a.Command("visible", "visible") 52 | a.Command("hidden", "hidden").Hidden() 53 | 54 | for _, tp := range templates { 55 | buf.Reset() 56 | a.UsageTemplate(tp.template) 57 | a.Parse(nil) 58 | // a.Parse([]string{"--help"}) 59 | usage := buf.String() 60 | t.Logf("Usage for %s is:\n%s\n", tp.name, usage) 61 | 62 | assert.NotContains(t, usage, "hidden") 63 | assert.Contains(t, usage, "visible") 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /vendor/src/github.com/alecthomas/kingpin/values.json: -------------------------------------------------------------------------------- 1 | [ 2 | {"type": "bool", "parser": "strconv.ParseBool(s)"}, 3 | {"type": "string", "parser": "s, error(nil)", "format": "string(*f)", "plural": "Strings"}, 4 | {"type": "uint", "parser": "strconv.ParseUint(s, 0, 64)", "plural": "Uints"}, 5 | {"type": "uint8", "parser": "strconv.ParseUint(s, 0, 8)"}, 6 | {"type": "uint16", "parser": "strconv.ParseUint(s, 0, 16)"}, 7 | {"type": "uint32", "parser": "strconv.ParseUint(s, 0, 32)"}, 8 | {"type": "uint64", "parser": "strconv.ParseUint(s, 0, 64)"}, 9 | {"type": "int", "parser": "strconv.ParseFloat(s, 64)", "plural": "Ints"}, 10 | {"type": "int8", "parser": "strconv.ParseInt(s, 0, 8)"}, 11 | {"type": "int16", "parser": "strconv.ParseInt(s, 0, 16)"}, 12 | {"type": "int32", "parser": "strconv.ParseInt(s, 0, 32)"}, 13 | {"type": "int64", "parser": "strconv.ParseInt(s, 0, 64)"}, 14 | {"type": "float64", "parser": "strconv.ParseFloat(s, 64)"}, 15 | {"type": "float32", "parser": "strconv.ParseFloat(s, 32)"}, 16 | {"name": "Duration", "type": "time.Duration", "no_value_parser": true}, 17 | {"name": "IP", "type": "net.IP", "no_value_parser": true}, 18 | {"name": "TCPAddr", "Type": "*net.TCPAddr", "plural": "TCPList", "no_value_parser": true}, 19 | {"name": "ExistingFile", "Type": "string", "plural": "ExistingFiles", "no_value_parser": true}, 20 | {"name": "ExistingDir", "Type": "string", "plural": "ExistingDirs", "no_value_parser": true}, 21 | {"name": "ExistingFileOrDir", "Type": "string", "plural": "ExistingFilesOrDirs", "no_value_parser": true} 22 | ] 23 | -------------------------------------------------------------------------------- /vendor/src/github.com/alecthomas/kingpin/values_test.go: -------------------------------------------------------------------------------- 1 | package kingpin 2 | 3 | import ( 4 | "github.com/stretchr/testify/assert" 5 | 6 | "testing" 7 | ) 8 | 9 | func TestAccumulatorStrings(t *testing.T) { 10 | target := []string{} 11 | acc := newAccumulator(&target, func(v interface{}) Value { return newStringValue(v.(*string)) }) 12 | acc.Set("a") 13 | assert.Equal(t, []string{"a"}, target) 14 | acc.Set("b") 15 | assert.Equal(t, []string{"a", "b"}, target) 16 | } 17 | 18 | func TestStrings(t *testing.T) { 19 | app := New("", "") 20 | app.Arg("a", "").Required().String() 21 | app.Arg("b", "").Required().String() 22 | c := app.Arg("c", "").Required().Strings() 23 | app.Parse([]string{"a", "b", "a", "b"}) 24 | assert.Equal(t, []string{"a", "b"}, *c) 25 | } 26 | 27 | func TestEnum(t *testing.T) { 28 | app := New("", "") 29 | a := app.Arg("a", "").Enum("one", "two", "three") 30 | _, err := app.Parse([]string{"moo"}) 31 | assert.Error(t, err) 32 | _, err = app.Parse([]string{"one"}) 33 | assert.NoError(t, err) 34 | assert.Equal(t, "one", *a) 35 | } 36 | 37 | func TestEnumVar(t *testing.T) { 38 | app := New("", "") 39 | var a string 40 | app.Arg("a", "").EnumVar(&a, "one", "two", "three") 41 | _, err := app.Parse([]string{"moo"}) 42 | assert.Error(t, err) 43 | _, err = app.Parse([]string{"one"}) 44 | assert.NoError(t, err) 45 | assert.Equal(t, "one", a) 46 | } 47 | -------------------------------------------------------------------------------- /vendor/src/github.com/alecthomas/template/README.md: -------------------------------------------------------------------------------- 1 | # Go's `text/template` package with newline elision 2 | 3 | This is a fork of Go 1.4's [text/template](http://golang.org/pkg/text/template/) package with one addition: a backslash immediately after a closing delimiter will delete all subsequent newlines until a non-newline. 4 | 5 | eg. 6 | 7 | ``` 8 | {{if true}}\ 9 | hello 10 | {{end}}\ 11 | ``` 12 | 13 | Will result in: 14 | 15 | ``` 16 | hello\n 17 | ``` 18 | 19 | Rather than: 20 | 21 | ``` 22 | \n 23 | hello\n 24 | \n 25 | ``` 26 | -------------------------------------------------------------------------------- /vendor/src/github.com/alecthomas/template/example_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2011 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package template_test 6 | 7 | import ( 8 | "log" 9 | "os" 10 | "github.com/alecthomas/template" 11 | ) 12 | 13 | func ExampleTemplate() { 14 | // Define a template. 15 | const letter = ` 16 | Dear {{.Name}}, 17 | {{if .Attended}} 18 | It was a pleasure to see you at the wedding.{{else}} 19 | It is a shame you couldn't make it to the wedding.{{end}} 20 | {{with .Gift}}Thank you for the lovely {{.}}. 21 | {{end}} 22 | Best wishes, 23 | Josie 24 | ` 25 | 26 | // Prepare some data to insert into the template. 27 | type Recipient struct { 28 | Name, Gift string 29 | Attended bool 30 | } 31 | var recipients = []Recipient{ 32 | {"Aunt Mildred", "bone china tea set", true}, 33 | {"Uncle John", "moleskin pants", false}, 34 | {"Cousin Rodney", "", false}, 35 | } 36 | 37 | // Create a new template and parse the letter into it. 38 | t := template.Must(template.New("letter").Parse(letter)) 39 | 40 | // Execute the template for each recipient. 41 | for _, r := range recipients { 42 | err := t.Execute(os.Stdout, r) 43 | if err != nil { 44 | log.Println("executing template:", err) 45 | } 46 | } 47 | 48 | // Output: 49 | // Dear Aunt Mildred, 50 | // 51 | // It was a pleasure to see you at the wedding. 52 | // Thank you for the lovely bone china tea set. 53 | // 54 | // Best wishes, 55 | // Josie 56 | // 57 | // Dear Uncle John, 58 | // 59 | // It is a shame you couldn't make it to the wedding. 60 | // Thank you for the lovely moleskin pants. 61 | // 62 | // Best wishes, 63 | // Josie 64 | // 65 | // Dear Cousin Rodney, 66 | // 67 | // It is a shame you couldn't make it to the wedding. 68 | // 69 | // Best wishes, 70 | // Josie 71 | } 72 | -------------------------------------------------------------------------------- /vendor/src/github.com/alecthomas/template/examplefunc_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2012 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package template_test 6 | 7 | import ( 8 | "log" 9 | "os" 10 | "strings" 11 | "github.com/alecthomas/template" 12 | ) 13 | 14 | // This example demonstrates a custom function to process template text. 15 | // It installs the strings.Title function and uses it to 16 | // Make Title Text Look Good In Our Template's Output. 17 | func ExampleTemplate_func() { 18 | // First we create a FuncMap with which to register the function. 19 | funcMap := template.FuncMap{ 20 | // The name "title" is what the function will be called in the template text. 21 | "title": strings.Title, 22 | } 23 | 24 | // A simple template definition to test our function. 25 | // We print the input text several ways: 26 | // - the original 27 | // - title-cased 28 | // - title-cased and then printed with %q 29 | // - printed with %q and then title-cased. 30 | const templateText = ` 31 | Input: {{printf "%q" .}} 32 | Output 0: {{title .}} 33 | Output 1: {{title . | printf "%q"}} 34 | Output 2: {{printf "%q" . | title}} 35 | ` 36 | 37 | // Create a template, add the function map, and parse the text. 38 | tmpl, err := template.New("titleTest").Funcs(funcMap).Parse(templateText) 39 | if err != nil { 40 | log.Fatalf("parsing: %s", err) 41 | } 42 | 43 | // Run the template to verify the output. 44 | err = tmpl.Execute(os.Stdout, "the go programming language") 45 | if err != nil { 46 | log.Fatalf("execution: %s", err) 47 | } 48 | 49 | // Output: 50 | // Input: "the go programming language" 51 | // Output 0: The Go Programming Language 52 | // Output 1: "The Go Programming Language" 53 | // Output 2: "The Go Programming Language" 54 | } 55 | -------------------------------------------------------------------------------- /vendor/src/github.com/alecthomas/template/testdata/file1.tmpl: -------------------------------------------------------------------------------- 1 | {{define "x"}}TEXT{{end}} 2 | {{define "dotV"}}{{.V}}{{end}} 3 | -------------------------------------------------------------------------------- /vendor/src/github.com/alecthomas/template/testdata/file2.tmpl: -------------------------------------------------------------------------------- 1 | {{define "dot"}}{{.}}{{end}} 2 | {{define "nested"}}{{template "dot" .}}{{end}} 3 | -------------------------------------------------------------------------------- /vendor/src/github.com/alecthomas/template/testdata/tmpl1.tmpl: -------------------------------------------------------------------------------- 1 | template1 2 | {{define "x"}}x{{end}} 3 | {{template "y"}} 4 | -------------------------------------------------------------------------------- /vendor/src/github.com/alecthomas/template/testdata/tmpl2.tmpl: -------------------------------------------------------------------------------- 1 | template2 2 | {{define "y"}}y{{end}} 3 | {{template "x"}} 4 | -------------------------------------------------------------------------------- /vendor/src/github.com/alecthomas/units/COPYING: -------------------------------------------------------------------------------- 1 | Copyright (C) 2014 Alec Thomas 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | this software and associated documentation files (the "Software"), to deal in 5 | the Software without restriction, including without limitation the rights to 6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 7 | of the Software, and to permit persons to whom the Software is furnished to do 8 | so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | -------------------------------------------------------------------------------- /vendor/src/github.com/alecthomas/units/README.md: -------------------------------------------------------------------------------- 1 | # Units - Helpful unit multipliers and functions for Go 2 | 3 | The goal of this package is to have functionality similar to the [time](http://golang.org/pkg/time/) package. 4 | 5 | It allows for code like this: 6 | 7 | ```go 8 | n, err := ParseBase2Bytes("1KB") 9 | // n == 1024 10 | n = units.Mebibyte * 512 11 | ``` 12 | -------------------------------------------------------------------------------- /vendor/src/github.com/alecthomas/units/bytes.go: -------------------------------------------------------------------------------- 1 | package units 2 | 3 | // Base2Bytes is the old non-SI power-of-2 byte scale (1024 bytes in a kilobyte, 4 | // etc.). 5 | type Base2Bytes int64 6 | 7 | // Base-2 byte units. 8 | const ( 9 | Kibibyte Base2Bytes = 1024 10 | KiB = Kibibyte 11 | Mebibyte = Kibibyte * 1024 12 | MiB = Mebibyte 13 | Gibibyte = Mebibyte * 1024 14 | GiB = Gibibyte 15 | Tebibyte = Gibibyte * 1024 16 | TiB = Tebibyte 17 | Pebibyte = Tebibyte * 1024 18 | PiB = Pebibyte 19 | Exbibyte = Pebibyte * 1024 20 | EiB = Exbibyte 21 | ) 22 | 23 | var ( 24 | bytesUnitMap = MakeUnitMap("iB", "B", 1024) 25 | oldBytesUnitMap = MakeUnitMap("B", "B", 1024) 26 | ) 27 | 28 | // ParseBase2Bytes supports both iB and B in base-2 multipliers. That is, KB 29 | // and KiB are both 1024. 30 | func ParseBase2Bytes(s string) (Base2Bytes, error) { 31 | n, err := ParseUnit(s, bytesUnitMap) 32 | if err != nil { 33 | n, err = ParseUnit(s, oldBytesUnitMap) 34 | } 35 | return Base2Bytes(n), err 36 | } 37 | 38 | func (b Base2Bytes) String() string { 39 | return ToString(int64(b), 1024, "iB", "B") 40 | } 41 | 42 | var ( 43 | metricBytesUnitMap = MakeUnitMap("B", "B", 1000) 44 | ) 45 | 46 | // MetricBytes are SI byte units (1000 bytes in a kilobyte). 47 | type MetricBytes SI 48 | 49 | // SI base-10 byte units. 50 | const ( 51 | Kilobyte MetricBytes = 1000 52 | KB = Kilobyte 53 | Megabyte = Kilobyte * 1000 54 | MB = Megabyte 55 | Gigabyte = Megabyte * 1000 56 | GB = Gigabyte 57 | Terabyte = Gigabyte * 1000 58 | TB = Terabyte 59 | Petabyte = Terabyte * 1000 60 | PB = Petabyte 61 | Exabyte = Petabyte * 1000 62 | EB = Exabyte 63 | ) 64 | 65 | // ParseMetricBytes parses base-10 metric byte units. That is, KB is 1000 bytes. 66 | func ParseMetricBytes(s string) (MetricBytes, error) { 67 | n, err := ParseUnit(s, metricBytesUnitMap) 68 | return MetricBytes(n), err 69 | } 70 | 71 | func (m MetricBytes) String() string { 72 | return ToString(int64(m), 1000, "B", "B") 73 | } 74 | 75 | // ParseStrictBytes supports both iB and B suffixes for base 2 and metric, 76 | // respectively. That is, KiB represents 1024 and KB represents 1000. 77 | func ParseStrictBytes(s string) (int64, error) { 78 | n, err := ParseUnit(s, bytesUnitMap) 79 | if err != nil { 80 | n, err = ParseUnit(s, metricBytesUnitMap) 81 | } 82 | return int64(n), err 83 | } 84 | -------------------------------------------------------------------------------- /vendor/src/github.com/alecthomas/units/bytes_test.go: -------------------------------------------------------------------------------- 1 | package units 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | ) 8 | 9 | func TestBase2BytesString(t *testing.T) { 10 | assert.Equal(t, Base2Bytes(0).String(), "0B") 11 | assert.Equal(t, Base2Bytes(1025).String(), "1KiB1B") 12 | assert.Equal(t, Base2Bytes(1048577).String(), "1MiB1B") 13 | } 14 | 15 | func TestParseBase2Bytes(t *testing.T) { 16 | n, err := ParseBase2Bytes("0B") 17 | assert.NoError(t, err) 18 | assert.Equal(t, 0, n) 19 | n, err = ParseBase2Bytes("1KB") 20 | assert.NoError(t, err) 21 | assert.Equal(t, 1024, n) 22 | n, err = ParseBase2Bytes("1MB1KB25B") 23 | assert.NoError(t, err) 24 | assert.Equal(t, 1049625, n) 25 | n, err = ParseBase2Bytes("1.5MB") 26 | assert.NoError(t, err) 27 | assert.Equal(t, 1572864, n) 28 | } 29 | 30 | func TestMetricBytesString(t *testing.T) { 31 | assert.Equal(t, MetricBytes(0).String(), "0B") 32 | assert.Equal(t, MetricBytes(1001).String(), "1KB1B") 33 | assert.Equal(t, MetricBytes(1001025).String(), "1MB1KB25B") 34 | } 35 | 36 | func TestParseMetricBytes(t *testing.T) { 37 | n, err := ParseMetricBytes("0B") 38 | assert.NoError(t, err) 39 | assert.Equal(t, 0, n) 40 | n, err = ParseMetricBytes("1KB1B") 41 | assert.NoError(t, err) 42 | assert.Equal(t, 1001, n) 43 | n, err = ParseMetricBytes("1MB1KB25B") 44 | assert.NoError(t, err) 45 | assert.Equal(t, 1001025, n) 46 | n, err = ParseMetricBytes("1.5MB") 47 | assert.NoError(t, err) 48 | assert.Equal(t, 1500000, n) 49 | } 50 | -------------------------------------------------------------------------------- /vendor/src/github.com/alecthomas/units/doc.go: -------------------------------------------------------------------------------- 1 | // Package units provides helpful unit multipliers and functions for Go. 2 | // 3 | // The goal of this package is to have functionality similar to the time [1] package. 4 | // 5 | // 6 | // [1] http://golang.org/pkg/time/ 7 | // 8 | // It allows for code like this: 9 | // 10 | // n, err := ParseBase2Bytes("1KB") 11 | // // n == 1024 12 | // n = units.Mebibyte * 512 13 | package units 14 | -------------------------------------------------------------------------------- /vendor/src/github.com/alecthomas/units/si.go: -------------------------------------------------------------------------------- 1 | package units 2 | 3 | // SI units. 4 | type SI int64 5 | 6 | // SI unit multiples. 7 | const ( 8 | Kilo SI = 1000 9 | Mega = Kilo * 1000 10 | Giga = Mega * 1000 11 | Tera = Giga * 1000 12 | Peta = Tera * 1000 13 | Exa = Peta * 1000 14 | ) 15 | 16 | func MakeUnitMap(suffix, shortSuffix string, scale int64) map[string]float64 { 17 | return map[string]float64{ 18 | shortSuffix: 1, 19 | "K" + suffix: float64(scale), 20 | "M" + suffix: float64(scale * scale), 21 | "G" + suffix: float64(scale * scale * scale), 22 | "T" + suffix: float64(scale * scale * scale * scale), 23 | "P" + suffix: float64(scale * scale * scale * scale * scale), 24 | "E" + suffix: float64(scale * scale * scale * scale * scale * scale), 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /vendor/src/github.com/bugsnag/bugsnag-go/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | 1.0.4 2 | ----- 3 | 4 | - Fix appengine integration broken by 1.0.3 5 | 6 | 1.0.3 7 | ----- 8 | 9 | - Allow any Logger with a Printf method. 10 | 11 | 1.0.2 12 | ----- 13 | 14 | - Use bugsnag copies of dependencies to avoid potential link rot 15 | 16 | 1.0.1 17 | ----- 18 | 19 | - gofmt/golint/govet docs improvements. 20 | 21 | 1.0.0 22 | ----- 23 | -------------------------------------------------------------------------------- /vendor/src/github.com/bugsnag/bugsnag-go/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | Contributing 2 | ============ 3 | 4 | - [Fork](https://help.github.com/articles/fork-a-repo) the [notifier on github](https://github.com/bugsnag/bugsnag-go) 5 | - Build and test your changes 6 | - Commit and push until you are happy with your contribution 7 | - [Make a pull request](https://help.github.com/articles/using-pull-requests) 8 | - Thanks! 9 | 10 | 11 | Installing the go development environment 12 | ------------------------------------- 13 | 14 | 1. Install homebrew 15 | 16 | ``` 17 | ruby -e "$(curl -fsSL https://raw.github.com/Homebrew/homebrew/go/install)" 18 | ``` 19 | 20 | 1. Install go 21 | 22 | ``` 23 | brew install go --cross-compile-all 24 | ``` 25 | 26 | 1. Configure `$GOPATH` in `~/.bashrc` 27 | 28 | ``` 29 | export GOPATH="$HOME/go" 30 | export PATH=$PATH:$GOPATH/bin 31 | ``` 32 | 33 | Installing the appengine development environment 34 | ------------------------------------------------ 35 | 36 | 1. Follow the [Google instructions](https://cloud.google.com/appengine/downloads). 37 | 38 | Downloading the code 39 | -------------------- 40 | 41 | You can download the code and its dependencies using 42 | 43 | ``` 44 | go get -t github.com/bugsnag/bugsnag-go 45 | ``` 46 | 47 | It will be put into "$GOPATH/src/github.com/bugsnag/bugsnag-go" 48 | 49 | Then install depend 50 | 51 | 52 | Running Tests 53 | ------------- 54 | 55 | You can run the tests with 56 | 57 | ```shell 58 | go test 59 | ``` 60 | 61 | If you've made significant changes, please also test the appengine integration with 62 | 63 | ```shell 64 | goapp test 65 | ``` 66 | 67 | Releasing a New Version 68 | ----------------------- 69 | 70 | If you are a project maintainer, you can build and release a new version of 71 | `bugsnag-go` as follows: 72 | 73 | 1. Commit all your changes. 74 | 2. Update the version number in `bugsnag.go`. 75 | 3. Add an entry to `CHANGELOG.md` and update the README if necessary. 76 | 4. commit tag and push 77 | 78 | git commit -mv1.0.x && git tag v1.0.x && git push origin v1.0.x 79 | -------------------------------------------------------------------------------- /vendor/src/github.com/bugsnag/bugsnag-go/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014 Bugsnag 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /vendor/src/github.com/bugsnag/bugsnag-go/Makefile: -------------------------------------------------------------------------------- 1 | default: 2 | go test 3 | -------------------------------------------------------------------------------- /vendor/src/github.com/bugsnag/bugsnag-go/appengine.go: -------------------------------------------------------------------------------- 1 | // +build appengine 2 | 3 | package bugsnag 4 | 5 | import ( 6 | "appengine" 7 | "appengine/urlfetch" 8 | "appengine/user" 9 | "fmt" 10 | "log" 11 | "net/http" 12 | ) 13 | 14 | func defaultPanicHandler() {} 15 | 16 | func init() { 17 | OnBeforeNotify(appengineMiddleware) 18 | } 19 | 20 | func appengineMiddleware(event *Event, config *Configuration) (err error) { 21 | var c appengine.Context 22 | 23 | for _, datum := range event.RawData { 24 | if r, ok := datum.(*http.Request); ok { 25 | c = appengine.NewContext(r) 26 | break 27 | } else if context, ok := datum.(appengine.Context); ok { 28 | c = context 29 | break 30 | } 31 | } 32 | 33 | if c == nil { 34 | return fmt.Errorf("No appengine context given") 35 | } 36 | 37 | // You can only use the builtin http library if you pay for appengine, 38 | // so we use the appengine urlfetch service instead. 39 | config.Transport = &urlfetch.Transport{ 40 | Context: c, 41 | } 42 | 43 | // Anything written to stderr/stdout is discarded, so lets log to the request. 44 | 45 | if configuredLogger, ok := config.Logger.(*log.Logger); ok { 46 | config.Logger = log.New(appengineWriter{c}, configuredLogger.Prefix(), configuredLogger.Flags()) 47 | } else { 48 | config.Logger = log.New(appengineWriter{c}, log.Prefix(), log.Flags()) 49 | } 50 | 51 | // Set the releaseStage appropriately 52 | if config.ReleaseStage == "" { 53 | if appengine.IsDevAppServer() { 54 | config.ReleaseStage = "development" 55 | } else { 56 | config.ReleaseStage = "production" 57 | } 58 | } 59 | 60 | if event.User == nil { 61 | u := user.Current(c) 62 | if u != nil { 63 | event.User = &User{ 64 | Id: u.ID, 65 | Email: u.Email, 66 | } 67 | } 68 | } 69 | 70 | return nil 71 | } 72 | 73 | // Convert an appengine.Context into an io.Writer so we can create a log.Logger. 74 | type appengineWriter struct { 75 | appengine.Context 76 | } 77 | 78 | func (c appengineWriter) Write(b []byte) (int, error) { 79 | c.Warningf(string(b)) 80 | return len(b), nil 81 | } 82 | -------------------------------------------------------------------------------- /vendor/src/github.com/bugsnag/bugsnag-go/appengine_test.go: -------------------------------------------------------------------------------- 1 | // +build appengine 2 | 3 | package bugsnag 4 | 5 | import ( 6 | "appengine/aetest" 7 | ) 8 | 9 | func init() { 10 | c, err := aetest.NewContext(nil) 11 | if err != nil { 12 | panic(err) 13 | } 14 | 15 | OnBeforeNotify(func(event *Event, config *Configuration) error { 16 | 17 | event.RawData = append(event.RawData, c) 18 | 19 | return nil 20 | }) 21 | } 22 | -------------------------------------------------------------------------------- /vendor/src/github.com/bugsnag/bugsnag-go/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Package bugsnag captures errors in real-time and reports them to Bugsnag (http://bugsnag.com). 3 | 4 | Using bugsnag-go is a three-step process. 5 | 6 | 1. As early as possible in your program configure the notifier with your APIKey. This sets up 7 | handling of panics that would otherwise crash your app. 8 | 9 | func init() { 10 | bugsnag.Configure(bugsnag.Configuration{ 11 | APIKey: "YOUR_API_KEY_HERE", 12 | }) 13 | } 14 | 15 | 2. Add bugsnag to places that already catch panics. For example you should add it to the HTTP server 16 | when you call ListenAndServer: 17 | 18 | http.ListenAndServe(":8080", bugsnag.Handler(nil)) 19 | 20 | If that's not possible, for example because you're using Google App Engine, you can also wrap each 21 | HTTP handler manually: 22 | 23 | http.HandleFunc("/" bugsnag.HandlerFunc(func (w http.ResponseWriter, r *http.Request) { 24 | ... 25 | }) 26 | 27 | 3. To notify Bugsnag of an error that is not a panic, pass it to bugsnag.Notify. This will also 28 | log the error message using the configured Logger. 29 | 30 | if err != nil { 31 | bugsnag.Notify(err) 32 | } 33 | 34 | For detailed integration instructions see https://bugsnag.com/docs/notifiers/go. 35 | 36 | Configuration 37 | 38 | The only required configuration is the Bugsnag API key which can be obtained by clicking "Settings" 39 | on the top of https://bugsnag.com/ after signing up. We also recommend you set the ReleaseStage 40 | and AppVersion if these make sense for your deployment workflow. 41 | 42 | RawData 43 | 44 | If you need to attach extra data to Bugsnag notifications you can do that using 45 | the rawData mechanism. Most of the functions that send errors to Bugsnag allow 46 | you to pass in any number of interface{} values as rawData. The rawData can 47 | consist of the Severity, Context, User or MetaData types listed below, and 48 | there is also builtin support for *http.Requests. 49 | 50 | bugsnag.Notify(err, bugsnag.SeverityError) 51 | 52 | If you want to add custom tabs to your bugsnag dashboard you can pass any value in as rawData, 53 | and then process it into the event's metadata using a bugsnag.OnBeforeNotify() hook. 54 | 55 | bugsnag.Notify(err, account) 56 | 57 | bugsnag.OnBeforeNotify(func (e *bugsnag.Event, c *bugsnag.Configuration) { 58 | for datum := range e.RawData { 59 | if account, ok := datum.(Account); ok { 60 | e.MetaData.Add("account", "name", account.Name) 61 | e.MetaData.Add("account", "url", account.URL) 62 | } 63 | } 64 | }) 65 | 66 | If necessary you can pass Configuration in as rawData, or modify the Configuration object passed 67 | into OnBeforeNotify hooks. Configuration passed in this way only affects the current notification. 68 | */ 69 | package bugsnag 70 | -------------------------------------------------------------------------------- /vendor/src/github.com/bugsnag/bugsnag-go/errors/README.md: -------------------------------------------------------------------------------- 1 | Adds stacktraces to errors in golang. 2 | 3 | This was made to help build the Bugsnag notifier but can be used standalone if 4 | you like to have stacktraces on errors. 5 | 6 | See [Godoc](https://godoc.org/github.com/bugsnag/bugsnag-go/errors) for the API docs. 7 | -------------------------------------------------------------------------------- /vendor/src/github.com/bugsnag/bugsnag-go/errors/error.go: -------------------------------------------------------------------------------- 1 | // Package errors provides errors that have stack-traces. 2 | package errors 3 | 4 | import ( 5 | "bytes" 6 | "fmt" 7 | "reflect" 8 | "runtime" 9 | ) 10 | 11 | // The maximum number of stackframes on any error. 12 | var MaxStackDepth = 50 13 | 14 | // Error is an error with an attached stacktrace. It can be used 15 | // wherever the builtin error interface is expected. 16 | type Error struct { 17 | Err error 18 | stack []uintptr 19 | frames []StackFrame 20 | } 21 | 22 | // New makes an Error from the given value. If that value is already an 23 | // error then it will be used directly, if not, it will be passed to 24 | // fmt.Errorf("%v"). The skip parameter indicates how far up the stack 25 | // to start the stacktrace. 0 is from the current call, 1 from its caller, etc. 26 | func New(e interface{}, skip int) *Error { 27 | var err error 28 | 29 | switch e := e.(type) { 30 | case *Error: 31 | return e 32 | case error: 33 | err = e 34 | default: 35 | err = fmt.Errorf("%v", e) 36 | } 37 | 38 | stack := make([]uintptr, MaxStackDepth) 39 | length := runtime.Callers(2+skip, stack[:]) 40 | return &Error{ 41 | Err: err, 42 | stack: stack[:length], 43 | } 44 | } 45 | 46 | // Errorf creates a new error with the given message. You can use it 47 | // as a drop-in replacement for fmt.Errorf() to provide descriptive 48 | // errors in return values. 49 | func Errorf(format string, a ...interface{}) *Error { 50 | return New(fmt.Errorf(format, a...), 1) 51 | } 52 | 53 | // Error returns the underlying error's message. 54 | func (err *Error) Error() string { 55 | return err.Err.Error() 56 | } 57 | 58 | // Stack returns the callstack formatted the same way that go does 59 | // in runtime/debug.Stack() 60 | func (err *Error) Stack() []byte { 61 | buf := bytes.Buffer{} 62 | 63 | for _, frame := range err.StackFrames() { 64 | buf.WriteString(frame.String()) 65 | } 66 | 67 | return buf.Bytes() 68 | } 69 | 70 | // StackFrames returns an array of frames containing information about the 71 | // stack. 72 | func (err *Error) StackFrames() []StackFrame { 73 | if err.frames == nil { 74 | err.frames = make([]StackFrame, len(err.stack)) 75 | 76 | for i, pc := range err.stack { 77 | err.frames[i] = NewStackFrame(pc) 78 | } 79 | } 80 | 81 | return err.frames 82 | } 83 | 84 | // TypeName returns the type this error. e.g. *errors.stringError. 85 | func (err *Error) TypeName() string { 86 | if _, ok := err.Err.(uncaughtPanic); ok { 87 | return "panic" 88 | } 89 | return reflect.TypeOf(err.Err).String() 90 | } 91 | -------------------------------------------------------------------------------- /vendor/src/github.com/bugsnag/bugsnag-go/errors/error_test.go: -------------------------------------------------------------------------------- 1 | package errors 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "io" 7 | "runtime/debug" 8 | "testing" 9 | ) 10 | 11 | func TestStackFormatMatches(t *testing.T) { 12 | 13 | defer func() { 14 | err := recover() 15 | if err != 'a' { 16 | t.Fatal(err) 17 | } 18 | 19 | bs := [][]byte{Errorf("hi").Stack(), debug.Stack()} 20 | 21 | // Ignore the first line (as it contains the PC of the .Stack() call) 22 | bs[0] = bytes.SplitN(bs[0], []byte("\n"), 2)[1] 23 | bs[1] = bytes.SplitN(bs[1], []byte("\n"), 2)[1] 24 | 25 | if bytes.Compare(bs[0], bs[1]) != 0 { 26 | t.Errorf("Stack didn't match") 27 | t.Errorf("%s", bs[0]) 28 | t.Errorf("%s", bs[1]) 29 | } 30 | }() 31 | 32 | a() 33 | } 34 | 35 | func TestSkipWorks(t *testing.T) { 36 | 37 | defer func() { 38 | err := recover() 39 | if err != 'a' { 40 | t.Fatal(err) 41 | } 42 | 43 | bs := [][]byte{New("hi", 2).Stack(), debug.Stack()} 44 | 45 | if !bytes.HasSuffix(bs[1], bs[0]) { 46 | t.Errorf("Stack didn't match") 47 | t.Errorf("%s", bs[0]) 48 | t.Errorf("%s", bs[1]) 49 | } 50 | }() 51 | 52 | a() 53 | } 54 | 55 | func TestNewError(t *testing.T) { 56 | 57 | e := func() error { 58 | return New("hi", 1) 59 | }() 60 | 61 | if e.Error() != "hi" { 62 | t.Errorf("Constructor with a string failed") 63 | } 64 | 65 | if New(fmt.Errorf("yo"), 0).Error() != "yo" { 66 | t.Errorf("Constructor with an error failed") 67 | } 68 | 69 | if New(e, 0) != e { 70 | t.Errorf("Constructor with an Error failed") 71 | } 72 | 73 | if New(nil, 0).Error() != "" { 74 | t.Errorf("Constructor with nil failed") 75 | } 76 | } 77 | 78 | func ExampleErrorf(x int) (int, error) { 79 | if x%2 == 1 { 80 | return 0, Errorf("can only halve even numbers, got %d", x) 81 | } 82 | return x / 2, nil 83 | } 84 | 85 | func ExampleNewError() (error, error) { 86 | // Wrap io.EOF with the current stack-trace and return it 87 | return nil, New(io.EOF, 0) 88 | } 89 | 90 | func ExampleNewError_skip() { 91 | defer func() { 92 | if err := recover(); err != nil { 93 | // skip 1 frame (the deferred function) and then return the wrapped err 94 | err = New(err, 1) 95 | } 96 | }() 97 | } 98 | 99 | func ExampleError_Stack(err Error) { 100 | fmt.Printf("Error: %s\n%s", err.Error(), err.Stack()) 101 | } 102 | 103 | func a() error { 104 | b(5) 105 | return nil 106 | } 107 | 108 | func b(i int) { 109 | c() 110 | } 111 | 112 | func c() { 113 | panic('a') 114 | } 115 | -------------------------------------------------------------------------------- /vendor/src/github.com/bugsnag/bugsnag-go/examples/appengine/README.md: -------------------------------------------------------------------------------- 1 | This is an example google app-engine app. 2 | 3 | To use it you will need to install the [App Engine 4 | SDK](https://cloud.google.com/appengine/downloads) for Go. 5 | 6 | Then run: 7 | 8 | goapp deploy 9 | 10 | Then open: https://bugsnag-test.appspot.com/ in your web-browser. 11 | -------------------------------------------------------------------------------- /vendor/src/github.com/bugsnag/bugsnag-go/examples/appengine/app.yaml: -------------------------------------------------------------------------------- 1 | application: bugsnag-test 2 | version: 1 3 | runtime: go 4 | api_version: go1 5 | 6 | handlers: 7 | - url: /.* 8 | script: _go_app 9 | -------------------------------------------------------------------------------- /vendor/src/github.com/bugsnag/bugsnag-go/examples/appengine/hello.go: -------------------------------------------------------------------------------- 1 | package mellow 2 | 3 | import ( 4 | "fmt" 5 | "github.com/bugsnag/bugsnag-go" 6 | "github.com/bugsnag/bugsnag-go/errors" 7 | "net/http" 8 | "os" 9 | ) 10 | 11 | func init() { 12 | bugsnag.OnBeforeNotify(func(event *bugsnag.Event, config *bugsnag.Configuration) error { 13 | event.MetaData.AddStruct("original", event.Error.StackFrames()) 14 | return nil 15 | }) 16 | bugsnag.Configure(bugsnag.Configuration{ 17 | APIKey: "066f5ad3590596f9aa8d601ea89af845", 18 | }) 19 | 20 | http.HandleFunc("/", bugsnag.HandlerFunc(handler)) 21 | } 22 | 23 | func handler(w http.ResponseWriter, r *http.Request) { 24 | fmt.Fprint(w, "welcome") 25 | notifier := bugsnag.New(r) 26 | notifier.Notify(fmt.Errorf("oh hia"), bugsnag.MetaData{"env": {"values": os.Environ()}}) 27 | fmt.Fprint(w, "welcome\n") 28 | 29 | panic("zoomg") 30 | 31 | fmt.Fprintf(w, "%#v", errors.Errorf("oahi").StackFrames()) 32 | } 33 | -------------------------------------------------------------------------------- /vendor/src/github.com/bugsnag/bugsnag-go/examples/appengine/mylogs.txt: -------------------------------------------------------------------------------- 1 | 2601:9:8480:11d2:7909:b2e5:3722:ef57 - - [08/Jul/2014:01:16:25 -0700] "GET / HTTP/1.1" 500 0 - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.153 Safari/537.36" 2 | 2601:9:8480:11d2:7909:b2e5:3722:ef57 - - [08/Jul/2014:01:16:25 -0700] "GET /favicon.ico HTTP/1.1" 500 0 - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.153 Safari/537.36" 3 | 2601:9:8480:11d2:7909:b2e5:3722:ef57 - - [08/Jul/2014:01:18:20 -0700] "GET / HTTP/1.1" 500 0 - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.153 Safari/537.36" 4 | 2601:9:8480:11d2:7909:b2e5:3722:ef57 - - [08/Jul/2014:01:18:20 -0700] "GET /favicon.ico HTTP/1.1" 500 0 - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.153 Safari/537.36" 5 | -------------------------------------------------------------------------------- /vendor/src/github.com/bugsnag/bugsnag-go/examples/http/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/bugsnag/bugsnag-go" 5 | "log" 6 | "net/http" 7 | ) 8 | 9 | func main() { 10 | 11 | http.HandleFunc("/", Get) 12 | 13 | bugsnag.Configure(bugsnag.Configuration{ 14 | APIKey: "066f5ad3590596f9aa8d601ea89af845", 15 | }) 16 | 17 | log.Println("Serving on 9001") 18 | http.ListenAndServe(":9001", bugsnag.Handler(nil)) 19 | } 20 | 21 | func Get(w http.ResponseWriter, r *http.Request) { 22 | w.WriteHeader(200) 23 | w.Write([]byte("OK\n")) 24 | 25 | var a struct{} 26 | crash(a) 27 | } 28 | 29 | func crash(a interface{}) string { 30 | return a.(string) 31 | } 32 | -------------------------------------------------------------------------------- /vendor/src/github.com/bugsnag/bugsnag-go/examples/revelapp/app/controllers/app.go: -------------------------------------------------------------------------------- 1 | package controllers 2 | 3 | import "github.com/revel/revel" 4 | import "time" 5 | 6 | type App struct { 7 | *revel.Controller 8 | } 9 | 10 | func (c App) Index() revel.Result { 11 | go func() { 12 | time.Sleep(5 * time.Second) 13 | panic("hello!") 14 | }() 15 | 16 | s := make([]string, 0) 17 | revel.INFO.Print(s[0]) 18 | return c.Render() 19 | } 20 | -------------------------------------------------------------------------------- /vendor/src/github.com/bugsnag/bugsnag-go/examples/revelapp/app/init.go: -------------------------------------------------------------------------------- 1 | package app 2 | 3 | import "github.com/revel/revel" 4 | import "github.com/bugsnag/bugsnag-go/revel" 5 | 6 | func init() { 7 | // Filters is the default set of global filters. 8 | revel.Filters = []revel.Filter{ 9 | revel.PanicFilter, // Recover from panics and display an error page instead. 10 | bugsnagrevel.Filter, // Send panics to Bugsnag 11 | revel.RouterFilter, // Use the routing table to select the right Action 12 | revel.FilterConfiguringFilter, // A hook for adding or removing per-Action filters. 13 | revel.ParamsFilter, // Parse parameters into Controller.Params. 14 | revel.SessionFilter, // Restore and write the session cookie. 15 | revel.FlashFilter, // Restore and write the flash cookie. 16 | revel.ValidationFilter, // Restore kept validation errors and save new ones from cookie. 17 | revel.I18nFilter, // Resolve the requested language 18 | HeaderFilter, // Add some security based headers 19 | revel.InterceptorFilter, // Run interceptors around the action. 20 | revel.CompressFilter, // Compress the result. 21 | revel.ActionInvoker, // Invoke the action. 22 | } 23 | 24 | // register startup functions with OnAppStart 25 | // ( order dependent ) 26 | // revel.OnAppStart(InitDB()) 27 | // revel.OnAppStart(FillCache()) 28 | } 29 | 30 | // TODO turn this into revel.HeaderFilter 31 | // should probably also have a filter for CSRF 32 | // not sure if it can go in the same filter or not 33 | var HeaderFilter = func(c *revel.Controller, fc []revel.Filter) { 34 | // Add some common security headers 35 | c.Response.Out.Header().Add("X-Frame-Options", "SAMEORIGIN") 36 | c.Response.Out.Header().Add("X-XSS-Protection", "1; mode=block") 37 | c.Response.Out.Header().Add("X-Content-Type-Options", "nosniff") 38 | 39 | fc[0](c, fc[1:]) // Execute the next filter stage. 40 | } 41 | -------------------------------------------------------------------------------- /vendor/src/github.com/bugsnag/bugsnag-go/examples/revelapp/app/views/App/Index.html: -------------------------------------------------------------------------------- 1 | {{set . "title" "Home"}} 2 | {{template "header.html" .}} 3 | 4 |
5 |
6 |
7 |
8 |

It works!

9 |

10 |
11 |
12 |
13 |
14 | 15 |
16 |
17 |
18 | {{template "flash.html" .}} 19 |
20 |
21 |
22 | 23 | {{template "footer.html" .}} 24 | -------------------------------------------------------------------------------- /vendor/src/github.com/bugsnag/bugsnag-go/examples/revelapp/app/views/debug.html: -------------------------------------------------------------------------------- 1 | 20 | 44 | 45 | 46 | 65 | -------------------------------------------------------------------------------- /vendor/src/github.com/bugsnag/bugsnag-go/examples/revelapp/app/views/errors/404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Not found 5 | 6 | 7 | {{if eq .RunMode "dev"}} 8 | {{template "errors/404-dev.html" .}} 9 | {{else}} 10 | {{with .Error}} 11 |

12 | {{.Title}} 13 |

14 |

15 | {{.Description}} 16 |

17 | {{end}} 18 | {{end}} 19 | 20 | 21 | -------------------------------------------------------------------------------- /vendor/src/github.com/bugsnag/bugsnag-go/examples/revelapp/app/views/errors/500.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Application error 5 | 6 | 7 | {{if eq .RunMode "dev"}} 8 | {{template "errors/500-dev.html" .}} 9 | {{else}} 10 |

Oops, an error occured

11 |

12 | This exception has been logged. 13 |

14 | {{end}} 15 | 16 | 17 | -------------------------------------------------------------------------------- /vendor/src/github.com/bugsnag/bugsnag-go/examples/revelapp/app/views/flash.html: -------------------------------------------------------------------------------- 1 | {{if .flash.success}} 2 |
3 | {{.flash.success}} 4 |
5 | {{end}} 6 | 7 | {{if or .errors .flash.error}} 8 |
9 | {{if .flash.error}} 10 | {{.flash.error}} 11 | {{end}} 12 |
    13 | {{range .errors}} 14 |
  • {{.}}
  • 15 | {{end}} 16 |
17 |
18 | {{end}} 19 | -------------------------------------------------------------------------------- /vendor/src/github.com/bugsnag/bugsnag-go/examples/revelapp/app/views/footer.html: -------------------------------------------------------------------------------- 1 | {{if eq .RunMode "dev"}} 2 | {{template "debug.html" .}} 3 | {{end}} 4 | 5 | 6 | -------------------------------------------------------------------------------- /vendor/src/github.com/bugsnag/bugsnag-go/examples/revelapp/app/views/header.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {{.title}} 6 | 7 | 8 | 9 | 10 | {{range .moreStyles}} 11 | 12 | {{end}} 13 | {{range .moreScripts}} 14 | 15 | {{end}} 16 | 17 | 18 | -------------------------------------------------------------------------------- /vendor/src/github.com/bugsnag/bugsnag-go/examples/revelapp/conf/app.conf: -------------------------------------------------------------------------------- 1 | app.name=revelapp 2 | app.secret=80ytgNbBeB0X4mfEYybT4QRXKEoYHoaGAIgZkIB7Z8cEVJjZJOPZupIoluJBMorr 3 | http.addr= 4 | http.port=9000 5 | http.ssl=false 6 | http.sslcert= 7 | http.sslkey= 8 | cookie.httponly=false 9 | cookie.prefix=REVEL 10 | cookie.secure=false 11 | format.date=01/02/2006 12 | format.datetime=01/02/2006 15:04 13 | results.chunked=false 14 | 15 | log.trace.prefix = "TRACE " 16 | log.info.prefix = "INFO " 17 | log.warn.prefix = "WARN " 18 | log.error.prefix = "ERROR " 19 | 20 | # The default language of this application. 21 | i18n.default_language=en 22 | 23 | module.static=github.com/revel/revel/modules/static 24 | 25 | bugsnag.apikey=066f5ad3590596f9aa8d601ea89af845 26 | 27 | [dev] 28 | mode.dev=true 29 | results.pretty=true 30 | watch=true 31 | 32 | module.testrunner = github.com/revel/revel/modules/testrunner 33 | 34 | log.trace.output = off 35 | log.info.output = stderr 36 | log.warn.output = stderr 37 | log.error.output = stderr 38 | 39 | [prod] 40 | mode.dev=false 41 | results.pretty=false 42 | watch=false 43 | 44 | module.testrunner = 45 | 46 | log.trace.output = off 47 | log.info.output = off 48 | log.warn.output = %(app.name)s.log 49 | log.error.output = %(app.name)s.log 50 | -------------------------------------------------------------------------------- /vendor/src/github.com/bugsnag/bugsnag-go/examples/revelapp/conf/routes: -------------------------------------------------------------------------------- 1 | # Routes 2 | # This file defines all application routes (Higher priority routes first) 3 | # ~~~~ 4 | 5 | module:testrunner 6 | 7 | GET / App.Index 8 | 9 | # Ignore favicon requests 10 | GET /favicon.ico 404 11 | 12 | # Map static resources from the /app/public folder to the /public path 13 | GET /public/*filepath Static.Serve("public") 14 | 15 | # Catch all 16 | * /:controller/:action :controller.:action 17 | -------------------------------------------------------------------------------- /vendor/src/github.com/bugsnag/bugsnag-go/examples/revelapp/messages/sample.en: -------------------------------------------------------------------------------- 1 | # Sample messages file for the English language (en) 2 | # Message file extensions should be ISO 639-1 codes (http://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) 3 | # Sections within each message file can optionally override the defaults using ISO 3166-1 alpha-2 codes (http://en.wikipedia.org/wiki/ISO_3166-1_alpha-2) 4 | # See also: 5 | # - http://www.rfc-editor.org/rfc/bcp/bcp47.txt 6 | # - http://www.w3.org/International/questions/qa-accept-lang-locales 7 | 8 | -------------------------------------------------------------------------------- /vendor/src/github.com/bugsnag/bugsnag-go/examples/revelapp/public/img/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nickschuch/marco/c5e47ec70e3f3e3acc0537684ee99a9dddb5538f/vendor/src/github.com/bugsnag/bugsnag-go/examples/revelapp/public/img/favicon.png -------------------------------------------------------------------------------- /vendor/src/github.com/bugsnag/bugsnag-go/examples/revelapp/public/img/glyphicons-halflings-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nickschuch/marco/c5e47ec70e3f3e3acc0537684ee99a9dddb5538f/vendor/src/github.com/bugsnag/bugsnag-go/examples/revelapp/public/img/glyphicons-halflings-white.png -------------------------------------------------------------------------------- /vendor/src/github.com/bugsnag/bugsnag-go/examples/revelapp/public/img/glyphicons-halflings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nickschuch/marco/c5e47ec70e3f3e3acc0537684ee99a9dddb5538f/vendor/src/github.com/bugsnag/bugsnag-go/examples/revelapp/public/img/glyphicons-halflings.png -------------------------------------------------------------------------------- /vendor/src/github.com/bugsnag/bugsnag-go/examples/revelapp/tests/apptest.go: -------------------------------------------------------------------------------- 1 | package tests 2 | 3 | import "github.com/revel/revel" 4 | 5 | type AppTest struct { 6 | revel.TestSuite 7 | } 8 | 9 | func (t *AppTest) Before() { 10 | println("Set up") 11 | } 12 | 13 | func (t AppTest) TestThatIndexPageWorks() { 14 | t.Get("/") 15 | t.AssertOk() 16 | t.AssertContentType("text/html; charset=utf-8") 17 | } 18 | 19 | func (t *AppTest) After() { 20 | println("Tear down") 21 | } 22 | -------------------------------------------------------------------------------- /vendor/src/github.com/bugsnag/bugsnag-go/json_tags.go: -------------------------------------------------------------------------------- 1 | // The code is stripped from: 2 | // http://golang.org/src/pkg/encoding/json/tags.go?m=text 3 | 4 | package bugsnag 5 | 6 | import ( 7 | "strings" 8 | ) 9 | 10 | // tagOptions is the string following a comma in a struct field's "json" 11 | // tag, or the empty string. It does not include the leading comma. 12 | type tagOptions string 13 | 14 | // parseTag splits a struct field's json tag into its name and 15 | // comma-separated options. 16 | func parseTag(tag string) (string, tagOptions) { 17 | if idx := strings.Index(tag, ","); idx != -1 { 18 | return tag[:idx], tagOptions(tag[idx+1:]) 19 | } 20 | return tag, tagOptions("") 21 | } 22 | 23 | // Contains reports whether a comma-separated list of options 24 | // contains a particular substr flag. substr must be surrounded by a 25 | // string boundary or commas. 26 | func (o tagOptions) Contains(optionName string) bool { 27 | if len(o) == 0 { 28 | return false 29 | } 30 | s := string(o) 31 | for s != "" { 32 | var next string 33 | i := strings.Index(s, ",") 34 | if i >= 0 { 35 | s, next = s[:i], s[i+1:] 36 | } 37 | if s == optionName { 38 | return true 39 | } 40 | s = next 41 | } 42 | return false 43 | } 44 | -------------------------------------------------------------------------------- /vendor/src/github.com/bugsnag/bugsnag-go/middleware_test.go: -------------------------------------------------------------------------------- 1 | package bugsnag 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "log" 7 | "reflect" 8 | "testing" 9 | ) 10 | 11 | func TestMiddlewareOrder(t *testing.T) { 12 | 13 | result := make([]int, 0, 7) 14 | stack := middlewareStack{} 15 | stack.OnBeforeNotify(func(e *Event, c *Configuration) error { 16 | result = append(result, 2) 17 | return nil 18 | }) 19 | stack.OnBeforeNotify(func(e *Event, c *Configuration) error { 20 | result = append(result, 1) 21 | return nil 22 | }) 23 | stack.OnBeforeNotify(func(e *Event, c *Configuration) error { 24 | result = append(result, 0) 25 | return nil 26 | }) 27 | 28 | stack.Run(nil, nil, func() error { 29 | result = append(result, 3) 30 | return nil 31 | }) 32 | 33 | if !reflect.DeepEqual(result, []int{0, 1, 2, 3}) { 34 | t.Errorf("unexpected middleware order %v", result) 35 | } 36 | } 37 | 38 | func TestBeforeNotifyReturnErr(t *testing.T) { 39 | 40 | stack := middlewareStack{} 41 | err := fmt.Errorf("test") 42 | 43 | stack.OnBeforeNotify(func(e *Event, c *Configuration) error { 44 | return err 45 | }) 46 | 47 | called := false 48 | 49 | e := stack.Run(nil, nil, func() error { 50 | called = true 51 | return nil 52 | }) 53 | 54 | if e != err { 55 | t.Errorf("Middleware didn't return the error") 56 | } 57 | 58 | if called == true { 59 | t.Errorf("Notify was called when BeforeNotify returned False") 60 | } 61 | } 62 | 63 | func TestBeforeNotifyPanic(t *testing.T) { 64 | 65 | stack := middlewareStack{} 66 | 67 | stack.OnBeforeNotify(func(e *Event, c *Configuration) error { 68 | panic("oops") 69 | }) 70 | 71 | called := false 72 | b := &bytes.Buffer{} 73 | 74 | stack.Run(nil, &Configuration{Logger: log.New(b, log.Prefix(), 0)}, func() error { 75 | called = true 76 | return nil 77 | }) 78 | 79 | logged := b.String() 80 | 81 | if logged != "bugsnag/middleware: unexpected panic: oops\n" { 82 | t.Errorf("Logged: %s", logged) 83 | } 84 | 85 | if called == false { 86 | t.Errorf("Notify was not called when BeforeNotify panicked") 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /vendor/src/github.com/bugsnag/bugsnag-go/panicwrap.go: -------------------------------------------------------------------------------- 1 | // +build !appengine 2 | 3 | package bugsnag 4 | 5 | import ( 6 | "github.com/bugsnag/panicwrap" 7 | "github.com/bugsnag/bugsnag-go/errors" 8 | ) 9 | 10 | // NOTE: this function does not return when you call it, instead it 11 | // re-exec()s the current process with panic monitoring. 12 | func defaultPanicHandler() { 13 | defer defaultNotifier.dontPanic() 14 | 15 | err := panicwrap.BasicMonitor(func(output string) { 16 | toNotify, err := errors.ParsePanic(output) 17 | 18 | if err != nil { 19 | defaultNotifier.Config.log("bugsnag.handleUncaughtPanic: %v", err) 20 | } 21 | Notify(toNotify, SeverityError, Configuration{Synchronous: true}) 22 | }) 23 | 24 | if err != nil { 25 | defaultNotifier.Config.log("bugsnag.handleUncaughtPanic: %v", err) 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /vendor/src/github.com/bugsnag/bugsnag-go/panicwrap_test.go: -------------------------------------------------------------------------------- 1 | // +build !appengine 2 | 3 | package bugsnag 4 | 5 | import ( 6 | "github.com/bitly/go-simplejson" 7 | "github.com/bugsnag/osext" 8 | "os" 9 | "os/exec" 10 | "testing" 11 | "time" 12 | ) 13 | 14 | func TestPanicHandler(t *testing.T) { 15 | startTestServer() 16 | 17 | exePath, err := osext.Executable() 18 | if err != nil { 19 | t.Fatal(err) 20 | } 21 | 22 | // Use the same trick as panicwrap() to re-run ourselves. 23 | // In the init() block below, we will then panic. 24 | cmd := exec.Command(exePath, os.Args[1:]...) 25 | cmd.Env = append(os.Environ(), "BUGSNAG_API_KEY="+testAPIKey, "BUGSNAG_ENDPOINT="+testEndpoint, "please_panic=please_panic") 26 | 27 | if err = cmd.Start(); err != nil { 28 | t.Fatal(err) 29 | } 30 | 31 | if err = cmd.Wait(); err.Error() != "exit status 2" { 32 | t.Fatal(err) 33 | } 34 | 35 | json, err := simplejson.NewJson(<-postedJSON) 36 | if err != nil { 37 | t.Fatal(err) 38 | } 39 | 40 | event := json.Get("events").GetIndex(0) 41 | 42 | if event.Get("severity").MustString() != "error" { 43 | t.Errorf("severity should be error") 44 | } 45 | exception := event.Get("exceptions").GetIndex(0) 46 | 47 | if exception.Get("message").MustString() != "ruh roh" { 48 | t.Errorf("caught wrong panic") 49 | } 50 | 51 | if exception.Get("errorClass").MustString() != "panic" { 52 | t.Errorf("caught wrong panic") 53 | } 54 | 55 | frame := exception.Get("stacktrace").GetIndex(1) 56 | 57 | // Yeah, we just caught a panic from the init() function below and sent it to the server running above (mindblown) 58 | if frame.Get("inProject").MustBool() != true || 59 | frame.Get("file").MustString() != "panicwrap_test.go" || 60 | frame.Get("lineNumber").MustInt() == 0 { 61 | t.Errorf("stack trace seemed wrong: %v", frame) 62 | } 63 | } 64 | 65 | func init() { 66 | if os.Getenv("please_panic") != "" { 67 | Configure(Configuration{APIKey: os.Getenv("BUGSNAG_API_KEY"), Endpoint: os.Getenv("BUGSNAG_ENDPOINT"), ProjectPackages: []string{"github.com/bugsnag/bugsnag-go"}}) 68 | go func() { 69 | panick() 70 | }() 71 | // Plenty of time to crash, it shouldn't need any of it. 72 | time.Sleep(1 * time.Second) 73 | } 74 | } 75 | 76 | func panick() { 77 | panic("ruh roh") 78 | } 79 | -------------------------------------------------------------------------------- /vendor/src/github.com/bugsnag/bugsnag-go/payload.go: -------------------------------------------------------------------------------- 1 | package bugsnag 2 | 3 | import ( 4 | "bytes" 5 | "encoding/json" 6 | "fmt" 7 | "net/http" 8 | ) 9 | 10 | type payload struct { 11 | *Event 12 | *Configuration 13 | } 14 | 15 | type hash map[string]interface{} 16 | 17 | func (p *payload) deliver() error { 18 | 19 | if len(p.APIKey) != 32 { 20 | return fmt.Errorf("bugsnag/payload.deliver: invalid api key") 21 | } 22 | 23 | buf, err := json.Marshal(p) 24 | 25 | if err != nil { 26 | return fmt.Errorf("bugsnag/payload.deliver: %v", err) 27 | } 28 | 29 | client := http.Client{ 30 | Transport: p.Transport, 31 | } 32 | 33 | resp, err := client.Post(p.Endpoint, "application/json", bytes.NewBuffer(buf)) 34 | 35 | if err != nil { 36 | return fmt.Errorf("bugsnag/payload.deliver: %v", err) 37 | } 38 | defer resp.Body.Close() 39 | 40 | if resp.StatusCode != 200 { 41 | return fmt.Errorf("bugsnag/payload.deliver: Got HTTP %s\n", resp.Status) 42 | } 43 | 44 | return nil 45 | } 46 | 47 | func (p *payload) MarshalJSON() ([]byte, error) { 48 | 49 | data := hash{ 50 | "apiKey": p.APIKey, 51 | 52 | "notifier": hash{ 53 | "name": "Bugsnag Go", 54 | "url": "https://github.com/bugsnag/bugsnag-go", 55 | "version": VERSION, 56 | }, 57 | 58 | "events": []hash{ 59 | { 60 | "payloadVersion": "2", 61 | "exceptions": []hash{ 62 | { 63 | "errorClass": p.ErrorClass, 64 | "message": p.Message, 65 | "stacktrace": p.Stacktrace, 66 | }, 67 | }, 68 | "severity": p.Severity.String, 69 | "app": hash{ 70 | "releaseStage": p.ReleaseStage, 71 | }, 72 | "user": p.User, 73 | "metaData": p.MetaData.sanitize(p.ParamsFilters), 74 | }, 75 | }, 76 | } 77 | 78 | event := data["events"].([]hash)[0] 79 | 80 | if p.Context != "" { 81 | event["context"] = p.Context 82 | } 83 | if p.GroupingHash != "" { 84 | event["groupingHash"] = p.GroupingHash 85 | } 86 | if p.Hostname != "" { 87 | event["device"] = hash{ 88 | "hostname": p.Hostname, 89 | } 90 | } 91 | if p.AppVersion != "" { 92 | event["app"].(hash)["version"] = p.AppVersion 93 | } 94 | return json.Marshal(data) 95 | 96 | } 97 | -------------------------------------------------------------------------------- /vendor/src/github.com/bugsnag/bugsnag-go/revel/bugsnagrevel.go: -------------------------------------------------------------------------------- 1 | // Package bugsnagrevel adds Bugsnag to revel. 2 | // It lets you pass *revel.Controller into bugsnag.Notify(), 3 | // and provides a Filter to catch errors. 4 | package bugsnagrevel 5 | 6 | import ( 7 | "strings" 8 | "sync" 9 | 10 | "github.com/bugsnag/bugsnag-go" 11 | "github.com/revel/revel" 12 | ) 13 | 14 | var once sync.Once 15 | 16 | // Filter should be added to the filter chain just after the PanicFilter. 17 | // It sends errors to Bugsnag automatically. Configuration is read out of 18 | // conf/app.conf, you should set bugsnag.apikey, and can also set 19 | // bugsnag.endpoint, bugsnag.releasestage, bugsnag.appversion, 20 | // bugsnag.projectroot, bugsnag.projectpackages if needed. 21 | func Filter(c *revel.Controller, fc []revel.Filter) { 22 | defer bugsnag.AutoNotify(c) 23 | fc[0](c, fc[1:]) 24 | } 25 | 26 | // Add support to bugsnag for reading data out of *revel.Controllers 27 | func middleware(event *bugsnag.Event, config *bugsnag.Configuration) error { 28 | for _, datum := range event.RawData { 29 | if controller, ok := datum.(*revel.Controller); ok { 30 | // make the request visible to the builtin HttpMIddleware 31 | event.RawData = append(event.RawData, controller.Request.Request) 32 | event.Context = controller.Action 33 | event.MetaData.AddStruct("Session", controller.Session) 34 | } 35 | } 36 | 37 | return nil 38 | } 39 | 40 | func init() { 41 | revel.OnAppStart(func() { 42 | bugsnag.OnBeforeNotify(middleware) 43 | 44 | var projectPackages []string 45 | if packages, ok := revel.Config.String("bugsnag.projectpackages"); ok { 46 | projectPackages = strings.Split(packages, ",") 47 | } else { 48 | projectPackages = []string{revel.ImportPath + "/app/*", revel.ImportPath + "/app"} 49 | } 50 | 51 | bugsnag.Configure(bugsnag.Configuration{ 52 | APIKey: revel.Config.StringDefault("bugsnag.apikey", ""), 53 | Endpoint: revel.Config.StringDefault("bugsnag.endpoint", ""), 54 | AppVersion: revel.Config.StringDefault("bugsnag.appversion", ""), 55 | ReleaseStage: revel.Config.StringDefault("bugsnag.releasestage", revel.RunMode), 56 | ProjectPackages: projectPackages, 57 | Logger: revel.ERROR, 58 | }) 59 | }) 60 | } 61 | -------------------------------------------------------------------------------- /vendor/src/github.com/bugsnag/osext/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012 Daniel Theophanes 2 | 3 | This software is provided 'as-is', without any express or implied 4 | warranty. In no event will the authors be held liable for any damages 5 | arising from the use of this software. 6 | 7 | Permission is granted to anyone to use this software for any purpose, 8 | including commercial applications, and to alter it and redistribute it 9 | freely, subject to the following restrictions: 10 | 11 | 1. The origin of this software must not be misrepresented; you must not 12 | claim that you wrote the original software. If you use this software 13 | in a product, an acknowledgment in the product documentation would be 14 | appreciated but is not required. 15 | 16 | 2. Altered source versions must be plainly marked as such, and must not be 17 | misrepresented as being the original software. 18 | 19 | 3. This notice may not be removed or altered from any source 20 | distribution. 21 | -------------------------------------------------------------------------------- /vendor/src/github.com/bugsnag/osext/osext.go: -------------------------------------------------------------------------------- 1 | // Copyright 2012 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // Extensions to the standard "os" package. 6 | package osext 7 | 8 | import "path/filepath" 9 | 10 | // Executable returns an absolute path that can be used to 11 | // re-invoke the current program. 12 | // It may not be valid after the current program exits. 13 | func Executable() (string, error) { 14 | p, err := executable() 15 | return filepath.Clean(p), err 16 | } 17 | 18 | // Returns same path as Executable, returns just the folder 19 | // path. Excludes the executable name. 20 | func ExecutableFolder() (string, error) { 21 | p, err := Executable() 22 | if err != nil { 23 | return "", err 24 | } 25 | folder, _ := filepath.Split(p) 26 | return folder, nil 27 | } 28 | 29 | // Depricated. Same as Executable(). 30 | func GetExePath() (exePath string, err error) { 31 | return Executable() 32 | } 33 | -------------------------------------------------------------------------------- /vendor/src/github.com/bugsnag/osext/osext_plan9.go: -------------------------------------------------------------------------------- 1 | // Copyright 2012 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package osext 6 | 7 | import "syscall" 8 | 9 | func executable() (string, error) { 10 | f, err := Open("/proc/" + itoa(Getpid()) + "/text") 11 | if err != nil { 12 | return "", err 13 | } 14 | defer f.Close() 15 | return syscall.Fd2path(int(f.Fd())) 16 | } 17 | -------------------------------------------------------------------------------- /vendor/src/github.com/bugsnag/osext/osext_procfs.go: -------------------------------------------------------------------------------- 1 | // Copyright 2012 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // +build linux netbsd openbsd 6 | 7 | package osext 8 | 9 | import ( 10 | "errors" 11 | "os" 12 | "runtime" 13 | ) 14 | 15 | func executable() (string, error) { 16 | switch runtime.GOOS { 17 | case "linux": 18 | return os.Readlink("/proc/self/exe") 19 | case "netbsd": 20 | return os.Readlink("/proc/curproc/exe") 21 | case "openbsd": 22 | return os.Readlink("/proc/curproc/file") 23 | } 24 | return "", errors.New("ExecPath not implemented for " + runtime.GOOS) 25 | } 26 | -------------------------------------------------------------------------------- /vendor/src/github.com/bugsnag/osext/osext_sysctl.go: -------------------------------------------------------------------------------- 1 | // Copyright 2012 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // +build darwin freebsd 6 | 7 | package osext 8 | 9 | import ( 10 | "os" 11 | "runtime" 12 | "syscall" 13 | "unsafe" 14 | ) 15 | 16 | var startUpcwd, getwdError = os.Getwd() 17 | 18 | func executable() (string, error) { 19 | var mib [4]int32 20 | switch runtime.GOOS { 21 | case "freebsd": 22 | mib = [4]int32{1 /* CTL_KERN */, 14 /* KERN_PROC */, 12 /* KERN_PROC_PATHNAME */, -1} 23 | case "darwin": 24 | mib = [4]int32{1 /* CTL_KERN */, 38 /* KERN_PROCARGS */, int32(os.Getpid()), -1} 25 | } 26 | 27 | n := uintptr(0) 28 | // get length 29 | _, _, err := syscall.Syscall6(syscall.SYS___SYSCTL, uintptr(unsafe.Pointer(&mib[0])), 4, 0, uintptr(unsafe.Pointer(&n)), 0, 0) 30 | if err != 0 { 31 | return "", err 32 | } 33 | if n == 0 { // shouldn't happen 34 | return "", nil 35 | } 36 | buf := make([]byte, n) 37 | _, _, err = syscall.Syscall6(syscall.SYS___SYSCTL, uintptr(unsafe.Pointer(&mib[0])), 4, uintptr(unsafe.Pointer(&buf[0])), uintptr(unsafe.Pointer(&n)), 0, 0) 38 | if err != 0 { 39 | return "", err 40 | } 41 | if n == 0 { // shouldn't happen 42 | return "", nil 43 | } 44 | for i, v := range buf { 45 | if v == 0 { 46 | buf = buf[:i] 47 | break 48 | } 49 | } 50 | if buf[0] != '/' { 51 | if getwdError != nil { 52 | return string(buf), getwdError 53 | } else { 54 | if buf[0] == '.' { 55 | buf = buf[1:] 56 | } 57 | if startUpcwd[len(startUpcwd)-1] != '/' { 58 | return startUpcwd + "/" + string(buf), nil 59 | } 60 | return startUpcwd + string(buf), nil 61 | } 62 | } 63 | return string(buf), nil 64 | } 65 | -------------------------------------------------------------------------------- /vendor/src/github.com/bugsnag/osext/osext_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2012 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // +build darwin linux freebsd netbsd windows 6 | 7 | package osext 8 | 9 | import ( 10 | "fmt" 11 | "os" 12 | oexec "os/exec" 13 | "path/filepath" 14 | "runtime" 15 | "testing" 16 | ) 17 | 18 | const execPath_EnvVar = "OSTEST_OUTPUT_EXECPATH" 19 | 20 | func TestExecPath(t *testing.T) { 21 | ep, err := Executable() 22 | if err != nil { 23 | t.Fatalf("ExecPath failed: %v", err) 24 | } 25 | // we want fn to be of the form "dir/prog" 26 | dir := filepath.Dir(filepath.Dir(ep)) 27 | fn, err := filepath.Rel(dir, ep) 28 | if err != nil { 29 | t.Fatalf("filepath.Rel: %v", err) 30 | } 31 | cmd := &oexec.Cmd{} 32 | // make child start with a relative program path 33 | cmd.Dir = dir 34 | cmd.Path = fn 35 | // forge argv[0] for child, so that we can verify we could correctly 36 | // get real path of the executable without influenced by argv[0]. 37 | cmd.Args = []string{"-", "-test.run=XXXX"} 38 | cmd.Env = []string{fmt.Sprintf("%s=1", execPath_EnvVar)} 39 | out, err := cmd.CombinedOutput() 40 | if err != nil { 41 | t.Fatalf("exec(self) failed: %v", err) 42 | } 43 | outs := string(out) 44 | if !filepath.IsAbs(outs) { 45 | t.Fatalf("Child returned %q, want an absolute path", out) 46 | } 47 | if !sameFile(outs, ep) { 48 | t.Fatalf("Child returned %q, not the same file as %q", out, ep) 49 | } 50 | } 51 | 52 | func sameFile(fn1, fn2 string) bool { 53 | fi1, err := os.Stat(fn1) 54 | if err != nil { 55 | return false 56 | } 57 | fi2, err := os.Stat(fn2) 58 | if err != nil { 59 | return false 60 | } 61 | return os.SameFile(fi1, fi2) 62 | } 63 | 64 | func init() { 65 | if e := os.Getenv(execPath_EnvVar); e != "" { 66 | // first chdir to another path 67 | dir := "/" 68 | if runtime.GOOS == "windows" { 69 | dir = filepath.VolumeName(".") 70 | } 71 | os.Chdir(dir) 72 | if ep, err := Executable(); err != nil { 73 | fmt.Fprint(os.Stderr, "ERROR: ", err) 74 | } else { 75 | fmt.Fprint(os.Stderr, ep) 76 | } 77 | os.Exit(0) 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /vendor/src/github.com/bugsnag/osext/osext_windows.go: -------------------------------------------------------------------------------- 1 | // Copyright 2012 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package osext 6 | 7 | import ( 8 | "syscall" 9 | "unicode/utf16" 10 | "unsafe" 11 | ) 12 | 13 | var ( 14 | kernel = syscall.MustLoadDLL("kernel32.dll") 15 | getModuleFileNameProc = kernel.MustFindProc("GetModuleFileNameW") 16 | ) 17 | 18 | // GetModuleFileName() with hModule = NULL 19 | func executable() (exePath string, err error) { 20 | return getModuleFileName() 21 | } 22 | 23 | func getModuleFileName() (string, error) { 24 | var n uint32 25 | b := make([]uint16, syscall.MAX_PATH) 26 | size := uint32(len(b)) 27 | 28 | r0, _, e1 := getModuleFileNameProc.Call(0, uintptr(unsafe.Pointer(&b[0])), uintptr(size)) 29 | n = uint32(r0) 30 | if n == 0 { 31 | return "", e1 32 | } 33 | return string(utf16.Decode(b[0:n])), nil 34 | } 35 | -------------------------------------------------------------------------------- /vendor/src/github.com/bugsnag/panicwrap/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2013 Mitchell Hashimoto 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /vendor/src/github.com/bugsnag/panicwrap/monitor.go: -------------------------------------------------------------------------------- 1 | // +build !windows 2 | 3 | package panicwrap 4 | 5 | import ( 6 | "github.com/bugsnag/osext" 7 | "os" 8 | "os/exec" 9 | "syscall" 10 | ) 11 | 12 | func monitor(c *WrapConfig) (int, error) { 13 | 14 | // If we're the child process, absorb panics. 15 | if Wrapped(c) { 16 | panicCh := make(chan string) 17 | 18 | go trackPanic(os.Stdin, os.Stderr, c.DetectDuration, panicCh) 19 | 20 | // Wait on the panic data 21 | panicTxt := <-panicCh 22 | if panicTxt != "" { 23 | if !c.HidePanic { 24 | os.Stderr.Write([]byte(panicTxt)) 25 | } 26 | 27 | c.Handler(panicTxt) 28 | } 29 | 30 | os.Exit(0) 31 | } 32 | 33 | exePath, err := osext.Executable() 34 | if err != nil { 35 | return -1, err 36 | } 37 | cmd := exec.Command(exePath, os.Args[1:]...) 38 | 39 | read, write, err := os.Pipe() 40 | if err != nil { 41 | return -1, err 42 | } 43 | 44 | cmd.Stdin = read 45 | cmd.Stdout = os.Stdout 46 | cmd.Stderr = os.Stderr 47 | cmd.Env = append(os.Environ(), c.CookieKey+"="+c.CookieValue) 48 | 49 | if err != nil { 50 | return -1, err 51 | } 52 | err = cmd.Start() 53 | if err != nil { 54 | return -1, err 55 | } 56 | 57 | err = syscall.Dup2(int(write.Fd()), int(os.Stderr.Fd())) 58 | if err != nil { 59 | return -1, err 60 | } 61 | 62 | return -1, nil 63 | } 64 | -------------------------------------------------------------------------------- /vendor/src/github.com/bugsnag/panicwrap/monitor_windows.go: -------------------------------------------------------------------------------- 1 | package panicwrap 2 | 3 | import "fmt" 4 | 5 | func monitor(c *WrapConfig) (int, error) { 6 | return -1, fmt.Errorf("Monitor is not supported on windows") 7 | } 8 | -------------------------------------------------------------------------------- /vendor/src/github.com/codahale/hdrhistogram/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Coda Hale 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /vendor/src/github.com/codahale/hdrhistogram/README.md: -------------------------------------------------------------------------------- 1 | hdrhistogram 2 | ============ 3 | 4 | [![Build Status](https://travis-ci.org/codahale/hdrhistogram.png?branch=master)](https://travis-ci.org/codahale/hdrhistogram) 5 | 6 | A pure Go implementation of the [HDR Histogram](https://github.com/HdrHistogram/HdrHistogram). 7 | 8 | > A Histogram that supports recording and analyzing sampled data value counts 9 | > across a configurable integer value range with configurable value precision 10 | > within the range. Value precision is expressed as the number of significant 11 | > digits in the value recording, and provides control over value quantization 12 | > behavior across the value range and the subsequent value resolution at any 13 | > given level. 14 | 15 | For documentation, check [godoc](http://godoc.org/github.com/codahale/hdrhistogram). 16 | -------------------------------------------------------------------------------- /vendor/src/github.com/codahale/hdrhistogram/window.go: -------------------------------------------------------------------------------- 1 | package hdrhistogram 2 | 3 | // A WindowedHistogram combines histograms to provide windowed statistics. 4 | type WindowedHistogram struct { 5 | idx int 6 | h []Histogram 7 | m *Histogram 8 | 9 | Current *Histogram 10 | } 11 | 12 | // NewWindowed creates a new WindowedHistogram with N underlying histograms with 13 | // the given parameters. 14 | func NewWindowed(n int, minValue, maxValue int64, sigfigs int) *WindowedHistogram { 15 | w := WindowedHistogram{ 16 | idx: -1, 17 | h: make([]Histogram, n), 18 | m: New(minValue, maxValue, sigfigs), 19 | } 20 | 21 | for i := range w.h { 22 | w.h[i] = *New(minValue, maxValue, sigfigs) 23 | } 24 | w.Rotate() 25 | 26 | return &w 27 | } 28 | 29 | // Merge returns a histogram which includes the recorded values from all the 30 | // sections of the window. 31 | func (w *WindowedHistogram) Merge() *Histogram { 32 | w.m.Reset() 33 | for _, h := range w.h { 34 | w.m.Merge(&h) 35 | } 36 | return w.m 37 | } 38 | 39 | // Rotate resets the oldest histogram and rotates it to be used as the current 40 | // histogram. 41 | func (w *WindowedHistogram) Rotate() { 42 | w.idx++ 43 | w.Current = &w.h[w.idx%len(w.h)] 44 | w.Current.Reset() 45 | } 46 | -------------------------------------------------------------------------------- /vendor/src/github.com/codahale/hdrhistogram/window_test.go: -------------------------------------------------------------------------------- 1 | package hdrhistogram_test 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/codahale/hdrhistogram" 7 | ) 8 | 9 | func TestWindowedHistogram(t *testing.T) { 10 | w := hdrhistogram.NewWindowed(2, 1, 1000, 3) 11 | 12 | for i := 0; i < 100; i++ { 13 | w.Current.RecordValue(int64(i)) 14 | } 15 | w.Rotate() 16 | 17 | for i := 100; i < 200; i++ { 18 | w.Current.RecordValue(int64(i)) 19 | } 20 | w.Rotate() 21 | 22 | for i := 200; i < 300; i++ { 23 | w.Current.RecordValue(int64(i)) 24 | } 25 | 26 | if v, want := w.Merge().ValueAtQuantile(50), int64(199); v != want { 27 | t.Errorf("Median was %v, but expected %v", v, want) 28 | } 29 | } 30 | 31 | func BenchmarkWindowedHistogramRecordAndRotate(b *testing.B) { 32 | w := hdrhistogram.NewWindowed(3, 1, 10000000, 3) 33 | b.ReportAllocs() 34 | b.ResetTimer() 35 | 36 | for i := 0; i < b.N; i++ { 37 | if err := w.Current.RecordValue(100); err != nil { 38 | b.Fatal(err) 39 | } 40 | 41 | if i%100000 == 1 { 42 | w.Rotate() 43 | } 44 | } 45 | } 46 | 47 | func BenchmarkWindowedHistogramMerge(b *testing.B) { 48 | w := hdrhistogram.NewWindowed(3, 1, 10000000, 3) 49 | for i := 0; i < 10000000; i++ { 50 | if err := w.Current.RecordValue(100); err != nil { 51 | b.Fatal(err) 52 | } 53 | 54 | if i%100000 == 1 { 55 | w.Rotate() 56 | } 57 | } 58 | b.ReportAllocs() 59 | b.ResetTimer() 60 | 61 | for i := 0; i < b.N; i++ { 62 | w.Merge() 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /vendor/src/github.com/getsentry/raven-go/Dockerfile.test: -------------------------------------------------------------------------------- 1 | FROM golang:1.4 2 | 3 | RUN mkdir -p /go/src/github.com/getsentry/raven-go 4 | WORKDIR /go/src/github.com/getsentry/raven-go 5 | ENV GOPATH /go 6 | 7 | RUN go install -race std && go get golang.org/x/tools/cmd/cover 8 | 9 | COPY . /go/src/github.com/getsentry/raven-go 10 | 11 | CMD ["./runtests.sh"] 12 | -------------------------------------------------------------------------------- /vendor/src/github.com/getsentry/raven-go/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013 Apollic Software, LLC. All rights reserved. 2 | Copyright (c) 2015 Functional Software, Inc. All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are 6 | met: 7 | 8 | * Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | * Redistributions in binary form must reproduce the above 11 | copyright notice, this list of conditions and the following disclaimer 12 | in the documentation and/or other materials provided with the 13 | distribution. 14 | * Neither the name of Apollic Software, LLC nor the names of its 15 | contributors may be used to endorse or promote products derived from 16 | this software without specific prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | -------------------------------------------------------------------------------- /vendor/src/github.com/getsentry/raven-go/README.md: -------------------------------------------------------------------------------- 1 | # raven [![Build Status](https://travis-ci.org/getsentry/raven-go.png?branch=master)](https://travis-ci.org/getsentry/raven-go) 2 | 3 | raven is a Go client for the [Sentry](https://github.com/getsentry/sentry) 4 | event/error logging system. 5 | 6 | [**Documentation**](http://godoc.org/github.com/getsentry/raven-go). 7 | 8 | ## Installation 9 | 10 | ```text 11 | go get github.com/getsentry/raven-go 12 | ``` 13 | -------------------------------------------------------------------------------- /vendor/src/github.com/getsentry/raven-go/docs/index.rst: -------------------------------------------------------------------------------- 1 | .. sentry:edition:: self 2 | 3 | Raven Go 4 | ======== 5 | 6 | .. sentry:edition:: hosted, on-premise 7 | 8 | .. class:: platform-go 9 | 10 | Go 11 | == 12 | 13 | Raven-Go provides a Sentry client implementation for the Go programming 14 | language. 15 | 16 | Installation 17 | ------------ 18 | 19 | Raven-Go can be installed like any other Go library through ``go get``:: 20 | 21 | $ go get github.com/getsentry/raven-go 22 | 23 | Minimal Example 24 | --------------- 25 | 26 | .. sourcecode:: go 27 | 28 | package main 29 | 30 | import ( 31 | "github.com/getsentry/raven-go" 32 | ) 33 | 34 | func main() { 35 | raven.SetDSN("___DSN___") 36 | 37 | _, err := DoSomethingThatFails() 38 | if err != nil { 39 | raven.CaptureErrorAndWait(err, nil); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /vendor/src/github.com/getsentry/raven-go/docs/sentry-doc-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "platforms": { 3 | "go": { 4 | "name": "Go", 5 | "type": "language", 6 | "doc_link": "", 7 | "wizard": [ 8 | "index#installation", 9 | "index#configuring-the-client", 10 | "index#reporting-errors" 11 | ] 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /vendor/src/github.com/getsentry/raven-go/example/example.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "github.com/getsentry/raven-go" 7 | "log" 8 | "net/http" 9 | "os" 10 | ) 11 | 12 | func trace() *raven.Stacktrace { 13 | return raven.NewStacktrace(0, 2, nil) 14 | } 15 | 16 | func main() { 17 | client, err := raven.NewWithTags(os.Args[1], map[string]string{"foo": "bar"}) 18 | if err != nil { 19 | log.Fatal(err) 20 | } 21 | httpReq, _ := http.NewRequest("GET", "http://example.com/foo?bar=true", nil) 22 | httpReq.RemoteAddr = "127.0.0.1:80" 23 | httpReq.Header = http.Header{"Content-Type": {"text/html"}, "Content-Length": {"42"}} 24 | packet := &raven.Packet{Message: "Test report", Interfaces: []raven.Interface{raven.NewException(errors.New("example"), trace()), raven.NewHttp(httpReq)}} 25 | _, ch := client.Capture(packet, nil) 26 | if err = <-ch; err != nil { 27 | log.Fatal(err) 28 | } 29 | log.Print("sent packet successfully") 30 | } 31 | 32 | // CheckError sends error report to sentry and records event id and error name to the logs 33 | func CheckError(err error, r *http.Request) { 34 | client, err := raven.NewWithTags(os.Args[1], map[string]string{"foo": "bar"}) 35 | if err != nil { 36 | log.Fatal(err) 37 | } 38 | packet := raven.NewPacket(err.Error(), raven.NewException(err, trace()), raven.NewHttp(r)) 39 | eventID, _ := client.Capture(packet, nil) 40 | message := fmt.Sprintf("Error event with id \"%s\" - %s", eventID, err.Error()) 41 | log.Println(message) 42 | } 43 | -------------------------------------------------------------------------------- /vendor/src/github.com/getsentry/raven-go/examples_test.go: -------------------------------------------------------------------------------- 1 | package raven 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "net/http" 7 | ) 8 | 9 | func Example() { 10 | // ... i.e. raisedErr is incoming error 11 | var raisedErr error 12 | // sentry DSN generated by Sentry server 13 | var sentryDSN string 14 | // r is a request performed when error occured 15 | var r *http.Request 16 | client, err := New(sentryDSN) 17 | if err != nil { 18 | log.Fatal(err) 19 | } 20 | trace := NewStacktrace(0, 2, nil) 21 | packet := NewPacket(raisedErr.Error(), NewException(raisedErr, trace), NewHttp(r)) 22 | eventID, ch := client.Capture(packet, nil) 23 | if err = <-ch; err != nil { 24 | log.Fatal(err) 25 | } 26 | message := fmt.Sprintf("Captured error with id %s: %q", eventID, raisedErr) 27 | log.Println(message) 28 | } 29 | -------------------------------------------------------------------------------- /vendor/src/github.com/getsentry/raven-go/exception.go: -------------------------------------------------------------------------------- 1 | package raven 2 | 3 | import ( 4 | "reflect" 5 | "regexp" 6 | ) 7 | 8 | var errorMsgPattern = regexp.MustCompile(`\A(\w+): (.+)\z`) 9 | 10 | func NewException(err error, stacktrace *Stacktrace) *Exception { 11 | msg := err.Error() 12 | ex := &Exception{ 13 | Stacktrace: stacktrace, 14 | Value: msg, 15 | Type: reflect.TypeOf(err).String(), 16 | } 17 | if m := errorMsgPattern.FindStringSubmatch(msg); m != nil { 18 | ex.Module, ex.Value = m[1], m[2] 19 | } 20 | return ex 21 | } 22 | 23 | // http://sentry.readthedocs.org/en/latest/developer/interfaces/index.html#sentry.interfaces.Exception 24 | type Exception struct { 25 | // Required 26 | Value string `json:"value"` 27 | 28 | // Optional 29 | Type string `json:"type,omitempty"` 30 | Module string `json:"module,omitempty"` 31 | Stacktrace *Stacktrace `json:"stacktrace,omitempty"` 32 | } 33 | 34 | func (e *Exception) Class() string { return "exception" } 35 | 36 | func (e *Exception) Culprit() string { 37 | if e.Stacktrace == nil { 38 | return "" 39 | } 40 | return e.Stacktrace.Culprit() 41 | } 42 | -------------------------------------------------------------------------------- /vendor/src/github.com/getsentry/raven-go/exception_test.go: -------------------------------------------------------------------------------- 1 | package raven 2 | 3 | import ( 4 | "errors" 5 | "testing" 6 | ) 7 | 8 | var newExceptionTests = []struct { 9 | err error 10 | Exception 11 | }{ 12 | {errors.New("foobar"), Exception{Value: "foobar", Type: "*errors.errorString"}}, 13 | {errors.New("bar: foobar"), Exception{Value: "foobar", Type: "*errors.errorString", Module: "bar"}}, 14 | } 15 | 16 | func TestNewException(t *testing.T) { 17 | for _, test := range newExceptionTests { 18 | actual := NewException(test.err, nil) 19 | if actual.Value != test.Value { 20 | t.Errorf("incorrect Value: got %s, want %s", actual.Value, test.Value) 21 | } 22 | if actual.Type != test.Type { 23 | t.Errorf("incorrect Type: got %s, want %s", actual.Type, test.Type) 24 | } 25 | if actual.Module != test.Module { 26 | t.Errorf("incorrect Module: got %s, want %s", actual.Module, test.Module) 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /vendor/src/github.com/getsentry/raven-go/http.go: -------------------------------------------------------------------------------- 1 | package raven 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "net" 7 | "net/http" 8 | "net/url" 9 | "runtime/debug" 10 | "strings" 11 | ) 12 | 13 | func NewHttp(req *http.Request) *Http { 14 | proto := "http" 15 | if req.TLS != nil || req.Header.Get("X-Forwarded-Proto") == "https" { 16 | proto = "https" 17 | } 18 | h := &Http{ 19 | Method: req.Method, 20 | Cookies: req.Header.Get("Cookie"), 21 | Query: sanitizeQuery(req.URL.Query()).Encode(), 22 | URL: proto + "://" + req.Host + req.URL.Path, 23 | Headers: make(map[string]string, len(req.Header)), 24 | } 25 | if addr, port, err := net.SplitHostPort(req.RemoteAddr); err == nil { 26 | h.Env = map[string]string{"REMOTE_ADDR": addr, "REMOTE_PORT": port} 27 | } 28 | for k, v := range req.Header { 29 | h.Headers[k] = strings.Join(v, ",") 30 | } 31 | return h 32 | } 33 | 34 | var querySecretFields = []string{"password", "passphrase", "passwd", "secret"} 35 | 36 | func sanitizeQuery(query url.Values) url.Values { 37 | for _, keyword := range querySecretFields { 38 | for field := range query { 39 | if strings.Contains(field, keyword) { 40 | query[field] = []string{"********"} 41 | } 42 | } 43 | } 44 | return query 45 | } 46 | 47 | // http://sentry.readthedocs.org/en/latest/developer/interfaces/index.html#sentry.interfaces.Http 48 | type Http struct { 49 | // Required 50 | URL string `json:"url"` 51 | Method string `json:"method"` 52 | Query string `json:"query_string,omitempty"` 53 | 54 | // Optional 55 | Cookies string `json:"cookies,omitempty"` 56 | Headers map[string]string `json:"headers,omitempty"` 57 | Env map[string]string `json:"env,omitempty"` 58 | 59 | // Must be either a string or map[string]string 60 | Data interface{} `json:"data,omitempty"` 61 | } 62 | 63 | func (h *Http) Class() string { return "request" } 64 | 65 | // Recovery handler to wrap the stdlib net/http Mux. 66 | // Example: 67 | // http.HandleFunc("/", raven.RecoveryHandler(func(w http.ResponseWriter, r *http.Request) { 68 | // ... 69 | // })) 70 | func RecoveryHandler(handler func(http.ResponseWriter, *http.Request)) func(http.ResponseWriter, *http.Request) { 71 | return func(w http.ResponseWriter, r *http.Request) { 72 | defer func() { 73 | if rval := recover(); rval != nil { 74 | debug.PrintStack() 75 | rvalStr := fmt.Sprint(rval) 76 | packet := NewPacket(rvalStr, NewException(errors.New(rvalStr), NewStacktrace(2, 3, nil)), NewHttp(r)) 77 | Capture(packet, nil) 78 | w.WriteHeader(http.StatusInternalServerError) 79 | } 80 | }() 81 | 82 | handler(w, r) 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /vendor/src/github.com/getsentry/raven-go/interfaces.go: -------------------------------------------------------------------------------- 1 | package raven 2 | 3 | // http://sentry.readthedocs.org/en/latest/developer/interfaces/index.html#sentry.interfaces.Message 4 | type Message struct { 5 | // Required 6 | Message string `json:"message"` 7 | 8 | // Optional 9 | Params []interface{} `json:"params,omitempty"` 10 | } 11 | 12 | func (m *Message) Class() string { return "logentry" } 13 | 14 | // http://sentry.readthedocs.org/en/latest/developer/interfaces/index.html#sentry.interfaces.Template 15 | type Template struct { 16 | // Required 17 | Filename string `json:"filename"` 18 | Lineno int `json:"lineno"` 19 | ContextLine string `json:"context_line"` 20 | 21 | // Optional 22 | PreContext []string `json:"pre_context,omitempty"` 23 | PostContext []string `json:"post_context,omitempty"` 24 | AbsolutePath string `json:"abs_path,omitempty"` 25 | } 26 | 27 | func (t *Template) Class() string { return "template" } 28 | 29 | // http://sentry.readthedocs.org/en/latest/developer/interfaces/index.html#sentry.interfaces.User 30 | type User struct { 31 | // All fields are optional 32 | ID string `json:"id,omitempty"` 33 | Username string `json:"username,omitempty"` 34 | Email string `json:"email,omitempty"` 35 | IP string `json:"ip_address,omitempty"` 36 | } 37 | 38 | func (h *User) Class() string { return "user" } 39 | 40 | // http://sentry.readthedocs.org/en/latest/developer/interfaces/index.html#sentry.interfaces.Query 41 | type Query struct { 42 | // Required 43 | Query string `json:"query"` 44 | 45 | // Optional 46 | Engine string `json:"engine,omitempty"` 47 | } 48 | 49 | func (q *Query) Class() string { return "query" } 50 | -------------------------------------------------------------------------------- /vendor/src/github.com/getsentry/raven-go/runtests.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | go test -race ./... 3 | go test -cover ./... 4 | go test -v ./... 5 | -------------------------------------------------------------------------------- /vendor/src/github.com/getsentry/raven-go/writer.go: -------------------------------------------------------------------------------- 1 | package raven 2 | 3 | type Writer struct { 4 | Client *Client 5 | Level Severity 6 | Logger string // Logger name reported to Sentry 7 | } 8 | 9 | // Write formats the byte slice p into a string, and sends a message to 10 | // Sentry at the severity level indicated by the Writer w. 11 | func (w *Writer) Write(p []byte) (int, error) { 12 | message := string(p) 13 | 14 | packet := NewPacket(message, &Message{message, nil}) 15 | packet.Level = w.Level 16 | packet.Logger = w.Logger 17 | w.Client.Capture(packet, nil) 18 | 19 | return len(p), nil 20 | } 21 | -------------------------------------------------------------------------------- /vendor/src/github.com/mailgun/multibuf/Makefile: -------------------------------------------------------------------------------- 1 | clean: 2 | find . -name flymake_* -delete 3 | 4 | test: clean 5 | go test -v . 6 | 7 | test-grep: clean 8 | go test -v . -check.f=$(e) 9 | 10 | cover: clean 11 | go test -v . -coverprofile=/tmp/coverage.out 12 | go tool cover -html=/tmp/coverage.out 13 | -------------------------------------------------------------------------------- /vendor/src/github.com/mailgun/multibuf/README.md: -------------------------------------------------------------------------------- 1 | Multibuf 2 | ======== 3 | 4 | Bytes buffer that implements seeking and partially persisting to disk. 5 | 6 | Please read http://godoc.org/github.com/mailgun/multibuf 7 | -------------------------------------------------------------------------------- /vendor/src/github.com/mailgun/oxy/forward/headers.go: -------------------------------------------------------------------------------- 1 | package forward 2 | 3 | const ( 4 | XForwardedProto = "X-Forwarded-Proto" 5 | XForwardedFor = "X-Forwarded-For" 6 | XForwardedHost = "X-Forwarded-Host" 7 | XForwardedServer = "X-Forwarded-Server" 8 | Connection = "Connection" 9 | KeepAlive = "Keep-Alive" 10 | ProxyAuthenticate = "Proxy-Authenticate" 11 | ProxyAuthorization = "Proxy-Authorization" 12 | Te = "Te" // canonicalized version of "TE" 13 | Trailers = "Trailers" 14 | TransferEncoding = "Transfer-Encoding" 15 | Upgrade = "Upgrade" 16 | ContentLength = "Content-Length" 17 | ) 18 | 19 | // Hop-by-hop headers. These are removed when sent to the backend. 20 | // http://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html 21 | // Copied from reverseproxy.go, too bad 22 | var HopHeaders = []string{ 23 | Connection, 24 | KeepAlive, 25 | ProxyAuthenticate, 26 | ProxyAuthorization, 27 | Te, // canonicalized version of "TE" 28 | Trailers, 29 | TransferEncoding, 30 | Upgrade, 31 | } 32 | -------------------------------------------------------------------------------- /vendor/src/github.com/mailgun/oxy/forward/rewrite.go: -------------------------------------------------------------------------------- 1 | package forward 2 | 3 | import ( 4 | "net" 5 | "net/http" 6 | "strings" 7 | 8 | "github.com/mailgun/oxy/utils" 9 | ) 10 | 11 | // Rewriter is responsible for removing hop-by-hop headers and setting forwarding headers 12 | type HeaderRewriter struct { 13 | TrustForwardHeader bool 14 | Hostname string 15 | } 16 | 17 | func (rw *HeaderRewriter) Rewrite(req *http.Request) { 18 | if clientIP, _, err := net.SplitHostPort(req.RemoteAddr); err == nil { 19 | if rw.TrustForwardHeader { 20 | if prior, ok := req.Header[XForwardedFor]; ok { 21 | clientIP = strings.Join(prior, ", ") + ", " + clientIP 22 | } 23 | } 24 | req.Header.Set(XForwardedFor, clientIP) 25 | } 26 | 27 | if xfp := req.Header.Get(XForwardedProto); xfp != "" && rw.TrustForwardHeader { 28 | req.Header.Set(XForwardedProto, xfp) 29 | } else if req.TLS != nil { 30 | req.Header.Set(XForwardedProto, "https") 31 | } else { 32 | req.Header.Set(XForwardedProto, "http") 33 | } 34 | 35 | if xfh := req.Header.Get(XForwardedHost); xfh != "" && rw.TrustForwardHeader { 36 | req.Header.Set(XForwardedHost, xfh) 37 | } else if req.Host != "" { 38 | req.Header.Set(XForwardedHost, req.Host) 39 | } 40 | 41 | if rw.Hostname != "" { 42 | req.Header.Set(XForwardedServer, rw.Hostname) 43 | } 44 | 45 | // Remove hop-by-hop headers to the backend. Especially important is "Connection" because we want a persistent 46 | // connection, regardless of what the client sent to us. 47 | utils.RemoveHeaders(req.Header, HopHeaders...) 48 | } 49 | -------------------------------------------------------------------------------- /vendor/src/github.com/mailgun/oxy/memmetrics/counter_test.go: -------------------------------------------------------------------------------- 1 | package memmetrics 2 | 3 | import ( 4 | "time" 5 | 6 | "github.com/mailgun/timetools" 7 | . "gopkg.in/check.v1" 8 | ) 9 | 10 | type CounterSuite struct { 11 | clock *timetools.FreezedTime 12 | } 13 | 14 | var _ = Suite(&CounterSuite{}) 15 | 16 | func (s *CounterSuite) SetUpSuite(c *C) { 17 | s.clock = &timetools.FreezedTime{ 18 | CurrentTime: time.Date(2012, 3, 4, 5, 6, 7, 0, time.UTC), 19 | } 20 | } 21 | 22 | func (s *CounterSuite) TestCloneExpired(c *C) { 23 | cnt, err := NewCounter(3, time.Second, CounterClock(s.clock)) 24 | c.Assert(err, IsNil) 25 | cnt.Inc(1) 26 | s.clock.Sleep(time.Second) 27 | cnt.Inc(1) 28 | s.clock.Sleep(time.Second) 29 | cnt.Inc(1) 30 | s.clock.Sleep(time.Second) 31 | 32 | out := cnt.Clone() 33 | c.Assert(out.Count(), Equals, int64(2)) 34 | } 35 | -------------------------------------------------------------------------------- /vendor/src/github.com/mailgun/oxy/memmetrics/ratio.go: -------------------------------------------------------------------------------- 1 | package memmetrics 2 | 3 | import ( 4 | "time" 5 | 6 | "github.com/mailgun/timetools" 7 | ) 8 | 9 | type ratioOptSetter func(r *RatioCounter) error 10 | 11 | func RatioClock(clock timetools.TimeProvider) ratioOptSetter { 12 | return func(r *RatioCounter) error { 13 | r.clock = clock 14 | return nil 15 | } 16 | } 17 | 18 | // RatioCounter calculates a ratio of a/a+b over a rolling window of predefined buckets 19 | type RatioCounter struct { 20 | clock timetools.TimeProvider 21 | a *RollingCounter 22 | b *RollingCounter 23 | } 24 | 25 | func NewRatioCounter(buckets int, resolution time.Duration, options ...ratioOptSetter) (*RatioCounter, error) { 26 | rc := &RatioCounter{} 27 | 28 | for _, o := range options { 29 | if err := o(rc); err != nil { 30 | return nil, err 31 | } 32 | } 33 | 34 | if rc.clock == nil { 35 | rc.clock = &timetools.RealTime{} 36 | } 37 | 38 | a, err := NewCounter(buckets, resolution, CounterClock(rc.clock)) 39 | if err != nil { 40 | return nil, err 41 | } 42 | 43 | b, err := NewCounter(buckets, resolution, CounterClock(rc.clock)) 44 | if err != nil { 45 | return nil, err 46 | } 47 | 48 | rc.a = a 49 | rc.b = b 50 | return rc, nil 51 | } 52 | 53 | func (r *RatioCounter) Reset() { 54 | r.a.Reset() 55 | r.b.Reset() 56 | } 57 | 58 | func (r *RatioCounter) IsReady() bool { 59 | return r.a.countedBuckets+r.b.countedBuckets >= len(r.a.values) 60 | } 61 | 62 | func (r *RatioCounter) CountA() int64 { 63 | return r.a.Count() 64 | } 65 | 66 | func (r *RatioCounter) CountB() int64 { 67 | return r.b.Count() 68 | } 69 | 70 | func (r *RatioCounter) Resolution() time.Duration { 71 | return r.a.Resolution() 72 | } 73 | 74 | func (r *RatioCounter) Buckets() int { 75 | return r.a.Buckets() 76 | } 77 | 78 | func (r *RatioCounter) WindowSize() time.Duration { 79 | return r.a.WindowSize() 80 | } 81 | 82 | func (r *RatioCounter) ProcessedCount() int64 { 83 | return r.CountA() + r.CountB() 84 | } 85 | 86 | func (r *RatioCounter) Ratio() float64 { 87 | a := r.a.Count() 88 | b := r.b.Count() 89 | // No data, return ok 90 | if a+b == 0 { 91 | return 0 92 | } 93 | return float64(a) / float64(a+b) 94 | } 95 | 96 | func (r *RatioCounter) IncA(v int) { 97 | r.a.Inc(v) 98 | } 99 | 100 | func (r *RatioCounter) IncB(v int) { 101 | r.b.Inc(v) 102 | } 103 | 104 | type TestMeter struct { 105 | Rate float64 106 | NotReady bool 107 | WindowSize time.Duration 108 | } 109 | 110 | func (tm *TestMeter) GetWindowSize() time.Duration { 111 | return tm.WindowSize 112 | } 113 | 114 | func (tm *TestMeter) IsReady() bool { 115 | return !tm.NotReady 116 | } 117 | 118 | func (tm *TestMeter) GetRate() float64 { 119 | return tm.Rate 120 | } 121 | -------------------------------------------------------------------------------- /vendor/src/github.com/mailgun/oxy/memmetrics/roundtrip_test.go: -------------------------------------------------------------------------------- 1 | package memmetrics 2 | 3 | import ( 4 | "time" 5 | 6 | "github.com/mailgun/timetools" 7 | . "gopkg.in/check.v1" 8 | ) 9 | 10 | type RRSuite struct { 11 | tm *timetools.FreezedTime 12 | } 13 | 14 | var _ = Suite(&RRSuite{}) 15 | 16 | func (s *RRSuite) SetUpSuite(c *C) { 17 | s.tm = &timetools.FreezedTime{ 18 | CurrentTime: time.Date(2012, 3, 4, 5, 6, 7, 0, time.UTC), 19 | } 20 | } 21 | 22 | func (s *RRSuite) TestDefaults(c *C) { 23 | rr, err := NewRTMetrics(RTClock(s.tm)) 24 | c.Assert(err, IsNil) 25 | c.Assert(rr, NotNil) 26 | 27 | rr.Record(200, time.Second) 28 | rr.Record(502, 2*time.Second) 29 | rr.Record(200, time.Second) 30 | rr.Record(200, time.Second) 31 | 32 | c.Assert(rr.NetworkErrorCount(), Equals, int64(1)) 33 | c.Assert(rr.TotalCount(), Equals, int64(4)) 34 | c.Assert(rr.StatusCodesCounts(), DeepEquals, map[int]int64{502: 1, 200: 3}) 35 | c.Assert(rr.NetworkErrorRatio(), Equals, float64(1)/float64(4)) 36 | c.Assert(rr.ResponseCodeRatio(500, 503, 200, 300), Equals, 1.0/3.0) 37 | 38 | h, err := rr.LatencyHistogram() 39 | c.Assert(err, IsNil) 40 | c.Assert(int(h.LatencyAtQuantile(100)/time.Second), Equals, 2) 41 | 42 | rr.Reset() 43 | c.Assert(rr.NetworkErrorCount(), Equals, int64(0)) 44 | c.Assert(rr.TotalCount(), Equals, int64(0)) 45 | c.Assert(rr.StatusCodesCounts(), DeepEquals, map[int]int64{}) 46 | c.Assert(rr.NetworkErrorRatio(), Equals, float64(0)) 47 | c.Assert(rr.ResponseCodeRatio(500, 503, 200, 300), Equals, float64(0)) 48 | 49 | h, err = rr.LatencyHistogram() 50 | c.Assert(err, IsNil) 51 | c.Assert(h.LatencyAtQuantile(100), Equals, time.Duration(0)) 52 | 53 | } 54 | 55 | func (s *RRSuite) TestAppend(c *C) { 56 | rr, err := NewRTMetrics(RTClock(s.tm)) 57 | c.Assert(err, IsNil) 58 | c.Assert(rr, NotNil) 59 | 60 | rr.Record(200, time.Second) 61 | rr.Record(502, 2*time.Second) 62 | rr.Record(200, time.Second) 63 | rr.Record(200, time.Second) 64 | 65 | rr2, err := NewRTMetrics(RTClock(s.tm)) 66 | c.Assert(err, IsNil) 67 | c.Assert(rr2, NotNil) 68 | 69 | rr2.Record(200, 3*time.Second) 70 | rr2.Record(501, 3*time.Second) 71 | rr2.Record(200, 3*time.Second) 72 | rr2.Record(200, 3*time.Second) 73 | 74 | c.Assert(rr2.Append(rr), IsNil) 75 | c.Assert(rr2.StatusCodesCounts(), DeepEquals, map[int]int64{501: 1, 502: 1, 200: 6}) 76 | c.Assert(rr2.NetworkErrorCount(), Equals, int64(1)) 77 | 78 | h, err := rr2.LatencyHistogram() 79 | c.Assert(err, IsNil) 80 | c.Assert(int(h.LatencyAtQuantile(100)/time.Second), Equals, 3) 81 | } 82 | -------------------------------------------------------------------------------- /vendor/src/github.com/mailgun/oxy/utils/auth.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "encoding/base64" 5 | "fmt" 6 | "strings" 7 | ) 8 | 9 | type BasicAuth struct { 10 | Username string 11 | Password string 12 | } 13 | 14 | func (ba *BasicAuth) String() string { 15 | encoded := base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf("%s:%s", ba.Username, ba.Password))) 16 | return fmt.Sprintf("Basic %s", encoded) 17 | } 18 | 19 | func ParseAuthHeader(header string) (*BasicAuth, error) { 20 | values := strings.Fields(header) 21 | if len(values) != 2 { 22 | return nil, fmt.Errorf(fmt.Sprintf("Failed to parse header '%s'", header)) 23 | } 24 | 25 | auth_type := strings.ToLower(values[0]) 26 | if auth_type != "basic" { 27 | return nil, fmt.Errorf("Expected basic auth type, got '%s'", auth_type) 28 | } 29 | 30 | encoded_string := values[1] 31 | decoded_string, err := base64.StdEncoding.DecodeString(encoded_string) 32 | if err != nil { 33 | return nil, fmt.Errorf("Failed to parse header '%s', base64 failed: %s", header, err) 34 | } 35 | 36 | values = strings.SplitN(string(decoded_string), ":", 2) 37 | if len(values) != 2 { 38 | return nil, fmt.Errorf("Failed to parse header '%s', expected separator ':'", header) 39 | } 40 | return &BasicAuth{Username: values[0], Password: values[1]}, nil 41 | } 42 | -------------------------------------------------------------------------------- /vendor/src/github.com/mailgun/oxy/utils/auth_test.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | . "gopkg.in/check.v1" 5 | ) 6 | 7 | type AuthSuite struct { 8 | } 9 | 10 | var _ = Suite(&AuthSuite{}) 11 | 12 | //Just to make sure we don't panic, return err and not 13 | //username and pass and cover the function 14 | func (s *AuthSuite) TestParseBadHeaders(c *C) { 15 | headers := []string{ 16 | //just empty string 17 | "", 18 | //missing auth type 19 | "justplainstring", 20 | //unknown auth type 21 | "Whut justplainstring", 22 | //invalid base64 23 | "Basic Shmasic", 24 | //random encoded string 25 | "Basic YW55IGNhcm5hbCBwbGVhcw==", 26 | } 27 | for _, h := range headers { 28 | _, err := ParseAuthHeader(h) 29 | c.Assert(err, NotNil) 30 | } 31 | } 32 | 33 | //Just to make sure we don't panic, return err and not 34 | //username and pass and cover the function 35 | func (s *AuthSuite) TestParseSuccess(c *C) { 36 | headers := []struct { 37 | Header string 38 | Expected BasicAuth 39 | }{ 40 | { 41 | "Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==", 42 | BasicAuth{Username: "Aladdin", Password: "open sesame"}, 43 | }, 44 | // Make sure that String() produces valid header 45 | { 46 | (&BasicAuth{Username: "Alice", Password: "Here's bob"}).String(), 47 | BasicAuth{Username: "Alice", Password: "Here's bob"}, 48 | }, 49 | //empty pass 50 | { 51 | "Basic QWxhZGRpbjo=", 52 | BasicAuth{Username: "Aladdin", Password: ""}, 53 | }, 54 | } 55 | for _, h := range headers { 56 | request, err := ParseAuthHeader(h.Header) 57 | c.Assert(err, IsNil) 58 | c.Assert(request.Username, Equals, h.Expected.Username) 59 | c.Assert(request.Password, Equals, h.Expected.Password) 60 | 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /vendor/src/github.com/mailgun/oxy/utils/handler.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "io" 5 | "net" 6 | "net/http" 7 | ) 8 | 9 | type ErrorHandler interface { 10 | ServeHTTP(w http.ResponseWriter, req *http.Request, err error) 11 | } 12 | 13 | var DefaultHandler ErrorHandler = &StdHandler{} 14 | 15 | type StdHandler struct { 16 | } 17 | 18 | func (e *StdHandler) ServeHTTP(w http.ResponseWriter, req *http.Request, err error) { 19 | statusCode := http.StatusInternalServerError 20 | if e, ok := err.(net.Error); ok { 21 | if e.Timeout() { 22 | statusCode = http.StatusGatewayTimeout 23 | } else { 24 | statusCode = http.StatusBadGateway 25 | } 26 | } else if err == io.EOF { 27 | statusCode = http.StatusBadGateway 28 | } 29 | w.WriteHeader(statusCode) 30 | w.Write([]byte(http.StatusText(statusCode))) 31 | } 32 | 33 | type ErrorHandlerFunc func(http.ResponseWriter, *http.Request, error) 34 | 35 | // ServeHTTP calls f(w, r). 36 | func (f ErrorHandlerFunc) ServeHTTP(w http.ResponseWriter, r *http.Request, err error) { 37 | f(w, r, err) 38 | } 39 | -------------------------------------------------------------------------------- /vendor/src/github.com/mailgun/oxy/utils/handler_test.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "bytes" 5 | "net/http" 6 | "net/http/httptest" 7 | "strings" 8 | 9 | . "gopkg.in/check.v1" 10 | ) 11 | 12 | type UtilsSuite struct{} 13 | 14 | var _ = Suite(&UtilsSuite{}) 15 | 16 | func (s *UtilsSuite) TestDefaultHandlerErrors(c *C) { 17 | srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 18 | h := w.(http.Hijacker) 19 | conn, _, _ := h.Hijack() 20 | conn.Close() 21 | })) 22 | defer srv.Close() 23 | 24 | request, err := http.NewRequest("GET", srv.URL, strings.NewReader("")) 25 | c.Assert(err, IsNil) 26 | 27 | _, err = http.DefaultTransport.RoundTrip(request) 28 | 29 | w := NewBufferWriter(NopWriteCloser(&bytes.Buffer{})) 30 | 31 | DefaultHandler.ServeHTTP(w, nil, err) 32 | 33 | c.Assert(w.Code, Equals, http.StatusBadGateway) 34 | } 35 | -------------------------------------------------------------------------------- /vendor/src/github.com/mailgun/oxy/utils/logging.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "io" 5 | "log" 6 | ) 7 | 8 | var NullLogger Logger = &NOPLogger{} 9 | 10 | // Logger defines a simple logging interface 11 | type Logger interface { 12 | Infof(format string, args ...interface{}) 13 | Warningf(format string, args ...interface{}) 14 | Errorf(format string, args ...interface{}) 15 | } 16 | 17 | type FileLogger struct { 18 | info *log.Logger 19 | warn *log.Logger 20 | error *log.Logger 21 | } 22 | 23 | func NewFileLogger(w io.Writer, lvl LogLevel) *FileLogger { 24 | l := &FileLogger{} 25 | flag := log.Ldate | log.Ltime | log.Lmicroseconds 26 | if lvl <= INFO { 27 | l.info = log.New(w, "INFO: ", flag) 28 | } 29 | if lvl <= WARN { 30 | l.warn = log.New(w, "WARN: ", flag) 31 | } 32 | if lvl <= ERROR { 33 | l.error = log.New(w, "ERR: ", flag) 34 | } 35 | return l 36 | } 37 | 38 | func (f *FileLogger) Infof(format string, args ...interface{}) { 39 | if f.info == nil { 40 | return 41 | } 42 | f.info.Printf(format, args...) 43 | } 44 | 45 | func (f *FileLogger) Warningf(format string, args ...interface{}) { 46 | if f.warn == nil { 47 | return 48 | } 49 | f.warn.Printf(format, args...) 50 | } 51 | 52 | func (f *FileLogger) Errorf(format string, args ...interface{}) { 53 | if f.error == nil { 54 | return 55 | } 56 | f.error.Printf(format, args...) 57 | } 58 | 59 | type NOPLogger struct { 60 | } 61 | 62 | func (*NOPLogger) Infof(format string, args ...interface{}) { 63 | 64 | } 65 | func (*NOPLogger) Warningf(format string, args ...interface{}) { 66 | } 67 | 68 | func (*NOPLogger) Errorf(format string, args ...interface{}) { 69 | } 70 | 71 | func (*NOPLogger) Info(string) { 72 | 73 | } 74 | func (*NOPLogger) Warning(string) { 75 | } 76 | 77 | func (*NOPLogger) Error(string) { 78 | } 79 | 80 | type LogLevel int 81 | 82 | const ( 83 | INFO = iota 84 | WARN 85 | ERROR 86 | ) 87 | -------------------------------------------------------------------------------- /vendor/src/github.com/mailgun/oxy/utils/netutils_test.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "net/http" 5 | "net/url" 6 | "testing" 7 | 8 | . "gopkg.in/check.v1" 9 | ) 10 | 11 | func TestUtils(t *testing.T) { TestingT(t) } 12 | 13 | type NetUtilsSuite struct{} 14 | 15 | var _ = Suite(&NetUtilsSuite{}) 16 | 17 | // Make sure copy does it right, so the copied url 18 | // is safe to alter without modifying the other 19 | func (s *NetUtilsSuite) TestCopyUrl(c *C) { 20 | urlA := &url.URL{ 21 | Scheme: "http", 22 | Host: "localhost:5000", 23 | Path: "/upstream", 24 | Opaque: "opaque", 25 | RawQuery: "a=1&b=2", 26 | Fragment: "#hello", 27 | User: &url.Userinfo{}, 28 | } 29 | urlB := CopyURL(urlA) 30 | c.Assert(urlB, DeepEquals, urlA) 31 | urlB.Scheme = "https" 32 | c.Assert(urlB, Not(DeepEquals), urlA) 33 | } 34 | 35 | // Make sure copy headers is not shallow and copies all headers 36 | func (s *NetUtilsSuite) TestCopyHeaders(c *C) { 37 | source, destination := make(http.Header), make(http.Header) 38 | source.Add("a", "b") 39 | source.Add("c", "d") 40 | 41 | CopyHeaders(destination, source) 42 | 43 | c.Assert(destination.Get("a"), Equals, "b") 44 | c.Assert(destination.Get("c"), Equals, "d") 45 | 46 | // make sure that altering source does not affect the destination 47 | source.Del("a") 48 | c.Assert(source.Get("a"), Equals, "") 49 | c.Assert(destination.Get("a"), Equals, "b") 50 | } 51 | 52 | func (s *NetUtilsSuite) TestHasHeaders(c *C) { 53 | source := make(http.Header) 54 | source.Add("a", "b") 55 | source.Add("c", "d") 56 | c.Assert(HasHeaders([]string{"a", "f"}, source), Equals, true) 57 | c.Assert(HasHeaders([]string{"i", "j"}, source), Equals, false) 58 | } 59 | 60 | func (s *NetUtilsSuite) TestRemoveHeaders(c *C) { 61 | source := make(http.Header) 62 | source.Add("a", "b") 63 | source.Add("a", "m") 64 | source.Add("c", "d") 65 | RemoveHeaders(source, "a") 66 | c.Assert(source.Get("a"), Equals, "") 67 | c.Assert(source.Get("c"), Equals, "d") 68 | } 69 | -------------------------------------------------------------------------------- /vendor/src/github.com/mailgun/oxy/utils/source.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "fmt" 5 | "net/http" 6 | "strings" 7 | ) 8 | 9 | // ExtractSource extracts the source from the request, e.g. that may be client ip, or particular header that 10 | // identifies the source. amount stands for amount of connections the source consumes, usually 1 for connection limiters 11 | // error should be returned when source can not be identified 12 | type SourceExtractor interface { 13 | Extract(req *http.Request) (token string, amount int64, err error) 14 | } 15 | 16 | type ExtractorFunc func(req *http.Request) (token string, amount int64, err error) 17 | 18 | func (f ExtractorFunc) Extract(req *http.Request) (string, int64, error) { 19 | return f(req) 20 | } 21 | 22 | type ExtractSource func(req *http.Request) 23 | 24 | func NewExtractor(variable string) (SourceExtractor, error) { 25 | if variable == "client.ip" { 26 | return ExtractorFunc(extractClientIP), nil 27 | } 28 | if variable == "request.host" { 29 | return ExtractorFunc(extractHost), nil 30 | } 31 | if strings.HasPrefix(variable, "request.header.") { 32 | header := strings.TrimPrefix(variable, "request.header.") 33 | if len(header) == 0 { 34 | return nil, fmt.Errorf("Wrong header: %s", header) 35 | } 36 | return makeHeaderExtractor(header), nil 37 | } 38 | return nil, fmt.Errorf("Unsupported limiting variable: '%s'", variable) 39 | } 40 | 41 | func extractClientIP(req *http.Request) (string, int64, error) { 42 | vals := strings.SplitN(req.RemoteAddr, ":", 2) 43 | if len(vals[0]) == 0 { 44 | return "", 0, fmt.Errorf("Failed to parse client IP: %v", req.RemoteAddr) 45 | } 46 | return vals[0], 1, nil 47 | } 48 | 49 | func extractHost(req *http.Request) (string, int64, error) { 50 | return req.Host, 1, nil 51 | } 52 | 53 | func makeHeaderExtractor(header string) SourceExtractor { 54 | return ExtractorFunc(func(req *http.Request) (string, int64, error) { 55 | return req.Header.Get(header), 1, nil 56 | }) 57 | } 58 | -------------------------------------------------------------------------------- /vendor/src/github.com/mailgun/predicate/Makefile: -------------------------------------------------------------------------------- 1 | 2 | test: clean 3 | go test -v ./... -cover 4 | 5 | clean: 6 | find . -name flymake_* -delete 7 | 8 | cover: clean 9 | go test -v . -coverprofile=/tmp/coverage.out 10 | go tool cover -html=/tmp/coverage.out 11 | 12 | sloccount: 13 | find . -name "*.go" -print0 | xargs -0 wc -l 14 | -------------------------------------------------------------------------------- /vendor/src/github.com/mailgun/predicate/README.md: -------------------------------------------------------------------------------- 1 | Predicate 2 | ========= 3 | 4 | Predicate package used to create interpreted mini languages with Go syntax - mostly to define 5 | various predicates for configuration, e.g. 6 | 7 | ``` 8 | Latency() > 40 || ErrorRate() > 0.5. 9 | ``` 10 | 11 | Here's an example of fully functional predicate language to deal with division remainders: 12 | 13 | ```go 14 | // takes number and returns true or false 15 | type numberPredicate func(v int) bool 16 | 17 | // Converts one number to another 18 | type numberMapper func(v int) int 19 | 20 | // Function that creates predicate to test if the remainder is 0 21 | func divisibleBy(divisor int) numberPredicate { 22 | return func(v int) bool { 23 | return v%divisor == 0 24 | } 25 | } 26 | 27 | // Function - logical operator AND that combines predicates 28 | func numberAND(a, b numberPredicate) numberPredicate { 29 | return func(v int) bool { 30 | return a(v) && b(v) 31 | } 32 | } 33 | 34 | func main(){ 35 | // Create a new parser and define the supported operators and methods 36 | p, err := NewParser(Def{ 37 | Operators: Operators{ 38 | AND: numberAND, 39 | }, 40 | Functions: map[string]interface{}{ 41 | "DivisibleBy": divisibleBy, 42 | }, 43 | }) 44 | 45 | pr, err := p.Parse("DivisibleBy(2) && DivisibleBy(3)") 46 | if err == nil { 47 | fmt.Fatalf("Error: %v", err) 48 | } 49 | pr.(numberPredicate)(2) // false 50 | pr.(numberPredicate)(3) // false 51 | pr.(numberPredicate)(6) // true 52 | } 53 | ``` 54 | -------------------------------------------------------------------------------- /vendor/src/github.com/mailgun/predicate/predicate.go: -------------------------------------------------------------------------------- 1 | /* 2 | Predicate package used to create interpreted mini languages with Go syntax - mostly to define 3 | various predicates for configuration, e.g. Latency() > 40 || ErrorRate() > 0.5. 4 | 5 | Here's an example of fully functional predicate language to deal with division remainders: 6 | 7 | // takes number and returns true or false 8 | type numberPredicate func(v int) bool 9 | 10 | // Converts one number to another 11 | type numberMapper func(v int) int 12 | 13 | // Function that creates predicate to test if the remainder is 0 14 | func divisibleBy(divisor int) numberPredicate { 15 | return func(v int) bool { 16 | return v%divisor == 0 17 | } 18 | } 19 | 20 | // Function - logical operator AND that combines predicates 21 | func numberAND(a, b numberPredicate) numberPredicate { 22 | return func(v int) bool { 23 | return a(v) && b(v) 24 | } 25 | } 26 | 27 | p, err := NewParser(Def{ 28 | Operators: Operators{ 29 | AND: numberAND, 30 | }, 31 | Functions: map[string]interface{}{ 32 | "DivisibleBy": divisibleBy, 33 | }, 34 | }) 35 | 36 | pr, err := p.Parse("DivisibleBy(2) && DivisibleBy(3)") 37 | if err == nil { 38 | fmt.Fatalf("Error: %v", err) 39 | } 40 | pr.(numberPredicate)(2) // false 41 | pr.(numberPredicate)(3) // false 42 | pr.(numberPredicate)(6) // true 43 | */ 44 | package predicate 45 | 46 | // Def contains supported operators (e.g. LT, GT) and functions passed in as a map. 47 | type Def struct { 48 | Operators Operators 49 | // Function matching is case sensitive, e.g. Len is different from len 50 | Functions map[string]interface{} 51 | } 52 | 53 | // Operators contain functions for equality and logical comparison. 54 | type Operators struct { 55 | EQ interface{} 56 | NEQ interface{} 57 | 58 | LT interface{} 59 | GT interface{} 60 | 61 | LE interface{} 62 | GE interface{} 63 | 64 | OR interface{} 65 | AND interface{} 66 | } 67 | 68 | // Parser takes the string with expression and calls the operators and functions. 69 | type Parser interface { 70 | Parse(string) (interface{}, error) 71 | } 72 | -------------------------------------------------------------------------------- /vendor/src/github.com/mailgun/timetools/README.md: -------------------------------------------------------------------------------- 1 | timetools 2 | ========= 3 | 4 | Go library with various time utilities used at Mailgun. 5 | -------------------------------------------------------------------------------- /vendor/src/github.com/mailgun/timetools/provider.go: -------------------------------------------------------------------------------- 1 | package timetools 2 | 3 | import ( 4 | "sync" 5 | "time" 6 | ) 7 | 8 | // TimeProvider is an interface we use to mock time in tests. 9 | type TimeProvider interface { 10 | UtcNow() time.Time 11 | Sleep(time.Duration) 12 | After(time.Duration) <-chan time.Time 13 | } 14 | 15 | // RealTime is a real clock time, used in production. 16 | type RealTime struct { 17 | } 18 | 19 | func (*RealTime) UtcNow() time.Time { 20 | return time.Now().UTC() 21 | } 22 | 23 | func (*RealTime) Sleep(d time.Duration) { 24 | time.Sleep(d) 25 | } 26 | 27 | func (*RealTime) After(d time.Duration) <-chan time.Time { 28 | return time.After(d) 29 | } 30 | 31 | // FreezedTime is manually controlled time for use in tests. 32 | type FreezedTime struct { 33 | CurrentTime time.Time 34 | } 35 | 36 | func (t *FreezedTime) UtcNow() time.Time { 37 | return t.CurrentTime 38 | } 39 | 40 | func (t *FreezedTime) Sleep(d time.Duration) { 41 | t.CurrentTime = t.CurrentTime.Add(d) 42 | } 43 | 44 | func (t *FreezedTime) After(d time.Duration) <-chan time.Time { 45 | t.Sleep(d) 46 | c := make(chan time.Time, 1) 47 | c <- t.CurrentTime 48 | return c 49 | } 50 | 51 | type sleepableTime struct { 52 | currentTime time.Time 53 | waiters map[time.Time][]chan time.Time 54 | mu sync.Mutex 55 | } 56 | 57 | // SleepProvider returns a TimeProvider that has good fakes for 58 | // time.Sleep and time.After. Both functions will behave as if 59 | // time is frozen until you call AdvanceTimeBy, at which point 60 | // any calls to time.Sleep that should return do return and 61 | // any ticks from time.After that should happen do happen. 62 | func SleepProvider(currentTime time.Time) TimeProvider { 63 | return &sleepableTime{ 64 | currentTime: currentTime, 65 | waiters: make(map[time.Time][]chan time.Time), 66 | } 67 | } 68 | 69 | func (t *sleepableTime) UtcNow() time.Time { 70 | return t.currentTime 71 | } 72 | 73 | func (t *sleepableTime) Sleep(d time.Duration) { 74 | <-t.After(d) 75 | } 76 | 77 | func (t *sleepableTime) After(d time.Duration) <-chan time.Time { 78 | t.mu.Lock() 79 | defer t.mu.Unlock() 80 | 81 | c := make(chan time.Time, 1) 82 | until := t.currentTime.Add(d) 83 | t.waiters[until] = append(t.waiters[until], c) 84 | return c 85 | } 86 | 87 | // AdvanceTimeBy simulates advancing time by some time.Duration d. 88 | // This function panics if st is not the result of a call to 89 | // SleepProvider. 90 | func AdvanceTimeBy(st TimeProvider, d time.Duration) { 91 | t := st.(*sleepableTime) 92 | t.mu.Lock() 93 | defer t.mu.Unlock() 94 | 95 | t.currentTime = t.currentTime.Add(d) 96 | for k, v := range t.waiters { 97 | if k.Before(t.currentTime) { 98 | for _, c := range v { 99 | c <- t.currentTime 100 | } 101 | delete(t.waiters, k) 102 | } 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /vendor/src/github.com/mailgun/timetools/provider_test.go: -------------------------------------------------------------------------------- 1 | package timetools 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | "time" 7 | ) 8 | 9 | var _ = fmt.Printf // for testing 10 | 11 | func TestRealTimeUtcNow(t *testing.T) { 12 | rt := RealTime{} 13 | 14 | rtNow := rt.UtcNow() 15 | atNow := time.Now().UTC() 16 | 17 | // times shouldn't be exact 18 | if rtNow.Equal(atNow) { 19 | t.Errorf("rt.UtcNow() = time.Now.UTC(), %v = %v, should be slightly different", rtNow, atNow) 20 | } 21 | 22 | rtNowPlusOne := atNow.Add(1 * time.Second) 23 | rtNowMinusOne := atNow.Add(-1 * time.Second) 24 | 25 | // but should be pretty close 26 | if atNow.After(rtNowPlusOne) || atNow.Before(rtNowMinusOne) { 27 | t.Errorf("timedelta between rt.UtcNow() and time.Now.UTC() greater than 2 seconds, %v, %v", rtNow, atNow) 28 | } 29 | } 30 | 31 | func TestFreezeTimeUtcNow(t *testing.T) { 32 | tm := time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC) 33 | ft := FreezedTime{tm} 34 | 35 | if !tm.Equal(ft.UtcNow()) { 36 | t.Errorf("ft.UtcNow() != time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC), %v, %v", tm, ft) 37 | } 38 | } 39 | 40 | func itTicks(c <-chan time.Time) bool { 41 | select { 42 | case <-c: 43 | return true 44 | case <-time.After(time.Millisecond): 45 | return false 46 | } 47 | } 48 | 49 | func TestSleepableTime(t *testing.T) { 50 | tm := time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC) 51 | st := SleepProvider(tm) 52 | 53 | if !tm.Equal(st.UtcNow()) { 54 | t.Errorf("st.UtcNow() != time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC), %v, %v", tm, st) 55 | } 56 | 57 | // Check After with no AdvanceTimeBy 58 | if itTicks(st.After(time.Nanosecond)) { 59 | t.Error("Got tick from After before calling AdvanceTimeBy") 60 | } 61 | 62 | // Check After with one call to AdvanceTimeBy 63 | c0 := st.After(time.Hour) 64 | AdvanceTimeBy(st, 2*time.Hour) 65 | if !itTicks(c0) { 66 | t.Error("Didn't get tick from After after calling AdvanceTimeBy") 67 | } 68 | 69 | // Check After with multiple calls to AdvanceTimeBy 70 | c0 = st.After(time.Hour) 71 | AdvanceTimeBy(st, 20*time.Minute) 72 | if itTicks(c0) { 73 | t.Error("Got tick from After before we AdvanceTimeBy'd enough") 74 | } 75 | AdvanceTimeBy(st, 20*time.Minute) 76 | if itTicks(c0) { 77 | t.Error("Got tick from After before we AdvanceTimeBy'd enough") 78 | } 79 | AdvanceTimeBy(st, 40*time.Minute) 80 | if !itTicks(c0) { 81 | t.Error("Didn't get tick from After after we AdvanceTimeBy'd enough") 82 | } 83 | 84 | // Check Sleep with no AdvanceTimeBy 85 | c1 := make(chan time.Time) 86 | go func() { 87 | st.Sleep(time.Nanosecond) 88 | c1 <- st.UtcNow() 89 | }() 90 | if itTicks(c1) { 91 | t.Error("Sleep returned before we called AdvanceTimeBy") 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /vendor/src/github.com/mailgun/timetools/rfc2822time.go: -------------------------------------------------------------------------------- 1 | package timetools 2 | 3 | import ( 4 | "strconv" 5 | "time" 6 | 7 | "gopkg.in/mgo.v2/bson" 8 | ) 9 | 10 | // We use RFC2822 format for timestamps everywhere ('Thu, 13 Oct 2011 18:02:00 GMT'), but 11 | // by default Go's JSON package uses another format when decoding/encoding timestamps. 12 | // That's why we declare our own timestamp type and implement its marshal/unmarshal methods 13 | // so JSON package decodes/encodes it properly. 14 | type RFC2822Time time.Time 15 | 16 | func NewRFC2822Time(timestamp int64) RFC2822Time { 17 | return RFC2822Time(time.Unix(timestamp, 0).UTC()) 18 | } 19 | 20 | func (t RFC2822Time) Unix() int64 { 21 | return time.Time(t).Unix() 22 | } 23 | 24 | func (t RFC2822Time) IsZero() bool { 25 | return time.Time(t).IsZero() 26 | } 27 | 28 | func (t RFC2822Time) MarshalJSON() ([]byte, error) { 29 | return []byte(strconv.Quote(time.Time(t).Format(time.RFC1123))), nil 30 | } 31 | 32 | func (t *RFC2822Time) UnmarshalJSON(s []byte) error { 33 | q, err := strconv.Unquote(string(s)) 34 | if err != nil { 35 | return err 36 | } 37 | if *(*time.Time)(t), err = time.Parse(time.RFC1123, q); err != nil { 38 | return err 39 | } 40 | return nil 41 | } 42 | 43 | func (t RFC2822Time) GetBSON() (interface{}, error) { 44 | return time.Time(t), nil 45 | } 46 | 47 | func (t *RFC2822Time) SetBSON(raw bson.Raw) error { 48 | var result time.Time 49 | err := raw.Unmarshal(&result) 50 | if err != nil { 51 | return err 52 | } 53 | *t = RFC2822Time(result) 54 | return nil 55 | } 56 | 57 | func (t RFC2822Time) String() string { 58 | return time.Time(t).Format(time.RFC1123) 59 | } 60 | -------------------------------------------------------------------------------- /vendor/src/github.com/nickschuch/marco-lib/README.md: -------------------------------------------------------------------------------- 1 | # Marco - Lib 2 | 3 | Standard library for Marco backends. 4 | 5 | An example can be seen here: 6 | 7 | https://github.com/nickschuch/marco-demo 8 | -------------------------------------------------------------------------------- /vendor/src/github.com/nickschuch/marco-lib/marco-lib.go: -------------------------------------------------------------------------------- 1 | package marco 2 | 3 | import ( 4 | "bytes" 5 | "encoding/json" 6 | "net/http" 7 | "net/url" 8 | ) 9 | 10 | type Backend struct { 11 | Type string 12 | Domain string 13 | Weight int 14 | List []*url.URL 15 | } 16 | 17 | func Send(backends []Backend, url string) error { 18 | b, err := json.Marshal(backends) 19 | if err != nil { 20 | return err 21 | } 22 | 23 | req, err := http.NewRequest("POST", url, bytes.NewBuffer(b)) 24 | req.Header.Set("Content-Type", "application/json") 25 | 26 | client := &http.Client{} 27 | resp, err := client.Do(req) 28 | if err != nil { 29 | return err 30 | } 31 | defer resp.Body.Close() 32 | 33 | return nil 34 | } 35 | -------------------------------------------------------------------------------- /vendor/src/github.com/stretchr/testify/assert/doc.go: -------------------------------------------------------------------------------- 1 | // Package assert provides a set of comprehensive testing tools for use with the normal Go testing system. 2 | // 3 | // Example Usage 4 | // 5 | // The following is a complete example using assert in a standard test function: 6 | // import ( 7 | // "testing" 8 | // "github.com/stretchr/testify/assert" 9 | // ) 10 | // 11 | // func TestSomething(t *testing.T) { 12 | // 13 | // var a string = "Hello" 14 | // var b string = "Hello" 15 | // 16 | // assert.Equal(t, a, b, "The two words should be the same.") 17 | // 18 | // } 19 | // 20 | // if you assert many times, use the format below: 21 | // 22 | // import ( 23 | // "testing" 24 | // "github.com/stretchr/testify/assert" 25 | // ) 26 | // 27 | // func TestSomething(t *testing.T) { 28 | // assert := assert.New(t) 29 | // 30 | // var a string = "Hello" 31 | // var b string = "Hello" 32 | // 33 | // assert.Equal(a, b, "The two words should be the same.") 34 | // } 35 | // 36 | // Assertions 37 | // 38 | // Assertions allow you to easily write test code, and are global funcs in the `assert` package. 39 | // All assertion functions take, as the first argument, the `*testing.T` object provided by the 40 | // testing framework. This allows the assertion funcs to write the failings and other details to 41 | // the correct place. 42 | // 43 | // Every assertion function also takes an optional string message as the final argument, 44 | // allowing custom error messages to be appended to the message the assertion method outputs. 45 | package assert 46 | -------------------------------------------------------------------------------- /vendor/src/github.com/stretchr/testify/assert/errors.go: -------------------------------------------------------------------------------- 1 | package assert 2 | 3 | import ( 4 | "errors" 5 | ) 6 | 7 | // AnError is an error instance useful for testing. If the code does not care 8 | // about error specifics, and only needs to return the error for example, this 9 | // error should be used to make the test code more readable. 10 | var AnError = errors.New("assert.AnError general error for testing") 11 | -------------------------------------------------------------------------------- /vendor/src/github.com/tobi/airbrake-go/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015 Tobias Lütke 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /vendor/src/github.com/tobi/airbrake-go/README: -------------------------------------------------------------------------------- 1 | Config 2 | ====== 3 | 4 | set airbrake.Endpoint and airbrake.ApiKey globals 5 | 6 | Methods 7 | ======= 8 | 9 | airbrake.Error(err) reports an error 10 | 11 | airbrake.RequestError(err, *http.Request) can be used to add more context if you are in a http context 12 | 13 | 14 | You can also automatically have this library report panics, use this method: 15 | 16 | airbrake.CapturePanic(*http.Request) 17 | 18 | 19 | example: 20 | 21 | func serve(w http.ResponseWriter, r *http.Request) { 22 | defer airbrake.CapturePanic(r) 23 | 24 | [...] 25 | 26 | panic("Oh no :-(") // will be recorded by airbrake 27 | 28 | } -------------------------------------------------------------------------------- /vendor/src/github.com/tobi/airbrake-go/handler.go: -------------------------------------------------------------------------------- 1 | package airbrake 2 | 3 | import ( 4 | "net/http" 5 | ) 6 | 7 | // CapturePanicHandler "middleware". 8 | // Wraps the http handler so that all panics will be dutifully reported to airbrake 9 | // 10 | // Example: 11 | // http.HandleFunc("/", airbrake.CapturePanicHandler(MyServerFunc)) 12 | func CapturePanicHandler(app http.HandlerFunc) http.HandlerFunc { 13 | return func(w http.ResponseWriter, r *http.Request) { 14 | defer CapturePanic(r) 15 | app(w, r) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /vendor/src/gopkg.in/alecthomas/kingpin.v1/COPYING: -------------------------------------------------------------------------------- 1 | Copyright (C) 2014 Alec Thomas 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | this software and associated documentation files (the "Software"), to deal in 5 | the Software without restriction, including without limitation the rights to 6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 7 | of the Software, and to permit persons to whom the Software is furnished to do 8 | so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | -------------------------------------------------------------------------------- /vendor/src/gopkg.in/alecthomas/kingpin.v1/args_test.go: -------------------------------------------------------------------------------- 1 | package kingpin 2 | 3 | import ( 4 | "github.com/stretchr/testify/assert" 5 | 6 | "testing" 7 | ) 8 | 9 | func TestArgRemainder(t *testing.T) { 10 | a := newArgGroup() 11 | v := a.Arg("test", "").Strings() 12 | a.init() 13 | args := []string{"hello", "world"} 14 | tokens := Tokenize(args) 15 | a.parse(tokens) 16 | assert.Equal(t, args, *v) 17 | } 18 | 19 | func TestArgRemainderErrorsWhenNotLast(t *testing.T) { 20 | a := newArgGroup() 21 | a.Arg("test", "").Strings() 22 | a.Arg("test2", "").String() 23 | assert.Error(t, a.init()) 24 | } 25 | 26 | func TestArgMultipleRequired(t *testing.T) { 27 | a := newArgGroup() 28 | a.Arg("a", "").Required().String() 29 | a.Arg("b", "").Required().String() 30 | a.init() 31 | 32 | err := a.parse(Tokenize([]string{})) 33 | assert.Error(t, err) 34 | err = a.parse(Tokenize([]string{"A"})) 35 | assert.Error(t, err) 36 | err = a.parse(Tokenize([]string{"A", "B"})) 37 | assert.NoError(t, err) 38 | } 39 | 40 | func TestInvalidArgsDefaultCanBeOverridden(t *testing.T) { 41 | a := newArgGroup() 42 | a.Arg("a", "").Default("invalid").Bool() 43 | assert.NoError(t, a.init()) 44 | tokens := Tokenize([]string{}) 45 | err := a.parse(tokens) 46 | assert.Error(t, err) 47 | } 48 | -------------------------------------------------------------------------------- /vendor/src/gopkg.in/alecthomas/kingpin.v1/cmd_test.go: -------------------------------------------------------------------------------- 1 | package kingpin 2 | 3 | import ( 4 | "github.com/stretchr/testify/assert" 5 | 6 | "testing" 7 | ) 8 | 9 | func TestNestedCommands(t *testing.T) { 10 | app := New("app", "") 11 | sub1 := app.Command("sub1", "") 12 | sub1.Flag("sub1", "") 13 | subsub1 := sub1.Command("sub1sub1", "") 14 | subsub1.Command("sub1sub1end", "") 15 | 16 | sub2 := app.Command("sub2", "") 17 | sub2.Flag("sub2", "") 18 | sub2.Command("sub2sub1", "") 19 | 20 | context := Tokenize([]string{"sub1", "sub1sub1", "sub1sub1end"}) 21 | selected, err := app.parse(context) 22 | assert.NoError(t, err) 23 | assert.Equal(t, 0, len(context.Tokens)) 24 | assert.Equal(t, "sub1 sub1sub1 sub1sub1end", selected) 25 | } 26 | 27 | func TestNestedCommandsWithArgs(t *testing.T) { 28 | app := New("app", "") 29 | cmd := app.Command("a", "").Command("b", "") 30 | a := cmd.Arg("a", "").String() 31 | b := cmd.Arg("b", "").String() 32 | context := Tokenize([]string{"a", "b", "c", "d"}) 33 | selected, err := app.parse(context) 34 | assert.NoError(t, err) 35 | assert.Equal(t, 0, len(context.Tokens)) 36 | assert.Equal(t, "a b", selected) 37 | assert.Equal(t, "c", *a) 38 | assert.Equal(t, "d", *b) 39 | } 40 | 41 | func TestNestedCommandsWithFlags(t *testing.T) { 42 | app := New("app", "") 43 | cmd := app.Command("a", "").Command("b", "") 44 | a := cmd.Flag("aaa", "").Short('a').String() 45 | b := cmd.Flag("bbb", "").Short('b').String() 46 | err := app.init() 47 | assert.NoError(t, err) 48 | context := Tokenize([]string{"a", "b", "--aaa", "x", "-b", "x"}) 49 | selected, err := app.parse(context) 50 | assert.NoError(t, err) 51 | assert.Equal(t, 0, len(context.Tokens)) 52 | assert.Equal(t, "a b", selected) 53 | assert.Equal(t, "x", *a) 54 | assert.Equal(t, "x", *b) 55 | } 56 | -------------------------------------------------------------------------------- /vendor/src/gopkg.in/alecthomas/kingpin.v1/doc.go: -------------------------------------------------------------------------------- 1 | // Package kingpin provides command line interfaces like this: 2 | // 3 | // $ chat 4 | // usage: chat [] [] [ ...] 5 | // 6 | // Flags: 7 | // --debug enable debug mode 8 | // --help Show help. 9 | // --server=127.0.0.1 server address 10 | // 11 | // Commands: 12 | // help 13 | // Show help for a command. 14 | // 15 | // post [] 16 | // Post a message to a channel. 17 | // 18 | // register 19 | // Register a new user. 20 | // 21 | // $ chat help post 22 | // usage: chat [] post [] [] 23 | // 24 | // Post a message to a channel. 25 | // 26 | // Flags: 27 | // --image=IMAGE image to post 28 | // 29 | // Args: 30 | // channel to post to 31 | // [] text to post 32 | // $ chat post --image=~/Downloads/owls.jpg pics 33 | // 34 | // From code like this: 35 | // 36 | // package main 37 | // 38 | // import "gopkg.in/alecthomas/kingpin.v1" 39 | // 40 | // var ( 41 | // debug = kingpin.Flag("debug", "enable debug mode").Default("false").Bool() 42 | // serverIP = kingpin.Flag("server", "server address").Default("127.0.0.1").IP() 43 | // 44 | // register = kingpin.Command("register", "Register a new user.") 45 | // registerNick = register.Arg("nick", "nickname for user").Required().String() 46 | // registerName = register.Arg("name", "name of user").Required().String() 47 | // 48 | // post = kingpin.Command("post", "Post a message to a channel.") 49 | // postImage = post.Flag("image", "image to post").File() 50 | // postChannel = post.Arg("channel", "channel to post to").Required().String() 51 | // postText = post.Arg("text", "text to post").String() 52 | // ) 53 | // 54 | // func main() { 55 | // switch kingpin.Parse() { 56 | // // Register user 57 | // case "register": 58 | // println(*registerNick) 59 | // 60 | // // Post message 61 | // case "post": 62 | // if *postImage != nil { 63 | // } 64 | // if *postText != "" { 65 | // } 66 | // } 67 | // } 68 | package kingpin 69 | -------------------------------------------------------------------------------- /vendor/src/gopkg.in/alecthomas/kingpin.v1/examples/ping/ping.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/alecthomas/kingpin" 7 | ) 8 | 9 | var ( 10 | debug = kingpin.Flag("debug", "Enable debug mode.").Bool() 11 | timeout = kingpin.Flag("timeout", "Timeout waiting for ping.").OverrideDefaultFromEnvar("PING_TIMEOUT").Required().Short('t').Duration() 12 | ip = kingpin.Arg("ip", "IP address to ping.").Required().IP() 13 | count = kingpin.Arg("count", "Number of packets to send").Int() 14 | ) 15 | 16 | func main() { 17 | kingpin.Version("0.0.1") 18 | kingpin.Parse() 19 | fmt.Printf("Would ping: %s with timeout %s and count %d", *ip, *timeout, *count) 20 | } 21 | -------------------------------------------------------------------------------- /vendor/src/gopkg.in/alecthomas/kingpin.v1/examples_test.go: -------------------------------------------------------------------------------- 1 | package kingpin 2 | 3 | import ( 4 | "fmt" 5 | "net/http" 6 | "strings" 7 | ) 8 | 9 | type HTTPHeaderValue http.Header 10 | 11 | func (h *HTTPHeaderValue) Set(value string) error { 12 | parts := strings.SplitN(value, ":", 2) 13 | if len(parts) != 2 { 14 | return fmt.Errorf("expected HEADER:VALUE got '%s'", value) 15 | } 16 | (*http.Header)(h).Add(parts[0], parts[1]) 17 | return nil 18 | } 19 | 20 | func (h *HTTPHeaderValue) String() string { 21 | return "" 22 | } 23 | 24 | func HTTPHeader(s Settings) (target *http.Header) { 25 | target = new(http.Header) 26 | s.SetValue((*HTTPHeaderValue)(target)) 27 | return 28 | } 29 | 30 | // This example ilustrates how to define custom parsers. HTTPHeader 31 | // cumulatively parses each encountered --header flag into a http.Header struct. 32 | func ExampleValue() { 33 | var ( 34 | curl = New("curl", "transfer a URL") 35 | headers = HTTPHeader(curl.Flag("headers", "Add HTTP headers to the request.").Short('H').PlaceHolder("HEADER:VALUE")) 36 | ) 37 | 38 | curl.Parse([]string{"-H Content-Type:application/octet-stream"}) 39 | for key, value := range *headers { 40 | fmt.Printf("%s = %s\n", key, value) 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /vendor/src/gopkg.in/alecthomas/kingpin.v1/flags_test.go: -------------------------------------------------------------------------------- 1 | package kingpin 2 | 3 | import ( 4 | "github.com/stretchr/testify/assert" 5 | 6 | "testing" 7 | ) 8 | 9 | func TestBool(t *testing.T) { 10 | fg := newFlagGroup() 11 | f := fg.Flag("b", "") 12 | b := f.Bool() 13 | fg.init() 14 | tokens := Tokenize([]string{"--b"}) 15 | fg.parse(tokens, false) 16 | assert.True(t, *b) 17 | } 18 | 19 | func TestNoBool(t *testing.T) { 20 | fg := newFlagGroup() 21 | f := fg.Flag("b", "").Default("true") 22 | b := f.Bool() 23 | fg.init() 24 | tokens := Tokenize([]string{"--no-b"}) 25 | err := fg.parse(tokens, false) 26 | assert.NoError(t, err) 27 | assert.False(t, *b) 28 | } 29 | 30 | func TestNegateNonBool(t *testing.T) { 31 | fg := newFlagGroup() 32 | f := fg.Flag("b", "") 33 | f.Int() 34 | fg.init() 35 | tokens := Tokenize([]string{"--no-b"}) 36 | err := fg.parse(tokens, false) 37 | assert.Error(t, err) 38 | } 39 | 40 | func TestInvalidFlagDefaultCanBeOverridden(t *testing.T) { 41 | fg := newFlagGroup() 42 | f := fg.Flag("a", "").Default("invalid") 43 | f.Bool() 44 | assert.NoError(t, fg.init()) 45 | tokens := Tokenize([]string{}) 46 | err := fg.parse(tokens, false) 47 | assert.Error(t, err) 48 | } 49 | 50 | func TestRequiredFlag(t *testing.T) { 51 | fg := newFlagGroup() 52 | fg.Flag("a", "").Required().Bool() 53 | assert.NoError(t, fg.init()) 54 | tokens := Tokenize([]string{"--a"}) 55 | err := fg.parse(tokens, false) 56 | assert.NoError(t, err) 57 | tokens = Tokenize([]string{}) 58 | err = fg.parse(tokens, false) 59 | assert.Error(t, err) 60 | } 61 | -------------------------------------------------------------------------------- /vendor/src/gopkg.in/alecthomas/kingpin.v1/global.go: -------------------------------------------------------------------------------- 1 | package kingpin 2 | 3 | import ( 4 | "os" 5 | "path/filepath" 6 | ) 7 | 8 | var ( 9 | // CommandLine is the default Kingpin parser. 10 | CommandLine = New(filepath.Base(os.Args[0]), "") 11 | ) 12 | 13 | // Command adds a new command to the default parser. 14 | func Command(name, help string) *CmdClause { 15 | return CommandLine.Command(name, help) 16 | } 17 | 18 | // Flag adds a new flag to the default parser. 19 | func Flag(name, help string) *FlagClause { 20 | return CommandLine.Flag(name, help) 21 | } 22 | 23 | // Arg adds a new argument to the top-level of the default parser. 24 | func Arg(name, help string) *ArgClause { 25 | return CommandLine.Arg(name, help) 26 | } 27 | 28 | // Parse and return the selected command. Will exit with a non-zero status if 29 | // an error was encountered. 30 | func Parse() string { 31 | selected := MustParse(CommandLine.Parse(os.Args[1:])) 32 | if selected == "" && CommandLine.cmdGroup.have() { 33 | Usage() 34 | os.Exit(0) 35 | } 36 | return selected 37 | } 38 | 39 | // ParseWithFileExpansion is the same as Parse() but will expand flags from 40 | // arguments in the form @FILE. 41 | func ParseWithFileExpansion() string { 42 | args, err := ExpandArgsFromFiles(os.Args[1:]) 43 | if err != nil { 44 | Fatalf("failed to expand flags: %s", err) 45 | } 46 | selected := MustParse(CommandLine.Parse(args)) 47 | if selected == "" && CommandLine.cmdGroup.have() { 48 | Usage() 49 | os.Exit(0) 50 | } 51 | return selected 52 | 53 | } 54 | 55 | // Fatalf prints an error message to stderr and exits. 56 | func Fatalf(format string, args ...interface{}) { 57 | CommandLine.Fatalf(os.Stderr, format, args...) 58 | } 59 | 60 | // FatalIfError prints an error and exits if err is not nil. The error is printed 61 | // with the given prefix. 62 | func FatalIfError(err error, prefix string) { 63 | CommandLine.FatalIfError(os.Stderr, err, prefix) 64 | } 65 | 66 | // UsageErrorf prints an error message followed by usage information, then 67 | // exits with a non-zero status. 68 | func UsageErrorf(format string, args ...interface{}) { 69 | CommandLine.UsageErrorf(os.Stderr, format, args...) 70 | } 71 | 72 | // Usage prints usage to stderr. 73 | func Usage() { 74 | CommandLine.Usage(os.Stderr) 75 | } 76 | 77 | // MustParse can be used with app.Parse(args) to exit with an error if parsing fails. 78 | func MustParse(command string, err error) string { 79 | if err != nil { 80 | Fatalf("%s, try --help", err) 81 | } 82 | return command 83 | } 84 | 85 | // Version adds a flag for displaying the application version number. 86 | func Version(version string) { 87 | CommandLine.Version(version) 88 | } 89 | -------------------------------------------------------------------------------- /vendor/src/gopkg.in/alecthomas/kingpin.v1/guesswidth.go: -------------------------------------------------------------------------------- 1 | // +build !linux,!freebsd,!darwin,!dragonfly,!netbsd,!openbsd 2 | 3 | package kingpin 4 | 5 | import "io" 6 | 7 | func guessWidth(w io.Writer) int { 8 | return 80 9 | } 10 | -------------------------------------------------------------------------------- /vendor/src/gopkg.in/alecthomas/kingpin.v1/guesswidth_unix.go: -------------------------------------------------------------------------------- 1 | // +build linux freebsd darwin dragonfly netbsd openbsd 2 | 3 | package kingpin 4 | 5 | import ( 6 | "io" 7 | "os" 8 | "strconv" 9 | "syscall" 10 | "unsafe" 11 | ) 12 | 13 | func guessWidth(w io.Writer) int { 14 | // check if COLUMNS env is set to comply with 15 | // http://pubs.opengroup.org/onlinepubs/009604499/basedefs/xbd_chap08.html 16 | cols_str := os.Getenv("COLUMNS") 17 | if cols_str != "" { 18 | if cols, err := strconv.Atoi(cols_str); err == nil { 19 | return cols 20 | } 21 | } 22 | 23 | if t, ok := w.(*os.File); ok { 24 | fd := t.Fd() 25 | var dimensions [4]uint16 26 | 27 | if _, _, err := syscall.Syscall6( 28 | syscall.SYS_IOCTL, 29 | uintptr(fd), 30 | uintptr(syscall.TIOCGWINSZ), 31 | uintptr(unsafe.Pointer(&dimensions)), 32 | 0, 0, 0, 33 | ); err == 0 { 34 | return int(dimensions[1]) 35 | } 36 | } 37 | return 80 38 | } 39 | -------------------------------------------------------------------------------- /vendor/src/gopkg.in/alecthomas/kingpin.v1/lexer_test.go: -------------------------------------------------------------------------------- 1 | package kingpin 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | ) 8 | 9 | func TestLexer(t *testing.T) { 10 | tokens := Tokenize([]string{"-abc", "foo", "--foo=bar", "--bar", "foo", "--", "-123"}).Tokens 11 | assert.Equal(t, 9, len(tokens)) 12 | tok := tokens.Peek() 13 | assert.Equal(t, &Token{TokenShort, "a"}, tok) 14 | tokens = tokens.Next() 15 | tok = tokens.Peek() 16 | assert.Equal(t, &Token{TokenShort, "b"}, tok) 17 | tokens = tokens.Next() 18 | tok = tokens.Peek() 19 | assert.Equal(t, &Token{TokenShort, "c"}, tok) 20 | tokens = tokens.Next() 21 | tok = tokens.Peek() 22 | assert.Equal(t, &Token{TokenArg, "foo"}, tok) 23 | tokens = tokens.Next() 24 | tok = tokens.Peek() 25 | assert.Equal(t, &Token{TokenLong, "foo"}, tok) 26 | tokens = tokens.Next() 27 | tok = tokens.Peek() 28 | assert.Equal(t, &Token{TokenArg, "bar"}, tok) 29 | tokens = tokens.Next() 30 | tok = tokens.Peek() 31 | assert.Equal(t, &Token{TokenLong, "bar"}, tok) 32 | tokens = tokens.Next() 33 | tok = tokens.Peek() 34 | assert.Equal(t, &Token{TokenArg, "foo"}, tok) 35 | tokens = tokens.Next() 36 | tok = tokens.Peek() 37 | assert.Equal(t, &Token{TokenArg, "-123"}, tok) 38 | tokens = tokens.Next() 39 | } 40 | -------------------------------------------------------------------------------- /vendor/src/gopkg.in/alecthomas/kingpin.v1/parser.go: -------------------------------------------------------------------------------- 1 | package kingpin 2 | 3 | type ParseContext struct { 4 | Tokens Tokens 5 | SelectedCommand string 6 | } 7 | 8 | func (p *ParseContext) Next() { 9 | p.Tokens = p.Tokens.Next() 10 | } 11 | 12 | func (p *ParseContext) Peek() *Token { 13 | return p.Tokens.Peek() 14 | } 15 | 16 | func (p *ParseContext) Return(token *Token) { 17 | p.Tokens = p.Tokens.Return(token) 18 | } 19 | 20 | func (p *ParseContext) String() string { 21 | return p.SelectedCommand + ": " + p.Tokens.String() 22 | } 23 | -------------------------------------------------------------------------------- /vendor/src/gopkg.in/alecthomas/kingpin.v1/parsers_test.go: -------------------------------------------------------------------------------- 1 | package kingpin 2 | 3 | import ( 4 | "io/ioutil" 5 | "net" 6 | "net/url" 7 | "os" 8 | 9 | "github.com/stretchr/testify/assert" 10 | 11 | "testing" 12 | ) 13 | 14 | func TestParseStrings(t *testing.T) { 15 | p := parserMixin{} 16 | v := p.Strings() 17 | p.value.Set("a") 18 | p.value.Set("b") 19 | assert.Equal(t, []string{"a", "b"}, *v) 20 | } 21 | 22 | func TestParseStringMap(t *testing.T) { 23 | p := parserMixin{} 24 | v := p.StringMap() 25 | p.value.Set("a:b") 26 | p.value.Set("b:c") 27 | assert.Equal(t, map[string]string{"a": "b", "b": "c"}, *v) 28 | } 29 | 30 | func TestParseIP(t *testing.T) { 31 | p := parserMixin{} 32 | v := p.IP() 33 | p.value.Set("10.1.1.2") 34 | ip := net.ParseIP("10.1.1.2") 35 | assert.Equal(t, ip, *v) 36 | } 37 | 38 | func TestParseURL(t *testing.T) { 39 | p := parserMixin{} 40 | v := p.URL() 41 | p.value.Set("http://w3.org") 42 | u, err := url.Parse("http://w3.org") 43 | assert.NoError(t, err) 44 | assert.Equal(t, *u, **v) 45 | } 46 | 47 | func TestParseExistingFile(t *testing.T) { 48 | f, err := ioutil.TempFile("", "") 49 | if err != nil { 50 | t.Fatal(err) 51 | } 52 | defer f.Close() 53 | defer os.Remove(f.Name()) 54 | 55 | p := parserMixin{} 56 | v := p.ExistingFile() 57 | err = p.value.Set(f.Name()) 58 | assert.NoError(t, err) 59 | assert.Equal(t, f.Name(), *v) 60 | err = p.value.Set("/etc/hostsDEFINITELYMISSING") 61 | assert.Error(t, err) 62 | } 63 | 64 | func TestParseTCPAddr(t *testing.T) { 65 | p := parserMixin{} 66 | v := p.TCP() 67 | err := p.value.Set("127.0.0.1:1234") 68 | assert.NoError(t, err) 69 | expected, err := net.ResolveTCPAddr("tcp", "127.0.0.1:1234") 70 | assert.NoError(t, err) 71 | assert.Equal(t, *expected, **v) 72 | } 73 | 74 | func TestParseTCPAddrList(t *testing.T) { 75 | p := parserMixin{} 76 | v := p.TCPList() 77 | err := p.value.Set("127.0.0.1:1234") 78 | assert.NoError(t, err) 79 | err = p.value.Set("127.0.0.1:1235") 80 | assert.NoError(t, err) 81 | assert.Equal(t, "127.0.0.1:1234,127.0.0.1:1235", (*tcpAddrsValue)(v).String()) 82 | } 83 | -------------------------------------------------------------------------------- /vendor/src/gopkg.in/alecthomas/kingpin.v1/usage_test.go: -------------------------------------------------------------------------------- 1 | package kingpin 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "strings" 7 | "testing" 8 | 9 | "github.com/stretchr/testify/assert" 10 | ) 11 | 12 | func TestFormatTwoColumns(t *testing.T) { 13 | buf := bytes.NewBuffer(nil) 14 | formatTwoColumns(buf, 2, 2, 20, [][2]string{ 15 | {"--hello", "Hello world help with something that is cool."}, 16 | }) 17 | expected := ` --hello Hello 18 | world 19 | help with 20 | something 21 | that is 22 | cool. 23 | ` 24 | assert.Equal(t, expected, buf.String()) 25 | } 26 | 27 | func TestFormatTwoColumnsWide(t *testing.T) { 28 | samples := [][2]string{ 29 | {strings.Repeat("x", 19), "19 chars"}, 30 | {strings.Repeat("x", 20), "20 chars"}} 31 | buf := bytes.NewBuffer(nil) 32 | formatTwoColumns(buf, 0, 0, 200, samples) 33 | fmt.Println(buf.String()) 34 | expected := `xxxxxxxxxxxxxxxxxxx19 chars 35 | xxxxxxxxxxxxxxxxxxxx 36 | 20 chars 37 | ` 38 | assert.Equal(t, expected, buf.String()) 39 | } 40 | -------------------------------------------------------------------------------- /vendor/src/gopkg.in/mgo.v2/bson/LICENSE: -------------------------------------------------------------------------------- 1 | BSON library for Go 2 | 3 | Copyright (c) 2010-2012 - Gustavo Niemeyer 4 | 5 | All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions are met: 9 | 10 | 1. Redistributions of source code must retain the above copyright notice, this 11 | list of conditions and the following disclaimer. 12 | 2. Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 17 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 20 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 23 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | --------------------------------------------------------------------------------