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 return &dataWriter{
42 logger: l,
43 stream: stream,
44 }
45}
46
47func (l *WorkflowLogger) ControlWriter(idx int, step Step) io.Writer {
48 return &controlWriter{
49 logger: l,
50 idx: idx,
51 step: step,
52 }
53}
54
55type dataWriter struct {
56 logger *WorkflowLogger
57 stream string
58}
59
60func (w *dataWriter) Write(p []byte) (int, error) {
61 line := strings.TrimRight(string(p), "\r\n")
62 entry := NewDataLogLine(line, w.stream)
63 if err := w.logger.encoder.Encode(entry); err != nil {
64 return 0, err
65 }
66 return len(p), nil
67}
68
69type controlWriter struct {
70 logger *WorkflowLogger
71 idx int
72 step Step
73}
74
75func (w *controlWriter) Write(_ []byte) (int, error) {
76 entry := NewControlLogLine(w.idx, w.step)
77 if err := w.logger.encoder.Encode(entry); err != nil {
78 return 0, err
79 }
80 return len(w.step.Name()), nil
81}