├── .gitignore ├── Procfile ├── README.md ├── app.json ├── cmd ├── queue-example-web │ └── main.go └── queue-example-worker │ └── main.go ├── shared.go └── vendor ├── github.com ├── Sirupsen │ └── logrus │ │ ├── CHANGELOG.md │ │ ├── LICENSE │ │ ├── README.md │ │ ├── doc.go │ │ ├── entry.go │ │ ├── exported.go │ │ ├── formatter.go │ │ ├── hooks.go │ │ ├── json_formatter.go │ │ ├── logger.go │ │ ├── logrus.go │ │ ├── terminal_bsd.go │ │ ├── terminal_linux.go │ │ ├── terminal_notwindows.go │ │ ├── terminal_solaris.go │ │ ├── terminal_windows.go │ │ ├── text_formatter.go │ │ └── writer.go ├── bgentry │ └── que-go │ │ ├── LICENSE │ │ ├── README.md │ │ ├── doc.go │ │ ├── que.go │ │ ├── schema.sql │ │ ├── sql.go │ │ ├── util.go │ │ └── worker.go ├── jackc │ └── pgx │ │ ├── CHANGELOG.md │ │ ├── LICENSE │ │ ├── README.md │ │ ├── conn.go │ │ ├── conn_config_test.go.example │ │ ├── conn_config_test.go.travis │ │ ├── conn_pool.go │ │ ├── doc.go │ │ ├── fastpath.go │ │ ├── hstore.go │ │ ├── large_objects.go │ │ ├── logger.go │ │ ├── messages.go │ │ ├── msg_reader.go │ │ ├── query.go │ │ ├── sql.go │ │ ├── tx.go │ │ ├── value_reader.go │ │ └── values.go └── pkg │ └── errors │ ├── LICENSE │ ├── README.md │ ├── appveyor.yml │ ├── errors.go │ └── stack.go └── vendor.json /.gitignore: -------------------------------------------------------------------------------- 1 | queue_example_web 2 | queue_example_worker 3 | -------------------------------------------------------------------------------- /Procfile: -------------------------------------------------------------------------------- 1 | web: queue-example-web 2 | worker: queue-example-worker 3 | release: psql $DATABASE_URL < vendor/github.com/bgentry/que-go/schema.sql -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # go-queue-example 2 | 3 | [![Deploy](https://www.herokucdn.com/deploy/button.png)](https://heroku.com/deploy) 4 | 5 | Go based Queue / Background Worker example. 6 | 7 | Please read the companion [Heroku Devcenter](https://devcenter.heroku.com/articles/que-go) article. 8 | 9 | After app setup you can test with the following commands: 10 | 11 | In one terminal run the following... 12 | 13 | ```term 14 | heroku logs --tail -a 15 | ``` 16 | 17 | In a different terminal run the following... 18 | 19 | ```term 20 | curl -XPOST "https://.herokuapp.com/index" -d '{"url": "http://google.com"}' 21 | ``` 22 | 23 | And you should see something like the following scroll by in the first terminal... 24 | 25 | ```term 26 | 2015-06-23T18:29:35.663096+00:00 heroku[router]: at=info method=POST path="/index" host=.herokuapp.com request_id=84f9d369-7d6e-4313-8f16-9db9bb7ed251 fwd="76.115.27.201" dyno=web.1 connect=19ms service=31ms status=202 bytes=141 27 | 2015-06-23T18:29:35.623878+00:00 app[web.1]: [negroni] Started POST /index 28 | 2015-06-23T18:29:35.644483+00:00 app[web.1]: [negroni] Completed 202 Accepted in 20.586125ms 29 | 2015-06-23T18:29:37.750543+00:00 app[worker.1]: time="2015-06-23T18:29:37Z" level=info msg="Processing IndexRequest! (not really)" IndexRequest={http://google.com} 30 | 2015-06-23T18:29:37.753021+00:00 app[worker.1]: 2015/06/23 18:29:37 event=job_worked job_id=1 job_type=IndexRequests 31 | ``` 32 | 33 | This shows the web process getting the request to index a url (http://google.com) and then the worker picking up the raw job and "processing" it. 34 | -------------------------------------------------------------------------------- /app.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Go Queue Example App", 3 | "description": "Go Background / Queue Example App", 4 | "keywords": [ 5 | "postgresql", 6 | "queue", 7 | "go" 8 | ], 9 | "buildpacks":[ 10 | {"url":"https://github.com/heroku/heroku-buildpack-addon-wait.git"}, 11 | {"url":"heroku/go"} 12 | ], 13 | "website": "http://github.com/heroku-examples/go_queue_example", 14 | "repository": "http://github.com/heroku-examples/go_queue_example", 15 | "addons": [ 16 | "heroku-postgresql" 17 | ], 18 | "formation":{ 19 | "web":{ 20 | "quantity":1 21 | }, 22 | "worker":{ 23 | "quantity":1 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /cmd/queue-example-web/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/json" 5 | "io" 6 | "net/http" 7 | "net/url" 8 | "os" 9 | "strings" 10 | 11 | "github.com/Sirupsen/logrus" 12 | que "github.com/bgentry/que-go" 13 | qe "github.com/heroku-examples/go-queue-example" 14 | "github.com/jackc/pgx" 15 | "github.com/pkg/errors" 16 | ) 17 | 18 | var ( 19 | log = logrus.WithField("cmd", "queue-example-web") 20 | qc *que.Client 21 | pgxpool *pgx.ConnPool 22 | ) 23 | 24 | // queueIndexRequest into the que as an encoded JSON object 25 | func queueIndexRequest(ir qe.IndexRequest) error { 26 | enc, err := json.Marshal(ir) 27 | if err != nil { 28 | return errors.Wrap(err, "Marshalling the IndexRequest") 29 | } 30 | 31 | j := que.Job{ 32 | Type: qe.IndexRequestJob, 33 | Args: enc, 34 | } 35 | 36 | return errors.Wrap(qc.Enqueue(&j), "Enqueueing Job") 37 | } 38 | 39 | // getIndexRequest from the body and further validate it. 40 | func getIndexRequest(r io.Reader) (qe.IndexRequest, error) { 41 | var ir qe.IndexRequest 42 | rd := json.NewDecoder(r) 43 | if err := rd.Decode(&ir); err != nil { 44 | return ir, errors.Wrap(err, "Error decoding JSON body.") 45 | } 46 | 47 | if ir.URL == "" || !strings.HasPrefix(ir.URL, "http") { 48 | return ir, errors.New("The request did not contain a url or was invalid") 49 | } 50 | 51 | _, err := url.Parse(ir.URL) 52 | if err != nil { 53 | return ir, errors.Wrap(err, "Error parsing URL") 54 | } 55 | 56 | return ir, nil 57 | } 58 | 59 | // handlePostIndexRequest from the outside world. We validate the request and 60 | // enqueue it for later processing returning a 202 if there were no errors 61 | func handlePostIndexRequest(w http.ResponseWriter, r *http.Request) { 62 | l := log.WithField("func", "handlePostIndexRequest") 63 | ir, err := getIndexRequest(r.Body) 64 | if err != nil { 65 | http.Error(w, err.Error(), http.StatusBadRequest) 66 | l.Println(err.Error()) 67 | return 68 | } 69 | 70 | if err := queueIndexRequest(ir); err != nil { 71 | l.Println(err.Error()) 72 | http.Error(w, err.Error(), http.StatusInternalServerError) 73 | return 74 | } 75 | 76 | w.WriteHeader(http.StatusAccepted) 77 | } 78 | 79 | func handleIndexRequest(w http.ResponseWriter, r *http.Request) { 80 | l := log.WithField("func", "handleIndexRequest") 81 | switch r.Method { 82 | case "POST": 83 | handlePostIndexRequest(w, r) 84 | default: 85 | err := "Invalid http method. Only POST is accepted." 86 | l.WithField("method", r.Method).Println(err) 87 | http.Error(w, err, http.StatusBadRequest) 88 | } 89 | } 90 | 91 | func handleIndex(w http.ResponseWriter, r *http.Request) { 92 | l := log.WithField("func", "handleIndex") 93 | if _, err := io.WriteString(w, `Usage: curl -XPOST "https://.herokuapp.com/index" -d '{"url": "http://google.com"}'`); err != nil { 94 | l.Println(err.Error()) 95 | } 96 | } 97 | 98 | func main() { 99 | port := os.Getenv("PORT") 100 | if port == "" { 101 | log.WithField("PORT", port).Fatal("$PORT must be set") 102 | } 103 | 104 | dbURL := os.Getenv("DATABASE_URL") 105 | var err error 106 | pgxpool, qc, err = qe.Setup(dbURL) 107 | if err != nil { 108 | log.WithField("DATABASE_URL", dbURL).Fatal("Unable to setup queue / database") 109 | } 110 | defer pgxpool.Close() 111 | 112 | http.HandleFunc("/", handleIndex) 113 | http.HandleFunc("/index", handleIndexRequest) 114 | log.Println(http.ListenAndServe(":"+port, nil)) 115 | } 116 | -------------------------------------------------------------------------------- /cmd/queue-example-worker/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/json" 5 | "os" 6 | "os/signal" 7 | "syscall" 8 | 9 | "github.com/Sirupsen/logrus" 10 | "github.com/bgentry/que-go" 11 | qe "github.com/heroku-examples/go-queue-example" 12 | "github.com/jackc/pgx" 13 | "github.com/pkg/errors" 14 | ) 15 | 16 | var ( 17 | log = logrus.WithField("cmd", "queue-example-worker") 18 | qc *que.Client 19 | pgxpool *pgx.ConnPool 20 | ) 21 | 22 | // indexURLJob would do whatever indexing is necessary in the background 23 | func indexURLJob(j *que.Job) error { 24 | var ir qe.IndexRequest 25 | if err := json.Unmarshal(j.Args, &ir); err != nil { 26 | return errors.Wrap(err, "Unable to unmarshal job arguments into IndexRequest: "+string(j.Args)) 27 | } 28 | 29 | log.WithField("IndexRequest", ir).Info("Processing IndexRequest! (not really)") 30 | // You would do real work here... 31 | 32 | return nil 33 | } 34 | 35 | func main() { 36 | var err error 37 | dbURL := os.Getenv("DATABASE_URL") 38 | pgxpool, qc, err = qe.Setup(dbURL) 39 | if err != nil { 40 | log.WithField("DATABASE_URL", dbURL).Fatal("Errors setting up the queue / database: ", err) 41 | } 42 | defer pgxpool.Close() 43 | 44 | wm := que.WorkMap{ 45 | qe.IndexRequestJob: indexURLJob, 46 | } 47 | 48 | // 2 worker go routines 49 | workers := que.NewWorkerPool(qc, wm, 2) 50 | 51 | // Catch signal so we can shutdown gracefully 52 | sigCh := make(chan os.Signal) 53 | signal.Notify(sigCh, syscall.SIGTERM, syscall.SIGINT) 54 | 55 | go workers.Start() 56 | 57 | // Wait for a signal 58 | sig := <-sigCh 59 | log.WithField("signal", sig).Info("Signal received. Shutting down.") 60 | 61 | workers.Shutdown() 62 | } 63 | -------------------------------------------------------------------------------- /shared.go: -------------------------------------------------------------------------------- 1 | package example 2 | 3 | import ( 4 | que "github.com/bgentry/que-go" 5 | "github.com/jackc/pgx" 6 | ) 7 | 8 | // IndexRequest container. 9 | // The URL is the url to index content from. 10 | type IndexRequest struct { 11 | URL string `json:"url"` 12 | } 13 | 14 | const ( 15 | // IndexRequestJob queue name52415697 16 | IndexRequestJob = "IndexRequests" 17 | ) 18 | 19 | // GetPgxPool based on the provided database URL 20 | func GetPgxPool(dbURL string) (*pgx.ConnPool, error) { 21 | pgxcfg, err := pgx.ParseURI(dbURL) 22 | if err != nil { 23 | return nil, err 24 | } 25 | 26 | pgxpool, err := pgx.NewConnPool(pgx.ConnPoolConfig{ 27 | ConnConfig: pgxcfg, 28 | AfterConnect: que.PrepareStatements, 29 | }) 30 | 31 | if err != nil { 32 | return nil, err 33 | } 34 | 35 | return pgxpool, nil 36 | } 37 | 38 | // Setup a *pgx.ConnPool and *que.Client 39 | // This is here so that setup routines can easily be shared between web and 40 | // workers 41 | func Setup(dbURL string) (*pgx.ConnPool, *que.Client, error) { 42 | pgxpool, err := GetPgxPool(dbURL) 43 | if err != nil { 44 | return nil, nil, err 45 | } 46 | 47 | qc := que.NewClient(pgxpool) 48 | 49 | return pgxpool, qc, err 50 | } 51 | -------------------------------------------------------------------------------- /vendor/github.com/Sirupsen/logrus/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # 0.10.0 2 | 3 | * feature: Add a test hook (#180) 4 | * feature: `ParseLevel` is now case-insensitive (#326) 5 | * feature: `FieldLogger` interface that generalizes `Logger` and `Entry` (#308) 6 | * performance: avoid re-allocations on `WithFields` (#335) 7 | 8 | # 0.9.0 9 | 10 | * logrus/text_formatter: don't emit empty msg 11 | * logrus/hooks/airbrake: move out of main repository 12 | * logrus/hooks/sentry: move out of main repository 13 | * logrus/hooks/papertrail: move out of main repository 14 | * logrus/hooks/bugsnag: move out of main repository 15 | * logrus/core: run tests with `-race` 16 | * logrus/core: detect TTY based on `stderr` 17 | * logrus/core: support `WithError` on logger 18 | * logrus/core: Solaris support 19 | 20 | # 0.8.7 21 | 22 | * logrus/core: fix possible race (#216) 23 | * logrus/doc: small typo fixes and doc improvements 24 | 25 | 26 | # 0.8.6 27 | 28 | * hooks/raven: allow passing an initialized client 29 | 30 | # 0.8.5 31 | 32 | * logrus/core: revert #208 33 | 34 | # 0.8.4 35 | 36 | * formatter/text: fix data race (#218) 37 | 38 | # 0.8.3 39 | 40 | * logrus/core: fix entry log level (#208) 41 | * logrus/core: improve performance of text formatter by 40% 42 | * logrus/core: expose `LevelHooks` type 43 | * logrus/core: add support for DragonflyBSD and NetBSD 44 | * formatter/text: print structs more verbosely 45 | 46 | # 0.8.2 47 | 48 | * logrus: fix more Fatal family functions 49 | 50 | # 0.8.1 51 | 52 | * logrus: fix not exiting on `Fatalf` and `Fatalln` 53 | 54 | # 0.8.0 55 | 56 | * logrus: defaults to stderr instead of stdout 57 | * hooks/sentry: add special field for `*http.Request` 58 | * formatter/text: ignore Windows for colors 59 | 60 | # 0.7.3 61 | 62 | * formatter/\*: allow configuration of timestamp layout 63 | 64 | # 0.7.2 65 | 66 | * formatter/text: Add configuration option for time format (#158) 67 | -------------------------------------------------------------------------------- /vendor/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/github.com/Sirupsen/logrus/README.md: -------------------------------------------------------------------------------- 1 | # Logrus :walrus: [![Build Status](https://travis-ci.org/Sirupsen/logrus.svg?branch=master)](https://travis-ci.org/Sirupsen/logrus) [![GoDoc](https://godoc.org/github.com/Sirupsen/logrus?status.svg)](https://godoc.org/github.com/Sirupsen/logrus) 2 | 3 | Logrus is a structured logger for Go (golang), completely API compatible with 4 | the standard library logger. [Godoc][godoc]. **Please note the Logrus API is not 5 | yet stable (pre 1.0). Logrus itself is completely stable and has been used in 6 | many large deployments. The core API is unlikely to change much but please 7 | version control your Logrus to make sure you aren't fetching latest `master` on 8 | every build.** 9 | 10 | Nicely color-coded in development (when a TTY is attached, otherwise just 11 | plain text): 12 | 13 | ![Colored](http://i.imgur.com/PY7qMwd.png) 14 | 15 | With `log.SetFormatter(&log.JSONFormatter{})`, for easy parsing by logstash 16 | or Splunk: 17 | 18 | ```json 19 | {"animal":"walrus","level":"info","msg":"A group of walrus emerges from the 20 | ocean","size":10,"time":"2014-03-10 19:57:38.562264131 -0400 EDT"} 21 | 22 | {"level":"warning","msg":"The group's number increased tremendously!", 23 | "number":122,"omg":true,"time":"2014-03-10 19:57:38.562471297 -0400 EDT"} 24 | 25 | {"animal":"walrus","level":"info","msg":"A giant walrus appears!", 26 | "size":10,"time":"2014-03-10 19:57:38.562500591 -0400 EDT"} 27 | 28 | {"animal":"walrus","level":"info","msg":"Tremendously sized cow enters the ocean.", 29 | "size":9,"time":"2014-03-10 19:57:38.562527896 -0400 EDT"} 30 | 31 | {"level":"fatal","msg":"The ice breaks!","number":100,"omg":true, 32 | "time":"2014-03-10 19:57:38.562543128 -0400 EDT"} 33 | ``` 34 | 35 | With the default `log.SetFormatter(&log.TextFormatter{})` when a TTY is not 36 | attached, the output is compatible with the 37 | [logfmt](http://godoc.org/github.com/kr/logfmt) format: 38 | 39 | ```text 40 | time="2015-03-26T01:27:38-04:00" level=debug msg="Started observing beach" animal=walrus number=8 41 | time="2015-03-26T01:27:38-04:00" level=info msg="A group of walrus emerges from the ocean" animal=walrus size=10 42 | time="2015-03-26T01:27:38-04:00" level=warning msg="The group's number increased tremendously!" number=122 omg=true 43 | time="2015-03-26T01:27:38-04:00" level=debug msg="Temperature changes" temperature=-4 44 | time="2015-03-26T01:27:38-04:00" level=panic msg="It's over 9000!" animal=orca size=9009 45 | time="2015-03-26T01:27:38-04:00" level=fatal msg="The ice breaks!" err=&{0x2082280c0 map[animal:orca size:9009] 2015-03-26 01:27:38.441574009 -0400 EDT panic It's over 9000!} number=100 omg=true 46 | exit status 1 47 | ``` 48 | 49 | #### Example 50 | 51 | The simplest way to use Logrus is simply the package-level exported logger: 52 | 53 | ```go 54 | package main 55 | 56 | import ( 57 | log "github.com/Sirupsen/logrus" 58 | ) 59 | 60 | func main() { 61 | log.WithFields(log.Fields{ 62 | "animal": "walrus", 63 | }).Info("A walrus appears") 64 | } 65 | ``` 66 | 67 | Note that it's completely api-compatible with the stdlib logger, so you can 68 | replace your `log` imports everywhere with `log "github.com/Sirupsen/logrus"` 69 | and you'll now have the flexibility of Logrus. You can customize it all you 70 | want: 71 | 72 | ```go 73 | package main 74 | 75 | import ( 76 | "os" 77 | log "github.com/Sirupsen/logrus" 78 | ) 79 | 80 | func init() { 81 | // Log as JSON instead of the default ASCII formatter. 82 | log.SetFormatter(&log.JSONFormatter{}) 83 | 84 | // Output to stderr instead of stdout, could also be a file. 85 | log.SetOutput(os.Stderr) 86 | 87 | // Only log the warning severity or above. 88 | log.SetLevel(log.WarnLevel) 89 | } 90 | 91 | func main() { 92 | log.WithFields(log.Fields{ 93 | "animal": "walrus", 94 | "size": 10, 95 | }).Info("A group of walrus emerges from the ocean") 96 | 97 | log.WithFields(log.Fields{ 98 | "omg": true, 99 | "number": 122, 100 | }).Warn("The group's number increased tremendously!") 101 | 102 | log.WithFields(log.Fields{ 103 | "omg": true, 104 | "number": 100, 105 | }).Fatal("The ice breaks!") 106 | 107 | // A common pattern is to re-use fields between logging statements by re-using 108 | // the logrus.Entry returned from WithFields() 109 | contextLogger := log.WithFields(log.Fields{ 110 | "common": "this is a common field", 111 | "other": "I also should be logged always", 112 | }) 113 | 114 | contextLogger.Info("I'll be logged with common and other field") 115 | contextLogger.Info("Me too") 116 | } 117 | ``` 118 | 119 | For more advanced usage such as logging to multiple locations from the same 120 | application, you can also create an instance of the `logrus` Logger: 121 | 122 | ```go 123 | package main 124 | 125 | import ( 126 | "github.com/Sirupsen/logrus" 127 | ) 128 | 129 | // Create a new instance of the logger. You can have any number of instances. 130 | var log = logrus.New() 131 | 132 | func main() { 133 | // The API for setting attributes is a little different than the package level 134 | // exported logger. See Godoc. 135 | log.Out = os.Stderr 136 | 137 | log.WithFields(logrus.Fields{ 138 | "animal": "walrus", 139 | "size": 10, 140 | }).Info("A group of walrus emerges from the ocean") 141 | } 142 | ``` 143 | 144 | #### Fields 145 | 146 | Logrus encourages careful, structured logging though logging fields instead of 147 | long, unparseable error messages. For example, instead of: `log.Fatalf("Failed 148 | to send event %s to topic %s with key %d")`, you should log the much more 149 | discoverable: 150 | 151 | ```go 152 | log.WithFields(log.Fields{ 153 | "event": event, 154 | "topic": topic, 155 | "key": key, 156 | }).Fatal("Failed to send event") 157 | ``` 158 | 159 | We've found this API forces you to think about logging in a way that produces 160 | much more useful logging messages. We've been in countless situations where just 161 | a single added field to a log statement that was already there would've saved us 162 | hours. The `WithFields` call is optional. 163 | 164 | In general, with Logrus using any of the `printf`-family functions should be 165 | seen as a hint you should add a field, however, you can still use the 166 | `printf`-family functions with Logrus. 167 | 168 | #### Hooks 169 | 170 | You can add hooks for logging levels. For example to send errors to an exception 171 | tracking service on `Error`, `Fatal` and `Panic`, info to StatsD or log to 172 | multiple places simultaneously, e.g. syslog. 173 | 174 | Logrus comes with [built-in hooks](hooks/). Add those, or your custom hook, in 175 | `init`: 176 | 177 | ```go 178 | import ( 179 | log "github.com/Sirupsen/logrus" 180 | "gopkg.in/gemnasium/logrus-airbrake-hook.v2" // the package is named "aibrake" 181 | logrus_syslog "github.com/Sirupsen/logrus/hooks/syslog" 182 | "log/syslog" 183 | ) 184 | 185 | func init() { 186 | 187 | // Use the Airbrake hook to report errors that have Error severity or above to 188 | // an exception tracker. You can create custom hooks, see the Hooks section. 189 | log.AddHook(airbrake.NewHook(123, "xyz", "production")) 190 | 191 | hook, err := logrus_syslog.NewSyslogHook("udp", "localhost:514", syslog.LOG_INFO, "") 192 | if err != nil { 193 | log.Error("Unable to connect to local syslog daemon") 194 | } else { 195 | log.AddHook(hook) 196 | } 197 | } 198 | ``` 199 | Note: Syslog hook also support connecting to local syslog (Ex. "/dev/log" or "/var/run/syslog" or "/var/run/log"). For the detail, please check the [syslog hook README](hooks/syslog/README.md). 200 | 201 | | Hook | Description | 202 | | ----- | ----------- | 203 | | [Airbrake](https://github.com/gemnasium/logrus-airbrake-hook) | Send errors to the Airbrake API V3. Uses the official [`gobrake`](https://github.com/airbrake/gobrake) behind the scenes. | 204 | | [Airbrake "legacy"](https://github.com/gemnasium/logrus-airbrake-legacy-hook) | Send errors to an exception tracking service compatible with the Airbrake API V2. Uses [`airbrake-go`](https://github.com/tobi/airbrake-go) behind the scenes. | 205 | | [Papertrail](https://github.com/polds/logrus-papertrail-hook) | Send errors to the [Papertrail](https://papertrailapp.com) hosted logging service via UDP. | 206 | | [Syslog](https://github.com/Sirupsen/logrus/blob/master/hooks/syslog/syslog.go) | Send errors to remote syslog server. Uses standard library `log/syslog` behind the scenes. | 207 | | [Bugsnag](https://github.com/Shopify/logrus-bugsnag/blob/master/bugsnag.go) | Send errors to the Bugsnag exception tracking service. | 208 | | [Sentry](https://github.com/evalphobia/logrus_sentry) | Send errors to the Sentry error logging and aggregation service. | 209 | | [Hiprus](https://github.com/nubo/hiprus) | Send errors to a channel in hipchat. | 210 | | [Logrusly](https://github.com/sebest/logrusly) | Send logs to [Loggly](https://www.loggly.com/) | 211 | | [Slackrus](https://github.com/johntdyer/slackrus) | Hook for Slack chat. | 212 | | [Journalhook](https://github.com/wercker/journalhook) | Hook for logging to `systemd-journald` | 213 | | [Graylog](https://github.com/gemnasium/logrus-graylog-hook) | Hook for logging to [Graylog](http://graylog2.org/) | 214 | | [Raygun](https://github.com/squirkle/logrus-raygun-hook) | Hook for logging to [Raygun.io](http://raygun.io/) | 215 | | [LFShook](https://github.com/rifflock/lfshook) | Hook for logging to the local filesystem | 216 | | [Honeybadger](https://github.com/agonzalezro/logrus_honeybadger) | Hook for sending exceptions to Honeybadger | 217 | | [Mail](https://github.com/zbindenren/logrus_mail) | Hook for sending exceptions via mail | 218 | | [Rollrus](https://github.com/heroku/rollrus) | Hook for sending errors to rollbar | 219 | | [Fluentd](https://github.com/evalphobia/logrus_fluent) | Hook for logging to fluentd | 220 | | [Mongodb](https://github.com/weekface/mgorus) | Hook for logging to mongodb | 221 | | [InfluxDB](https://github.com/Abramovic/logrus_influxdb) | Hook for logging to influxdb | 222 | | [Octokit](https://github.com/dorajistyle/logrus-octokit-hook) | Hook for logging to github via octokit | 223 | | [DeferPanic](https://github.com/deferpanic/dp-logrus) | Hook for logging to DeferPanic | 224 | | [Redis-Hook](https://github.com/rogierlommers/logrus-redis-hook) | Hook for logging to a ELK stack (through Redis) | 225 | | [Amqp-Hook](https://github.com/vladoatanasov/logrus_amqp) | Hook for logging to Amqp broker (Like RabbitMQ) | 226 | | [KafkaLogrus](https://github.com/goibibo/KafkaLogrus) | Hook for logging to kafka | 227 | | [Typetalk](https://github.com/dragon3/logrus-typetalk-hook) | Hook for logging to [Typetalk](https://www.typetalk.in/) | 228 | | [ElasticSearch](https://github.com/sohlich/elogrus) | Hook for logging to ElasticSearch| 229 | 230 | 231 | #### Level logging 232 | 233 | Logrus has six logging levels: Debug, Info, Warning, Error, Fatal and Panic. 234 | 235 | ```go 236 | log.Debug("Useful debugging information.") 237 | log.Info("Something noteworthy happened!") 238 | log.Warn("You should probably take a look at this.") 239 | log.Error("Something failed but I'm not quitting.") 240 | // Calls os.Exit(1) after logging 241 | log.Fatal("Bye.") 242 | // Calls panic() after logging 243 | log.Panic("I'm bailing.") 244 | ``` 245 | 246 | You can set the logging level on a `Logger`, then it will only log entries with 247 | that severity or anything above it: 248 | 249 | ```go 250 | // Will log anything that is info or above (warn, error, fatal, panic). Default. 251 | log.SetLevel(log.InfoLevel) 252 | ``` 253 | 254 | It may be useful to set `log.Level = logrus.DebugLevel` in a debug or verbose 255 | environment if your application has that. 256 | 257 | #### Entries 258 | 259 | Besides the fields added with `WithField` or `WithFields` some fields are 260 | automatically added to all logging events: 261 | 262 | 1. `time`. The timestamp when the entry was created. 263 | 2. `msg`. The logging message passed to `{Info,Warn,Error,Fatal,Panic}` after 264 | the `AddFields` call. E.g. `Failed to send event.` 265 | 3. `level`. The logging level. E.g. `info`. 266 | 267 | #### Environments 268 | 269 | Logrus has no notion of environment. 270 | 271 | If you wish for hooks and formatters to only be used in specific environments, 272 | you should handle that yourself. For example, if your application has a global 273 | variable `Environment`, which is a string representation of the environment you 274 | could do: 275 | 276 | ```go 277 | import ( 278 | log "github.com/Sirupsen/logrus" 279 | ) 280 | 281 | init() { 282 | // do something here to set environment depending on an environment variable 283 | // or command-line flag 284 | if Environment == "production" { 285 | log.SetFormatter(&log.JSONFormatter{}) 286 | } else { 287 | // The TextFormatter is default, you don't actually have to do this. 288 | log.SetFormatter(&log.TextFormatter{}) 289 | } 290 | } 291 | ``` 292 | 293 | This configuration is how `logrus` was intended to be used, but JSON in 294 | production is mostly only useful if you do log aggregation with tools like 295 | Splunk or Logstash. 296 | 297 | #### Formatters 298 | 299 | The built-in logging formatters are: 300 | 301 | * `logrus.TextFormatter`. Logs the event in colors if stdout is a tty, otherwise 302 | without colors. 303 | * *Note:* to force colored output when there is no TTY, set the `ForceColors` 304 | field to `true`. To force no colored output even if there is a TTY set the 305 | `DisableColors` field to `true` 306 | * `logrus.JSONFormatter`. Logs fields as JSON. 307 | * `logrus/formatters/logstash.LogstashFormatter`. Logs fields as [Logstash](http://logstash.net) Events. 308 | 309 | ```go 310 | logrus.SetFormatter(&logstash.LogstashFormatter{Type: "application_name"}) 311 | ``` 312 | 313 | Third party logging formatters: 314 | 315 | * [`prefixed`](https://github.com/x-cray/logrus-prefixed-formatter). Displays log entry source along with alternative layout. 316 | * [`zalgo`](https://github.com/aybabtme/logzalgo). Invoking the P͉̫o̳̼̊w̖͈̰͎e̬͔̭͂r͚̼̹̲ ̫͓͉̳͈ō̠͕͖̚f̝͍̠ ͕̲̞͖͑Z̖̫̤̫ͪa͉̬͈̗l͖͎g̳̥o̰̥̅!̣͔̲̻͊̄ ̙̘̦̹̦. 317 | 318 | You can define your formatter by implementing the `Formatter` interface, 319 | requiring a `Format` method. `Format` takes an `*Entry`. `entry.Data` is a 320 | `Fields` type (`map[string]interface{}`) with all your fields as well as the 321 | default ones (see Entries section above): 322 | 323 | ```go 324 | type MyJSONFormatter struct { 325 | } 326 | 327 | log.SetFormatter(new(MyJSONFormatter)) 328 | 329 | func (f *MyJSONFormatter) Format(entry *Entry) ([]byte, error) { 330 | // Note this doesn't include Time, Level and Message which are available on 331 | // the Entry. Consult `godoc` on information about those fields or read the 332 | // source of the official loggers. 333 | serialized, err := json.Marshal(entry.Data) 334 | if err != nil { 335 | return nil, fmt.Errorf("Failed to marshal fields to JSON, %v", err) 336 | } 337 | return append(serialized, '\n'), nil 338 | } 339 | ``` 340 | 341 | #### Logger as an `io.Writer` 342 | 343 | Logrus can be transformed into an `io.Writer`. That writer is the end of an `io.Pipe` and it is your responsibility to close it. 344 | 345 | ```go 346 | w := logger.Writer() 347 | defer w.Close() 348 | 349 | srv := http.Server{ 350 | // create a stdlib log.Logger that writes to 351 | // logrus.Logger. 352 | ErrorLog: log.New(w, "", 0), 353 | } 354 | ``` 355 | 356 | Each line written to that writer will be printed the usual way, using formatters 357 | and hooks. The level for those entries is `info`. 358 | 359 | #### Rotation 360 | 361 | Log rotation is not provided with Logrus. Log rotation should be done by an 362 | external program (like `logrotate(8)`) that can compress and delete old log 363 | entries. It should not be a feature of the application-level logger. 364 | 365 | #### Tools 366 | 367 | | Tool | Description | 368 | | ---- | ----------- | 369 | |[Logrus Mate](https://github.com/gogap/logrus_mate)|Logrus mate is a tool for Logrus to manage loggers, you can initial logger's level, hook and formatter by config file, the logger will generated with different config at different environment.| 370 | 371 | #### Testing 372 | 373 | Logrus has a built in facility for asserting the presence of log messages. This is implemented through the `test` hook and provides: 374 | 375 | * decorators for existing logger (`test.NewLocal` and `test.NewGlobal`) which basically just add the `test` hook 376 | * a test logger (`test.NewNullLogger`) that just records log messages (and does not output any): 377 | 378 | ```go 379 | logger, hook := NewNullLogger() 380 | logger.Error("Hello error") 381 | 382 | assert.Equal(1, len(hook.Entries)) 383 | assert.Equal(logrus.ErrorLevel, hook.LastEntry().Level) 384 | assert.Equal("Hello error", hook.LastEntry().Message) 385 | 386 | hook.Reset() 387 | assert.Nil(hook.LastEntry()) 388 | ``` 389 | -------------------------------------------------------------------------------- /vendor/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/github.com/Sirupsen/logrus/entry.go: -------------------------------------------------------------------------------- 1 | package logrus 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "io" 7 | "os" 8 | "time" 9 | ) 10 | 11 | // Defines the key when adding errors using WithError. 12 | var ErrorKey = "error" 13 | 14 | // An entry is the final or intermediate Logrus logging entry. It contains all 15 | // the fields passed with WithField{,s}. It's finally logged when Debug, Info, 16 | // Warn, Error, Fatal or Panic is called on it. These objects can be reused and 17 | // passed around as much as you wish to avoid field duplication. 18 | type Entry struct { 19 | Logger *Logger 20 | 21 | // Contains all the fields set by the user. 22 | Data Fields 23 | 24 | // Time at which the log entry was created 25 | Time time.Time 26 | 27 | // Level the log entry was logged at: Debug, Info, Warn, Error, Fatal or Panic 28 | Level Level 29 | 30 | // Message passed to Debug, Info, Warn, Error, Fatal or Panic 31 | Message string 32 | } 33 | 34 | func NewEntry(logger *Logger) *Entry { 35 | return &Entry{ 36 | Logger: logger, 37 | // Default is three fields, give a little extra room 38 | Data: make(Fields, 5), 39 | } 40 | } 41 | 42 | // Returns a reader for the entry, which is a proxy to the formatter. 43 | func (entry *Entry) Reader() (*bytes.Buffer, error) { 44 | serialized, err := entry.Logger.Formatter.Format(entry) 45 | return bytes.NewBuffer(serialized), err 46 | } 47 | 48 | // Returns the string representation from the reader and ultimately the 49 | // formatter. 50 | func (entry *Entry) String() (string, error) { 51 | reader, err := entry.Reader() 52 | if err != nil { 53 | return "", err 54 | } 55 | 56 | return reader.String(), err 57 | } 58 | 59 | // Add an error as single field (using the key defined in ErrorKey) to the Entry. 60 | func (entry *Entry) WithError(err error) *Entry { 61 | return entry.WithField(ErrorKey, err) 62 | } 63 | 64 | // Add a single field to the Entry. 65 | func (entry *Entry) WithField(key string, value interface{}) *Entry { 66 | return entry.WithFields(Fields{key: value}) 67 | } 68 | 69 | // Add a map of fields to the Entry. 70 | func (entry *Entry) WithFields(fields Fields) *Entry { 71 | data := make(Fields, len(entry.Data)+len(fields)) 72 | for k, v := range entry.Data { 73 | data[k] = v 74 | } 75 | for k, v := range fields { 76 | data[k] = v 77 | } 78 | return &Entry{Logger: entry.Logger, Data: data} 79 | } 80 | 81 | // This function is not declared with a pointer value because otherwise 82 | // race conditions will occur when using multiple goroutines 83 | func (entry Entry) log(level Level, msg string) { 84 | entry.Time = time.Now() 85 | entry.Level = level 86 | entry.Message = msg 87 | 88 | if err := entry.Logger.Hooks.Fire(level, &entry); err != nil { 89 | entry.Logger.mu.Lock() 90 | fmt.Fprintf(os.Stderr, "Failed to fire hook: %v\n", err) 91 | entry.Logger.mu.Unlock() 92 | } 93 | 94 | reader, err := entry.Reader() 95 | if err != nil { 96 | entry.Logger.mu.Lock() 97 | fmt.Fprintf(os.Stderr, "Failed to obtain reader, %v\n", err) 98 | entry.Logger.mu.Unlock() 99 | } 100 | 101 | entry.Logger.mu.Lock() 102 | defer entry.Logger.mu.Unlock() 103 | 104 | _, err = io.Copy(entry.Logger.Out, reader) 105 | if err != nil { 106 | fmt.Fprintf(os.Stderr, "Failed to write to log, %v\n", err) 107 | } 108 | 109 | // To avoid Entry#log() returning a value that only would make sense for 110 | // panic() to use in Entry#Panic(), we avoid the allocation by checking 111 | // directly here. 112 | if level <= PanicLevel { 113 | panic(&entry) 114 | } 115 | } 116 | 117 | func (entry *Entry) Debug(args ...interface{}) { 118 | if entry.Logger.Level >= DebugLevel { 119 | entry.log(DebugLevel, fmt.Sprint(args...)) 120 | } 121 | } 122 | 123 | func (entry *Entry) Print(args ...interface{}) { 124 | entry.Info(args...) 125 | } 126 | 127 | func (entry *Entry) Info(args ...interface{}) { 128 | if entry.Logger.Level >= InfoLevel { 129 | entry.log(InfoLevel, fmt.Sprint(args...)) 130 | } 131 | } 132 | 133 | func (entry *Entry) Warn(args ...interface{}) { 134 | if entry.Logger.Level >= WarnLevel { 135 | entry.log(WarnLevel, fmt.Sprint(args...)) 136 | } 137 | } 138 | 139 | func (entry *Entry) Warning(args ...interface{}) { 140 | entry.Warn(args...) 141 | } 142 | 143 | func (entry *Entry) Error(args ...interface{}) { 144 | if entry.Logger.Level >= ErrorLevel { 145 | entry.log(ErrorLevel, fmt.Sprint(args...)) 146 | } 147 | } 148 | 149 | func (entry *Entry) Fatal(args ...interface{}) { 150 | if entry.Logger.Level >= FatalLevel { 151 | entry.log(FatalLevel, fmt.Sprint(args...)) 152 | } 153 | os.Exit(1) 154 | } 155 | 156 | func (entry *Entry) Panic(args ...interface{}) { 157 | if entry.Logger.Level >= PanicLevel { 158 | entry.log(PanicLevel, fmt.Sprint(args...)) 159 | } 160 | panic(fmt.Sprint(args...)) 161 | } 162 | 163 | // Entry Printf family functions 164 | 165 | func (entry *Entry) Debugf(format string, args ...interface{}) { 166 | if entry.Logger.Level >= DebugLevel { 167 | entry.Debug(fmt.Sprintf(format, args...)) 168 | } 169 | } 170 | 171 | func (entry *Entry) Infof(format string, args ...interface{}) { 172 | if entry.Logger.Level >= InfoLevel { 173 | entry.Info(fmt.Sprintf(format, args...)) 174 | } 175 | } 176 | 177 | func (entry *Entry) Printf(format string, args ...interface{}) { 178 | entry.Infof(format, args...) 179 | } 180 | 181 | func (entry *Entry) Warnf(format string, args ...interface{}) { 182 | if entry.Logger.Level >= WarnLevel { 183 | entry.Warn(fmt.Sprintf(format, args...)) 184 | } 185 | } 186 | 187 | func (entry *Entry) Warningf(format string, args ...interface{}) { 188 | entry.Warnf(format, args...) 189 | } 190 | 191 | func (entry *Entry) Errorf(format string, args ...interface{}) { 192 | if entry.Logger.Level >= ErrorLevel { 193 | entry.Error(fmt.Sprintf(format, args...)) 194 | } 195 | } 196 | 197 | func (entry *Entry) Fatalf(format string, args ...interface{}) { 198 | if entry.Logger.Level >= FatalLevel { 199 | entry.Fatal(fmt.Sprintf(format, args...)) 200 | } 201 | os.Exit(1) 202 | } 203 | 204 | func (entry *Entry) Panicf(format string, args ...interface{}) { 205 | if entry.Logger.Level >= PanicLevel { 206 | entry.Panic(fmt.Sprintf(format, args...)) 207 | } 208 | } 209 | 210 | // Entry Println family functions 211 | 212 | func (entry *Entry) Debugln(args ...interface{}) { 213 | if entry.Logger.Level >= DebugLevel { 214 | entry.Debug(entry.sprintlnn(args...)) 215 | } 216 | } 217 | 218 | func (entry *Entry) Infoln(args ...interface{}) { 219 | if entry.Logger.Level >= InfoLevel { 220 | entry.Info(entry.sprintlnn(args...)) 221 | } 222 | } 223 | 224 | func (entry *Entry) Println(args ...interface{}) { 225 | entry.Infoln(args...) 226 | } 227 | 228 | func (entry *Entry) Warnln(args ...interface{}) { 229 | if entry.Logger.Level >= WarnLevel { 230 | entry.Warn(entry.sprintlnn(args...)) 231 | } 232 | } 233 | 234 | func (entry *Entry) Warningln(args ...interface{}) { 235 | entry.Warnln(args...) 236 | } 237 | 238 | func (entry *Entry) Errorln(args ...interface{}) { 239 | if entry.Logger.Level >= ErrorLevel { 240 | entry.Error(entry.sprintlnn(args...)) 241 | } 242 | } 243 | 244 | func (entry *Entry) Fatalln(args ...interface{}) { 245 | if entry.Logger.Level >= FatalLevel { 246 | entry.Fatal(entry.sprintlnn(args...)) 247 | } 248 | os.Exit(1) 249 | } 250 | 251 | func (entry *Entry) Panicln(args ...interface{}) { 252 | if entry.Logger.Level >= PanicLevel { 253 | entry.Panic(entry.sprintlnn(args...)) 254 | } 255 | } 256 | 257 | // Sprintlnn => Sprint no newline. This is to get the behavior of how 258 | // fmt.Sprintln where spaces are always added between operands, regardless of 259 | // their type. Instead of vendoring the Sprintln implementation to spare a 260 | // string allocation, we do the simplest thing. 261 | func (entry *Entry) sprintlnn(args ...interface{}) string { 262 | msg := fmt.Sprintln(args...) 263 | return msg[:len(msg)-1] 264 | } 265 | -------------------------------------------------------------------------------- /vendor/github.com/Sirupsen/logrus/exported.go: -------------------------------------------------------------------------------- 1 | package logrus 2 | 3 | import ( 4 | "io" 5 | ) 6 | 7 | var ( 8 | // std is the name of the standard logger in stdlib `log` 9 | std = New() 10 | ) 11 | 12 | func StandardLogger() *Logger { 13 | return std 14 | } 15 | 16 | // SetOutput sets the standard logger output. 17 | func SetOutput(out io.Writer) { 18 | std.mu.Lock() 19 | defer std.mu.Unlock() 20 | std.Out = out 21 | } 22 | 23 | // SetFormatter sets the standard logger formatter. 24 | func SetFormatter(formatter Formatter) { 25 | std.mu.Lock() 26 | defer std.mu.Unlock() 27 | std.Formatter = formatter 28 | } 29 | 30 | // SetLevel sets the standard logger level. 31 | func SetLevel(level Level) { 32 | std.mu.Lock() 33 | defer std.mu.Unlock() 34 | std.Level = level 35 | } 36 | 37 | // GetLevel returns the standard logger level. 38 | func GetLevel() Level { 39 | std.mu.Lock() 40 | defer std.mu.Unlock() 41 | return std.Level 42 | } 43 | 44 | // AddHook adds a hook to the standard logger hooks. 45 | func AddHook(hook Hook) { 46 | std.mu.Lock() 47 | defer std.mu.Unlock() 48 | std.Hooks.Add(hook) 49 | } 50 | 51 | // WithError creates an entry from the standard logger and adds an error to it, using the value defined in ErrorKey as key. 52 | func WithError(err error) *Entry { 53 | return std.WithField(ErrorKey, err) 54 | } 55 | 56 | // WithField creates an entry from the standard logger and adds a field to 57 | // it. If you want multiple fields, use `WithFields`. 58 | // 59 | // Note that it doesn't log until you call Debug, Print, Info, Warn, Fatal 60 | // or Panic on the Entry it returns. 61 | func WithField(key string, value interface{}) *Entry { 62 | return std.WithField(key, value) 63 | } 64 | 65 | // WithFields creates an entry from the standard logger and adds multiple 66 | // fields to it. This is simply a helper for `WithField`, invoking it 67 | // once for each field. 68 | // 69 | // Note that it doesn't log until you call Debug, Print, Info, Warn, Fatal 70 | // or Panic on the Entry it returns. 71 | func WithFields(fields Fields) *Entry { 72 | return std.WithFields(fields) 73 | } 74 | 75 | // Debug logs a message at level Debug on the standard logger. 76 | func Debug(args ...interface{}) { 77 | std.Debug(args...) 78 | } 79 | 80 | // Print logs a message at level Info on the standard logger. 81 | func Print(args ...interface{}) { 82 | std.Print(args...) 83 | } 84 | 85 | // Info logs a message at level Info on the standard logger. 86 | func Info(args ...interface{}) { 87 | std.Info(args...) 88 | } 89 | 90 | // Warn logs a message at level Warn on the standard logger. 91 | func Warn(args ...interface{}) { 92 | std.Warn(args...) 93 | } 94 | 95 | // Warning logs a message at level Warn on the standard logger. 96 | func Warning(args ...interface{}) { 97 | std.Warning(args...) 98 | } 99 | 100 | // Error logs a message at level Error on the standard logger. 101 | func Error(args ...interface{}) { 102 | std.Error(args...) 103 | } 104 | 105 | // Panic logs a message at level Panic on the standard logger. 106 | func Panic(args ...interface{}) { 107 | std.Panic(args...) 108 | } 109 | 110 | // Fatal logs a message at level Fatal on the standard logger. 111 | func Fatal(args ...interface{}) { 112 | std.Fatal(args...) 113 | } 114 | 115 | // Debugf logs a message at level Debug on the standard logger. 116 | func Debugf(format string, args ...interface{}) { 117 | std.Debugf(format, args...) 118 | } 119 | 120 | // Printf logs a message at level Info on the standard logger. 121 | func Printf(format string, args ...interface{}) { 122 | std.Printf(format, args...) 123 | } 124 | 125 | // Infof logs a message at level Info on the standard logger. 126 | func Infof(format string, args ...interface{}) { 127 | std.Infof(format, args...) 128 | } 129 | 130 | // Warnf logs a message at level Warn on the standard logger. 131 | func Warnf(format string, args ...interface{}) { 132 | std.Warnf(format, args...) 133 | } 134 | 135 | // Warningf logs a message at level Warn on the standard logger. 136 | func Warningf(format string, args ...interface{}) { 137 | std.Warningf(format, args...) 138 | } 139 | 140 | // Errorf logs a message at level Error on the standard logger. 141 | func Errorf(format string, args ...interface{}) { 142 | std.Errorf(format, args...) 143 | } 144 | 145 | // Panicf logs a message at level Panic on the standard logger. 146 | func Panicf(format string, args ...interface{}) { 147 | std.Panicf(format, args...) 148 | } 149 | 150 | // Fatalf logs a message at level Fatal on the standard logger. 151 | func Fatalf(format string, args ...interface{}) { 152 | std.Fatalf(format, args...) 153 | } 154 | 155 | // Debugln logs a message at level Debug on the standard logger. 156 | func Debugln(args ...interface{}) { 157 | std.Debugln(args...) 158 | } 159 | 160 | // Println logs a message at level Info on the standard logger. 161 | func Println(args ...interface{}) { 162 | std.Println(args...) 163 | } 164 | 165 | // Infoln logs a message at level Info on the standard logger. 166 | func Infoln(args ...interface{}) { 167 | std.Infoln(args...) 168 | } 169 | 170 | // Warnln logs a message at level Warn on the standard logger. 171 | func Warnln(args ...interface{}) { 172 | std.Warnln(args...) 173 | } 174 | 175 | // Warningln logs a message at level Warn on the standard logger. 176 | func Warningln(args ...interface{}) { 177 | std.Warningln(args...) 178 | } 179 | 180 | // Errorln logs a message at level Error on the standard logger. 181 | func Errorln(args ...interface{}) { 182 | std.Errorln(args...) 183 | } 184 | 185 | // Panicln logs a message at level Panic on the standard logger. 186 | func Panicln(args ...interface{}) { 187 | std.Panicln(args...) 188 | } 189 | 190 | // Fatalln logs a message at level Fatal on the standard logger. 191 | func Fatalln(args ...interface{}) { 192 | std.Fatalln(args...) 193 | } 194 | -------------------------------------------------------------------------------- /vendor/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/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/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/github.com/Sirupsen/logrus/logger.go: -------------------------------------------------------------------------------- 1 | package logrus 2 | 3 | import ( 4 | "io" 5 | "os" 6 | "sync" 7 | ) 8 | 9 | type Logger struct { 10 | // The logs are `io.Copy`'d to this in a mutex. It's common to set this to a 11 | // file, or leave it default which is `os.Stderr`. You can also set this to 12 | // something more adventorous, such as logging to Kafka. 13 | Out io.Writer 14 | // Hooks for the logger instance. These allow firing events based on logging 15 | // levels and log entries. For example, to send errors to an error tracking 16 | // service, log to StatsD or dump the core on fatal errors. 17 | Hooks LevelHooks 18 | // All log entries pass through the formatter before logged to Out. The 19 | // included formatters are `TextFormatter` and `JSONFormatter` for which 20 | // TextFormatter is the default. In development (when a TTY is attached) it 21 | // logs with colors, but to a file it wouldn't. You can easily implement your 22 | // own that implements the `Formatter` interface, see the `README` or included 23 | // formatters for examples. 24 | Formatter Formatter 25 | // The logging level the logger should log at. This is typically (and defaults 26 | // to) `logrus.Info`, which allows Info(), Warn(), Error() and Fatal() to be 27 | // logged. `logrus.Debug` is useful in 28 | Level Level 29 | // Used to sync writing to the log. 30 | mu sync.Mutex 31 | } 32 | 33 | // Creates a new logger. Configuration should be set by changing `Formatter`, 34 | // `Out` and `Hooks` directly on the default logger instance. You can also just 35 | // instantiate your own: 36 | // 37 | // var log = &Logger{ 38 | // Out: os.Stderr, 39 | // Formatter: new(JSONFormatter), 40 | // Hooks: make(LevelHooks), 41 | // Level: logrus.DebugLevel, 42 | // } 43 | // 44 | // It's recommended to make this a global instance called `log`. 45 | func New() *Logger { 46 | return &Logger{ 47 | Out: os.Stderr, 48 | Formatter: new(TextFormatter), 49 | Hooks: make(LevelHooks), 50 | Level: InfoLevel, 51 | } 52 | } 53 | 54 | // Adds a field to the log entry, note that you it doesn't log until you call 55 | // Debug, Print, Info, Warn, Fatal or Panic. It only creates a log entry. 56 | // If you want multiple fields, use `WithFields`. 57 | func (logger *Logger) WithField(key string, value interface{}) *Entry { 58 | return NewEntry(logger).WithField(key, value) 59 | } 60 | 61 | // Adds a struct of fields to the log entry. All it does is call `WithField` for 62 | // each `Field`. 63 | func (logger *Logger) WithFields(fields Fields) *Entry { 64 | return NewEntry(logger).WithFields(fields) 65 | } 66 | 67 | // Add an error as single field to the log entry. All it does is call 68 | // `WithError` for the given `error`. 69 | func (logger *Logger) WithError(err error) *Entry { 70 | return NewEntry(logger).WithError(err) 71 | } 72 | 73 | func (logger *Logger) Debugf(format string, args ...interface{}) { 74 | if logger.Level >= DebugLevel { 75 | NewEntry(logger).Debugf(format, args...) 76 | } 77 | } 78 | 79 | func (logger *Logger) Infof(format string, args ...interface{}) { 80 | if logger.Level >= InfoLevel { 81 | NewEntry(logger).Infof(format, args...) 82 | } 83 | } 84 | 85 | func (logger *Logger) Printf(format string, args ...interface{}) { 86 | NewEntry(logger).Printf(format, args...) 87 | } 88 | 89 | func (logger *Logger) Warnf(format string, args ...interface{}) { 90 | if logger.Level >= WarnLevel { 91 | NewEntry(logger).Warnf(format, args...) 92 | } 93 | } 94 | 95 | func (logger *Logger) Warningf(format string, args ...interface{}) { 96 | if logger.Level >= WarnLevel { 97 | NewEntry(logger).Warnf(format, args...) 98 | } 99 | } 100 | 101 | func (logger *Logger) Errorf(format string, args ...interface{}) { 102 | if logger.Level >= ErrorLevel { 103 | NewEntry(logger).Errorf(format, args...) 104 | } 105 | } 106 | 107 | func (logger *Logger) Fatalf(format string, args ...interface{}) { 108 | if logger.Level >= FatalLevel { 109 | NewEntry(logger).Fatalf(format, args...) 110 | } 111 | os.Exit(1) 112 | } 113 | 114 | func (logger *Logger) Panicf(format string, args ...interface{}) { 115 | if logger.Level >= PanicLevel { 116 | NewEntry(logger).Panicf(format, args...) 117 | } 118 | } 119 | 120 | func (logger *Logger) Debug(args ...interface{}) { 121 | if logger.Level >= DebugLevel { 122 | NewEntry(logger).Debug(args...) 123 | } 124 | } 125 | 126 | func (logger *Logger) Info(args ...interface{}) { 127 | if logger.Level >= InfoLevel { 128 | NewEntry(logger).Info(args...) 129 | } 130 | } 131 | 132 | func (logger *Logger) Print(args ...interface{}) { 133 | NewEntry(logger).Info(args...) 134 | } 135 | 136 | func (logger *Logger) Warn(args ...interface{}) { 137 | if logger.Level >= WarnLevel { 138 | NewEntry(logger).Warn(args...) 139 | } 140 | } 141 | 142 | func (logger *Logger) Warning(args ...interface{}) { 143 | if logger.Level >= WarnLevel { 144 | NewEntry(logger).Warn(args...) 145 | } 146 | } 147 | 148 | func (logger *Logger) Error(args ...interface{}) { 149 | if logger.Level >= ErrorLevel { 150 | NewEntry(logger).Error(args...) 151 | } 152 | } 153 | 154 | func (logger *Logger) Fatal(args ...interface{}) { 155 | if logger.Level >= FatalLevel { 156 | NewEntry(logger).Fatal(args...) 157 | } 158 | os.Exit(1) 159 | } 160 | 161 | func (logger *Logger) Panic(args ...interface{}) { 162 | if logger.Level >= PanicLevel { 163 | NewEntry(logger).Panic(args...) 164 | } 165 | } 166 | 167 | func (logger *Logger) Debugln(args ...interface{}) { 168 | if logger.Level >= DebugLevel { 169 | NewEntry(logger).Debugln(args...) 170 | } 171 | } 172 | 173 | func (logger *Logger) Infoln(args ...interface{}) { 174 | if logger.Level >= InfoLevel { 175 | NewEntry(logger).Infoln(args...) 176 | } 177 | } 178 | 179 | func (logger *Logger) Println(args ...interface{}) { 180 | NewEntry(logger).Println(args...) 181 | } 182 | 183 | func (logger *Logger) Warnln(args ...interface{}) { 184 | if logger.Level >= WarnLevel { 185 | NewEntry(logger).Warnln(args...) 186 | } 187 | } 188 | 189 | func (logger *Logger) Warningln(args ...interface{}) { 190 | if logger.Level >= WarnLevel { 191 | NewEntry(logger).Warnln(args...) 192 | } 193 | } 194 | 195 | func (logger *Logger) Errorln(args ...interface{}) { 196 | if logger.Level >= ErrorLevel { 197 | NewEntry(logger).Errorln(args...) 198 | } 199 | } 200 | 201 | func (logger *Logger) Fatalln(args ...interface{}) { 202 | if logger.Level >= FatalLevel { 203 | NewEntry(logger).Fatalln(args...) 204 | } 205 | os.Exit(1) 206 | } 207 | 208 | func (logger *Logger) Panicln(args ...interface{}) { 209 | if logger.Level >= PanicLevel { 210 | NewEntry(logger).Panicln(args...) 211 | } 212 | } 213 | -------------------------------------------------------------------------------- /vendor/github.com/Sirupsen/logrus/logrus.go: -------------------------------------------------------------------------------- 1 | package logrus 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "strings" 7 | ) 8 | 9 | // Fields type, used to pass to `WithFields`. 10 | type Fields map[string]interface{} 11 | 12 | // Level type 13 | type Level uint8 14 | 15 | // Convert the Level to a string. E.g. PanicLevel becomes "panic". 16 | func (level Level) String() string { 17 | switch level { 18 | case DebugLevel: 19 | return "debug" 20 | case InfoLevel: 21 | return "info" 22 | case WarnLevel: 23 | return "warning" 24 | case ErrorLevel: 25 | return "error" 26 | case FatalLevel: 27 | return "fatal" 28 | case PanicLevel: 29 | return "panic" 30 | } 31 | 32 | return "unknown" 33 | } 34 | 35 | // ParseLevel takes a string level and returns the Logrus log level constant. 36 | func ParseLevel(lvl string) (Level, error) { 37 | switch strings.ToLower(lvl) { 38 | case "panic": 39 | return PanicLevel, nil 40 | case "fatal": 41 | return FatalLevel, nil 42 | case "error": 43 | return ErrorLevel, nil 44 | case "warn", "warning": 45 | return WarnLevel, nil 46 | case "info": 47 | return InfoLevel, nil 48 | case "debug": 49 | return DebugLevel, nil 50 | } 51 | 52 | var l Level 53 | return l, fmt.Errorf("not a valid logrus Level: %q", lvl) 54 | } 55 | 56 | // A constant exposing all logging levels 57 | var AllLevels = []Level{ 58 | PanicLevel, 59 | FatalLevel, 60 | ErrorLevel, 61 | WarnLevel, 62 | InfoLevel, 63 | DebugLevel, 64 | } 65 | 66 | // These are the different logging levels. You can set the logging level to log 67 | // on your instance of logger, obtained with `logrus.New()`. 68 | const ( 69 | // PanicLevel level, highest level of severity. Logs and then calls panic with the 70 | // message passed to Debug, Info, ... 71 | PanicLevel Level = iota 72 | // FatalLevel level. Logs and then calls `os.Exit(1)`. It will exit even if the 73 | // logging level is set to Panic. 74 | FatalLevel 75 | // ErrorLevel level. Logs. Used for errors that should definitely be noted. 76 | // Commonly used for hooks to send errors to an error tracking service. 77 | ErrorLevel 78 | // WarnLevel level. Non-critical entries that deserve eyes. 79 | WarnLevel 80 | // InfoLevel level. General operational entries about what's going on inside the 81 | // application. 82 | InfoLevel 83 | // DebugLevel level. Usually only enabled when debugging. Very verbose logging. 84 | DebugLevel 85 | ) 86 | 87 | // Won't compile if StdLogger can't be realized by a log.Logger 88 | var ( 89 | _ StdLogger = &log.Logger{} 90 | _ StdLogger = &Entry{} 91 | _ StdLogger = &Logger{} 92 | ) 93 | 94 | // StdLogger is what your logrus-enabled library should take, that way 95 | // it'll accept a stdlib logger and a logrus logger. There's no standard 96 | // interface, this is the closest we get, unfortunately. 97 | type StdLogger interface { 98 | Print(...interface{}) 99 | Printf(string, ...interface{}) 100 | Println(...interface{}) 101 | 102 | Fatal(...interface{}) 103 | Fatalf(string, ...interface{}) 104 | Fatalln(...interface{}) 105 | 106 | Panic(...interface{}) 107 | Panicf(string, ...interface{}) 108 | Panicln(...interface{}) 109 | } 110 | 111 | // The FieldLogger interface generalizes the Entry and Logger types 112 | type FieldLogger interface { 113 | WithField(key string, value interface{}) *Entry 114 | WithFields(fields Fields) *Entry 115 | WithError(err error) *Entry 116 | 117 | Debugf(format string, args ...interface{}) 118 | Infof(format string, args ...interface{}) 119 | Printf(format string, args ...interface{}) 120 | Warnf(format string, args ...interface{}) 121 | Warningf(format string, args ...interface{}) 122 | Errorf(format string, args ...interface{}) 123 | Fatalf(format string, args ...interface{}) 124 | Panicf(format string, args ...interface{}) 125 | 126 | Debug(args ...interface{}) 127 | Info(args ...interface{}) 128 | Print(args ...interface{}) 129 | Warn(args ...interface{}) 130 | Warning(args ...interface{}) 131 | Error(args ...interface{}) 132 | Fatal(args ...interface{}) 133 | Panic(args ...interface{}) 134 | 135 | Debugln(args ...interface{}) 136 | Infoln(args ...interface{}) 137 | Println(args ...interface{}) 138 | Warnln(args ...interface{}) 139 | Warningln(args ...interface{}) 140 | Errorln(args ...interface{}) 141 | Fatalln(args ...interface{}) 142 | Panicln(args ...interface{}) 143 | } 144 | -------------------------------------------------------------------------------- /vendor/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/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/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 stderr's file descriptor is a terminal. 16 | func IsTerminal() bool { 17 | fd := syscall.Stderr 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/github.com/Sirupsen/logrus/terminal_solaris.go: -------------------------------------------------------------------------------- 1 | // +build solaris 2 | 3 | package logrus 4 | 5 | import ( 6 | "os" 7 | 8 | "golang.org/x/sys/unix" 9 | ) 10 | 11 | // IsTerminal returns true if the given file descriptor is a terminal. 12 | func IsTerminal() bool { 13 | _, err := unix.IoctlGetTermios(int(os.Stdout.Fd()), unix.TCGETA) 14 | return err == nil 15 | } 16 | -------------------------------------------------------------------------------- /vendor/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 stderr's file descriptor is a terminal. 22 | func IsTerminal() bool { 23 | fd := syscall.Stderr 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/github.com/Sirupsen/logrus/text_formatter.go: -------------------------------------------------------------------------------- 1 | package logrus 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "runtime" 7 | "sort" 8 | "strings" 9 | "time" 10 | ) 11 | 12 | const ( 13 | nocolor = 0 14 | red = 31 15 | green = 32 16 | yellow = 33 17 | blue = 34 18 | gray = 37 19 | ) 20 | 21 | var ( 22 | baseTimestamp time.Time 23 | isTerminal bool 24 | ) 25 | 26 | func init() { 27 | baseTimestamp = time.Now() 28 | isTerminal = IsTerminal() 29 | } 30 | 31 | func miniTS() int { 32 | return int(time.Since(baseTimestamp) / time.Second) 33 | } 34 | 35 | type TextFormatter struct { 36 | // Set to true to bypass checking for a TTY before outputting colors. 37 | ForceColors bool 38 | 39 | // Force disabling colors. 40 | DisableColors bool 41 | 42 | // Disable timestamp logging. useful when output is redirected to logging 43 | // system that already adds timestamps. 44 | DisableTimestamp bool 45 | 46 | // Enable logging the full timestamp when a TTY is attached instead of just 47 | // the time passed since beginning of execution. 48 | FullTimestamp bool 49 | 50 | // TimestampFormat to use for display when a full timestamp is printed 51 | TimestampFormat string 52 | 53 | // The fields are sorted by default for a consistent output. For applications 54 | // that log extremely frequently and don't use the JSON formatter this may not 55 | // be desired. 56 | DisableSorting bool 57 | } 58 | 59 | func (f *TextFormatter) Format(entry *Entry) ([]byte, error) { 60 | var keys []string = make([]string, 0, len(entry.Data)) 61 | for k := range entry.Data { 62 | keys = append(keys, k) 63 | } 64 | 65 | if !f.DisableSorting { 66 | sort.Strings(keys) 67 | } 68 | 69 | b := &bytes.Buffer{} 70 | 71 | prefixFieldClashes(entry.Data) 72 | 73 | isColorTerminal := isTerminal && (runtime.GOOS != "windows") 74 | isColored := (f.ForceColors || isColorTerminal) && !f.DisableColors 75 | 76 | timestampFormat := f.TimestampFormat 77 | if timestampFormat == "" { 78 | timestampFormat = DefaultTimestampFormat 79 | } 80 | if isColored { 81 | f.printColored(b, entry, keys, timestampFormat) 82 | } else { 83 | if !f.DisableTimestamp { 84 | f.appendKeyValue(b, "time", entry.Time.Format(timestampFormat)) 85 | } 86 | f.appendKeyValue(b, "level", entry.Level.String()) 87 | if entry.Message != "" { 88 | f.appendKeyValue(b, "msg", entry.Message) 89 | } 90 | for _, key := range keys { 91 | f.appendKeyValue(b, key, entry.Data[key]) 92 | } 93 | } 94 | 95 | b.WriteByte('\n') 96 | return b.Bytes(), nil 97 | } 98 | 99 | func (f *TextFormatter) printColored(b *bytes.Buffer, entry *Entry, keys []string, timestampFormat string) { 100 | var levelColor int 101 | switch entry.Level { 102 | case DebugLevel: 103 | levelColor = gray 104 | case WarnLevel: 105 | levelColor = yellow 106 | case ErrorLevel, FatalLevel, PanicLevel: 107 | levelColor = red 108 | default: 109 | levelColor = blue 110 | } 111 | 112 | levelText := strings.ToUpper(entry.Level.String())[0:4] 113 | 114 | if !f.FullTimestamp { 115 | fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%04d] %-44s ", levelColor, levelText, miniTS(), entry.Message) 116 | } else { 117 | fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m[%s] %-44s ", levelColor, levelText, entry.Time.Format(timestampFormat), entry.Message) 118 | } 119 | for _, k := range keys { 120 | v := entry.Data[k] 121 | fmt.Fprintf(b, " \x1b[%dm%s\x1b[0m=%+v", levelColor, k, v) 122 | } 123 | } 124 | 125 | func needsQuoting(text string) bool { 126 | for _, ch := range text { 127 | if !((ch >= 'a' && ch <= 'z') || 128 | (ch >= 'A' && ch <= 'Z') || 129 | (ch >= '0' && ch <= '9') || 130 | ch == '-' || ch == '.') { 131 | return false 132 | } 133 | } 134 | return true 135 | } 136 | 137 | func (f *TextFormatter) appendKeyValue(b *bytes.Buffer, key string, value interface{}) { 138 | 139 | b.WriteString(key) 140 | b.WriteByte('=') 141 | 142 | switch value := value.(type) { 143 | case string: 144 | if needsQuoting(value) { 145 | b.WriteString(value) 146 | } else { 147 | fmt.Fprintf(b, "%q", value) 148 | } 149 | case error: 150 | errmsg := value.Error() 151 | if needsQuoting(errmsg) { 152 | b.WriteString(errmsg) 153 | } else { 154 | fmt.Fprintf(b, "%q", value) 155 | } 156 | default: 157 | fmt.Fprint(b, value) 158 | } 159 | 160 | b.WriteByte(' ') 161 | } 162 | -------------------------------------------------------------------------------- /vendor/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/github.com/bgentry/que-go/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Blake Gentry 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 all 13 | 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 THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /vendor/github.com/bgentry/que-go/README.md: -------------------------------------------------------------------------------- 1 | # que-go 2 | 3 | [![GoDoc](https://godoc.org/github.com/bgentry/que-go?status.svg)][godoc] 4 | 5 | Que-go is a fully interoperable Golang port of [Chris Hanks][chanks]' [Ruby Que 6 | queuing library][ruby-que] for PostgreSQL. Que uses PostgreSQL's advisory locks 7 | for speed and reliability. 8 | 9 | Because que-go is an interoperable port of Que, you can enqueue jobs in Ruby 10 | (i.e. from a Rails app) and write your workers in Go. Or if you have a limited 11 | set of jobs that you want to write in Go, you can leave most of your workers in 12 | Ruby and just add a few Go workers on a different queue name. Or you can just 13 | write everything in Go :) 14 | 15 | ## pgx PostgreSQL driver 16 | 17 | This package uses the [pgx][pgx] Go PostgreSQL driver rather than the more 18 | popular [pq][pq]. Because Que uses session-level advisory locks, we have to hold 19 | the same connection throughout the process of getting a job, working it, 20 | deleting it, and removing the lock. 21 | 22 | Pq and the built-in database/sql interfaces do not offer this functionality, so 23 | we'd have to implement our own connection pool. Fortunately, pgx already has a 24 | perfectly usable one built for us. Even better, it offers better performance 25 | than pq due largely to its use of binary encoding. 26 | 27 | Please see the [godocs][godoc] for more info and examples. 28 | 29 | [godoc]: https://godoc.org/github.com/bgentry/que-go 30 | [chanks]: https://github.com/chanks 31 | [ruby-que]: https://github.com/chanks/que 32 | [pgx]: https://github.com/jackc/pgx 33 | [pq]: https://github.com/lib/pq 34 | -------------------------------------------------------------------------------- /vendor/github.com/bgentry/que-go/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Package que-go is a fully interoperable Golang port of Chris Hanks' Ruby Que 3 | queueing library for PostgreSQL. Que uses PostgreSQL's advisory locks 4 | for speed and reliability. See the original Que documentation for more details: 5 | https://github.com/chanks/que 6 | 7 | Because que-go is an interoperable port of Que, you can enqueue jobs in Ruby 8 | (i.e. from a Rails app) and write your workers in Go. Or if you have a limited 9 | set of jobs that you want to write in Go, you can leave most of your workers in 10 | Ruby and just add a few Go workers on a different queue name. 11 | 12 | PostgreSQL Driver pgx 13 | 14 | Instead of using database/sql and the more popular pq PostgreSQL driver, this 15 | package uses the pgx driver: https://github.com/jackc/pgx 16 | 17 | Because Que uses session-level advisory locks, we have to hold the same 18 | connection throughout the process of getting a job, working it, deleting it, and 19 | removing the lock. 20 | 21 | Pq and the built-in database/sql interfaces do not offer this functionality, so 22 | we'd have to implement our own connection pool. Fortunately, pgx already has a 23 | perfectly usable one built for us. Even better, it offers better performance 24 | than pq due largely to its use of binary encoding. 25 | 26 | Prepared Statements 27 | 28 | que-go relies on prepared statements for performance. As of now these have to 29 | be initialized manually on your connection pool like so: 30 | 31 | pgxpool, err := pgx.NewConnPool(pgx.ConnPoolConfig{ 32 | ConnConfig: pgxcfg, 33 | AfterConnect: que.PrepareStatements, 34 | }) 35 | 36 | If you have suggestions on how to cleanly do this automatically, please open an 37 | issue! 38 | 39 | Usage 40 | 41 | Here is a complete example showing worker setup and two jobs enqueued, one with a delay: 42 | 43 | type printNameArgs struct { 44 | Name string 45 | } 46 | 47 | printName := func(j *que.Job) error { 48 | var args printNameArgs 49 | if err := json.Unmarshal(j.Args, &args); err != nil { 50 | return err 51 | } 52 | fmt.Printf("Hello %s!\n", args.Name) 53 | return nil 54 | } 55 | 56 | pgxcfg, err := pgx.ParseURI(os.Getenv("DATABASE_URL")) 57 | if err != nil { 58 | log.Fatal(err) 59 | } 60 | 61 | pgxpool, err := pgx.NewConnPool(pgx.ConnPoolConfig{ 62 | ConnConfig: pgxcfg, 63 | AfterConnect: que.PrepareStatements, 64 | }) 65 | if err != nil { 66 | log.Fatal(err) 67 | } 68 | defer pgxpool.Close() 69 | 70 | qc := que.NewClient(pgxpool) 71 | wm := que.WorkMap{ 72 | "PrintName": printName, 73 | } 74 | workers := que.NewWorkerPool(qc, wm, 2) // create a pool w/ 2 workers 75 | go workers.Start() // work jobs in another goroutine 76 | 77 | args, err := json.Marshal(printNameArgs{Name: "bgentry"}) 78 | if err != nil { 79 | log.Fatal(err) 80 | } 81 | 82 | j := &que.Job{ 83 | Type: "PrintName", 84 | Args: args, 85 | } 86 | if err := qc.Enqueue(j); err != nil { 87 | log.Fatal(err) 88 | } 89 | 90 | j := &que.Job{ 91 | Type: "PrintName", 92 | RunAt: time.Now().UTC().Add(30 * time.Second), // delay 30 seconds 93 | Args: args, 94 | } 95 | if err := qc.Enqueue(j); err != nil { 96 | log.Fatal(err) 97 | } 98 | 99 | time.Sleep(35 * time.Second) // wait for while 100 | 101 | workers.Shutdown() 102 | 103 | */ 104 | package que 105 | -------------------------------------------------------------------------------- /vendor/github.com/bgentry/que-go/que.go: -------------------------------------------------------------------------------- 1 | package que 2 | 3 | import ( 4 | "errors" 5 | "sync" 6 | "time" 7 | 8 | "github.com/jackc/pgx" 9 | ) 10 | 11 | // Job is a single unit of work for Que to perform. 12 | type Job struct { 13 | // ID is the unique database ID of the Job. It is ignored on job creation. 14 | ID int64 15 | 16 | // Queue is the name of the queue. It defaults to the empty queue "". 17 | Queue string 18 | 19 | // Priority is the priority of the Job. The default priority is 100, and a 20 | // lower number means a higher priority. A priority of 5 would be very 21 | // important. 22 | Priority int16 23 | 24 | // RunAt is the time that this job should be executed. It defaults to now(), 25 | // meaning the job will execute immediately. Set it to a value in the future 26 | // to delay a job's execution. 27 | RunAt time.Time 28 | 29 | // Type corresponds to the Ruby job_class. If you are interoperating with 30 | // Ruby, you should pick suitable Ruby class names (such as MyJob). 31 | Type string 32 | 33 | // Args must be the bytes of a valid JSON string 34 | Args []byte 35 | 36 | // ErrorCount is the number of times this job has attempted to run, but 37 | // failed with an error. It is ignored on job creation. 38 | ErrorCount int32 39 | 40 | // LastError is the error message or stack trace from the last time the job 41 | // failed. It is ignored on job creation. 42 | LastError pgx.NullString 43 | 44 | mu sync.Mutex 45 | deleted bool 46 | pool *pgx.ConnPool 47 | conn *pgx.Conn 48 | } 49 | 50 | // Conn returns the pgx connection that this job is locked to. You may initiate 51 | // transactions on this connection or use it as you please until you call 52 | // Done(). At that point, this conn will be returned to the pool and it is 53 | // unsafe to keep using it. This function will return nil if the Job's 54 | // connection has already been released with Done(). 55 | func (j *Job) Conn() *pgx.Conn { 56 | j.mu.Lock() 57 | defer j.mu.Unlock() 58 | 59 | return j.conn 60 | } 61 | 62 | // Delete marks this job as complete by deleting it form the database. 63 | // 64 | // You must also later call Done() to return this job's database connection to 65 | // the pool. 66 | func (j *Job) Delete() error { 67 | j.mu.Lock() 68 | defer j.mu.Unlock() 69 | 70 | if j.deleted { 71 | return nil 72 | } 73 | 74 | _, err := j.conn.Exec("que_destroy_job", j.Queue, j.Priority, j.RunAt, j.ID) 75 | if err != nil { 76 | return err 77 | } 78 | 79 | j.deleted = true 80 | return nil 81 | } 82 | 83 | // Done releases the Postgres advisory lock on the job and returns the database 84 | // connection to the pool. 85 | func (j *Job) Done() { 86 | j.mu.Lock() 87 | defer j.mu.Unlock() 88 | 89 | if j.conn == nil || j.pool == nil { 90 | // already marked as done 91 | return 92 | } 93 | 94 | var ok bool 95 | // Swallow this error because we don't want an unlock failure to cause work to 96 | // stop. 97 | _ = j.conn.QueryRow("que_unlock_job", j.ID).Scan(&ok) 98 | 99 | j.pool.Release(j.conn) 100 | j.pool = nil 101 | j.conn = nil 102 | } 103 | 104 | // Error marks the job as failed and schedules it to be reworked. An error 105 | // message or backtrace can be provided as msg, which will be saved on the job. 106 | // It will also increase the error count. 107 | // 108 | // You must also later call Done() to return this job's database connection to 109 | // the pool. 110 | func (j *Job) Error(msg string) error { 111 | errorCount := j.ErrorCount + 1 112 | delay := intPow(int(errorCount), 4) + 3 // TODO: configurable delay 113 | 114 | _, err := j.conn.Exec("que_set_error", errorCount, delay, msg, j.Queue, j.Priority, j.RunAt, j.ID) 115 | if err != nil { 116 | return err 117 | } 118 | return nil 119 | } 120 | 121 | // Client is a Que client that can add jobs to the queue and remove jobs from 122 | // the queue. 123 | type Client struct { 124 | pool *pgx.ConnPool 125 | 126 | // TODO: add a way to specify default queueing options 127 | } 128 | 129 | // NewClient creates a new Client that uses the pgx pool. 130 | func NewClient(pool *pgx.ConnPool) *Client { 131 | return &Client{pool: pool} 132 | } 133 | 134 | // ErrMissingType is returned when you attempt to enqueue a job with no Type 135 | // specified. 136 | var ErrMissingType = errors.New("job type must be specified") 137 | 138 | // Enqueue adds a job to the queue. 139 | func (c *Client) Enqueue(j *Job) error { 140 | return execEnqueue(j, c.pool) 141 | } 142 | 143 | // EnqueueInTx adds a job to the queue within the scope of the transaction tx. 144 | // This allows you to guarantee that an enqueued job will either be committed or 145 | // rolled back atomically with other changes in the course of this transaction. 146 | // 147 | // It is the caller's responsibility to Commit or Rollback the transaction after 148 | // this function is called. 149 | func (c *Client) EnqueueInTx(j *Job, tx *pgx.Tx) error { 150 | return execEnqueue(j, tx) 151 | } 152 | 153 | func execEnqueue(j *Job, q queryable) error { 154 | if j.Type == "" { 155 | return ErrMissingType 156 | } 157 | 158 | queue := pgx.NullString{ 159 | String: j.Queue, 160 | Valid: j.Queue != "", 161 | } 162 | priority := pgx.NullInt16{ 163 | Int16: int16(j.Priority), 164 | Valid: j.Priority != 0, 165 | } 166 | runAt := pgx.NullTime{ 167 | Time: j.RunAt, 168 | Valid: !j.RunAt.IsZero(), 169 | } 170 | args := bytea(j.Args) 171 | 172 | _, err := q.Exec("que_insert_job", queue, priority, runAt, j.Type, args) 173 | return err 174 | } 175 | 176 | type bytea []byte 177 | 178 | func (b bytea) Encode(w *pgx.WriteBuf, oid pgx.Oid) error { 179 | if len(b) == 0 { 180 | w.WriteInt32(-1) 181 | return nil 182 | } 183 | w.WriteInt32(int32(len(b))) 184 | w.WriteBytes(b) 185 | return nil 186 | } 187 | 188 | func (b bytea) FormatCode() int16 { 189 | return pgx.TextFormatCode 190 | } 191 | 192 | type queryable interface { 193 | Exec(sql string, arguments ...interface{}) (commandTag pgx.CommandTag, err error) 194 | Query(sql string, args ...interface{}) (*pgx.Rows, error) 195 | QueryRow(sql string, args ...interface{}) *pgx.Row 196 | } 197 | 198 | // Maximum number of loop iterations in LockJob before giving up. This is to 199 | // avoid looping forever in case something is wrong. 200 | const maxLockJobAttempts = 10 201 | 202 | // Returned by LockJob if a job could not be retrieved from the queue after 203 | // several attempts because of concurrently running transactions. This error 204 | // should not be returned unless the queue is under extremely heavy 205 | // concurrency. 206 | var ErrAgain = errors.New("maximum number of LockJob attempts reached") 207 | 208 | // TODO: consider an alternate Enqueue func that also returns the newly 209 | // enqueued Job struct. The query sqlInsertJobAndReturn was already written for 210 | // this. 211 | 212 | // LockJob attempts to retrieve a Job from the database in the specified queue. 213 | // If a job is found, a session-level Postgres advisory lock is created for the 214 | // Job's ID. If no job is found, nil will be returned instead of an error. 215 | // 216 | // Because Que uses session-level advisory locks, we have to hold the 217 | // same connection throughout the process of getting a job, working it, 218 | // deleting it, and removing the lock. 219 | // 220 | // After the Job has been worked, you must call either Done() or Error() on it 221 | // in order to return the database connection to the pool and remove the lock. 222 | func (c *Client) LockJob(queue string) (*Job, error) { 223 | conn, err := c.pool.Acquire() 224 | if err != nil { 225 | return nil, err 226 | } 227 | 228 | j := Job{pool: c.pool, conn: conn} 229 | 230 | for i := 0; i < maxLockJobAttempts; i++ { 231 | err = conn.QueryRow("que_lock_job", queue).Scan( 232 | &j.Queue, 233 | &j.Priority, 234 | &j.RunAt, 235 | &j.ID, 236 | &j.Type, 237 | &j.Args, 238 | &j.ErrorCount, 239 | ) 240 | if err != nil { 241 | c.pool.Release(conn) 242 | if err == pgx.ErrNoRows { 243 | return nil, nil 244 | } 245 | return nil, err 246 | } 247 | 248 | // Deal with race condition. Explanation from the Ruby Que gem: 249 | // 250 | // Edge case: It's possible for the lock_job query to have 251 | // grabbed a job that's already been worked, if it took its MVCC 252 | // snapshot while the job was processing, but didn't attempt the 253 | // advisory lock until it was finished. Since we have the lock, a 254 | // previous worker would have deleted it by now, so we just 255 | // double check that it still exists before working it. 256 | // 257 | // Note that there is currently no spec for this behavior, since 258 | // I'm not sure how to reliably commit a transaction that deletes 259 | // the job in a separate thread between lock_job and check_job. 260 | var ok bool 261 | err = conn.QueryRow("que_check_job", j.Queue, j.Priority, j.RunAt, j.ID).Scan(&ok) 262 | if err == nil { 263 | return &j, nil 264 | } else if err == pgx.ErrNoRows { 265 | // Encountered job race condition; start over from the beginning. 266 | // We're still holding the advisory lock, though, so we need to 267 | // release it before resuming. Otherwise we leak the lock, 268 | // eventually causing the server to run out of locks. 269 | // 270 | // Also swallow the possible error, exactly like in Done. 271 | _ = conn.QueryRow("que_unlock_job", j.ID).Scan(&ok) 272 | continue 273 | } else { 274 | c.pool.Release(conn) 275 | return nil, err 276 | } 277 | } 278 | return nil, ErrAgain 279 | } 280 | 281 | var preparedStatements = map[string]string{ 282 | "que_check_job": sqlCheckJob, 283 | "que_destroy_job": sqlDeleteJob, 284 | "que_insert_job": sqlInsertJob, 285 | "que_lock_job": sqlLockJob, 286 | "que_set_error": sqlSetError, 287 | "que_unlock_job": sqlUnlockJob, 288 | } 289 | 290 | func PrepareStatements(conn *pgx.Conn) error { 291 | for name, sql := range preparedStatements { 292 | if _, err := conn.Prepare(name, sql); err != nil { 293 | return err 294 | } 295 | } 296 | return nil 297 | } 298 | -------------------------------------------------------------------------------- /vendor/github.com/bgentry/que-go/schema.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE que_jobs 2 | ( 3 | priority smallint NOT NULL DEFAULT 100, 4 | run_at timestamptz NOT NULL DEFAULT now(), 5 | job_id bigserial NOT NULL, 6 | job_class text NOT NULL, 7 | args json NOT NULL DEFAULT '[]'::json, 8 | error_count integer NOT NULL DEFAULT 0, 9 | last_error text, 10 | queue text NOT NULL DEFAULT '', 11 | 12 | CONSTRAINT que_jobs_pkey PRIMARY KEY (queue, priority, run_at, job_id) 13 | ); 14 | 15 | COMMENT ON TABLE que_jobs IS '3'; 16 | -------------------------------------------------------------------------------- /vendor/github.com/bgentry/que-go/sql.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2013 Chris Hanks 2 | // 3 | // MIT License 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining 6 | // a copy of this software and associated documentation files (the 7 | // "Software"), to deal in the Software without restriction, including 8 | // without limitation the rights to use, copy, modify, merge, publish, 9 | // distribute, sublicense, and/or sell copies of the Software, and to 10 | // permit persons to whom the Software is furnished to do so, subject to 11 | // the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be 14 | // included in all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | 24 | package que 25 | 26 | // Thanks to RhodiumToad in #postgresql for help with the job lock CTE. 27 | const ( 28 | sqlLockJob = ` 29 | WITH RECURSIVE jobs AS ( 30 | SELECT (j).*, pg_try_advisory_lock((j).job_id) AS locked 31 | FROM ( 32 | SELECT j 33 | FROM que_jobs AS j 34 | WHERE queue = $1::text 35 | AND run_at <= now() 36 | ORDER BY priority, run_at, job_id 37 | LIMIT 1 38 | ) AS t1 39 | UNION ALL ( 40 | SELECT (j).*, pg_try_advisory_lock((j).job_id) AS locked 41 | FROM ( 42 | SELECT ( 43 | SELECT j 44 | FROM que_jobs AS j 45 | WHERE queue = $1::text 46 | AND run_at <= now() 47 | AND (priority, run_at, job_id) > (jobs.priority, jobs.run_at, jobs.job_id) 48 | ORDER BY priority, run_at, job_id 49 | LIMIT 1 50 | ) AS j 51 | FROM jobs 52 | WHERE jobs.job_id IS NOT NULL 53 | LIMIT 1 54 | ) AS t1 55 | ) 56 | ) 57 | SELECT queue, priority, run_at, job_id, job_class, args, error_count 58 | FROM jobs 59 | WHERE locked 60 | LIMIT 1 61 | ` 62 | 63 | sqlUnlockJob = ` 64 | SELECT pg_advisory_unlock($1) 65 | ` 66 | 67 | sqlCheckJob = ` 68 | SELECT true AS exists 69 | FROM que_jobs 70 | WHERE queue = $1::text 71 | AND priority = $2::smallint 72 | AND run_at = $3::timestamptz 73 | AND job_id = $4::bigint 74 | ` 75 | 76 | sqlSetError = ` 77 | UPDATE que_jobs 78 | SET error_count = $1::integer, 79 | run_at = now() + $2::bigint * '1 second'::interval, 80 | last_error = $3::text 81 | WHERE queue = $4::text 82 | AND priority = $5::smallint 83 | AND run_at = $6::timestamptz 84 | AND job_id = $7::bigint 85 | ` 86 | 87 | sqlInsertJob = ` 88 | INSERT INTO que_jobs 89 | (queue, priority, run_at, job_class, args) 90 | VALUES 91 | (coalesce($1::text, ''::text), coalesce($2::smallint, 100::smallint), coalesce($3::timestamptz, now()::timestamptz), $4::text, coalesce($5::json, '[]'::json)) 92 | ` 93 | 94 | sqlDeleteJob = ` 95 | DELETE FROM que_jobs 96 | WHERE queue = $1::text 97 | AND priority = $2::smallint 98 | AND run_at = $3::timestamptz 99 | AND job_id = $4::bigint 100 | ` 101 | 102 | sqlJobStats = ` 103 | SELECT queue, 104 | job_class, 105 | count(*) AS count, 106 | count(locks.job_id) AS count_working, 107 | sum((error_count > 0)::int) AS count_errored, 108 | max(error_count) AS highest_error_count, 109 | min(run_at) AS oldest_run_at 110 | FROM que_jobs 111 | LEFT JOIN ( 112 | SELECT (classid::bigint << 32) + objid::bigint AS job_id 113 | FROM pg_locks 114 | WHERE locktype = 'advisory' 115 | ) locks USING (job_id) 116 | GROUP BY queue, job_class 117 | ORDER BY count(*) DESC 118 | ` 119 | 120 | sqlWorkerStates = ` 121 | SELECT que_jobs.*, 122 | pg.pid AS pg_backend_pid, 123 | pg.state AS pg_state, 124 | pg.state_change AS pg_state_changed_at, 125 | pg.query AS pg_last_query, 126 | pg.query_start AS pg_last_query_started_at, 127 | pg.xact_start AS pg_transaction_started_at, 128 | pg.waiting AS pg_waiting_on_lock 129 | FROM que_jobs 130 | JOIN ( 131 | SELECT (classid::bigint << 32) + objid::bigint AS job_id, pg_stat_activity.* 132 | FROM pg_locks 133 | JOIN pg_stat_activity USING (pid) 134 | WHERE locktype = 'advisory' 135 | ) pg USING (job_id) 136 | ` 137 | ) 138 | -------------------------------------------------------------------------------- /vendor/github.com/bgentry/que-go/util.go: -------------------------------------------------------------------------------- 1 | package que 2 | 3 | // intPow returns x**y, the base-x exponential of y. 4 | func intPow(x, y int) (r int) { 5 | if x == r || y < r { 6 | return 7 | } 8 | r = 1 9 | if x == r { 10 | return 11 | } 12 | if x < 0 { 13 | x = -x 14 | if y&1 == 1 { 15 | r = -1 16 | } 17 | } 18 | for y > 0 { 19 | if y&1 == 1 { 20 | r *= x 21 | } 22 | x *= x 23 | y >>= 1 24 | } 25 | return 26 | } 27 | -------------------------------------------------------------------------------- /vendor/github.com/bgentry/que-go/worker.go: -------------------------------------------------------------------------------- 1 | package que 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "log" 7 | "os" 8 | "runtime" 9 | "strconv" 10 | "sync" 11 | "time" 12 | ) 13 | 14 | // WorkFunc is a function that performs a Job. If an error is returned, the job 15 | // is reenqueued with exponential backoff. 16 | type WorkFunc func(j *Job) error 17 | 18 | // WorkMap is a map of Job names to WorkFuncs that are used to perform Jobs of a 19 | // given type. 20 | type WorkMap map[string]WorkFunc 21 | 22 | // Worker is a single worker that pulls jobs off the specified Queue. If no Job 23 | // is found, the Worker will sleep for Interval seconds. 24 | type Worker struct { 25 | // Interval is the amount of time that this Worker should sleep before trying 26 | // to find another Job. 27 | Interval time.Duration 28 | 29 | // Queue is the name of the queue to pull Jobs off of. The default value, "", 30 | // is usable and is the default for both que-go and the ruby que library. 31 | Queue string 32 | 33 | c *Client 34 | m WorkMap 35 | 36 | mu sync.Mutex 37 | done bool 38 | ch chan struct{} 39 | } 40 | 41 | var defaultWakeInterval = 5 * time.Second 42 | 43 | func init() { 44 | if v := os.Getenv("QUE_WAKE_INTERVAL"); v != "" { 45 | if newInt, err := strconv.Atoi(v); err == nil { 46 | defaultWakeInterval = time.Duration(newInt) * time.Second 47 | } 48 | } 49 | } 50 | 51 | // NewWorker returns a Worker that fetches Jobs from the Client and executes 52 | // them using WorkMap. If the type of Job is not registered in the WorkMap, it's 53 | // considered an error and the job is re-enqueued with a backoff. 54 | // 55 | // Workers default to an Interval of 5 seconds, which can be overridden by 56 | // setting the environment variable QUE_WAKE_INTERVAL. The default Queue is the 57 | // nameless queue "", which can be overridden by setting QUE_QUEUE. Either of 58 | // these settings can be changed on the returned Worker before it is started 59 | // with Work(). 60 | func NewWorker(c *Client, m WorkMap) *Worker { 61 | return &Worker{ 62 | Interval: defaultWakeInterval, 63 | Queue: os.Getenv("QUE_QUEUE"), 64 | c: c, 65 | m: m, 66 | ch: make(chan struct{}), 67 | } 68 | } 69 | 70 | // Work pulls jobs off the Worker's Queue at its Interval. This function only 71 | // returns after Shutdown() is called, so it should be run in its own goroutine. 72 | func (w *Worker) Work() { 73 | for { 74 | select { 75 | case <-w.ch: 76 | log.Println("worker done") 77 | return 78 | case <-time.After(w.Interval): 79 | for { 80 | if didWork := w.WorkOne(); !didWork { 81 | break // didn't do any work, go back to sleep 82 | } 83 | } 84 | } 85 | } 86 | } 87 | 88 | func (w *Worker) WorkOne() (didWork bool) { 89 | j, err := w.c.LockJob(w.Queue) 90 | if err != nil { 91 | log.Printf("attempting to lock job: %v", err) 92 | return 93 | } 94 | if j == nil { 95 | return // no job was available 96 | } 97 | defer j.Done() 98 | defer recoverPanic(j) 99 | 100 | didWork = true 101 | 102 | wf, ok := w.m[j.Type] 103 | if !ok { 104 | msg := fmt.Sprintf("unknown job type: %q", j.Type) 105 | log.Println(msg) 106 | if err = j.Error(msg); err != nil { 107 | log.Printf("attempting to save error on job %d: %v", j.ID, err) 108 | } 109 | return 110 | } 111 | 112 | if err = wf(j); err != nil { 113 | j.Error(err.Error()) 114 | return 115 | } 116 | 117 | if err = j.Delete(); err != nil { 118 | log.Printf("attempting to delete job %d: %v", j.ID, err) 119 | } 120 | log.Printf("event=job_worked job_id=%d job_type=%s", j.ID, j.Type) 121 | return 122 | } 123 | 124 | // Shutdown tells the worker to finish processing its current job and then stop. 125 | // There is currently no timeout for in-progress jobs. This function blocks 126 | // until the Worker has stopped working. It should only be called on an active 127 | // Worker. 128 | func (w *Worker) Shutdown() { 129 | w.mu.Lock() 130 | defer w.mu.Unlock() 131 | 132 | if w.done { 133 | return 134 | } 135 | 136 | log.Println("worker shutting down gracefully...") 137 | w.ch <- struct{}{} 138 | w.done = true 139 | close(w.ch) 140 | } 141 | 142 | // recoverPanic tries to handle panics in job execution. 143 | // A stacktrace is stored into Job last_error. 144 | func recoverPanic(j *Job) { 145 | if r := recover(); r != nil { 146 | // record an error on the job with panic message and stacktrace 147 | stackBuf := make([]byte, 1024) 148 | n := runtime.Stack(stackBuf, false) 149 | 150 | buf := &bytes.Buffer{} 151 | fmt.Fprintf(buf, "%v\n", r) 152 | fmt.Fprintln(buf, string(stackBuf[:n])) 153 | fmt.Fprintln(buf, "[...]") 154 | stacktrace := buf.String() 155 | log.Printf("event=panic job_id=%d job_type=%s\n%s", j.ID, j.Type, stacktrace) 156 | if err := j.Error(stacktrace); err != nil { 157 | log.Printf("attempting to save error on job %d: %v", j.ID, err) 158 | } 159 | } 160 | } 161 | 162 | // WorkerPool is a pool of Workers, each working jobs from the queue Queue 163 | // at the specified Interval using the WorkMap. 164 | type WorkerPool struct { 165 | WorkMap WorkMap 166 | Interval time.Duration 167 | Queue string 168 | 169 | c *Client 170 | workers []*Worker 171 | mu sync.Mutex 172 | done bool 173 | } 174 | 175 | // NewWorkerPool creates a new WorkerPool with count workers using the Client c. 176 | func NewWorkerPool(c *Client, wm WorkMap, count int) *WorkerPool { 177 | return &WorkerPool{ 178 | c: c, 179 | WorkMap: wm, 180 | Interval: defaultWakeInterval, 181 | workers: make([]*Worker, count), 182 | } 183 | } 184 | 185 | // Start starts all of the Workers in the WorkerPool. 186 | func (w *WorkerPool) Start() { 187 | w.mu.Lock() 188 | defer w.mu.Unlock() 189 | 190 | for i := range w.workers { 191 | w.workers[i] = NewWorker(w.c, w.WorkMap) 192 | w.workers[i].Interval = w.Interval 193 | w.workers[i].Queue = w.Queue 194 | go w.workers[i].Work() 195 | } 196 | } 197 | 198 | // Shutdown sends a Shutdown signal to each of the Workers in the WorkerPool and 199 | // waits for them all to finish shutting down. 200 | func (w *WorkerPool) Shutdown() { 201 | w.mu.Lock() 202 | defer w.mu.Unlock() 203 | 204 | if w.done { 205 | return 206 | } 207 | var wg sync.WaitGroup 208 | wg.Add(len(w.workers)) 209 | 210 | for _, worker := range w.workers { 211 | go func(worker *Worker) { 212 | worker.Shutdown() 213 | wg.Done() 214 | }(worker) 215 | } 216 | wg.Wait() 217 | w.done = true 218 | } 219 | -------------------------------------------------------------------------------- /vendor/github.com/jackc/pgx/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # 2.8.1 (March 24, 2016) 2 | 3 | ## Features 4 | 5 | * Scan accepts nil argument to ignore a column 6 | 7 | ## Fixes 8 | 9 | * Fix compilation on 32-bit architecture 10 | * Fix Tx.status not being set on error on Commit 11 | * Fix Listen/Unlisten with special characters 12 | 13 | # 2.8.0 (March 18, 2016) 14 | 15 | ## Fixes 16 | 17 | * Fix unrecognized commit failure 18 | * Fix msgReader.rxMsg bug when msgReader already has error 19 | * Go float64 can no longer be encoded to a PostgreSQL float4 20 | * Fix connection corruption when query with error is closed early 21 | 22 | ## Features 23 | 24 | This release adds multiple extension points helpful when wrapping pgx with 25 | custom application behavior. pgx can now use custom types designed for the 26 | standard database/sql package such as 27 | [github.com/shopspring/decimal](https://github.com/shopspring/decimal). 28 | 29 | * Add *Tx.AfterClose() hook 30 | * Add *Tx.Conn() 31 | * Add *Tx.Status() 32 | * Add *Tx.Err() 33 | * Add *Rows.AfterClose() hook 34 | * Add *Rows.Conn() 35 | * Add *Conn.SetLogger() to allow changing logger 36 | * Add *Conn.SetLogLevel() to allow changing log level 37 | * Add ConnPool.Reset method 38 | * Add support for database/sql.Scanner and database/sql/driver.Valuer interfaces 39 | * Rows.Scan errors now include which argument caused error 40 | * Add Encode() to allow custom Encoders to reuse internal encoding functionality 41 | * Add Decode() to allow customer Decoders to reuse internal decoding functionality 42 | * Add ConnPool.Prepare method 43 | * Add ConnPool.Deallocate method 44 | * Add Scan to uint32 and uint64 (utrack) 45 | * Add encode and decode to []uint16, []uint32, and []uint64 (Max Musatov) 46 | 47 | ## Performance 48 | 49 | * []byte skips encoding/decoding 50 | 51 | # 2.7.1 (October 26, 2015) 52 | 53 | * Disable SSL renegotiation 54 | 55 | # 2.7.0 (October 16, 2015) 56 | 57 | * Add RuntimeParams to ConnConfig 58 | * ParseURI extracts RuntimeParams 59 | * ParseDSN extracts RuntimeParams 60 | * ParseEnvLibpq extracts PGAPPNAME 61 | * Prepare is now idempotent 62 | * Rows.Values now supports oid type 63 | * ConnPool.Release automatically unlistens connections (Joseph Glanville) 64 | * Add trace log level 65 | * Add more efficient log leveling 66 | * Retry automatically on ConnPool.Begin (Joseph Glanville) 67 | * Encode from net.IP to inet and cidr 68 | * Generalize encoding pointer to string to any PostgreSQL type 69 | * Add UUID encoding from pointer to string (Joseph Glanville) 70 | * Add null mapping to pointer to pointer (Jonathan Rudenberg) 71 | * Add JSON and JSONB type support (Joseph Glanville) 72 | 73 | # 2.6.0 (September 3, 2015) 74 | 75 | * Add inet and cidr type support 76 | * Add binary decoding to TimestampOid in stdlib driver (Samuel Stauffer) 77 | * Add support for specifying sslmode in connection strings (Rick Snyder) 78 | * Allow ConnPool to have MaxConnections of 1 79 | * Add basic PGSSLMODE to support to ParseEnvLibpq 80 | * Add fallback TLS config 81 | * Expose specific error for TSL refused 82 | * More error details exposed in PgError 83 | * Support custom dialer (Lewis Marshall) 84 | 85 | # 2.5.0 (April 15, 2015) 86 | 87 | * Fix stdlib nil support (Blaž Hrastnik) 88 | * Support custom Scanner not reading entire value 89 | * Fix empty array scanning (Laurent Debacker) 90 | * Add ParseDSN (deoxxa) 91 | * Add timestamp support to NullTime 92 | * Remove unused text format scanners 93 | * Return error when too many parameters on Prepare 94 | * Add Travis CI integration (Jonathan Rudenberg) 95 | * Large object support (Jonathan Rudenberg) 96 | * Fix reading null byte arrays (Karl Seguin) 97 | * Add timestamptz[] support 98 | * Add timestamp[] support (Karl Seguin) 99 | * Add bool[] support (Karl Seguin) 100 | * Allow writing []byte into text and varchar columns without type conversion (Hari Bhaskaran) 101 | * Fix ConnPool Close panic 102 | * Add Listen / notify example 103 | * Reduce memory allocations (Karl Seguin) 104 | 105 | # 2.4.0 (October 3, 2014) 106 | 107 | * Add per connection oid to name map 108 | * Add Hstore support (Andy Walker) 109 | * Move introductory docs to godoc from readme 110 | * Fix documentation references to TextEncoder and BinaryEncoder 111 | * Add keep-alive to TCP connections (Andy Walker) 112 | * Add support for EmptyQueryResponse / Allow no-op Exec (Andy Walker) 113 | * Allow reading any type into []byte 114 | * WaitForNotification detects lost connections quicker 115 | 116 | # 2.3.0 (September 16, 2014) 117 | 118 | * Truncate logged strings and byte slices 119 | * Extract more error information from PostgreSQL 120 | * Fix data race with Rows and ConnPool 121 | -------------------------------------------------------------------------------- /vendor/github.com/jackc/pgx/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013 Jack Christensen 2 | 3 | MIT License 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining 6 | a copy of this software and associated documentation files (the 7 | "Software"), to deal in the Software without restriction, including 8 | without limitation the rights to use, copy, modify, merge, publish, 9 | distribute, sublicense, and/or sell copies of the Software, and to 10 | permit persons to whom the Software is furnished to do so, subject to 11 | the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /vendor/github.com/jackc/pgx/README.md: -------------------------------------------------------------------------------- 1 | # Pgx 2 | 3 | Pgx is a a pure Go database connection library designed specifically for 4 | PostgreSQL. Pgx is different from other drivers such as 5 | [pq](http://godoc.org/github.com/lib/pq) because, while it can operate as a 6 | database/sql compatible driver, pgx is primarily intended to be used directly. 7 | It offers a native interface similar to database/sql that offers better 8 | performance and more features. 9 | 10 | ## Features 11 | 12 | Pgx supports many additional features beyond what is available through database/sql. 13 | 14 | * Listen / notify 15 | * Transaction isolation level control 16 | * Full TLS connection control 17 | * Binary format support for custom types (can be much faster) 18 | * Logging support 19 | * Configurable connection pool with after connect hooks to do arbitrary connection setup 20 | * PostgreSQL array to Go slice mapping for integers, floats, and strings 21 | * Hstore support 22 | * JSON and JSONB support 23 | * Maps inet and cidr PostgreSQL types to net.IPNet 24 | * Large object support 25 | * Null mapping to Null* struct or pointer to pointer. 26 | * Supports database/sql.Scanner and database/sql/driver.Valuer interfaces for custom types 27 | 28 | ## Performance 29 | 30 | Pgx performs roughly equivalent to [pq](http://godoc.org/github.com/lib/pq) and 31 | [go-pg](https://github.com/go-pg/pg) for selecting a single column from a single 32 | row, but it is substantially faster when selecting multiple entire rows (6893 33 | queries/sec for pgx vs. 3968 queries/sec for pq -- 73% faster). 34 | 35 | See this [gist](https://gist.github.com/jackc/d282f39e088b495fba3e) for the 36 | underlying benchmark results or checkout 37 | [go_db_bench](https://github.com/jackc/go_db_bench) to run tests for yourself. 38 | 39 | ## database/sql 40 | 41 | Import the ```github.com/jackc/pgx/stdlib``` package to use pgx as a driver for 42 | database/sql. It is possible to retrieve a pgx connection from database/sql on 43 | demand. This allows using the database/sql interface in most places, but using 44 | pgx directly when more performance or PostgreSQL specific features are needed. 45 | 46 | ## Documentation 47 | 48 | pgx includes extensive documentation in the godoc format. It is viewable online at [godoc.org](https://godoc.org/github.com/jackc/pgx). 49 | 50 | ## Testing 51 | 52 | pgx supports multiple connection and authentication types. Setting up a test 53 | environment that can test all of them can be cumbersome. In particular, 54 | Windows cannot test Unix domain socket connections. Because of this pgx will 55 | skip tests for connection types that are not configured. 56 | 57 | ### Normal Test Environment 58 | 59 | To setup the normal test environment run the following SQL: 60 | 61 | create user pgx_md5 password 'secret'; 62 | create database pgx_test; 63 | 64 | Connect to database pgx_test and run: 65 | 66 | create extension hstore; 67 | 68 | Next open connection_settings_test.go.example and make a copy without the 69 | .example. If your PostgreSQL server is accepting connections on 127.0.0.1, 70 | then you are done. 71 | 72 | ### Connection and Authentication Test Environment 73 | 74 | Complete the normal test environment setup and also do the following. 75 | 76 | Run the following SQL: 77 | 78 | create user pgx_none; 79 | create user pgx_pw password 'secret'; 80 | 81 | Add the following to your pg_hba.conf: 82 | 83 | If you are developing on Unix with domain socket connections: 84 | 85 | local pgx_test pgx_none trust 86 | local pgx_test pgx_pw password 87 | local pgx_test pgx_md5 md5 88 | 89 | If you are developing on Windows with TCP connections: 90 | 91 | host pgx_test pgx_none 127.0.0.1/32 trust 92 | host pgx_test pgx_pw 127.0.0.1/32 password 93 | host pgx_test pgx_md5 127.0.0.1/32 md5 94 | 95 | ## Version Policy 96 | 97 | pgx follows semantic versioning for the documented public API. ```master``` 98 | branch tracks the latest stable branch (```v2```). Consider using ```import 99 | "gopkg.in/jackc/pgx.v2"``` to lock to the ```v2``` branch or use a vendoring 100 | tool such as [godep](https://github.com/tools/godep). 101 | -------------------------------------------------------------------------------- /vendor/github.com/jackc/pgx/conn_config_test.go.example: -------------------------------------------------------------------------------- 1 | package pgx_test 2 | 3 | import ( 4 | "github.com/jackc/pgx" 5 | ) 6 | 7 | var defaultConnConfig *pgx.ConnConfig = &pgx.ConnConfig{Host: "127.0.0.1", User: "pgx_md5", Password: "secret", Database: "pgx_test"} 8 | 9 | // To skip tests for specific connection / authentication types set that connection param to nil 10 | var tcpConnConfig *pgx.ConnConfig = nil 11 | var unixSocketConnConfig *pgx.ConnConfig = nil 12 | var md5ConnConfig *pgx.ConnConfig = nil 13 | var plainPasswordConnConfig *pgx.ConnConfig = nil 14 | var noPasswordConnConfig *pgx.ConnConfig = nil 15 | var invalidUserConnConfig *pgx.ConnConfig = nil 16 | var tlsConnConfig *pgx.ConnConfig = nil 17 | var customDialerConnConfig *pgx.ConnConfig = nil 18 | 19 | // var tcpConnConfig *pgx.ConnConfig = &pgx.ConnConfig{Host: "127.0.0.1", User: "pgx_md5", Password: "secret", Database: "pgx_test"} 20 | // var unixSocketConnConfig *pgx.ConnConfig = &pgx.ConnConfig{Host: "/private/tmp", User: "pgx_none", Database: "pgx_test"} 21 | // var md5ConnConfig *pgx.ConnConfig = &pgx.ConnConfig{Host: "127.0.0.1", User: "pgx_md5", Password: "secret", Database: "pgx_test"} 22 | // var plainPasswordConnConfig *pgx.ConnConfig = &pgx.ConnConfig{Host: "127.0.0.1", User: "pgx_pw", Password: "secret", Database: "pgx_test"} 23 | // var noPasswordConnConfig *pgx.ConnConfig = &pgx.ConnConfig{Host: "127.0.0.1", User: "pgx_none", Database: "pgx_test"} 24 | // var invalidUserConnConfig *pgx.ConnConfig = &pgx.ConnConfig{Host: "127.0.0.1", User: "invalid", Database: "pgx_test"} 25 | // var tlsConnConfig *pgx.ConnConfig = &pgx.ConnConfig{Host: "127.0.0.1", User: "pgx_md5", Password: "secret", Database: "pgx_test", TLSConfig: &tls.Config{InsecureSkipVerify: true}} 26 | // var customDialerConnConfig *pgx.ConnConfig = &pgx.ConnConfig{Host: "127.0.0.1", User: "pgx_md5", Password: "secret", Database: "pgx_test"} 27 | -------------------------------------------------------------------------------- /vendor/github.com/jackc/pgx/conn_config_test.go.travis: -------------------------------------------------------------------------------- 1 | package pgx_test 2 | 3 | import ( 4 | "crypto/tls" 5 | "github.com/jackc/pgx" 6 | ) 7 | 8 | var defaultConnConfig = &pgx.ConnConfig{Host: "127.0.0.1", User: "pgx_md5", Password: "secret", Database: "pgx_test"} 9 | var tcpConnConfig = &pgx.ConnConfig{Host: "127.0.0.1", User: "pgx_md5", Password: "secret", Database: "pgx_test"} 10 | var unixSocketConnConfig = &pgx.ConnConfig{Host: "/var/run/postgresql", User: "postgres", Database: "pgx_test"} 11 | var md5ConnConfig = &pgx.ConnConfig{Host: "127.0.0.1", User: "pgx_md5", Password: "secret", Database: "pgx_test"} 12 | var plainPasswordConnConfig = &pgx.ConnConfig{Host: "127.0.0.1", User: "pgx_pw", Password: "secret", Database: "pgx_test"} 13 | var invalidUserConnConfig = &pgx.ConnConfig{Host: "127.0.0.1", User: "invalid", Database: "pgx_test"} 14 | var tlsConnConfig = &pgx.ConnConfig{Host: "127.0.0.1", User: "pgx_ssl", Password: "secret", Database: "pgx_test", TLSConfig: &tls.Config{InsecureSkipVerify: true}} 15 | var customDialerConnConfig = &pgx.ConnConfig{Host: "127.0.0.1", User: "pgx_md5", Password: "secret", Database: "pgx_test"} 16 | -------------------------------------------------------------------------------- /vendor/github.com/jackc/pgx/conn_pool.go: -------------------------------------------------------------------------------- 1 | package pgx 2 | 3 | import ( 4 | "errors" 5 | "sync" 6 | ) 7 | 8 | type ConnPoolConfig struct { 9 | ConnConfig 10 | MaxConnections int // max simultaneous connections to use, default 5, must be at least 2 11 | AfterConnect func(*Conn) error // function to call on every new connection 12 | } 13 | 14 | type ConnPool struct { 15 | allConnections []*Conn 16 | availableConnections []*Conn 17 | cond *sync.Cond 18 | config ConnConfig // config used when establishing connection 19 | maxConnections int 20 | resetCount int 21 | afterConnect func(*Conn) error 22 | logger Logger 23 | logLevel int 24 | closed bool 25 | preparedStatements map[string]*PreparedStatement 26 | } 27 | 28 | type ConnPoolStat struct { 29 | MaxConnections int // max simultaneous connections to use 30 | CurrentConnections int // current live connections 31 | AvailableConnections int // unused live connections 32 | } 33 | 34 | // NewConnPool creates a new ConnPool. config.ConnConfig is passed through to 35 | // Connect directly. 36 | func NewConnPool(config ConnPoolConfig) (p *ConnPool, err error) { 37 | p = new(ConnPool) 38 | p.config = config.ConnConfig 39 | p.maxConnections = config.MaxConnections 40 | if p.maxConnections == 0 { 41 | p.maxConnections = 5 42 | } 43 | if p.maxConnections < 1 { 44 | return nil, errors.New("MaxConnections must be at least 1") 45 | } 46 | 47 | p.afterConnect = config.AfterConnect 48 | 49 | if config.LogLevel != 0 { 50 | p.logLevel = config.LogLevel 51 | } else { 52 | // Preserve pre-LogLevel behavior by defaulting to LogLevelDebug 53 | p.logLevel = LogLevelDebug 54 | } 55 | p.logger = config.Logger 56 | if p.logger == nil { 57 | p.logLevel = LogLevelNone 58 | } 59 | 60 | p.allConnections = make([]*Conn, 0, p.maxConnections) 61 | p.availableConnections = make([]*Conn, 0, p.maxConnections) 62 | p.preparedStatements = make(map[string]*PreparedStatement) 63 | p.cond = sync.NewCond(new(sync.Mutex)) 64 | 65 | // Initially establish one connection 66 | var c *Conn 67 | c, err = p.createConnection() 68 | if err != nil { 69 | return 70 | } 71 | p.allConnections = append(p.allConnections, c) 72 | p.availableConnections = append(p.availableConnections, c) 73 | 74 | return 75 | } 76 | 77 | // Acquire takes exclusive use of a connection until it is released. 78 | func (p *ConnPool) Acquire() (*Conn, error) { 79 | p.cond.L.Lock() 80 | c, err := p.acquire() 81 | p.cond.L.Unlock() 82 | return c, err 83 | } 84 | 85 | // acquire performs acquision assuming pool is already locked 86 | func (p *ConnPool) acquire() (*Conn, error) { 87 | if p.closed { 88 | return nil, errors.New("cannot acquire from closed pool") 89 | } 90 | 91 | // A connection is available 92 | if len(p.availableConnections) > 0 { 93 | c := p.availableConnections[len(p.availableConnections)-1] 94 | c.poolResetCount = p.resetCount 95 | p.availableConnections = p.availableConnections[:len(p.availableConnections)-1] 96 | return c, nil 97 | } 98 | 99 | // No connections are available, but we can create more 100 | if len(p.allConnections) < p.maxConnections { 101 | c, err := p.createConnection() 102 | if err != nil { 103 | return nil, err 104 | } 105 | c.poolResetCount = p.resetCount 106 | p.allConnections = append(p.allConnections, c) 107 | return c, nil 108 | } 109 | 110 | // All connections are in use and we cannot create more 111 | if p.logLevel >= LogLevelWarn { 112 | p.logger.Warn("All connections in pool are busy - waiting...") 113 | } 114 | 115 | // Wait until there is an available connection OR room to create a new connection 116 | for len(p.availableConnections) == 0 && len(p.allConnections) == p.maxConnections { 117 | p.cond.Wait() 118 | } 119 | 120 | return p.acquire() 121 | } 122 | 123 | // Release gives up use of a connection. 124 | func (p *ConnPool) Release(conn *Conn) { 125 | if conn.TxStatus != 'I' { 126 | conn.Exec("rollback") 127 | } 128 | 129 | if len(conn.channels) > 0 { 130 | if err := conn.Unlisten("*"); err != nil { 131 | conn.die(err) 132 | } 133 | conn.channels = make(map[string]struct{}) 134 | } 135 | conn.notifications = nil 136 | 137 | p.cond.L.Lock() 138 | 139 | if conn.poolResetCount != p.resetCount { 140 | conn.Close() 141 | p.cond.L.Unlock() 142 | p.cond.Signal() 143 | return 144 | } 145 | 146 | if conn.IsAlive() { 147 | p.availableConnections = append(p.availableConnections, conn) 148 | } else { 149 | ac := p.allConnections 150 | for i, c := range ac { 151 | if conn == c { 152 | ac[i] = ac[len(ac)-1] 153 | p.allConnections = ac[0 : len(ac)-1] 154 | break 155 | } 156 | } 157 | } 158 | p.cond.L.Unlock() 159 | p.cond.Signal() 160 | } 161 | 162 | // Close ends the use of a connection pool. It prevents any new connections 163 | // from being acquired, waits until all acquired connections are released, 164 | // then closes all underlying connections. 165 | func (p *ConnPool) Close() { 166 | p.cond.L.Lock() 167 | defer p.cond.L.Unlock() 168 | 169 | p.closed = true 170 | 171 | // Wait until all connections are released 172 | if len(p.availableConnections) != len(p.allConnections) { 173 | for len(p.availableConnections) != len(p.allConnections) { 174 | p.cond.Wait() 175 | } 176 | } 177 | 178 | for _, c := range p.allConnections { 179 | _ = c.Close() 180 | } 181 | } 182 | 183 | // Reset closes all open connections, but leaves the pool open. It is intended 184 | // for use when an error is detected that would disrupt all connections (such as 185 | // a network interruption or a server state change). 186 | // 187 | // It is safe to reset a pool while connections are checked out. Those 188 | // connections will be closed when they are returned to the pool. 189 | func (p *ConnPool) Reset() { 190 | p.cond.L.Lock() 191 | defer p.cond.L.Unlock() 192 | 193 | p.resetCount++ 194 | p.allConnections = make([]*Conn, 0, p.maxConnections) 195 | p.availableConnections = make([]*Conn, 0, p.maxConnections) 196 | } 197 | 198 | // invalidateAcquired causes all acquired connections to be closed when released. 199 | // The pool must already be locked. 200 | func (p *ConnPool) invalidateAcquired() { 201 | p.resetCount++ 202 | 203 | for _, c := range p.availableConnections { 204 | c.poolResetCount = p.resetCount 205 | } 206 | 207 | p.allConnections = p.allConnections[:len(p.availableConnections)] 208 | copy(p.allConnections, p.availableConnections) 209 | } 210 | 211 | // Stat returns connection pool statistics 212 | func (p *ConnPool) Stat() (s ConnPoolStat) { 213 | p.cond.L.Lock() 214 | defer p.cond.L.Unlock() 215 | 216 | s.MaxConnections = p.maxConnections 217 | s.CurrentConnections = len(p.allConnections) 218 | s.AvailableConnections = len(p.availableConnections) 219 | return 220 | } 221 | 222 | func (p *ConnPool) createConnection() (*Conn, error) { 223 | c, err := Connect(p.config) 224 | if err != nil { 225 | return nil, err 226 | } 227 | 228 | if p.afterConnect != nil { 229 | err = p.afterConnect(c) 230 | if err != nil { 231 | c.die(err) 232 | return nil, err 233 | } 234 | } 235 | 236 | for _, ps := range p.preparedStatements { 237 | if _, err := c.Prepare(ps.Name, ps.SQL); err != nil { 238 | c.die(err) 239 | return nil, err 240 | } 241 | } 242 | 243 | return c, nil 244 | } 245 | 246 | // Exec acquires a connection, delegates the call to that connection, and releases the connection 247 | func (p *ConnPool) Exec(sql string, arguments ...interface{}) (commandTag CommandTag, err error) { 248 | var c *Conn 249 | if c, err = p.Acquire(); err != nil { 250 | return 251 | } 252 | defer p.Release(c) 253 | 254 | return c.Exec(sql, arguments...) 255 | } 256 | 257 | // Query acquires a connection and delegates the call to that connection. When 258 | // *Rows are closed, the connection is released automatically. 259 | func (p *ConnPool) Query(sql string, args ...interface{}) (*Rows, error) { 260 | c, err := p.Acquire() 261 | if err != nil { 262 | // Because checking for errors can be deferred to the *Rows, build one with the error 263 | return &Rows{closed: true, err: err}, err 264 | } 265 | 266 | rows, err := c.Query(sql, args...) 267 | if err != nil { 268 | p.Release(c) 269 | return rows, err 270 | } 271 | 272 | rows.AfterClose(p.rowsAfterClose) 273 | 274 | return rows, nil 275 | } 276 | 277 | // QueryRow acquires a connection and delegates the call to that connection. The 278 | // connection is released automatically after Scan is called on the returned 279 | // *Row. 280 | func (p *ConnPool) QueryRow(sql string, args ...interface{}) *Row { 281 | rows, _ := p.Query(sql, args...) 282 | return (*Row)(rows) 283 | } 284 | 285 | // Begin acquires a connection and begins a transaction on it. When the 286 | // transaction is closed the connection will be automatically released. 287 | func (p *ConnPool) Begin() (*Tx, error) { 288 | return p.BeginIso("") 289 | } 290 | 291 | // Prepare creates a prepared statement on a connection in the pool to test the 292 | // statement is valid. If it succeeds all connections accessed through the pool 293 | // will have the statement available. 294 | // 295 | // Prepare creates a prepared statement with name and sql. sql can contain 296 | // placeholders for bound parameters. These placeholders are referenced 297 | // positional as $1, $2, etc. 298 | // 299 | // Prepare is idempotent; i.e. it is safe to call Prepare multiple times with 300 | // the same name and sql arguments. This allows a code path to Prepare and 301 | // Query/Exec without concern for if the statement has already been prepared. 302 | func (p *ConnPool) Prepare(name, sql string) (*PreparedStatement, error) { 303 | p.cond.L.Lock() 304 | defer p.cond.L.Unlock() 305 | 306 | if ps, ok := p.preparedStatements[name]; ok && ps.SQL == sql { 307 | return ps, nil 308 | } 309 | 310 | c, err := p.acquire() 311 | if err != nil { 312 | return nil, err 313 | } 314 | ps, err := c.Prepare(name, sql) 315 | p.availableConnections = append(p.availableConnections, c) 316 | if err != nil { 317 | return nil, err 318 | } 319 | 320 | for _, c := range p.availableConnections { 321 | _, err := c.Prepare(name, sql) 322 | if err != nil { 323 | return nil, err 324 | } 325 | } 326 | 327 | p.invalidateAcquired() 328 | p.preparedStatements[name] = ps 329 | 330 | return ps, err 331 | } 332 | 333 | // Deallocate releases a prepared statement from all connections in the pool. 334 | func (p *ConnPool) Deallocate(name string) (err error) { 335 | p.cond.L.Lock() 336 | defer p.cond.L.Unlock() 337 | 338 | for _, c := range p.availableConnections { 339 | if err := c.Deallocate(name); err != nil { 340 | return err 341 | } 342 | } 343 | 344 | p.invalidateAcquired() 345 | 346 | return nil 347 | } 348 | 349 | // BeginIso acquires a connection and begins a transaction in isolation mode iso 350 | // on it. When the transaction is closed the connection will be automatically 351 | // released. 352 | func (p *ConnPool) BeginIso(iso string) (*Tx, error) { 353 | for { 354 | c, err := p.Acquire() 355 | if err != nil { 356 | return nil, err 357 | } 358 | 359 | tx, err := c.BeginIso(iso) 360 | if err != nil { 361 | alive := c.IsAlive() 362 | p.Release(c) 363 | 364 | // If connection is still alive then the error is not something trying 365 | // again on a new connection would fix, so just return the error. But 366 | // if the connection is dead try to acquire a new connection and try 367 | // again. 368 | if alive { 369 | return nil, err 370 | } else { 371 | continue 372 | } 373 | } 374 | 375 | tx.AfterClose(p.txAfterClose) 376 | return tx, nil 377 | } 378 | } 379 | 380 | func (p *ConnPool) txAfterClose(tx *Tx) { 381 | p.Release(tx.Conn()) 382 | } 383 | 384 | func (p *ConnPool) rowsAfterClose(rows *Rows) { 385 | p.Release(rows.Conn()) 386 | } 387 | -------------------------------------------------------------------------------- /vendor/github.com/jackc/pgx/doc.go: -------------------------------------------------------------------------------- 1 | // Package pgx is a PostgreSQL database driver. 2 | /* 3 | pgx provides lower level access to PostgreSQL than the standard database/sql 4 | It remains as similar to the database/sql interface as possible while 5 | providing better speed and access to PostgreSQL specific features. Import 6 | github.com/jack/pgx/stdlib to use pgx as a database/sql compatible driver. 7 | 8 | Query Interface 9 | 10 | pgx implements Query and Scan in the familiar database/sql style. 11 | 12 | var sum int32 13 | 14 | // Send the query to the server. The returned rows MUST be closed 15 | // before conn can be used again. 16 | rows, err := conn.Query("select generate_series(1,$1)", 10) 17 | if err != nil { 18 | return err 19 | } 20 | 21 | // rows.Close is called by rows.Next when all rows are read 22 | // or an error occurs in Next or Scan. So it may optionally be 23 | // omitted if nothing in the rows.Next loop can panic. It is 24 | // safe to close rows multiple times. 25 | defer rows.Close() 26 | 27 | // Iterate through the result set 28 | for rows.Next() { 29 | var n int32 30 | err = rows.Scan(&n) 31 | if err != nil { 32 | return err 33 | } 34 | sum += n 35 | } 36 | 37 | // Any errors encountered by rows.Next or rows.Scan will be returned here 38 | if rows.Err() != nil { 39 | return err 40 | } 41 | 42 | // No errors found - do something with sum 43 | 44 | pgx also implements QueryRow in the same style as database/sql. 45 | 46 | var name string 47 | var weight int64 48 | err := conn.QueryRow("select name, weight from widgets where id=$1", 42).Scan(&name, &weight) 49 | if err != nil { 50 | return err 51 | } 52 | 53 | Use exec to execute a query that does not return a result set. 54 | 55 | commandTag, err := conn.Exec("delete from widgets where id=$1", 42) 56 | if err != nil { 57 | return err 58 | } 59 | if commandTag.RowsAffected() != 1 { 60 | return errors.New("No row found to delete") 61 | } 62 | 63 | Connection Pool 64 | 65 | Connection pool usage is explicit and configurable. In pgx, a connection can 66 | be created and managed directly, or a connection pool with a configurable 67 | maximum connections can be used. Also, the connection pool offers an after 68 | connect hook that allows every connection to be automatically setup before 69 | being made available in the connection pool. This is especially useful to 70 | ensure all connections have the same prepared statements available or to 71 | change any other connection settings. 72 | 73 | It delegates Query, QueryRow, Exec, and Begin functions to an automatically 74 | checked out and released connection so you can avoid manually acquiring and 75 | releasing connections when you do not need that level of control. 76 | 77 | var name string 78 | var weight int64 79 | err := pool.QueryRow("select name, weight from widgets where id=$1", 42).Scan(&name, &weight) 80 | if err != nil { 81 | return err 82 | } 83 | 84 | Transactions 85 | 86 | Transactions are started by calling Begin or BeginIso. The BeginIso variant 87 | creates a transaction with a specified isolation level. 88 | 89 | tx, err := conn.Begin() 90 | if err != nil { 91 | return err 92 | } 93 | // Rollback is safe to call even if the tx is already closed, so if 94 | // the tx commits successfully, this is a no-op 95 | defer tx.Rollback() 96 | 97 | _, err = tx.Exec("insert into foo(id) values (1)") 98 | if err != nil { 99 | return err 100 | } 101 | 102 | err = tx.Commit() 103 | if err != nil { 104 | return err 105 | } 106 | 107 | Listen and Notify 108 | 109 | pgx can listen to the PostgreSQL notification system with the 110 | WaitForNotification function. It takes a maximum time to wait for a 111 | notification. 112 | 113 | err := conn.Listen("channelname") 114 | if err != nil { 115 | return nil 116 | } 117 | 118 | if notification, err := conn.WaitForNotification(time.Second); err != nil { 119 | // do something with notification 120 | } 121 | 122 | Null Mapping 123 | 124 | pgx can map nulls in two ways. The first is Null* types that have a data field 125 | and a valid field. They work in a similar fashion to database/sql. The second 126 | is to use a pointer to a pointer. 127 | 128 | var foo pgx.NullString 129 | var bar *string 130 | err := conn.QueryRow("select foo, bar from widgets where id=$1", 42).Scan(&a, &b) 131 | if err != nil { 132 | return err 133 | } 134 | 135 | Array Mapping 136 | 137 | pgx maps between int16, int32, int64, float32, float64, and string Go slices 138 | and the equivalent PostgreSQL array type. Go slices of native types do not 139 | support nulls, so if a PostgreSQL array that contains a slice is read into a 140 | native Go slice an error will occur. 141 | 142 | Hstore Mapping 143 | 144 | pgx includes an Hstore type and a NullHstore type. Hstore is simply a 145 | map[string]string and is preferred when the hstore contains no nulls. NullHstore 146 | follows the Null* pattern and supports null values. 147 | 148 | JSON and JSONB Mapping 149 | 150 | pgx includes built-in support to marshal and unmarshal between Go types and 151 | the PostgreSQL JSON and JSONB. 152 | 153 | Inet and Cidr Mapping 154 | 155 | pgx encodes from net.IPNet to and from inet and cidr PostgreSQL types. In 156 | addition, as a convenience pgx will encode from a net.IP; it will assume a /32 157 | netmask for IPv4 and a /128 for IPv6. 158 | 159 | Custom Type Support 160 | 161 | pgx includes support for the common data types like integers, floats, strings, 162 | dates, and times that have direct mappings between Go and SQL. Support can be 163 | added for additional types like point, hstore, numeric, etc. that do not have 164 | direct mappings in Go by the types implementing Scanner and Encoder. 165 | 166 | Custom types can support text or binary formats. Binary format can provide a 167 | large performance increase. The natural place for deciding the format for a 168 | value would be in Scanner as it is responsible for decoding the returned data. 169 | However, that is impossible as the query has already been sent by the time the 170 | Scanner is invoked. The solution to this is the global DefaultTypeFormats. If a 171 | custom type prefers binary format it should register it there. 172 | 173 | pgx.DefaultTypeFormats["point"] = pgx.BinaryFormatCode 174 | 175 | Note that the type is referred to by name, not by OID. This is because custom 176 | PostgreSQL types like hstore will have different OIDs on different servers. When 177 | pgx establishes a connection it queries the pg_type table for all types. It then 178 | matches the names in DefaultTypeFormats with the returned OIDs and stores it in 179 | Conn.PgTypes. 180 | 181 | See example_custom_type_test.go for an example of a custom type for the 182 | PostgreSQL point type. 183 | 184 | pgx also includes support for custom types implementing the database/sql.Scanner 185 | and database/sql/driver.Valuer interfaces. 186 | 187 | Raw Bytes Mapping 188 | 189 | []byte passed as arguments to Query, QueryRow, and Exec are passed unmodified 190 | to PostgreSQL. In like manner, a *[]byte passed to Scan will be filled with 191 | the raw bytes returned by PostgreSQL. This can be especially useful for reading 192 | varchar, text, json, and jsonb values directly into a []byte and avoiding the 193 | type conversion from string. 194 | 195 | TLS 196 | 197 | The pgx ConnConfig struct has a TLSConfig field. If this field is 198 | nil, then TLS will be disabled. If it is present, then it will be used to 199 | configure the TLS connection. This allows total configuration of the TLS 200 | connection. 201 | 202 | Logging 203 | 204 | pgx defines a simple logger interface. Connections optionally accept a logger 205 | that satisfies this interface. The log15 package 206 | (http://gopkg.in/inconshreveable/log15.v2) satisfies this interface and it is 207 | simple to define adapters for other loggers. Set LogLevel to control logging 208 | verbosity. 209 | */ 210 | package pgx 211 | -------------------------------------------------------------------------------- /vendor/github.com/jackc/pgx/fastpath.go: -------------------------------------------------------------------------------- 1 | package pgx 2 | 3 | import ( 4 | "encoding/binary" 5 | ) 6 | 7 | type fastpathArg []byte 8 | 9 | func newFastpath(cn *Conn) *fastpath { 10 | return &fastpath{cn: cn, fns: make(map[string]Oid)} 11 | } 12 | 13 | type fastpath struct { 14 | cn *Conn 15 | fns map[string]Oid 16 | } 17 | 18 | func (f *fastpath) functionOID(name string) Oid { 19 | return f.fns[name] 20 | } 21 | 22 | func (f *fastpath) addFunction(name string, oid Oid) { 23 | f.fns[name] = oid 24 | } 25 | 26 | func (f *fastpath) addFunctions(rows *Rows) error { 27 | for rows.Next() { 28 | var name string 29 | var oid Oid 30 | if err := rows.Scan(&name, &oid); err != nil { 31 | return err 32 | } 33 | f.addFunction(name, oid) 34 | } 35 | return rows.Err() 36 | } 37 | 38 | type fpArg []byte 39 | 40 | func fpIntArg(n int32) fpArg { 41 | res := make([]byte, 4) 42 | binary.BigEndian.PutUint32(res, uint32(n)) 43 | return res 44 | } 45 | 46 | func fpInt64Arg(n int64) fpArg { 47 | res := make([]byte, 8) 48 | binary.BigEndian.PutUint64(res, uint64(n)) 49 | return res 50 | } 51 | 52 | func (f *fastpath) Call(oid Oid, args []fpArg) (res []byte, err error) { 53 | wbuf := newWriteBuf(f.cn, 'F') // function call 54 | wbuf.WriteInt32(int32(oid)) // function object id 55 | wbuf.WriteInt16(1) // # of argument format codes 56 | wbuf.WriteInt16(1) // format code: binary 57 | wbuf.WriteInt16(int16(len(args))) // # of arguments 58 | for _, arg := range args { 59 | wbuf.WriteInt32(int32(len(arg))) // length of argument 60 | wbuf.WriteBytes(arg) // argument value 61 | } 62 | wbuf.WriteInt16(1) // response format code (binary) 63 | wbuf.closeMsg() 64 | 65 | if _, err := f.cn.conn.Write(wbuf.buf); err != nil { 66 | return nil, err 67 | } 68 | 69 | for { 70 | var t byte 71 | var r *msgReader 72 | t, r, err = f.cn.rxMsg() 73 | if err != nil { 74 | return nil, err 75 | } 76 | switch t { 77 | case 'V': // FunctionCallResponse 78 | data := r.readBytes(r.readInt32()) 79 | res = make([]byte, len(data)) 80 | copy(res, data) 81 | case 'Z': // Ready for query 82 | f.cn.rxReadyForQuery(r) 83 | // done 84 | return 85 | default: 86 | if err := f.cn.processContextFreeMsg(t, r); err != nil { 87 | return nil, err 88 | } 89 | } 90 | } 91 | } 92 | 93 | func (f *fastpath) CallFn(fn string, args []fpArg) ([]byte, error) { 94 | return f.Call(f.functionOID(fn), args) 95 | } 96 | 97 | func fpInt32(data []byte, err error) (int32, error) { 98 | if err != nil { 99 | return 0, err 100 | } 101 | n := int32(binary.BigEndian.Uint32(data)) 102 | return n, nil 103 | } 104 | 105 | func fpInt64(data []byte, err error) (int64, error) { 106 | if err != nil { 107 | return 0, err 108 | } 109 | return int64(binary.BigEndian.Uint64(data)), nil 110 | } 111 | -------------------------------------------------------------------------------- /vendor/github.com/jackc/pgx/hstore.go: -------------------------------------------------------------------------------- 1 | package pgx 2 | 3 | import ( 4 | "bytes" 5 | "errors" 6 | "fmt" 7 | "unicode" 8 | "unicode/utf8" 9 | ) 10 | 11 | const ( 12 | hsPre = iota 13 | hsKey 14 | hsSep 15 | hsVal 16 | hsNul 17 | hsNext 18 | hsEnd 19 | ) 20 | 21 | type hstoreParser struct { 22 | str string 23 | pos int 24 | } 25 | 26 | func newHSP(in string) *hstoreParser { 27 | return &hstoreParser{ 28 | pos: 0, 29 | str: in, 30 | } 31 | } 32 | 33 | func (p *hstoreParser) Consume() (r rune, end bool) { 34 | if p.pos >= len(p.str) { 35 | end = true 36 | return 37 | } 38 | r, w := utf8.DecodeRuneInString(p.str[p.pos:]) 39 | p.pos += w 40 | return 41 | } 42 | 43 | func (p *hstoreParser) Peek() (r rune, end bool) { 44 | if p.pos >= len(p.str) { 45 | end = true 46 | return 47 | } 48 | r, _ = utf8.DecodeRuneInString(p.str[p.pos:]) 49 | return 50 | } 51 | 52 | func parseHstoreToMap(s string) (m map[string]string, err error) { 53 | keys, values, err := ParseHstore(s) 54 | if err != nil { 55 | return 56 | } 57 | m = make(map[string]string, len(keys)) 58 | for i, key := range keys { 59 | if !values[i].Valid { 60 | err = fmt.Errorf("key '%s' has NULL value", key) 61 | m = nil 62 | return 63 | } 64 | m[key] = values[i].String 65 | } 66 | return 67 | } 68 | 69 | func parseHstoreToNullHstore(s string) (store map[string]NullString, err error) { 70 | keys, values, err := ParseHstore(s) 71 | if err != nil { 72 | return 73 | } 74 | 75 | store = make(map[string]NullString, len(keys)) 76 | 77 | for i, key := range keys { 78 | store[key] = values[i] 79 | } 80 | return 81 | } 82 | 83 | // ParseHstore parses the string representation of an hstore column (the same 84 | // you would get from an ordinary SELECT) into two slices of keys and values. it 85 | // is used internally in the default parsing of hstores, but is exported for use 86 | // in handling custom data structures backed by an hstore column without the 87 | // overhead of creating a map[string]string 88 | func ParseHstore(s string) (k []string, v []NullString, err error) { 89 | if s == "" { 90 | return 91 | } 92 | 93 | buf := bytes.Buffer{} 94 | keys := []string{} 95 | values := []NullString{} 96 | p := newHSP(s) 97 | 98 | r, end := p.Consume() 99 | state := hsPre 100 | 101 | for !end { 102 | switch state { 103 | case hsPre: 104 | if r == '"' { 105 | state = hsKey 106 | } else { 107 | err = errors.New("String does not begin with \"") 108 | } 109 | case hsKey: 110 | switch r { 111 | case '"': //End of the key 112 | if buf.Len() == 0 { 113 | err = errors.New("Empty Key is invalid") 114 | } else { 115 | keys = append(keys, buf.String()) 116 | buf = bytes.Buffer{} 117 | state = hsSep 118 | } 119 | case '\\': //Potential escaped character 120 | n, end := p.Consume() 121 | switch { 122 | case end: 123 | err = errors.New("Found EOS in key, expecting character or \"") 124 | case n == '"', n == '\\': 125 | buf.WriteRune(n) 126 | default: 127 | buf.WriteRune(r) 128 | buf.WriteRune(n) 129 | } 130 | default: //Any other character 131 | buf.WriteRune(r) 132 | } 133 | case hsSep: 134 | if r == '=' { 135 | r, end = p.Consume() 136 | switch { 137 | case end: 138 | err = errors.New("Found EOS after '=', expecting '>'") 139 | case r == '>': 140 | r, end = p.Consume() 141 | switch { 142 | case end: 143 | err = errors.New("Found EOS after '=>', expecting '\"' or 'NULL'") 144 | case r == '"': 145 | state = hsVal 146 | case r == 'N': 147 | state = hsNul 148 | default: 149 | err = fmt.Errorf("Invalid character '%c' after '=>', expecting '\"' or 'NULL'", r) 150 | } 151 | default: 152 | err = fmt.Errorf("Invalid character after '=', expecting '>'") 153 | } 154 | } else { 155 | err = fmt.Errorf("Invalid character '%c' after value, expecting '='", r) 156 | } 157 | case hsVal: 158 | switch r { 159 | case '"': //End of the value 160 | values = append(values, NullString{String: buf.String(), Valid: true}) 161 | buf = bytes.Buffer{} 162 | state = hsNext 163 | case '\\': //Potential escaped character 164 | n, end := p.Consume() 165 | switch { 166 | case end: 167 | err = errors.New("Found EOS in key, expecting character or \"") 168 | case n == '"', n == '\\': 169 | buf.WriteRune(n) 170 | default: 171 | buf.WriteRune(r) 172 | buf.WriteRune(n) 173 | } 174 | default: //Any other character 175 | buf.WriteRune(r) 176 | } 177 | case hsNul: 178 | nulBuf := make([]rune, 3) 179 | nulBuf[0] = r 180 | for i := 1; i < 3; i++ { 181 | r, end = p.Consume() 182 | if end { 183 | err = errors.New("Found EOS in NULL value") 184 | return 185 | } 186 | nulBuf[i] = r 187 | } 188 | if nulBuf[0] == 'U' && nulBuf[1] == 'L' && nulBuf[2] == 'L' { 189 | values = append(values, NullString{String: "", Valid: false}) 190 | state = hsNext 191 | } else { 192 | err = fmt.Errorf("Invalid NULL value: 'N%s'", string(nulBuf)) 193 | } 194 | case hsNext: 195 | if r == ',' { 196 | r, end = p.Consume() 197 | switch { 198 | case end: 199 | err = errors.New("Found EOS after ',', expcting space") 200 | case (unicode.IsSpace(r)): 201 | r, end = p.Consume() 202 | state = hsKey 203 | default: 204 | err = fmt.Errorf("Invalid character '%c' after ', ', expecting \"", r) 205 | } 206 | } else { 207 | err = fmt.Errorf("Invalid character '%c' after value, expecting ','", r) 208 | } 209 | } 210 | 211 | if err != nil { 212 | return 213 | } 214 | r, end = p.Consume() 215 | } 216 | if state != hsNext { 217 | err = errors.New("Improperly formatted hstore") 218 | return 219 | } 220 | k = keys 221 | v = values 222 | return 223 | } 224 | -------------------------------------------------------------------------------- /vendor/github.com/jackc/pgx/large_objects.go: -------------------------------------------------------------------------------- 1 | package pgx 2 | 3 | import ( 4 | "io" 5 | ) 6 | 7 | // LargeObjects is a structure used to access the large objects API. It is only 8 | // valid within the transaction where it was created. 9 | // 10 | // For more details see: http://www.postgresql.org/docs/current/static/largeobjects.html 11 | type LargeObjects struct { 12 | // Has64 is true if the server is capable of working with 64-bit numbers 13 | Has64 bool 14 | fp *fastpath 15 | } 16 | 17 | const largeObjectFns = `select proname, oid from pg_catalog.pg_proc 18 | where proname in ( 19 | 'lo_open', 20 | 'lo_close', 21 | 'lo_create', 22 | 'lo_unlink', 23 | 'lo_lseek', 24 | 'lo_lseek64', 25 | 'lo_tell', 26 | 'lo_tell64', 27 | 'lo_truncate', 28 | 'lo_truncate64', 29 | 'loread', 30 | 'lowrite') 31 | and pronamespace = (select oid from pg_catalog.pg_namespace where nspname = 'pg_catalog')` 32 | 33 | // LargeObjects returns a LargeObjects instance for the transaction. 34 | func (tx *Tx) LargeObjects() (*LargeObjects, error) { 35 | if tx.conn.fp == nil { 36 | tx.conn.fp = newFastpath(tx.conn) 37 | } 38 | if _, exists := tx.conn.fp.fns["lo_open"]; !exists { 39 | res, err := tx.Query(largeObjectFns) 40 | if err != nil { 41 | return nil, err 42 | } 43 | if err := tx.conn.fp.addFunctions(res); err != nil { 44 | return nil, err 45 | } 46 | } 47 | 48 | lo := &LargeObjects{fp: tx.conn.fp} 49 | _, lo.Has64 = lo.fp.fns["lo_lseek64"] 50 | 51 | return lo, nil 52 | } 53 | 54 | type LargeObjectMode int32 55 | 56 | const ( 57 | LargeObjectModeWrite LargeObjectMode = 0x20000 58 | LargeObjectModeRead LargeObjectMode = 0x40000 59 | ) 60 | 61 | // Create creates a new large object. If id is zero, the server assigns an 62 | // unused OID. 63 | func (o *LargeObjects) Create(id Oid) (Oid, error) { 64 | newOid, err := fpInt32(o.fp.CallFn("lo_create", []fpArg{fpIntArg(int32(id))})) 65 | return Oid(newOid), err 66 | } 67 | 68 | // Open opens an existing large object with the given mode. 69 | func (o *LargeObjects) Open(oid Oid, mode LargeObjectMode) (*LargeObject, error) { 70 | fd, err := fpInt32(o.fp.CallFn("lo_open", []fpArg{fpIntArg(int32(oid)), fpIntArg(int32(mode))})) 71 | return &LargeObject{fd: fd, lo: o}, err 72 | } 73 | 74 | // Unlink removes a large object from the database. 75 | func (o *LargeObjects) Unlink(oid Oid) error { 76 | _, err := o.fp.CallFn("lo_unlink", []fpArg{fpIntArg(int32(oid))}) 77 | return err 78 | } 79 | 80 | // A LargeObject is a large object stored on the server. It is only valid within 81 | // the transaction that it was initialized in. It implements these interfaces: 82 | // 83 | // io.Writer 84 | // io.Reader 85 | // io.Seeker 86 | // io.Closer 87 | type LargeObject struct { 88 | fd int32 89 | lo *LargeObjects 90 | } 91 | 92 | // Write writes p to the large object and returns the number of bytes written 93 | // and an error if not all of p was written. 94 | func (o *LargeObject) Write(p []byte) (int, error) { 95 | n, err := fpInt32(o.lo.fp.CallFn("lowrite", []fpArg{fpIntArg(o.fd), p})) 96 | return int(n), err 97 | } 98 | 99 | // Read reads up to len(p) bytes into p returning the number of bytes read. 100 | func (o *LargeObject) Read(p []byte) (int, error) { 101 | res, err := o.lo.fp.CallFn("loread", []fpArg{fpIntArg(o.fd), fpIntArg(int32(len(p)))}) 102 | if len(res) < len(p) { 103 | err = io.EOF 104 | } 105 | return copy(p, res), err 106 | } 107 | 108 | // Seek moves the current location pointer to the new location specified by offset. 109 | func (o *LargeObject) Seek(offset int64, whence int) (n int64, err error) { 110 | if o.lo.Has64 { 111 | n, err = fpInt64(o.lo.fp.CallFn("lo_lseek64", []fpArg{fpIntArg(o.fd), fpInt64Arg(offset), fpIntArg(int32(whence))})) 112 | } else { 113 | var n32 int32 114 | n32, err = fpInt32(o.lo.fp.CallFn("lo_lseek", []fpArg{fpIntArg(o.fd), fpIntArg(int32(offset)), fpIntArg(int32(whence))})) 115 | n = int64(n32) 116 | } 117 | return 118 | } 119 | 120 | // Tell returns the current read or write location of the large object 121 | // descriptor. 122 | func (o *LargeObject) Tell() (n int64, err error) { 123 | if o.lo.Has64 { 124 | n, err = fpInt64(o.lo.fp.CallFn("lo_tell64", []fpArg{fpIntArg(o.fd)})) 125 | } else { 126 | var n32 int32 127 | n32, err = fpInt32(o.lo.fp.CallFn("lo_tell", []fpArg{fpIntArg(o.fd)})) 128 | n = int64(n32) 129 | } 130 | return 131 | } 132 | 133 | // Trunctes the large object to size. 134 | func (o *LargeObject) Truncate(size int64) (err error) { 135 | if o.lo.Has64 { 136 | _, err = o.lo.fp.CallFn("lo_truncate64", []fpArg{fpIntArg(o.fd), fpInt64Arg(size)}) 137 | } else { 138 | _, err = o.lo.fp.CallFn("lo_truncate", []fpArg{fpIntArg(o.fd), fpIntArg(int32(size))}) 139 | } 140 | return 141 | } 142 | 143 | // Close closees the large object descriptor. 144 | func (o *LargeObject) Close() error { 145 | _, err := o.lo.fp.CallFn("lo_close", []fpArg{fpIntArg(o.fd)}) 146 | return err 147 | } 148 | -------------------------------------------------------------------------------- /vendor/github.com/jackc/pgx/logger.go: -------------------------------------------------------------------------------- 1 | package pgx 2 | 3 | import ( 4 | "encoding/hex" 5 | "errors" 6 | "fmt" 7 | ) 8 | 9 | // The values for log levels are chosen such that the zero value means that no 10 | // log level was specified and we can default to LogLevelDebug to preserve 11 | // the behavior that existed prior to log level introduction. 12 | const ( 13 | LogLevelTrace = 6 14 | LogLevelDebug = 5 15 | LogLevelInfo = 4 16 | LogLevelWarn = 3 17 | LogLevelError = 2 18 | LogLevelNone = 1 19 | ) 20 | 21 | // Logger is the interface used to get logging from pgx internals. 22 | // https://github.com/inconshreveable/log15 is the recommended logging package. 23 | // This logging interface was extracted from there. However, it should be simple 24 | // to adapt any logger to this interface. 25 | type Logger interface { 26 | // Log a message at the given level with context key/value pairs 27 | Debug(msg string, ctx ...interface{}) 28 | Info(msg string, ctx ...interface{}) 29 | Warn(msg string, ctx ...interface{}) 30 | Error(msg string, ctx ...interface{}) 31 | } 32 | 33 | // Converts log level string to constant 34 | // 35 | // Valid levels: 36 | // trace 37 | // debug 38 | // info 39 | // warn 40 | // error 41 | // none 42 | func LogLevelFromString(s string) (int, error) { 43 | switch s { 44 | case "trace": 45 | return LogLevelTrace, nil 46 | case "debug": 47 | return LogLevelDebug, nil 48 | case "info": 49 | return LogLevelInfo, nil 50 | case "warn": 51 | return LogLevelWarn, nil 52 | case "error": 53 | return LogLevelError, nil 54 | case "none": 55 | return LogLevelNone, nil 56 | default: 57 | return 0, errors.New("invalid log level") 58 | } 59 | } 60 | 61 | func logQueryArgs(args []interface{}) []interface{} { 62 | logArgs := make([]interface{}, 0, len(args)) 63 | 64 | for _, a := range args { 65 | switch v := a.(type) { 66 | case []byte: 67 | if len(v) < 64 { 68 | a = hex.EncodeToString(v) 69 | } else { 70 | a = fmt.Sprintf("%x (truncated %d bytes)", v[:64], len(v)-64) 71 | } 72 | case string: 73 | if len(v) > 64 { 74 | a = fmt.Sprintf("%s (truncated %d bytes)", v[:64], len(v)-64) 75 | } 76 | } 77 | logArgs = append(logArgs, a) 78 | } 79 | 80 | return logArgs 81 | } 82 | -------------------------------------------------------------------------------- /vendor/github.com/jackc/pgx/messages.go: -------------------------------------------------------------------------------- 1 | package pgx 2 | 3 | import ( 4 | "encoding/binary" 5 | ) 6 | 7 | const ( 8 | protocolVersionNumber = 196608 // 3.0 9 | ) 10 | 11 | const ( 12 | backendKeyData = 'K' 13 | authenticationX = 'R' 14 | readyForQuery = 'Z' 15 | rowDescription = 'T' 16 | dataRow = 'D' 17 | commandComplete = 'C' 18 | errorResponse = 'E' 19 | noticeResponse = 'N' 20 | parseComplete = '1' 21 | parameterDescription = 't' 22 | bindComplete = '2' 23 | notificationResponse = 'A' 24 | emptyQueryResponse = 'I' 25 | noData = 'n' 26 | closeComplete = '3' 27 | flush = 'H' 28 | ) 29 | 30 | type startupMessage struct { 31 | options map[string]string 32 | } 33 | 34 | func newStartupMessage() *startupMessage { 35 | return &startupMessage{map[string]string{}} 36 | } 37 | 38 | func (self *startupMessage) Bytes() (buf []byte) { 39 | buf = make([]byte, 8, 128) 40 | binary.BigEndian.PutUint32(buf[4:8], uint32(protocolVersionNumber)) 41 | for key, value := range self.options { 42 | buf = append(buf, key...) 43 | buf = append(buf, 0) 44 | buf = append(buf, value...) 45 | buf = append(buf, 0) 46 | } 47 | buf = append(buf, ("\000")...) 48 | binary.BigEndian.PutUint32(buf[0:4], uint32(len(buf))) 49 | return buf 50 | } 51 | 52 | type Oid int32 53 | 54 | type FieldDescription struct { 55 | Name string 56 | Table Oid 57 | AttributeNumber int16 58 | DataType Oid 59 | DataTypeSize int16 60 | DataTypeName string 61 | Modifier int32 62 | FormatCode int16 63 | } 64 | 65 | // PgError represents an error reported by the PostgreSQL server. See 66 | // http://www.postgresql.org/docs/9.3/static/protocol-error-fields.html for 67 | // detailed field description. 68 | type PgError struct { 69 | Severity string 70 | Code string 71 | Message string 72 | Detail string 73 | Hint string 74 | Position int32 75 | InternalPosition int32 76 | InternalQuery string 77 | Where string 78 | SchemaName string 79 | TableName string 80 | ColumnName string 81 | DataTypeName string 82 | ConstraintName string 83 | File string 84 | Line int32 85 | Routine string 86 | } 87 | 88 | func (self PgError) Error() string { 89 | return self.Severity + ": " + self.Message + " (SQLSTATE " + self.Code + ")" 90 | } 91 | 92 | func newWriteBuf(c *Conn, t byte) *WriteBuf { 93 | buf := append(c.wbuf[0:0], t, 0, 0, 0, 0) 94 | return &WriteBuf{buf: buf, sizeIdx: 1, conn: c} 95 | } 96 | 97 | // WrifeBuf is used build messages to send to the PostgreSQL server. It is used 98 | // by the Encoder interface when implementing custom encoders. 99 | type WriteBuf struct { 100 | buf []byte 101 | sizeIdx int 102 | conn *Conn 103 | } 104 | 105 | func (wb *WriteBuf) startMsg(t byte) { 106 | wb.closeMsg() 107 | wb.buf = append(wb.buf, t, 0, 0, 0, 0) 108 | wb.sizeIdx = len(wb.buf) - 4 109 | } 110 | 111 | func (wb *WriteBuf) closeMsg() { 112 | binary.BigEndian.PutUint32(wb.buf[wb.sizeIdx:wb.sizeIdx+4], uint32(len(wb.buf)-wb.sizeIdx)) 113 | } 114 | 115 | func (wb *WriteBuf) WriteByte(b byte) { 116 | wb.buf = append(wb.buf, b) 117 | } 118 | 119 | func (wb *WriteBuf) WriteCString(s string) { 120 | wb.buf = append(wb.buf, []byte(s)...) 121 | wb.buf = append(wb.buf, 0) 122 | } 123 | 124 | func (wb *WriteBuf) WriteInt16(n int16) { 125 | b := make([]byte, 2) 126 | binary.BigEndian.PutUint16(b, uint16(n)) 127 | wb.buf = append(wb.buf, b...) 128 | } 129 | 130 | func (wb *WriteBuf) WriteInt32(n int32) { 131 | b := make([]byte, 4) 132 | binary.BigEndian.PutUint32(b, uint32(n)) 133 | wb.buf = append(wb.buf, b...) 134 | } 135 | 136 | func (wb *WriteBuf) WriteInt64(n int64) { 137 | b := make([]byte, 8) 138 | binary.BigEndian.PutUint64(b, uint64(n)) 139 | wb.buf = append(wb.buf, b...) 140 | } 141 | 142 | func (wb *WriteBuf) WriteBytes(b []byte) { 143 | wb.buf = append(wb.buf, b...) 144 | } 145 | -------------------------------------------------------------------------------- /vendor/github.com/jackc/pgx/msg_reader.go: -------------------------------------------------------------------------------- 1 | package pgx 2 | 3 | import ( 4 | "bufio" 5 | "encoding/binary" 6 | "errors" 7 | "io" 8 | "io/ioutil" 9 | ) 10 | 11 | // msgReader is a helper that reads values from a PostgreSQL message. 12 | type msgReader struct { 13 | reader *bufio.Reader 14 | buf [128]byte 15 | msgBytesRemaining int32 16 | err error 17 | log func(lvl int, msg string, ctx ...interface{}) 18 | shouldLog func(lvl int) bool 19 | } 20 | 21 | // Err returns any error that the msgReader has experienced 22 | func (r *msgReader) Err() error { 23 | return r.err 24 | } 25 | 26 | // fatal tells r that a Fatal error has occurred 27 | func (r *msgReader) fatal(err error) { 28 | if r.shouldLog(LogLevelTrace) { 29 | r.log(LogLevelTrace, "msgReader.fatal", "error", err, "msgBytesRemaining", r.msgBytesRemaining) 30 | } 31 | r.err = err 32 | } 33 | 34 | // rxMsg reads the type and size of the next message. 35 | func (r *msgReader) rxMsg() (byte, error) { 36 | if r.err != nil { 37 | return 0, r.err 38 | } 39 | 40 | if r.msgBytesRemaining > 0 { 41 | if r.shouldLog(LogLevelTrace) { 42 | r.log(LogLevelTrace, "msgReader.rxMsg discarding unread previous message", "msgBytesRemaining", r.msgBytesRemaining) 43 | } 44 | 45 | io.CopyN(ioutil.Discard, r.reader, int64(r.msgBytesRemaining)) 46 | } 47 | 48 | b := r.buf[0:5] 49 | _, err := io.ReadFull(r.reader, b) 50 | r.msgBytesRemaining = int32(binary.BigEndian.Uint32(b[1:])) - 4 51 | return b[0], err 52 | } 53 | 54 | func (r *msgReader) readByte() byte { 55 | if r.err != nil { 56 | return 0 57 | } 58 | 59 | r.msgBytesRemaining -= 1 60 | if r.msgBytesRemaining < 0 { 61 | r.fatal(errors.New("read past end of message")) 62 | return 0 63 | } 64 | 65 | b, err := r.reader.ReadByte() 66 | if err != nil { 67 | r.fatal(err) 68 | return 0 69 | } 70 | 71 | if r.shouldLog(LogLevelTrace) { 72 | r.log(LogLevelTrace, "msgReader.readByte", "value", b, "byteAsString", string(b), "msgBytesRemaining", r.msgBytesRemaining) 73 | } 74 | 75 | return b 76 | } 77 | 78 | func (r *msgReader) readInt16() int16 { 79 | if r.err != nil { 80 | return 0 81 | } 82 | 83 | r.msgBytesRemaining -= 2 84 | if r.msgBytesRemaining < 0 { 85 | r.fatal(errors.New("read past end of message")) 86 | return 0 87 | } 88 | 89 | b := r.buf[0:2] 90 | _, err := io.ReadFull(r.reader, b) 91 | if err != nil { 92 | r.fatal(err) 93 | return 0 94 | } 95 | 96 | n := int16(binary.BigEndian.Uint16(b)) 97 | 98 | if r.shouldLog(LogLevelTrace) { 99 | r.log(LogLevelTrace, "msgReader.readInt16", "value", n, "msgBytesRemaining", r.msgBytesRemaining) 100 | } 101 | 102 | return n 103 | } 104 | 105 | func (r *msgReader) readInt32() int32 { 106 | if r.err != nil { 107 | return 0 108 | } 109 | 110 | r.msgBytesRemaining -= 4 111 | if r.msgBytesRemaining < 0 { 112 | r.fatal(errors.New("read past end of message")) 113 | return 0 114 | } 115 | 116 | b := r.buf[0:4] 117 | _, err := io.ReadFull(r.reader, b) 118 | if err != nil { 119 | r.fatal(err) 120 | return 0 121 | } 122 | 123 | n := int32(binary.BigEndian.Uint32(b)) 124 | 125 | if r.shouldLog(LogLevelTrace) { 126 | r.log(LogLevelTrace, "msgReader.readInt32", "value", n, "msgBytesRemaining", r.msgBytesRemaining) 127 | } 128 | 129 | return n 130 | } 131 | 132 | func (r *msgReader) readInt64() int64 { 133 | if r.err != nil { 134 | return 0 135 | } 136 | 137 | r.msgBytesRemaining -= 8 138 | if r.msgBytesRemaining < 0 { 139 | r.fatal(errors.New("read past end of message")) 140 | return 0 141 | } 142 | 143 | b := r.buf[0:8] 144 | _, err := io.ReadFull(r.reader, b) 145 | if err != nil { 146 | r.fatal(err) 147 | return 0 148 | } 149 | 150 | n := int64(binary.BigEndian.Uint64(b)) 151 | 152 | if r.shouldLog(LogLevelTrace) { 153 | r.log(LogLevelTrace, "msgReader.readInt64", "value", n, "msgBytesRemaining", r.msgBytesRemaining) 154 | } 155 | 156 | return n 157 | } 158 | 159 | func (r *msgReader) readOid() Oid { 160 | return Oid(r.readInt32()) 161 | } 162 | 163 | // readCString reads a null terminated string 164 | func (r *msgReader) readCString() string { 165 | if r.err != nil { 166 | return "" 167 | } 168 | 169 | b, err := r.reader.ReadBytes(0) 170 | if err != nil { 171 | r.fatal(err) 172 | return "" 173 | } 174 | 175 | r.msgBytesRemaining -= int32(len(b)) 176 | if r.msgBytesRemaining < 0 { 177 | r.fatal(errors.New("read past end of message")) 178 | return "" 179 | } 180 | 181 | s := string(b[0 : len(b)-1]) 182 | 183 | if r.shouldLog(LogLevelTrace) { 184 | r.log(LogLevelTrace, "msgReader.readCString", "value", s, "msgBytesRemaining", r.msgBytesRemaining) 185 | } 186 | 187 | return s 188 | } 189 | 190 | // readString reads count bytes and returns as string 191 | func (r *msgReader) readString(count int32) string { 192 | if r.err != nil { 193 | return "" 194 | } 195 | 196 | r.msgBytesRemaining -= count 197 | if r.msgBytesRemaining < 0 { 198 | r.fatal(errors.New("read past end of message")) 199 | return "" 200 | } 201 | 202 | var b []byte 203 | if count <= int32(len(r.buf)) { 204 | b = r.buf[0:int(count)] 205 | } else { 206 | b = make([]byte, int(count)) 207 | } 208 | 209 | _, err := io.ReadFull(r.reader, b) 210 | if err != nil { 211 | r.fatal(err) 212 | return "" 213 | } 214 | 215 | s := string(b) 216 | 217 | if r.shouldLog(LogLevelTrace) { 218 | r.log(LogLevelTrace, "msgReader.readString", "value", s, "msgBytesRemaining", r.msgBytesRemaining) 219 | } 220 | 221 | return s 222 | } 223 | 224 | // readBytes reads count bytes and returns as []byte 225 | func (r *msgReader) readBytes(count int32) []byte { 226 | if r.err != nil { 227 | return nil 228 | } 229 | 230 | r.msgBytesRemaining -= count 231 | if r.msgBytesRemaining < 0 { 232 | r.fatal(errors.New("read past end of message")) 233 | return nil 234 | } 235 | 236 | b := make([]byte, int(count)) 237 | 238 | _, err := io.ReadFull(r.reader, b) 239 | if err != nil { 240 | r.fatal(err) 241 | return nil 242 | } 243 | 244 | if r.shouldLog(LogLevelTrace) { 245 | r.log(LogLevelTrace, "msgReader.readBytes", "value", b, "msgBytesRemaining", r.msgBytesRemaining) 246 | } 247 | 248 | return b 249 | } 250 | -------------------------------------------------------------------------------- /vendor/github.com/jackc/pgx/query.go: -------------------------------------------------------------------------------- 1 | package pgx 2 | 3 | import ( 4 | "database/sql" 5 | "errors" 6 | "fmt" 7 | "time" 8 | ) 9 | 10 | // Row is a convenience wrapper over Rows that is returned by QueryRow. 11 | type Row Rows 12 | 13 | // Scan works the same as (*Rows Scan) with the following exceptions. If no 14 | // rows were found it returns ErrNoRows. If multiple rows are returned it 15 | // ignores all but the first. 16 | func (r *Row) Scan(dest ...interface{}) (err error) { 17 | rows := (*Rows)(r) 18 | 19 | if rows.Err() != nil { 20 | return rows.Err() 21 | } 22 | 23 | if !rows.Next() { 24 | if rows.Err() == nil { 25 | return ErrNoRows 26 | } else { 27 | return rows.Err() 28 | } 29 | } 30 | 31 | rows.Scan(dest...) 32 | rows.Close() 33 | return rows.Err() 34 | } 35 | 36 | // Rows is the result set returned from *Conn.Query. Rows must be closed before 37 | // the *Conn can be used again. Rows are closed by explicitly calling Close(), 38 | // calling Next() until it returns false, or when a fatal error occurs. 39 | type Rows struct { 40 | conn *Conn 41 | mr *msgReader 42 | fields []FieldDescription 43 | vr ValueReader 44 | rowCount int 45 | columnIdx int 46 | err error 47 | startTime time.Time 48 | sql string 49 | args []interface{} 50 | log func(lvl int, msg string, ctx ...interface{}) 51 | shouldLog func(lvl int) bool 52 | afterClose func(*Rows) 53 | unlockConn bool 54 | closed bool 55 | } 56 | 57 | func (rows *Rows) FieldDescriptions() []FieldDescription { 58 | return rows.fields 59 | } 60 | 61 | func (rows *Rows) close() { 62 | if rows.closed { 63 | return 64 | } 65 | 66 | if rows.unlockConn { 67 | rows.conn.unlock() 68 | rows.unlockConn = false 69 | } 70 | 71 | rows.closed = true 72 | 73 | if rows.err == nil { 74 | if rows.shouldLog(LogLevelInfo) { 75 | endTime := time.Now() 76 | rows.log(LogLevelInfo, "Query", "sql", rows.sql, "args", logQueryArgs(rows.args), "time", endTime.Sub(rows.startTime), "rowCount", rows.rowCount) 77 | } 78 | } else if rows.shouldLog(LogLevelError) { 79 | rows.log(LogLevelError, "Query", "sql", rows.sql, "args", logQueryArgs(rows.args)) 80 | } 81 | 82 | if rows.afterClose != nil { 83 | rows.afterClose(rows) 84 | } 85 | } 86 | 87 | func (rows *Rows) readUntilReadyForQuery() { 88 | for { 89 | t, r, err := rows.conn.rxMsg() 90 | if err != nil { 91 | rows.close() 92 | return 93 | } 94 | 95 | switch t { 96 | case readyForQuery: 97 | rows.conn.rxReadyForQuery(r) 98 | rows.close() 99 | return 100 | case rowDescription: 101 | case dataRow: 102 | case commandComplete: 103 | case bindComplete: 104 | case errorResponse: 105 | err = rows.conn.rxErrorResponse(r) 106 | if rows.err == nil { 107 | rows.err = err 108 | } 109 | default: 110 | err = rows.conn.processContextFreeMsg(t, r) 111 | if err != nil { 112 | rows.close() 113 | return 114 | } 115 | } 116 | } 117 | } 118 | 119 | // Close closes the rows, making the connection ready for use again. It is safe 120 | // to call Close after rows is already closed. 121 | func (rows *Rows) Close() { 122 | if rows.closed { 123 | return 124 | } 125 | rows.readUntilReadyForQuery() 126 | rows.close() 127 | } 128 | 129 | func (rows *Rows) Err() error { 130 | return rows.err 131 | } 132 | 133 | // abort signals that the query was not successfully sent to the server. 134 | // This differs from Fatal in that it is not necessary to readUntilReadyForQuery 135 | func (rows *Rows) abort(err error) { 136 | if rows.err != nil { 137 | return 138 | } 139 | 140 | rows.err = err 141 | rows.close() 142 | } 143 | 144 | // Fatal signals an error occurred after the query was sent to the server. It 145 | // closes the rows automatically. 146 | func (rows *Rows) Fatal(err error) { 147 | if rows.err != nil { 148 | return 149 | } 150 | 151 | rows.err = err 152 | rows.Close() 153 | } 154 | 155 | // Next prepares the next row for reading. It returns true if there is another 156 | // row and false if no more rows are available. It automatically closes rows 157 | // when all rows are read. 158 | func (rows *Rows) Next() bool { 159 | if rows.closed { 160 | return false 161 | } 162 | 163 | rows.rowCount++ 164 | rows.columnIdx = 0 165 | rows.vr = ValueReader{} 166 | 167 | for { 168 | t, r, err := rows.conn.rxMsg() 169 | if err != nil { 170 | rows.Fatal(err) 171 | return false 172 | } 173 | 174 | switch t { 175 | case readyForQuery: 176 | rows.conn.rxReadyForQuery(r) 177 | rows.close() 178 | return false 179 | case dataRow: 180 | fieldCount := r.readInt16() 181 | if int(fieldCount) != len(rows.fields) { 182 | rows.Fatal(ProtocolError(fmt.Sprintf("Row description field count (%v) and data row field count (%v) do not match", len(rows.fields), fieldCount))) 183 | return false 184 | } 185 | 186 | rows.mr = r 187 | return true 188 | case commandComplete: 189 | case bindComplete: 190 | default: 191 | err = rows.conn.processContextFreeMsg(t, r) 192 | if err != nil { 193 | rows.Fatal(err) 194 | return false 195 | } 196 | } 197 | } 198 | } 199 | 200 | // Conn returns the *Conn this *Rows is using. 201 | func (rows *Rows) Conn() *Conn { 202 | return rows.conn 203 | } 204 | 205 | func (rows *Rows) nextColumn() (*ValueReader, bool) { 206 | if rows.closed { 207 | return nil, false 208 | } 209 | if len(rows.fields) <= rows.columnIdx { 210 | rows.Fatal(ProtocolError("No next column available")) 211 | return nil, false 212 | } 213 | 214 | if rows.vr.Len() > 0 { 215 | rows.mr.readBytes(rows.vr.Len()) 216 | } 217 | 218 | fd := &rows.fields[rows.columnIdx] 219 | rows.columnIdx++ 220 | size := rows.mr.readInt32() 221 | rows.vr = ValueReader{mr: rows.mr, fd: fd, valueBytesRemaining: size} 222 | return &rows.vr, true 223 | } 224 | 225 | type scanArgError struct { 226 | col int 227 | err error 228 | } 229 | 230 | func (e scanArgError) Error() string { 231 | return fmt.Sprintf("can't scan into dest[%d]: %v", e.col, e.err) 232 | } 233 | 234 | // Scan reads the values from the current row into dest values positionally. 235 | // dest can include pointers to core types, values implementing the Scanner 236 | // interface, []byte, and nil. []byte will skip the decoding process and directly 237 | // copy the raw bytes received from PostgreSQL. nil will skip the value entirely. 238 | func (rows *Rows) Scan(dest ...interface{}) (err error) { 239 | if len(rows.fields) != len(dest) { 240 | err = fmt.Errorf("Scan received wrong number of arguments, got %d but expected %d", len(dest), len(rows.fields)) 241 | rows.Fatal(err) 242 | return err 243 | } 244 | 245 | for i, d := range dest { 246 | vr, _ := rows.nextColumn() 247 | 248 | if d == nil { 249 | continue 250 | } 251 | 252 | // Check for []byte first as we allow sidestepping the decoding process and retrieving the raw bytes 253 | if b, ok := d.(*[]byte); ok { 254 | // If it actually is a bytea then pass it through decodeBytea (so it can be decoded if it is in text format) 255 | // Otherwise read the bytes directly regardless of what the actual type is. 256 | if vr.Type().DataType == ByteaOid { 257 | *b = decodeBytea(vr) 258 | } else { 259 | if vr.Len() != -1 { 260 | *b = vr.ReadBytes(vr.Len()) 261 | } else { 262 | *b = nil 263 | } 264 | } 265 | } else if s, ok := d.(Scanner); ok { 266 | err = s.Scan(vr) 267 | if err != nil { 268 | rows.Fatal(scanArgError{col: i, err: err}) 269 | } 270 | } else if s, ok := d.(sql.Scanner); ok { 271 | var val interface{} 272 | if 0 <= vr.Len() { 273 | switch vr.Type().DataType { 274 | case BoolOid: 275 | val = decodeBool(vr) 276 | case Int8Oid: 277 | val = int64(decodeInt8(vr)) 278 | case Int2Oid: 279 | val = int64(decodeInt2(vr)) 280 | case Int4Oid: 281 | val = int64(decodeInt4(vr)) 282 | case TextOid, VarcharOid: 283 | val = decodeText(vr) 284 | case OidOid: 285 | val = int64(decodeOid(vr)) 286 | case Float4Oid: 287 | val = float64(decodeFloat4(vr)) 288 | case Float8Oid: 289 | val = decodeFloat8(vr) 290 | case DateOid: 291 | val = decodeDate(vr) 292 | case TimestampOid: 293 | val = decodeTimestamp(vr) 294 | case TimestampTzOid: 295 | val = decodeTimestampTz(vr) 296 | default: 297 | val = vr.ReadBytes(vr.Len()) 298 | } 299 | } 300 | err = s.Scan(val) 301 | if err != nil { 302 | rows.Fatal(scanArgError{col: i, err: err}) 303 | } 304 | } else if vr.Type().DataType == JsonOid || vr.Type().DataType == JsonbOid { 305 | decodeJson(vr, &d) 306 | } else { 307 | if err := Decode(vr, d); err != nil { 308 | rows.Fatal(scanArgError{col: i, err: err}) 309 | } 310 | } 311 | if vr.Err() != nil { 312 | rows.Fatal(scanArgError{col: i, err: vr.Err()}) 313 | } 314 | 315 | if rows.Err() != nil { 316 | return rows.Err() 317 | } 318 | } 319 | 320 | return nil 321 | } 322 | 323 | // Values returns an array of the row values 324 | func (rows *Rows) Values() ([]interface{}, error) { 325 | if rows.closed { 326 | return nil, errors.New("rows is closed") 327 | } 328 | 329 | values := make([]interface{}, 0, len(rows.fields)) 330 | 331 | for _, _ = range rows.fields { 332 | vr, _ := rows.nextColumn() 333 | 334 | if vr.Len() == -1 { 335 | values = append(values, nil) 336 | continue 337 | } 338 | 339 | switch vr.Type().FormatCode { 340 | // All intrinsic types (except string) are encoded with binary 341 | // encoding so anything else should be treated as a string 342 | case TextFormatCode: 343 | values = append(values, vr.ReadString(vr.Len())) 344 | case BinaryFormatCode: 345 | switch vr.Type().DataType { 346 | case BoolOid: 347 | values = append(values, decodeBool(vr)) 348 | case ByteaOid: 349 | values = append(values, decodeBytea(vr)) 350 | case Int8Oid: 351 | values = append(values, decodeInt8(vr)) 352 | case Int2Oid: 353 | values = append(values, decodeInt2(vr)) 354 | case Int4Oid: 355 | values = append(values, decodeInt4(vr)) 356 | case OidOid: 357 | values = append(values, decodeOid(vr)) 358 | case Float4Oid: 359 | values = append(values, decodeFloat4(vr)) 360 | case Float8Oid: 361 | values = append(values, decodeFloat8(vr)) 362 | case BoolArrayOid: 363 | values = append(values, decodeBoolArray(vr)) 364 | case Int2ArrayOid: 365 | values = append(values, decodeInt2Array(vr)) 366 | case Int4ArrayOid: 367 | values = append(values, decodeInt4Array(vr)) 368 | case Int8ArrayOid: 369 | values = append(values, decodeInt8Array(vr)) 370 | case Float4ArrayOid: 371 | values = append(values, decodeFloat4Array(vr)) 372 | case Float8ArrayOid: 373 | values = append(values, decodeFloat8Array(vr)) 374 | case TextArrayOid, VarcharArrayOid: 375 | values = append(values, decodeTextArray(vr)) 376 | case TimestampArrayOid, TimestampTzArrayOid: 377 | values = append(values, decodeTimestampArray(vr)) 378 | case DateOid: 379 | values = append(values, decodeDate(vr)) 380 | case TimestampTzOid: 381 | values = append(values, decodeTimestampTz(vr)) 382 | case TimestampOid: 383 | values = append(values, decodeTimestamp(vr)) 384 | case InetOid, CidrOid: 385 | values = append(values, decodeInet(vr)) 386 | case JsonOid: 387 | var d interface{} 388 | decodeJson(vr, &d) 389 | values = append(values, d) 390 | case JsonbOid: 391 | var d interface{} 392 | decodeJson(vr, &d) 393 | values = append(values, d) 394 | default: 395 | rows.Fatal(errors.New("Values cannot handle binary format non-intrinsic types")) 396 | } 397 | default: 398 | rows.Fatal(errors.New("Unknown format code")) 399 | } 400 | 401 | if vr.Err() != nil { 402 | rows.Fatal(vr.Err()) 403 | } 404 | 405 | if rows.Err() != nil { 406 | return nil, rows.Err() 407 | } 408 | } 409 | 410 | return values, rows.Err() 411 | } 412 | 413 | // AfterClose adds f to a LILO queue of functions that will be called when 414 | // rows is closed. 415 | func (rows *Rows) AfterClose(f func(*Rows)) { 416 | if rows.afterClose == nil { 417 | rows.afterClose = f 418 | } else { 419 | prevFn := rows.afterClose 420 | rows.afterClose = func(rows *Rows) { 421 | f(rows) 422 | prevFn(rows) 423 | } 424 | } 425 | } 426 | 427 | // Query executes sql with args. If there is an error the returned *Rows will 428 | // be returned in an error state. So it is allowed to ignore the error returned 429 | // from Query and handle it in *Rows. 430 | func (c *Conn) Query(sql string, args ...interface{}) (*Rows, error) { 431 | c.lastActivityTime = time.Now() 432 | rows := &Rows{conn: c, startTime: c.lastActivityTime, sql: sql, args: args, log: c.log, shouldLog: c.shouldLog} 433 | 434 | if err := c.lock(); err != nil { 435 | rows.abort(err) 436 | return rows, err 437 | } 438 | rows.unlockConn = true 439 | 440 | ps, ok := c.preparedStatements[sql] 441 | if !ok { 442 | var err error 443 | ps, err = c.Prepare("", sql) 444 | if err != nil { 445 | rows.abort(err) 446 | return rows, rows.err 447 | } 448 | } 449 | 450 | rows.fields = ps.FieldDescriptions 451 | err := c.sendPreparedQuery(ps, args...) 452 | if err != nil { 453 | rows.abort(err) 454 | } 455 | return rows, rows.err 456 | } 457 | 458 | // QueryRow is a convenience wrapper over Query. Any error that occurs while 459 | // querying is deferred until calling Scan on the returned *Row. That *Row will 460 | // error with ErrNoRows if no rows are returned. 461 | func (c *Conn) QueryRow(sql string, args ...interface{}) *Row { 462 | rows, _ := c.Query(sql, args...) 463 | return (*Row)(rows) 464 | } 465 | -------------------------------------------------------------------------------- /vendor/github.com/jackc/pgx/sql.go: -------------------------------------------------------------------------------- 1 | package pgx 2 | 3 | import ( 4 | "strconv" 5 | ) 6 | 7 | // QueryArgs is a container for arguments to an SQL query. It is helpful when 8 | // building SQL statements where the number of arguments is variable. 9 | type QueryArgs []interface{} 10 | 11 | var placeholders []string 12 | 13 | func init() { 14 | placeholders = make([]string, 64) 15 | 16 | for i := 1; i < 64; i++ { 17 | placeholders[i] = "$" + strconv.FormatInt(int64(i), 10) 18 | } 19 | } 20 | 21 | // Append adds a value to qa and returns the placeholder value for the 22 | // argument. e.g. $1, $2, etc. 23 | func (qa *QueryArgs) Append(v interface{}) string { 24 | *qa = append(*qa, v) 25 | if len(*qa) < len(placeholders) { 26 | return placeholders[len(*qa)] 27 | } 28 | return "$" + strconv.FormatInt(int64(len(*qa)), 10) 29 | } 30 | -------------------------------------------------------------------------------- /vendor/github.com/jackc/pgx/tx.go: -------------------------------------------------------------------------------- 1 | package pgx 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | ) 7 | 8 | // Transaction isolation levels 9 | const ( 10 | Serializable = "serializable" 11 | RepeatableRead = "repeatable read" 12 | ReadCommitted = "read committed" 13 | ReadUncommitted = "read uncommitted" 14 | ) 15 | 16 | const ( 17 | TxStatusInProgress = 0 18 | TxStatusCommitFailure = -1 19 | TxStatusRollbackFailure = -2 20 | TxStatusCommitSuccess = 1 21 | TxStatusRollbackSuccess = 2 22 | ) 23 | 24 | var ErrTxClosed = errors.New("tx is closed") 25 | 26 | // ErrTxCommitRollback occurs when an error has occurred in a transaction and 27 | // Commit() is called. PostgreSQL accepts COMMIT on aborted transactions, but 28 | // it is treated as ROLLBACK. 29 | var ErrTxCommitRollback = errors.New("commit unexpectedly resulted in rollback") 30 | 31 | // Begin starts a transaction with the default isolation level for the current 32 | // connection. To use a specific isolation level see BeginIso. 33 | func (c *Conn) Begin() (*Tx, error) { 34 | return c.begin("") 35 | } 36 | 37 | // BeginIso starts a transaction with isoLevel as the transaction isolation 38 | // level. 39 | // 40 | // Valid isolation levels (and their constants) are: 41 | // serializable (pgx.Serializable) 42 | // repeatable read (pgx.RepeatableRead) 43 | // read committed (pgx.ReadCommitted) 44 | // read uncommitted (pgx.ReadUncommitted) 45 | func (c *Conn) BeginIso(isoLevel string) (*Tx, error) { 46 | return c.begin(isoLevel) 47 | } 48 | 49 | func (c *Conn) begin(isoLevel string) (*Tx, error) { 50 | var beginSql string 51 | if isoLevel == "" { 52 | beginSql = "begin" 53 | } else { 54 | beginSql = fmt.Sprintf("begin isolation level %s", isoLevel) 55 | } 56 | 57 | _, err := c.Exec(beginSql) 58 | if err != nil { 59 | return nil, err 60 | } 61 | 62 | return &Tx{conn: c}, nil 63 | } 64 | 65 | // Tx represents a database transaction. 66 | // 67 | // All Tx methods return ErrTxClosed if Commit or Rollback has already been 68 | // called on the Tx. 69 | type Tx struct { 70 | conn *Conn 71 | afterClose func(*Tx) 72 | err error 73 | status int8 74 | } 75 | 76 | // Commit commits the transaction 77 | func (tx *Tx) Commit() error { 78 | if tx.status != TxStatusInProgress { 79 | return ErrTxClosed 80 | } 81 | 82 | commandTag, err := tx.conn.Exec("commit") 83 | if err == nil && commandTag == "COMMIT" { 84 | tx.status = TxStatusCommitSuccess 85 | } else if err == nil && commandTag == "ROLLBACK" { 86 | tx.status = TxStatusCommitFailure 87 | tx.err = ErrTxCommitRollback 88 | } else { 89 | tx.status = TxStatusCommitFailure 90 | tx.err = err 91 | } 92 | 93 | if tx.afterClose != nil { 94 | tx.afterClose(tx) 95 | } 96 | return tx.err 97 | } 98 | 99 | // Rollback rolls back the transaction. Rollback will return ErrTxClosed if the 100 | // Tx is already closed, but is otherwise safe to call multiple times. Hence, a 101 | // defer tx.Rollback() is safe even if tx.Commit() will be called first in a 102 | // non-error condition. 103 | func (tx *Tx) Rollback() error { 104 | if tx.status != TxStatusInProgress { 105 | return ErrTxClosed 106 | } 107 | 108 | _, tx.err = tx.conn.Exec("rollback") 109 | if tx.err == nil { 110 | tx.status = TxStatusRollbackSuccess 111 | } else { 112 | tx.status = TxStatusRollbackFailure 113 | } 114 | 115 | if tx.afterClose != nil { 116 | tx.afterClose(tx) 117 | } 118 | return tx.err 119 | } 120 | 121 | // Exec delegates to the underlying *Conn 122 | func (tx *Tx) Exec(sql string, arguments ...interface{}) (commandTag CommandTag, err error) { 123 | if tx.status != TxStatusInProgress { 124 | return CommandTag(""), ErrTxClosed 125 | } 126 | 127 | return tx.conn.Exec(sql, arguments...) 128 | } 129 | 130 | // Query delegates to the underlying *Conn 131 | func (tx *Tx) Query(sql string, args ...interface{}) (*Rows, error) { 132 | if tx.status != TxStatusInProgress { 133 | // Because checking for errors can be deferred to the *Rows, build one with the error 134 | err := ErrTxClosed 135 | return &Rows{closed: true, err: err}, err 136 | } 137 | 138 | return tx.conn.Query(sql, args...) 139 | } 140 | 141 | // QueryRow delegates to the underlying *Conn 142 | func (tx *Tx) QueryRow(sql string, args ...interface{}) *Row { 143 | rows, _ := tx.Query(sql, args...) 144 | return (*Row)(rows) 145 | } 146 | 147 | // Conn returns the *Conn this transaction is using. 148 | func (tx *Tx) Conn() *Conn { 149 | return tx.conn 150 | } 151 | 152 | // Status returns the status of the transaction from the set of 153 | // pgx.TxStatus* constants. 154 | func (tx *Tx) Status() int8 { 155 | return tx.status 156 | } 157 | 158 | // Err returns the final error state, if any, of calling Commit or Rollback. 159 | func (tx *Tx) Err() error { 160 | return tx.err 161 | } 162 | 163 | // AfterClose adds f to a LILO queue of functions that will be called when 164 | // the transaction is closed (either Commit or Rollback). 165 | func (tx *Tx) AfterClose(f func(*Tx)) { 166 | if tx.afterClose == nil { 167 | tx.afterClose = f 168 | } else { 169 | prevFn := tx.afterClose 170 | tx.afterClose = func(tx *Tx) { 171 | f(tx) 172 | prevFn(tx) 173 | } 174 | } 175 | } 176 | -------------------------------------------------------------------------------- /vendor/github.com/jackc/pgx/value_reader.go: -------------------------------------------------------------------------------- 1 | package pgx 2 | 3 | import ( 4 | "errors" 5 | ) 6 | 7 | // ValueReader is used by the Scanner interface to decode values. 8 | type ValueReader struct { 9 | mr *msgReader 10 | fd *FieldDescription 11 | valueBytesRemaining int32 12 | err error 13 | } 14 | 15 | // Err returns any error that the ValueReader has experienced 16 | func (r *ValueReader) Err() error { 17 | return r.err 18 | } 19 | 20 | // Fatal tells r that a Fatal error has occurred 21 | func (r *ValueReader) Fatal(err error) { 22 | r.err = err 23 | } 24 | 25 | // Len returns the number of unread bytes 26 | func (r *ValueReader) Len() int32 { 27 | return r.valueBytesRemaining 28 | } 29 | 30 | // Type returns the *FieldDescription of the value 31 | func (r *ValueReader) Type() *FieldDescription { 32 | return r.fd 33 | } 34 | 35 | func (r *ValueReader) ReadByte() byte { 36 | if r.err != nil { 37 | return 0 38 | } 39 | 40 | r.valueBytesRemaining -= 1 41 | if r.valueBytesRemaining < 0 { 42 | r.Fatal(errors.New("read past end of value")) 43 | return 0 44 | } 45 | 46 | return r.mr.readByte() 47 | } 48 | 49 | func (r *ValueReader) ReadInt16() int16 { 50 | if r.err != nil { 51 | return 0 52 | } 53 | 54 | r.valueBytesRemaining -= 2 55 | if r.valueBytesRemaining < 0 { 56 | r.Fatal(errors.New("read past end of value")) 57 | return 0 58 | } 59 | 60 | return r.mr.readInt16() 61 | } 62 | 63 | func (r *ValueReader) ReadInt32() int32 { 64 | if r.err != nil { 65 | return 0 66 | } 67 | 68 | r.valueBytesRemaining -= 4 69 | if r.valueBytesRemaining < 0 { 70 | r.Fatal(errors.New("read past end of value")) 71 | return 0 72 | } 73 | 74 | return r.mr.readInt32() 75 | } 76 | 77 | func (r *ValueReader) ReadInt64() int64 { 78 | if r.err != nil { 79 | return 0 80 | } 81 | 82 | r.valueBytesRemaining -= 8 83 | if r.valueBytesRemaining < 0 { 84 | r.Fatal(errors.New("read past end of value")) 85 | return 0 86 | } 87 | 88 | return r.mr.readInt64() 89 | } 90 | 91 | func (r *ValueReader) ReadOid() Oid { 92 | return Oid(r.ReadInt32()) 93 | } 94 | 95 | // ReadString reads count bytes and returns as string 96 | func (r *ValueReader) ReadString(count int32) string { 97 | if r.err != nil { 98 | return "" 99 | } 100 | 101 | r.valueBytesRemaining -= count 102 | if r.valueBytesRemaining < 0 { 103 | r.Fatal(errors.New("read past end of value")) 104 | return "" 105 | } 106 | 107 | return r.mr.readString(count) 108 | } 109 | 110 | // ReadBytes reads count bytes and returns as []byte 111 | func (r *ValueReader) ReadBytes(count int32) []byte { 112 | if r.err != nil { 113 | return nil 114 | } 115 | 116 | if count < 0 { 117 | r.Fatal(errors.New("count must not be negative")) 118 | return nil 119 | } 120 | 121 | r.valueBytesRemaining -= count 122 | if r.valueBytesRemaining < 0 { 123 | r.Fatal(errors.New("read past end of value")) 124 | return nil 125 | } 126 | 127 | return r.mr.readBytes(count) 128 | } 129 | -------------------------------------------------------------------------------- /vendor/github.com/pkg/errors/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015, Dave Cheney 2 | 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 met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 18 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 20 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 21 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 22 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | -------------------------------------------------------------------------------- /vendor/github.com/pkg/errors/README.md: -------------------------------------------------------------------------------- 1 | # errors [![Travis-CI](https://travis-ci.org/pkg/errors.svg)](https://travis-ci.org/pkg/errors) [![AppVeyor](https://ci.appveyor.com/api/projects/status/b98mptawhudj53ep/branch/master?svg=true)](https://ci.appveyor.com/project/davecheney/errors/branch/master) [![GoDoc](https://godoc.org/github.com/pkg/errors?status.svg)](http://godoc.org/github.com/pkg/errors) [![Report card](https://goreportcard.com/badge/github.com/pkg/errors)](https://goreportcard.com/report/github.com/pkg/errors) 2 | 3 | Package errors provides simple error handling primitives. 4 | 5 | `go get github.com/pkg/errors` 6 | 7 | The traditional error handling idiom in Go is roughly akin to 8 | ```go 9 | if err != nil { 10 | return err 11 | } 12 | ``` 13 | which applied recursively up the call stack results in error reports without context or debugging information. The errors package allows programmers to add context to the failure path in their code in a way that does not destroy the original value of the error. 14 | 15 | ## Adding context to an error 16 | 17 | The errors.Wrap function returns a new error that adds context to the original error. For example 18 | ```go 19 | _, err := ioutil.ReadAll(r) 20 | if err != nil { 21 | return errors.Wrap(err, "read failed") 22 | } 23 | ``` 24 | ## Retrieving the cause of an error 25 | 26 | Using `errors.Wrap` constructs a stack of errors, adding context to the preceding error. Depending on the nature of the error it may be necessary to reverse the operation of errors.Wrap to retrieve the original error for inspection. Any error value which implements this interface can be inspected by `errors.Cause`. 27 | ```go 28 | type causer interface { 29 | Cause() error 30 | } 31 | ``` 32 | `errors.Cause` will recursively retrieve the topmost error which does not implement `causer`, which is assumed to be the original cause. For example: 33 | ```go 34 | switch err := errors.Cause(err).(type) { 35 | case *MyError: 36 | // handle specifically 37 | default: 38 | // unknown error 39 | } 40 | ``` 41 | 42 | [Read the package documentation for more information](https://godoc.org/github.com/pkg/errors). 43 | 44 | ## Contributing 45 | 46 | We welcome pull requests, bug fixes and issue reports. With that said, the bar for adding new symbols to this package is intentionally set high. 47 | 48 | Before proposing a change, please discuss your change by raising an issue. 49 | 50 | ## Licence 51 | 52 | BSD-2-Clause 53 | -------------------------------------------------------------------------------- /vendor/github.com/pkg/errors/appveyor.yml: -------------------------------------------------------------------------------- 1 | version: build-{build}.{branch} 2 | 3 | clone_folder: C:\gopath\src\github.com\pkg\errors 4 | shallow_clone: true # for startup speed 5 | 6 | environment: 7 | GOPATH: C:\gopath 8 | 9 | platform: 10 | - x64 11 | 12 | # http://www.appveyor.com/docs/installed-software 13 | install: 14 | # some helpful output for debugging builds 15 | - go version 16 | - go env 17 | # pre-installed MinGW at C:\MinGW is 32bit only 18 | # but MSYS2 at C:\msys64 has mingw64 19 | - set PATH=C:\msys64\mingw64\bin;%PATH% 20 | - gcc --version 21 | - g++ --version 22 | 23 | build_script: 24 | - go install -v ./... 25 | 26 | test_script: 27 | - set PATH=C:\gopath\bin;%PATH% 28 | - go test -v ./... 29 | 30 | #artifacts: 31 | # - path: '%GOPATH%\bin\*.exe' 32 | deploy: off 33 | -------------------------------------------------------------------------------- /vendor/github.com/pkg/errors/errors.go: -------------------------------------------------------------------------------- 1 | // Package errors provides simple error handling primitives. 2 | // 3 | // The traditional error handling idiom in Go is roughly akin to 4 | // 5 | // if err != nil { 6 | // return err 7 | // } 8 | // 9 | // which applied recursively up the call stack results in error reports 10 | // without context or debugging information. The errors package allows 11 | // programmers to add context to the failure path in their code in a way 12 | // that does not destroy the original value of the error. 13 | // 14 | // Adding context to an error 15 | // 16 | // The errors.Wrap function returns a new error that adds context to the 17 | // original error. For example 18 | // 19 | // _, err := ioutil.ReadAll(r) 20 | // if err != nil { 21 | // return errors.Wrap(err, "read failed") 22 | // } 23 | // 24 | // Retrieving the cause of an error 25 | // 26 | // Using errors.Wrap constructs a stack of errors, adding context to the 27 | // preceding error. Depending on the nature of the error it may be necessary 28 | // to reverse the operation of errors.Wrap to retrieve the original error 29 | // for inspection. Any error value which implements this interface 30 | // 31 | // type causer interface { 32 | // Cause() error 33 | // } 34 | // 35 | // can be inspected by errors.Cause. errors.Cause will recursively retrieve 36 | // the topmost error which does not implement causer, which is assumed to be 37 | // the original cause. For example: 38 | // 39 | // switch err := errors.Cause(err).(type) { 40 | // case *MyError: 41 | // // handle specifically 42 | // default: 43 | // // unknown error 44 | // } 45 | // 46 | // causer interface is not exported by this package, but is considered a part 47 | // of stable public API. 48 | // 49 | // Formatted printing of errors 50 | // 51 | // All error values returned from this package implement fmt.Formatter and can 52 | // be formatted by the fmt package. The following verbs are supported 53 | // 54 | // %s print the error. If the error has a Cause it will be 55 | // printed recursively 56 | // %v see %s 57 | // %+v extended format. Each Frame of the error's StackTrace will 58 | // be printed in detail. 59 | // 60 | // Retrieving the stack trace of an error or wrapper 61 | // 62 | // New, Errorf, Wrap, and Wrapf record a stack trace at the point they are 63 | // invoked. This information can be retrieved with the following interface. 64 | // 65 | // type stackTracer interface { 66 | // StackTrace() errors.StackTrace 67 | // } 68 | // 69 | // Where errors.StackTrace is defined as 70 | // 71 | // type StackTrace []Frame 72 | // 73 | // The Frame type represents a call site in the stack trace. Frame supports 74 | // the fmt.Formatter interface that can be used for printing information about 75 | // the stack trace of this error. For example: 76 | // 77 | // if err, ok := err.(stackTracer); ok { 78 | // for _, f := range err.StackTrace() { 79 | // fmt.Printf("%+s:%d", f) 80 | // } 81 | // } 82 | // 83 | // stackTracer interface is not exported by this package, but is considered a part 84 | // of stable public API. 85 | // 86 | // See the documentation for Frame.Format for more details. 87 | package errors 88 | 89 | import ( 90 | "fmt" 91 | "io" 92 | ) 93 | 94 | // New returns an error with the supplied message. 95 | // New also records the stack trace at the point it was called. 96 | func New(message string) error { 97 | return &fundamental{ 98 | msg: message, 99 | stack: callers(), 100 | } 101 | } 102 | 103 | // Errorf formats according to a format specifier and returns the string 104 | // as a value that satisfies error. 105 | // Errorf also records the stack trace at the point it was called. 106 | func Errorf(format string, args ...interface{}) error { 107 | return &fundamental{ 108 | msg: fmt.Sprintf(format, args...), 109 | stack: callers(), 110 | } 111 | } 112 | 113 | // fundamental is an error that has a message and a stack, but no caller. 114 | type fundamental struct { 115 | msg string 116 | *stack 117 | } 118 | 119 | func (f *fundamental) Error() string { return f.msg } 120 | 121 | func (f *fundamental) Format(s fmt.State, verb rune) { 122 | switch verb { 123 | case 'v': 124 | if s.Flag('+') { 125 | io.WriteString(s, f.msg) 126 | f.stack.Format(s, verb) 127 | return 128 | } 129 | fallthrough 130 | case 's', 'q': 131 | io.WriteString(s, f.msg) 132 | } 133 | } 134 | 135 | type withStack struct { 136 | error 137 | *stack 138 | } 139 | 140 | func (w *withStack) Cause() error { return w.error } 141 | 142 | func (w *withStack) Format(s fmt.State, verb rune) { 143 | switch verb { 144 | case 'v': 145 | if s.Flag('+') { 146 | fmt.Fprintf(s, "%+v", w.Cause()) 147 | w.stack.Format(s, verb) 148 | return 149 | } 150 | fallthrough 151 | case 's': 152 | io.WriteString(s, w.Error()) 153 | case 'q': 154 | fmt.Fprintf(s, "%q", w.Error()) 155 | } 156 | } 157 | 158 | // Wrap returns an error annotating err with message. 159 | // If err is nil, Wrap returns nil. 160 | func Wrap(err error, message string) error { 161 | if err == nil { 162 | return nil 163 | } 164 | err = &withMessage{ 165 | cause: err, 166 | msg: message, 167 | } 168 | return &withStack{ 169 | err, 170 | callers(), 171 | } 172 | } 173 | 174 | // Wrapf returns an error annotating err with the format specifier. 175 | // If err is nil, Wrapf returns nil. 176 | func Wrapf(err error, format string, args ...interface{}) error { 177 | if err == nil { 178 | return nil 179 | } 180 | err = &withMessage{ 181 | cause: err, 182 | msg: fmt.Sprintf(format, args...), 183 | } 184 | return &withStack{ 185 | err, 186 | callers(), 187 | } 188 | } 189 | 190 | type withMessage struct { 191 | cause error 192 | msg string 193 | } 194 | 195 | func (w *withMessage) Error() string { return w.msg + ": " + w.cause.Error() } 196 | func (w *withMessage) Cause() error { return w.cause } 197 | 198 | func (w *withMessage) Format(s fmt.State, verb rune) { 199 | switch verb { 200 | case 'v': 201 | if s.Flag('+') { 202 | fmt.Fprintf(s, "%+v\n", w.Cause()) 203 | io.WriteString(s, w.msg) 204 | return 205 | } 206 | fallthrough 207 | case 's', 'q': 208 | io.WriteString(s, w.Error()) 209 | } 210 | } 211 | 212 | // Cause returns the underlying cause of the error, if possible. 213 | // An error value has a cause if it implements the following 214 | // interface: 215 | // 216 | // type causer interface { 217 | // Cause() error 218 | // } 219 | // 220 | // If the error does not implement Cause, the original error will 221 | // be returned. If the error is nil, nil will be returned without further 222 | // investigation. 223 | func Cause(err error) error { 224 | type causer interface { 225 | Cause() error 226 | } 227 | 228 | for err != nil { 229 | cause, ok := err.(causer) 230 | if !ok { 231 | break 232 | } 233 | err = cause.Cause() 234 | } 235 | return err 236 | } 237 | -------------------------------------------------------------------------------- /vendor/github.com/pkg/errors/stack.go: -------------------------------------------------------------------------------- 1 | package errors 2 | 3 | import ( 4 | "fmt" 5 | "io" 6 | "path" 7 | "runtime" 8 | "strings" 9 | ) 10 | 11 | // Frame represents a program counter inside a stack frame. 12 | type Frame uintptr 13 | 14 | // pc returns the program counter for this frame; 15 | // multiple frames may have the same PC value. 16 | func (f Frame) pc() uintptr { return uintptr(f) - 1 } 17 | 18 | // file returns the full path to the file that contains the 19 | // function for this Frame's pc. 20 | func (f Frame) file() string { 21 | fn := runtime.FuncForPC(f.pc()) 22 | if fn == nil { 23 | return "unknown" 24 | } 25 | file, _ := fn.FileLine(f.pc()) 26 | return file 27 | } 28 | 29 | // line returns the line number of source code of the 30 | // function for this Frame's pc. 31 | func (f Frame) line() int { 32 | fn := runtime.FuncForPC(f.pc()) 33 | if fn == nil { 34 | return 0 35 | } 36 | _, line := fn.FileLine(f.pc()) 37 | return line 38 | } 39 | 40 | // Format formats the frame according to the fmt.Formatter interface. 41 | // 42 | // %s source file 43 | // %d source line 44 | // %n function name 45 | // %v equivalent to %s:%d 46 | // 47 | // Format accepts flags that alter the printing of some verbs, as follows: 48 | // 49 | // %+s path of source file relative to the compile time GOPATH 50 | // %+v equivalent to %+s:%d 51 | func (f Frame) Format(s fmt.State, verb rune) { 52 | switch verb { 53 | case 's': 54 | switch { 55 | case s.Flag('+'): 56 | pc := f.pc() 57 | fn := runtime.FuncForPC(pc) 58 | if fn == nil { 59 | io.WriteString(s, "unknown") 60 | } else { 61 | file, _ := fn.FileLine(pc) 62 | fmt.Fprintf(s, "%s\n\t%s", fn.Name(), file) 63 | } 64 | default: 65 | io.WriteString(s, path.Base(f.file())) 66 | } 67 | case 'd': 68 | fmt.Fprintf(s, "%d", f.line()) 69 | case 'n': 70 | name := runtime.FuncForPC(f.pc()).Name() 71 | io.WriteString(s, funcname(name)) 72 | case 'v': 73 | f.Format(s, 's') 74 | io.WriteString(s, ":") 75 | f.Format(s, 'd') 76 | } 77 | } 78 | 79 | // StackTrace is stack of Frames from innermost (newest) to outermost (oldest). 80 | type StackTrace []Frame 81 | 82 | func (st StackTrace) Format(s fmt.State, verb rune) { 83 | switch verb { 84 | case 'v': 85 | switch { 86 | case s.Flag('+'): 87 | for _, f := range st { 88 | fmt.Fprintf(s, "\n%+v", f) 89 | } 90 | case s.Flag('#'): 91 | fmt.Fprintf(s, "%#v", []Frame(st)) 92 | default: 93 | fmt.Fprintf(s, "%v", []Frame(st)) 94 | } 95 | case 's': 96 | fmt.Fprintf(s, "%s", []Frame(st)) 97 | } 98 | } 99 | 100 | // stack represents a stack of program counters. 101 | type stack []uintptr 102 | 103 | func (s *stack) Format(st fmt.State, verb rune) { 104 | switch verb { 105 | case 'v': 106 | switch { 107 | case st.Flag('+'): 108 | for _, pc := range *s { 109 | f := Frame(pc) 110 | fmt.Fprintf(st, "\n%+v", f) 111 | } 112 | } 113 | } 114 | } 115 | 116 | func (s *stack) StackTrace() StackTrace { 117 | f := make([]Frame, len(*s)) 118 | for i := 0; i < len(f); i++ { 119 | f[i] = Frame((*s)[i]) 120 | } 121 | return f 122 | } 123 | 124 | func callers() *stack { 125 | const depth = 32 126 | var pcs [depth]uintptr 127 | n := runtime.Callers(3, pcs[:]) 128 | var st stack = pcs[0:n] 129 | return &st 130 | } 131 | 132 | // funcname removes the path prefix component of a function's name reported by func.Name(). 133 | func funcname(name string) string { 134 | i := strings.LastIndex(name, "/") 135 | name = name[i+1:] 136 | i = strings.Index(name, ".") 137 | return name[i+1:] 138 | } 139 | 140 | func trimGOPATH(name, file string) string { 141 | // Here we want to get the source file path relative to the compile time 142 | // GOPATH. As of Go 1.6.x there is no direct way to know the compiled 143 | // GOPATH at runtime, but we can infer the number of path segments in the 144 | // GOPATH. We note that fn.Name() returns the function name qualified by 145 | // the import path, which does not include the GOPATH. Thus we can trim 146 | // segments from the beginning of the file path until the number of path 147 | // separators remaining is one more than the number of path separators in 148 | // the function name. For example, given: 149 | // 150 | // GOPATH /home/user 151 | // file /home/user/src/pkg/sub/file.go 152 | // fn.Name() pkg/sub.Type.Method 153 | // 154 | // We want to produce: 155 | // 156 | // pkg/sub/file.go 157 | // 158 | // From this we can easily see that fn.Name() has one less path separator 159 | // than our desired output. We count separators from the end of the file 160 | // path until it finds two more than in the function name and then move 161 | // one character forward to preserve the initial path segment without a 162 | // leading separator. 163 | const sep = "/" 164 | goal := strings.Count(name, sep) + 2 165 | i := len(file) 166 | for n := 0; n < goal; n++ { 167 | i = strings.LastIndex(file[:i], sep) 168 | if i == -1 { 169 | // not enough separators found, set i so that the slice expression 170 | // below leaves file unmodified 171 | i = -len(sep) 172 | break 173 | } 174 | } 175 | // get back to 0 or trim the leading separator 176 | file = file[i+len(sep):] 177 | return file 178 | } 179 | -------------------------------------------------------------------------------- /vendor/vendor.json: -------------------------------------------------------------------------------- 1 | { 2 | "comment": "", 3 | "heroku": { 4 | "install": [ 5 | "./cmd/..." 6 | ] 7 | }, 8 | "ignore": "test solaris", 9 | "package": [ 10 | { 11 | "checksumSHA1": "DWPL08pD/SQ2GzLfoR7ZXnjj7Sw=", 12 | "path": "github.com/Sirupsen/logrus", 13 | "revision": "4b6ea7319e214d98c938f12692336f7ca9348d6b" 14 | }, 15 | { 16 | "checksumSHA1": "Yi01kv5j7xmEXhv1kPTQnM8O8og=", 17 | "path": "github.com/bgentry/que-go", 18 | "revision": "e2fa4b8f0b5ef9ca86ab2d59f0ace88b96ac1a50" 19 | }, 20 | { 21 | "checksumSHA1": "ffSK5lJrsPqKc7iJPH4Gu9pIO1k=", 22 | "path": "github.com/jackc/pgx", 23 | "revision": "9edd770c70e274b7ef67fa9f4039c824be0f8bda" 24 | }, 25 | { 26 | "checksumSHA1": "QoVjlQFru1ixgV8vh63T4/JAtLI=", 27 | "path": "github.com/pkg/errors", 28 | "revision": "a22138067af1c4942683050411a841ade67fe1eb", 29 | "revisionTime": "2016-08-08T05:55:40Z" 30 | } 31 | ], 32 | "rootPath": "github.com/heroku-examples/go-queue-example" 33 | } 34 | --------------------------------------------------------------------------------