Skip to content

Commit 71603fa

Browse files
committed
internal/relui: persist logs to database
Save log output from workflow tasks in the database. Render logs in the UI alongside each task. This will almost certainly be a performance problem if we have many logs until we implement pagination. For golang/go#47401 Change-Id: I4ddc3d7845e4559cc636b3b7972e0adefe9fcec4 Reviewed-on: https://go-review.googlesource.com/c/build/+/353170 Trust: Alexander Rakoczy <[email protected]> Run-TryBot: Alexander Rakoczy <[email protected]> TryBot-Result: Go Bot <[email protected]> Reviewed-by: Carlos Amedee <[email protected]> Reviewed-by: Heschi Kreinick <[email protected]>
1 parent 7959cfa commit 71603fa

16 files changed

+537
-136
lines changed

cmd/relui/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ postgres-dev: $(DEV_CFG)/pgpass
3333

3434
schema.sql: $(MIGRATION_FILES) $(GO_FILES)
3535
docker build -f Dockerfile -t golang/relui:$(VERSION) ../..
36-
docker run --rm --name=relui-dev-migrate -v $(POSTGRES_RUN_DEV) $(DOCKER_TAG) --only-migrate
36+
docker run --rm --name=relui-dev-migrate -v $(POSTGRES_RUN_DEV) -e PGUSER=$(POSTGRES_USER) -e PGDATABASE=relui-dev $(DOCKER_TAG) --only-migrate
3737
docker exec postgres-dev pg_dump --username=$(POSTGRES_USER) --schema-only relui-dev > schema.sql
3838

3939
.PHONY: test

cmd/relui/schema.sql

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,44 @@ CREATE TABLE public.migrations (
3232

3333
ALTER TABLE public.migrations OWNER TO postgres;
3434

35+
--
36+
-- Name: task_logs; Type: TABLE; Schema: public; Owner: postgres
37+
--
38+
39+
CREATE TABLE public.task_logs (
40+
id integer NOT NULL,
41+
workflow_id uuid NOT NULL,
42+
task_name text NOT NULL,
43+
body text NOT NULL,
44+
created_at timestamp with time zone DEFAULT CURRENT_TIMESTAMP NOT NULL,
45+
updated_at timestamp with time zone DEFAULT CURRENT_TIMESTAMP NOT NULL
46+
);
47+
48+
49+
ALTER TABLE public.task_logs OWNER TO postgres;
50+
51+
--
52+
-- Name: task_logs_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
53+
--
54+
55+
CREATE SEQUENCE public.task_logs_id_seq
56+
AS integer
57+
START WITH 1
58+
INCREMENT BY 1
59+
NO MINVALUE
60+
NO MAXVALUE
61+
CACHE 1;
62+
63+
64+
ALTER TABLE public.task_logs_id_seq OWNER TO postgres;
65+
66+
--
67+
-- Name: task_logs_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
68+
--
69+
70+
ALTER SEQUENCE public.task_logs_id_seq OWNED BY public.task_logs.id;
71+
72+
3573
--
3674
-- Name: tasks; Type: TABLE; Schema: public; Owner: postgres
3775
--
@@ -64,6 +102,13 @@ CREATE TABLE public.workflows (
64102

65103
ALTER TABLE public.workflows OWNER TO postgres;
66104

105+
--
106+
-- Name: task_logs id; Type: DEFAULT; Schema: public; Owner: postgres
107+
--
108+
109+
ALTER TABLE ONLY public.task_logs ALTER COLUMN id SET DEFAULT nextval('public.task_logs_id_seq'::regclass);
110+
111+
67112
--
68113
-- Name: migrations migrations_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres
69114
--
@@ -72,6 +117,14 @@ ALTER TABLE ONLY public.migrations
72117
ADD CONSTRAINT migrations_pkey PRIMARY KEY (version);
73118

74119

120+
--
121+
-- Name: task_logs task_logs_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres
122+
--
123+
124+
ALTER TABLE ONLY public.task_logs
125+
ADD CONSTRAINT task_logs_pkey PRIMARY KEY (id);
126+
127+
75128
--
76129
-- Name: tasks tasks_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres
77130
--
@@ -88,6 +141,14 @@ ALTER TABLE ONLY public.workflows
88141
ADD CONSTRAINT workflows_pkey PRIMARY KEY (id);
89142

90143

144+
--
145+
-- Name: task_logs task_logs_workflow_id_task_name_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres
146+
--
147+
148+
ALTER TABLE ONLY public.task_logs
149+
ADD CONSTRAINT task_logs_workflow_id_task_name_fkey FOREIGN KEY (workflow_id, task_name) REFERENCES public.tasks(workflow_id, name);
150+
151+
91152
--
92153
-- Name: tasks tasks_workflow_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres
93154
--

internal/relui/db/models.go

Lines changed: 9 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

internal/relui/db/workflows.sql.go

Lines changed: 103 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

internal/relui/listener.go

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
// Copyright 2021 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
package relui
6+
7+
import (
8+
"context"
9+
"database/sql"
10+
"encoding/json"
11+
"fmt"
12+
"log"
13+
"time"
14+
15+
"github.com/google/uuid"
16+
"github.com/jackc/pgx/v4"
17+
"github.com/jackc/pgx/v4/pgxpool"
18+
"golang.org/x/build/internal/relui/db"
19+
"golang.org/x/build/internal/workflow"
20+
)
21+
22+
// listener implements workflow.Listener for recording workflow state.
23+
type listener struct {
24+
db *pgxpool.Pool
25+
}
26+
27+
// TaskStateChanged is called whenever a task is updated by the
28+
// workflow. The workflow.TaskState is persisted as a db.Task,
29+
// creating or updating a row as necessary.
30+
func (l *listener) TaskStateChanged(workflowID uuid.UUID, taskName string, state *workflow.TaskState) error {
31+
log.Printf("TaskStateChanged(%q, %q, %v)", workflowID, taskName, state)
32+
ctx, cancel := context.WithCancel(context.Background())
33+
defer cancel()
34+
result, err := json.Marshal(state.Result)
35+
if err != nil {
36+
return err
37+
}
38+
err = l.db.BeginFunc(ctx, func(tx pgx.Tx) error {
39+
q := db.New(tx)
40+
updated := time.Now()
41+
_, err := q.UpsertTask(ctx, db.UpsertTaskParams{
42+
WorkflowID: workflowID,
43+
Name: taskName,
44+
Finished: state.Finished,
45+
Result: sql.NullString{String: string(result), Valid: len(result) > 0},
46+
Error: sql.NullString{},
47+
CreatedAt: updated,
48+
UpdatedAt: updated,
49+
})
50+
return err
51+
})
52+
if err != nil {
53+
log.Printf("TaskStateChanged(%q, %q, %v) = %v", workflowID, taskName, state, err)
54+
}
55+
return err
56+
}
57+
58+
func (l *listener) Logger(workflowID uuid.UUID, taskName string) workflow.Logger {
59+
return &postgresLogger{
60+
db: l.db,
61+
workflowID: workflowID,
62+
taskName: taskName,
63+
}
64+
}
65+
66+
// postgresLogger logs task output to the database. It implements workflow.Logger.
67+
type postgresLogger struct {
68+
db *pgxpool.Pool
69+
workflowID uuid.UUID
70+
taskName string
71+
}
72+
73+
func (l *postgresLogger) Printf(format string, v ...interface{}) {
74+
ctx := context.Background()
75+
err := l.db.BeginFunc(ctx, func(tx pgx.Tx) error {
76+
q := db.New(tx)
77+
body := fmt.Sprintf(format, v...)
78+
_, err := q.CreateTaskLog(ctx, db.CreateTaskLogParams{
79+
WorkflowID: l.workflowID,
80+
TaskName: l.taskName,
81+
Body: body,
82+
})
83+
if err != nil {
84+
log.Printf("q.CreateTaskLog(%v, %v, %q) = %v", l.workflowID, l.taskName, body, err)
85+
}
86+
return err
87+
})
88+
if err != nil {
89+
log.Printf("l.Printf(%q, %v) = %v", format, v, err)
90+
}
91+
}

0 commit comments

Comments
 (0)