Skip to content
Permalink
Browse files

fix log flushing, make it synchronous. Closes #545

  • Loading branch information...
tj committed Feb 23, 2018
1 parent fdd6b59 commit ffbcfcf83214101530d7435d2707506dd6261cb7
@@ -469,24 +469,6 @@ Would be collected as:
ERROR: Failed to sign in: something broke
```

Multi-line indented logs are also supported, and are treated as a single message. For example:

```js
console.log('User signed in')
console.log(' name: %s', user.name)
console.log(' email: %s', user.email)
```

Would be collected as the single entry:

```
INFO: User signed in
name: tj
email: tj@apex.sh
```

This feature is especially useful for stack traces.

### JSON

The second option is structured logging with JSON events, which is preferred as it allows you to query against specific fields and treat logs like events.
@@ -27,11 +27,6 @@ import (
// log context.
var ctx = logs.Plugin("relay")

// flusher is the interface used for flushing logs.
type flusher interface {
Flush()
}

// DefaultTransport used by relay.
var DefaultTransport http.RoundTripper = &http.Transport{
DialContext: (&net.Dialer{
@@ -106,7 +101,6 @@ func New(c *up.Config) (http.Handler, error) {
stderr: writer.New(stderr, ctx),
}

defer p.flushLogs()
if err := p.Start(); err != nil {
return nil, err
}
@@ -139,8 +133,6 @@ func (p *Proxy) Start() error {

// Restart the server.
func (p *Proxy) Restart() error {
defer p.flushLogs()

ctx.Warn("restarting")
p.restarts++

@@ -156,9 +148,7 @@ func (p *Proxy) Restart() error {
func (p *Proxy) ServeHTTP(w http.ResponseWriter, r *http.Request) {
p.mu.Lock()
defer p.mu.Unlock()

p.ReverseProxy.ServeHTTP(w, r)
p.flushLogs()
}

// RoundTrip implementation.
@@ -329,12 +319,6 @@ func (p *Proxy) command(s string, env []string) *exec.Cmd {
return cmd
}

// flushLogs flushes any pending logs.
func (p *Proxy) flushLogs() {
p.stdout.Flush()
p.stderr.Flush()
}

// env returns an environment variable.
func env(name string, val interface{}) string {
return fmt.Sprintf("%s=%v", name, val)

This file was deleted.

Oops, something went wrong.

This file was deleted.

Oops, something went wrong.
@@ -4,64 +4,48 @@
package writer

import (
"bufio"
"bytes"
"encoding/json"
"io"

"github.com/apex/log"
"github.com/apex/up/internal/linereader"
"github.com/apex/up/internal/util"
"github.com/pkg/errors"
)

// Writer struct.
type Writer struct {
log log.Interface
level log.Level
}

// New writer with the given log level.
func New(l log.Level, ctx log.Interface) *Writer {
pr, pw := io.Pipe()

w := &Writer{
PipeWriter: pw,
LineReader: linereader.New(pr),
done: make(chan struct{}),
}

lw := &logWriter{
return &Writer{
log: ctx,
level: l,
}

go func() {
defer close(w.done)
io.Copy(lw, w.LineReader)
}()

return w
}

// Writer is a writer which copies lines with
// indentation support to a logWriter.
type Writer struct {
*io.PipeWriter
*linereader.LineReader
done chan struct{}
}
// Write implementation.
func (w *Writer) Write(b []byte) (int, error) {
s := bufio.NewScanner(bytes.NewReader(b))

// Close implementation.
func (w *Writer) Close() error {
if err := w.PipeWriter.Close(); err != nil {
return err
for s.Scan() {
if n, err := w.write(s.Bytes()); err != nil {
return n, err
}
}

<-w.done
return nil
}
if err := s.Err(); err != nil {
return 0, err
}

// logWriter is a write which logs distinct writes as log lines.
type logWriter struct {
log log.Interface
level log.Level
return len(b), nil
}

// Write implementation.
func (w *logWriter) Write(b []byte) (int, error) {
// write the line.
func (w *Writer) write(b []byte) (int, error) {
if util.IsJSONLog(string(b)) {
return w.writeJSON(b)
}
@@ -70,7 +54,7 @@ func (w *logWriter) Write(b []byte) (int, error) {
}

// writeJSON writes a json log, interpreting it as a log.Entry.
func (w *logWriter) writeJSON(b []byte) (int, error) {
func (w *Writer) writeJSON(b []byte) (int, error) {
// TODO: make this less ugly in apex/log,
// you should be able to write an arbitrary Entry.
var e log.Entry
@@ -97,7 +81,7 @@ func (w *logWriter) writeJSON(b []byte) (int, error) {
}

// writeText writes plain text.
func (w *logWriter) writeText(b []byte) (int, error) {
func (w *Writer) writeText(b []byte) (int, error) {
switch w.level {
case log.InfoLevel:
w.log.Info(string(b))
Oops, something went wrong.

0 comments on commit ffbcfcf

Please sign in to comment.
You can’t perform that action at this time.