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