v3.4.0 593c1c3

diagnostics.go RawHistoryFolder

1package deployment
2
3import (
4	"bufio"
5	"context"
6	"io"
7	"strings"
8
9	"github.com/bnema/gordon/internal/domain"
10)
11
12// logTail returns the bounded recent log tail of the failing container.
13// The read is bounded by the caller's deadline and by an internal cap so
14// a slow or hung log stream cannot stall the operation.
15func (s *Service) logTail(ctx context.Context, containerID string) []string {
16	if containerID == "" || ctx.Err() != nil {
17		return nil
18	}
19	tailCtx, cancel := context.WithTimeout(ctx, failLogTailTimeout)
20	defer cancel()
21	stream, err := s.deps.Runtime.GetContainerLogs(tailCtx, containerID, false)
22	if err != nil {
23		return nil
24	}
25	defer func() { _ = stream.Close() }()
26	lines, err := tailLines(stream, failLogTailLines)
27	if err != nil {
28		return nil
29	}
30	return lines
31}
32
33// redactDiagnostics replaces every value of this service's secrets in the
34// given log lines. Secret values are read into memory only. When a secret
35// cannot be read, diagnostics are dropped entirely: unredacted application
36// output is never persisted.
37func (s *Service) redactDiagnostics(ctx context.Context, app string, p pinnedService, lines []string) []string {
38	if len(lines) == 0 {
39		return nil
40	}
41	if len(p.spec.Secrets) == 0 || s.deps.Secrets == nil {
42		return lines
43	}
44	id, err := s.appSecretID(ctx, app)
45	if err != nil {
46		return nil
47	}
48	redacted := append([]string(nil), lines...)
49	for _, name := range p.spec.Secrets {
50		path := domain.AppSecretPathForID(id, app, p.spec.Name, name)
51		value, err := s.deps.Secrets.GetSecret(ctx, path)
52		if err != nil || value == "" {
53			return nil
54		}
55		for i, line := range redacted {
56			redacted[i] = strings.ReplaceAll(line, value, "[redacted]")
57		}
58	}
59	return redacted
60}
61
62// tailLines keeps the last N lines; logs are untrusted app output.
63func tailLines(r io.Reader, n int) ([]string, error) {
64	scanner := bufio.NewScanner(r)
65	scanner.Buffer(make([]byte, 64*1024), 1024*1024)
66	var lines []string
67	for scanner.Scan() {
68		lines = append(lines, scanner.Text())
69		if len(lines) > n {
70			lines = lines[len(lines)-n:]
71		}
72	}
73	if err := scanner.Err(); err != nil {
74		return nil, err
75	}
76	return lines, nil
77}

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 7

Tags 106

↑↓ moveenter openesc close