add logs to stage output

pull/1/head
Brad Rydzewski 5 years ago
parent 48f68a1e1b
commit 0c4ca16947

@ -51,18 +51,30 @@ func HandleIndex(t *history.History) http.HandlerFunc {
// HandleStage returns a http.HandlerFunc that displays the
// stage details.
func HandleStage(t *history.History) http.HandlerFunc {
func HandleStage(hist *history.History, logger *hook.Hook) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
id, _ := strconv.ParseInt(r.FormValue("id"), 10, 64)
for _, e := range t.Entries() {
if e.Stage.ID == id {
nocache(w)
render(w, "stage.tmpl", e)
return
}
// filter logs by stage id.
logs := logger.Filter(func(entry *hook.Entry) bool {
return entry.Data["stage.id"] == id
})
// find pipeline by stage id
entry := hist.Entry(id)
if entry == nil {
w.WriteHeader(404)
return
}
// TODO(bradrydzewski) we need an error template.
w.WriteHeader(404)
nocache(w)
render(w, "stage.tmpl", struct {
*history.Entry
Logs []*hook.Entry
}{
Entry: entry,
Logs: logs,
})
}
}

@ -43,7 +43,7 @@ func New(tracer *history.History, history *hook.Hook, config Config) http.Handle
// dashboard handles.
mux.Handle("/static/", http.StripPrefix("/static/", fs))
mux.Handle("/logs", auth(handler.HandleLogHistory(history)))
mux.Handle("/view", auth(handler.HandleStage(tracer)))
mux.Handle("/view", auth(handler.HandleStage(tracer, history)))
mux.Handle("/", auth(handler.HandleIndex(tracer)))
return mux
}

@ -173,7 +173,7 @@ a.card {
.steps .step {
display: grid;
grid-gap: 10px 0px;
grid-template-columns: 30px auto;
grid-template-columns: 30px auto 100px;
padding: 10px 15px;
}
@ -218,6 +218,16 @@ a.card {
display: none;
}
.steps .status-name {
align-items: center;
color: rgba(30,55,90,.6);
display: flex;
font-size: 14px;
font-style: italic;
justify-content: flex-end;
text-transform: capitalize;
}
/**
* breadcrumb component
*/

@ -228,8 +228,8 @@ var files = map[string]file{
data: file11,
FileInfo: &fileInfo{
name: "style.css",
size: 8275,
modTime: time.Unix(1563076316, 0),
size: 8488,
modTime: time.Unix(1563131883, 0),
},
},
"/timeago.js": {
@ -1337,7 +1337,7 @@ a.card {
.steps .step {
display: grid;
grid-gap: 10px 0px;
grid-template-columns: 30px auto;
grid-template-columns: 30px auto 100px;
padding: 10px 15px;
}
@ -1382,6 +1382,16 @@ a.card {
display: none;
}
.steps .status-name {
align-items: center;
color: rgba(30,55,90,.6);
display: flex;
font-size: 14px;
font-style: italic;
justify-content: flex-end;
text-transform: capitalize;
}
/**
* breadcrumb component
*/

@ -2,7 +2,9 @@
<html>
<head>
<meta charset="UTF-8">
<meta http-equiv="refresh" content="10">
{{- if not (done .Stage.Status) }}
<meta http-equiv="refresh" content="30">
{{- end }}
<title>Dashboard</title>
<link rel="stylesheet" type="text/css" href="/static/reset.css">
<link rel="stylesheet" type="text/css" href="/static/style.css">
@ -61,20 +63,34 @@
{{ if .Stage.Steps }}
<div class="card steps">
<header>
<span class="status {{ .Stage.Status }}"></span>
<span class="name">{{ .Stage.Name }}</span>
</header>
<div class="body">
{{ range .Stage.Steps }}
<div class="step">
<span class="status {{ .Status }}"></span>
<span class="name"> {{ .Name }}</span>
<span class="name">{{ .Name }}</span>
<span class="status-name">{{ .Status }}</span>
</div>
{{ end }}
</div>
</div>
{{ end }}
{{ if .Logs }}
<div class="logs">
{{ range .Logs }}
<div class="entry">
<span class="level {{ .Level }}">{{ .Level }}</span>
<span class="message">{{ .Message }}</span>
<span class="fields">
{{ range $key, $val := .Data }}
<span><em>{{ $key }}</em>{{ $val }}</span>
{{ end }}
</span>
<span class="time" datetime="{{ timestamp .Unix }}"></span>
</div>
{{ end }}
</div>
{{ end }}
</section>
</main>

@ -103,4 +103,7 @@ var funcMap = map[string]interface{}{
"tag": func(s string) string {
return strings.TrimPrefix(s, "refs/tags/")
},
"done": func(s string) bool {
return s != "pending" && s != "running"
},
}

@ -33,4 +33,7 @@ var funcMap = map[string]interface{}{
"tag": func(s string) string {
return strings.TrimPrefix(s, "refs/tags/")
},
"done": func(s string) bool {
return s != "pending" && s != "running"
},
}

@ -164,7 +164,9 @@ var stage = `<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta http-equiv="refresh" content="10">
{{- if not (done .Stage.Status) }}
<meta http-equiv="refresh" content="30">
{{- end }}
<title>Dashboard</title>
<link rel="stylesheet" type="text/css" href="/static/reset.css">
<link rel="stylesheet" type="text/css" href="/static/style.css">
@ -223,20 +225,34 @@ var stage = `<!DOCTYPE html>
{{ if .Stage.Steps }}
<div class="card steps">
<header>
<span class="status {{ .Stage.Status }}"></span>
<span class="name">{{ .Stage.Name }}</span>
</header>
<div class="body">
{{ range .Stage.Steps }}
<div class="step">
<span class="status {{ .Status }}"></span>
<span class="name"> {{ .Name }}</span>
<span class="name">{{ .Name }}</span>
<span class="status-name">{{ .Status }}</span>
</div>
{{ end }}
</div>
</div>
{{ end }}
{{ if .Logs }}
<div class="logs">
{{ range .Logs }}
<div class="entry">
<span class="level {{ .Level }}">{{ .Level }}</span>
<span class="message">{{ .Message }}</span>
<span class="fields">
{{ range $key, $val := .Data }}
<span><em>{{ $key }}</em>{{ $val }}</span>
{{ end }}
</span>
<span class="time" datetime="{{ timestamp .Unix }}"></span>
</div>
{{ end }}
</div>
{{ end }}
</section>
</main>

@ -15,7 +15,7 @@
},
"Stage": {
"Name": "test",
"Status": "success",
"Status": "running",
"Started": 1563059000,
"Created": 1563059000,
"Steps": [
@ -24,5 +24,71 @@
{ "Name": "test", "Status": "success" },
{ "Name": "deploy", "Status": "success" }
]
}
},
"Logs": [
{
"Level": "debug",
"Message": "updated stage to running",
"Data": {
"build.id": 110,
"build.number": 110,
"repo.id": 48,
"repo.name": "hello-world",
"repo.namespace": "octocat",
"stage.id": 110,
"stage.name": "test",
"stage.number": 1,
"thread": 1
},
"Unix": 1563058875
},
{
"Level": "debug",
"Message": "process started",
"Data": {
"build.id": 110,
"build.number": 110,
"repo.id": 48,
"repo.name": "hello-world",
"repo.namespace": "octocat",
"stage.id": 110,
"stage.name": "test",
"stage.number": 1,
"thread": 1
},
"Unix": 1563058875
},
{
"Level": "debug",
"Message": "process finished",
"Data": {
"build.id": 110,
"build.number": 110,
"repo.id": 48,
"repo.name": "hello-world",
"repo.namespace": "octocat",
"stage.id": 110,
"stage.name": "test",
"stage.number": 1,
"thread": 1
},
"Unix": 1563058975
},
{
"Level": "debug",
"Message": "updated stage to complete",
"Data": {
"build.id": 110,
"build.number": 110,
"repo.id": 48,
"repo.name": "hello-world",
"repo.namespace": "octocat",
"stage.id": 110,
"stage.name": "test",
"stage.number": 1,
"thread": 1
},
"Unix": 1563058977
}
]
}

@ -85,6 +85,20 @@ func (h *Hook) Entries() []*Entry {
return entries
}
// Filter returns a list of all entries for which the filter
// function returns true.
func (h *Hook) Filter(filter func(*Entry) bool) []*Entry {
h.RLock()
defer h.RUnlock()
var entries []*Entry
for _, entry := range h.entries {
if filter(entry) {
entries = append(entries, copyEntry(entry))
}
}
return entries
}
// helper funtion copies an entry for threadsafe access.
func copyEntry(src *Entry) *Entry {
dst := new(Entry)

@ -107,3 +107,38 @@ func TestHistory(t *testing.T) {
t.Log(diff)
}
}
func TestFilter(t *testing.T) {
hook := New()
now := time.Now()
hook.Fire(&logrus.Entry{
Level: logrus.DebugLevel,
Message: "foo",
Data: logrus.Fields{"foo": "bar"},
Time: now,
})
hook.Fire(&logrus.Entry{
Level: logrus.InfoLevel,
Message: "bar",
Data: logrus.Fields{"baz": "qux"},
Time: now,
})
expect := []*Entry{
{
Level: LevelDebug,
Message: "foo",
Data: logrus.Fields{"foo": "bar"},
Unix: now.Unix(),
},
}
entries := hook.Filter(func(entry *Entry) bool {
return entry.Data["foo"] == "bar"
})
if diff := cmp.Diff(entries, expect); diff != "" {
t.Errorf("Entries should return an exact copy of all entries")
t.Log(diff)
}
}

@ -64,6 +64,20 @@ func (h *History) Entries() []*Entry {
return entries
}
// Entry returns the entry by id.
func (h *History) Entry(id int64) *Entry {
h.Lock()
defer h.Unlock()
for _, src := range h.items {
if src.Stage.ID == id {
dst := new(Entry)
*dst = *src
return dst
}
}
return nil
}
// Limit returns the history limit.
func (h *History) Limit() int {
if h.limit == 0 {

@ -116,6 +116,21 @@ func TestEntries(t *testing.T) {
}
}
func TestEntry(t *testing.T) {
s1 := &drone.Stage{ID: 1}
s2 := &drone.Stage{ID: 2}
v := History{}
v.items = append(v.items, &Entry{Stage: s1}, &Entry{Stage: s2})
if got := v.Entry(99); got != nil {
t.Errorf("Want nil when stage not found")
}
if got := v.Entry(s1.ID); got == nil {
t.Errorf("Want entry by stage ID, got nil")
return
}
}
func TestLimit(t *testing.T) {
v := History{}
if got, want := v.Limit(), defaultLimit; got != want {

Loading…
Cancel
Save