Monorepo for Tangled
1package models
2
3import (
4 "encoding/json"
5 "fmt"
6 "io"
7 "os"
8 "path/filepath"
9 "strings"
10)
11
12type WorkflowLogger interface {
13 Close() error
14 DataWriter(idx int, stream string) io.Writer
15 ControlWriter(idx int, step Step, stepStatus StepStatus) io.Writer
16}
17
18type FileWorkflowLogger struct {
19 file *os.File
20 encoder *json.Encoder
21 mask *SecretMask
22}
23
24func NewFileWorkflowLogger(baseDir string, wid WorkflowId, secretValues []string) (*FileWorkflowLogger, error) {
25 path := LogFilePath(baseDir, wid)
26 file, err := os.OpenFile(path, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
27 if err != nil {
28 return nil, fmt.Errorf("creating log file: %w", err)
29 }
30 return &FileWorkflowLogger{
31 file: file,
32 encoder: json.NewEncoder(file),
33 mask: NewSecretMask(secretValues),
34 }, nil
35}
36
37func LogFilePath(baseDir string, workflowID WorkflowId) string {
38 logFilePath := filepath.Join(baseDir, fmt.Sprintf("%s.log", workflowID.String()))
39 return logFilePath
40}
41
42func (l *FileWorkflowLogger) Close() error {
43 return l.file.Close()
44}
45
46func (l *FileWorkflowLogger) DataWriter(idx int, stream string) io.Writer {
47 return &dataWriter{
48 logger: l,
49 idx: idx,
50 stream: stream,
51 }
52}
53
54func (l *FileWorkflowLogger) ControlWriter(idx int, step Step, stepStatus StepStatus) io.Writer {
55 return &controlWriter{
56 logger: l,
57 idx: idx,
58 step: step,
59 stepStatus: stepStatus,
60 }
61}
62
63type dataWriter struct {
64 logger *FileWorkflowLogger
65 idx int
66 stream string
67}
68
69func (w *dataWriter) Write(p []byte) (int, error) {
70 line := strings.TrimRight(string(p), "\r\n")
71 if w.logger.mask != nil {
72 line = w.logger.mask.Mask(line)
73 }
74 entry := NewDataLogLine(w.idx, line, w.stream)
75 if err := w.logger.encoder.Encode(entry); err != nil {
76 return 0, err
77 }
78 return len(p), nil
79}
80
81type controlWriter struct {
82 logger *FileWorkflowLogger
83 idx int
84 step Step
85 stepStatus StepStatus
86}
87
88func (w *controlWriter) Write(_ []byte) (int, error) {
89 entry := NewControlLogLine(w.idx, w.step, w.stepStatus)
90 if err := w.logger.encoder.Encode(entry); err != nil {
91 return 0, err
92 }
93 return len(w.step.Name()), nil
94}