This repository has been archived by the owner on May 19, 2020. It is now read-only.
/
log.go
95 lines (85 loc) · 2.78 KB
/
log.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
package controllers
import (
"github.com/cloudfoundry/loggregatorlib/logmessage"
"github.com/gocraft/web"
"github.com/gogo/protobuf/proto"
"bytes"
"encoding/json"
"fmt"
"io"
"mime"
"mime/multipart"
"net/http"
)
// LogContext stores the session info and access token per user.
// All routes within LogContext represent the Loggregator routes
type LogContext struct {
*SecureContext // Required.
}
// RecentLogs returns a log dump of the given app.
func (c *LogContext) RecentLogs(rw web.ResponseWriter, req *web.Request) {
reqURL := fmt.Sprintf("%s/%s", c.Settings.LogURL, "recent?app="+req.URL.Query().Get("app"))
c.Proxy(rw, req.Request, reqURL, c.logMessageResponseHandler)
}
// logMessageResponseHandler is a response handler that constructs log messages structs from the response
// given by the loggregator.
func (c *LogContext) logMessageResponseHandler(rw http.ResponseWriter, response *http.Response) {
messages, err := c.ParseLogMessages(&(response.Body), response.Header.Get("Content-Type"))
if err != nil {
rw.WriteHeader(http.StatusInternalServerError)
rw.Write([]byte(err.Error()))
return
}
rw.WriteHeader(response.StatusCode)
rw.Write(messages.Bytes())
return
}
// ParseLogMessages is a modified version of httpRecent.
// https://github.com/cloudfoundry/loggregator_consumer/blob/89d7fe237afae1e8222554359ec03b72c8466d10/consumer.go#L145
// Also, when using their Recent function, we would get unauthorized errors. If we make the request ourselves, it works.
// TODO eventually figure out the cause of the unauthorized errors
func (c *LogContext) ParseLogMessages(body *io.ReadCloser, contentType string) (*bytes.Buffer, error) {
_, params, err := mime.ParseMediaType(contentType)
if err != nil {
return nil, err
}
var msg logmessage.LogMessage
reader := multipart.NewReader(*body, params["boundary"])
var buffer bytes.Buffer
var messages bytes.Buffer
firstNotInserted := true
messages.WriteRune('[')
for part, loopErr := reader.NextPart(); loopErr == nil; part, loopErr = reader.NextPart() {
// Skip putting a comma if we haven't put the first element in there yet.
if !firstNotInserted {
messages.WriteRune(',')
} else {
firstNotInserted = false
}
// Clear out temporary buffer.
buffer.Reset()
msg = logmessage.LogMessage{}
// Read raw bytes.
_, err := buffer.ReadFrom(part)
if err != nil {
break
}
// Try to unmarshal the bytes into a LogMessage struct.
proto.Unmarshal(buffer.Bytes(), &msg)
// Marshal the data into json with only the Message.
json, err := json.Marshal(struct {
Message string `json:"message"`
}{
Message: string(msg.GetMessage()),
})
if err != nil {
return nil, err
}
// Write it to our buffer.
messages.Write(json)
part.Close()
}
messages.WriteRune(']')
buffer.Reset()
return &messages, nil
}