diff --git a/README.md b/README.md index 9d8678df5..ab16dfce3 100644 --- a/README.md +++ b/README.md @@ -23,12 +23,10 @@ curl -H "Content-Type: application/json" -X POST -d '{ }' http://localhost:8080/v1/apps ``` -Now that we have an app, we can add routes to functions. +Now that we have an app, we can map routes to functions. ### Add a route to a Function - - ```sh curl -H "Content-Type: application/json" -X POST -d '{ "route": { diff --git a/api/runner/logger.go b/api/runner/logger.go new file mode 100644 index 000000000..29d625e60 --- /dev/null +++ b/api/runner/logger.go @@ -0,0 +1,37 @@ +// This reads STDERR output from a container and outputs it in a parseable structured log format, see: https://github.com/iron-io/functions/issues/76 +package runner + +import ( + "bufio" + "io" + + "github.com/Sirupsen/logrus" +) + +type FuncLogger struct { + r io.Reader + w io.Writer +} + +func NewFuncLogger(appName, path, function, requestID string) io.Writer { + r, w := io.Pipe() + funcLogger := &FuncLogger{ + r: r, + w: w, + } + log := logrus.WithFields(logrus.Fields{"app_name": appName, "path": path, "function": function, "request_id": requestID}) + go func(reader io.Reader) { + scanner := bufio.NewScanner(reader) + for scanner.Scan() { + log.Println(scanner.Text()) + } + if err := scanner.Err(); err != nil { + log.WithError(err).Println("There was an error with the scanner in attached container") + } + }(r) + return funcLogger +} + +func (l *FuncLogger) Write(p []byte) (n int, err error) { + return l.w.Write(p) +} diff --git a/api/server/runner.go b/api/server/runner.go index 3be2d3be7..72f2bf984 100644 --- a/api/server/runner.go +++ b/api/server/runner.go @@ -112,7 +112,9 @@ func handleRunner(c *gin.Context) { log.WithField("routes", routes).Debug("Got routes from datastore") for _, el := range routes { if params, match := matchRoute(el.Path, route); match { - var stdout, stderr bytes.Buffer + + var stdout bytes.Buffer // TODO: should limit the size of this, error if gets too big. akin to: https://golang.org/pkg/io/#LimitReader + stderr := runner.NewFuncLogger(appName, route, el.Image, reqID) envVars := map[string]string{ "METHOD": c.Request.Method, @@ -142,7 +144,7 @@ func handleRunner(c *gin.Context) { ID: reqID, AppName: appName, Stdout: &stdout, - Stderr: &stderr, + Stderr: stderr, Env: envVars, } @@ -157,7 +159,7 @@ func handleRunner(c *gin.Context) { if result.Status() == "success" { c.Data(http.StatusOK, "", stdout.Bytes()) } else { - log.WithFields(logrus.Fields{"app": appName, "route": el, "req_id": reqID}).Debug(stderr.String()) + // log.WithFields(logrus.Fields{"app": appName, "route": el, "req_id": reqID}).Debug(stderr.String()) c.AbortWithStatus(http.StatusInternalServerError) } } diff --git a/examples/hello/hello.rb b/examples/hello/hello.rb index 71ec89bba..f171f4b03 100644 --- a/examples/hello/hello.rb +++ b/examples/hello/hello.rb @@ -6,7 +6,7 @@ name = "World" # or using env vars: ENV['PAYLOAD'] payload = ENV['PAYLOAD'] -puts 'ARGF: ' + payload.inspect +STDERR.puts 'payload: ' + payload.inspect if payload != "" payload = JSON.parse(payload) name = payload['name']