Skip to content

Commit d052480

Browse files
authored
Merge pull request #384 from HyperloopUPV-H8/backend/logger
refactor(logger): improve structure, fix issues and add test coverage
2 parents 6bf6349 + 355518d commit d052480

File tree

15 files changed

+1709
-361
lines changed

15 files changed

+1709
-361
lines changed

backend/.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,3 +24,8 @@ audience_static
2424

2525
cmd/adj/
2626
cmd/config.toml
27+
28+
29+
# Test data
30+
c.out
31+
cover.out

backend/cmd/main.go

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,6 @@ import (
4444
"github.com/HyperloopUPV-H8/h9-backend/pkg/logger"
4545
data_logger "github.com/HyperloopUPV-H8/h9-backend/pkg/logger/data"
4646
order_logger "github.com/HyperloopUPV-H8/h9-backend/pkg/logger/order"
47-
protection_logger "github.com/HyperloopUPV-H8/h9-backend/pkg/logger/protection"
48-
state_logger "github.com/HyperloopUPV-H8/h9-backend/pkg/logger/state"
4947
"github.com/HyperloopUPV-H8/h9-backend/pkg/transport"
5048
"github.com/HyperloopUPV-H8/h9-backend/pkg/transport/network/sniffer"
5149
"github.com/HyperloopUPV-H8/h9-backend/pkg/transport/network/tcp"
@@ -176,12 +174,9 @@ func main() {
176174
updateFactory := update_factory.NewFactory(boardToPackets)
177175

178176
// <--- logger --->
179-
var boardMap map[abstraction.BoardId]string
180177
var subloggers = map[abstraction.LoggerName]abstraction.Logger{
181-
data_logger.Name: data_logger.NewLogger(),
182-
protection_logger.Name: protection_logger.NewLogger(boardMap),
183-
order_logger.Name: order_logger.NewLogger(),
184-
state_logger.Name: state_logger.NewLogger(),
178+
data_logger.Name: data_logger.NewLogger(),
179+
order_logger.Name: order_logger.NewLogger(),
185180
}
186181

187182
logger.SetFormatTimestamp(logger.TimeUnit(config.Logging.TimeUnit)) // MUST be before creating subloggers

backend/pkg/logger/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
logger/

backend/pkg/logger/base/logger.go

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
package loggerbase
2+
3+
import (
4+
"fmt"
5+
"os"
6+
"path"
7+
"sync/atomic"
8+
"time"
9+
10+
"github.com/HyperloopUPV-H8/h9-backend/pkg/abstraction"
11+
loggerHandler "github.com/HyperloopUPV-H8/h9-backend/pkg/logger"
12+
"github.com/HyperloopUPV-H8/h9-backend/pkg/transport/packet/data"
13+
)
14+
15+
/*********
16+
* Record *
17+
*********/
18+
19+
type Record struct {
20+
Packet *data.Packet
21+
From string
22+
To string
23+
Timestamp time.Time
24+
}
25+
26+
/*************
27+
* BaseLogger *
28+
*************/
29+
30+
type BaseLogger struct {
31+
32+
// An atomic boolean is used in order to use CompareAndSwap in the Start and Stop methods
33+
Running *atomic.Bool
34+
35+
// save the starting time of the logger in Unix microseconds in order to log relative timestamps
36+
StartTime int64
37+
38+
// Name of the logger
39+
Name abstraction.LoggerName
40+
}
41+
42+
// Function to start the base logger
43+
func (sublogger *BaseLogger) Start() error {
44+
if !sublogger.Running.CompareAndSwap(false, true) {
45+
fmt.Println("Logger already running")
46+
return nil
47+
}
48+
49+
sublogger.StartTime = loggerHandler.FormatTimestamp(time.Now()) // Update the start time
50+
51+
fmt.Println("Logger started " + string(sublogger.Name) + ".")
52+
return nil
53+
}
54+
55+
// Function to create the base file path
56+
57+
func (sublogger *BaseLogger) CreateFile(filename string) (*os.File, error) {
58+
59+
err := os.MkdirAll(path.Dir(filename), os.ModePerm)
60+
if err != nil {
61+
return nil, loggerHandler.ErrCreatingAllDir{
62+
Name: sublogger.Name,
63+
Timestamp: time.Now(),
64+
Path: filename,
65+
}
66+
}
67+
68+
return os.Create(path.Join(filename))
69+
}
70+
71+
// Create a base Logger with default values
72+
func NewBaseLogger(name abstraction.LoggerName) *BaseLogger {
73+
return &BaseLogger{
74+
Running: &atomic.Bool{},
75+
StartTime: 0,
76+
Name: name,
77+
}
78+
}
79+
80+
func (sublogger *BaseLogger) PullRecord(abstraction.LoggerRequest) (abstraction.LoggerRecord, error) {
81+
panic("TODO!")
82+
}
83+
84+
// Function to stop the base logger
85+
// Param templateStop is a function that contains the specific stop actions of each logger
86+
func (sublogger *BaseLogger) Stop(templateStop func() error) error {
87+
if !sublogger.Running.CompareAndSwap(true, false) {
88+
fmt.Println("Logger already stopped" + string(sublogger.Name) + ".")
89+
return nil
90+
}
91+
92+
output := templateStop()
93+
94+
fmt.Println("Logger stopped " + string(sublogger.Name) + ".")
95+
return output
96+
}
Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
package loggerbase
2+
3+
import (
4+
"os"
5+
6+
"testing"
7+
)
8+
9+
func createLoggerForTest(t *testing.T) *BaseLogger {
10+
11+
t.Helper() // Marks this function as a test helper, avoids cluttering test output
12+
13+
logger := NewBaseLogger("TEST")
14+
return logger
15+
}
16+
17+
// chdirTemp changes the current working directory to a temporary directory for the duration of the test.
18+
func chdirTemp(t *testing.T) string {
19+
t.Helper()
20+
tmp := t.TempDir()
21+
old, err := os.Getwd()
22+
if err != nil {
23+
t.Fatal(err)
24+
}
25+
if err := os.Chdir(tmp); err != nil {
26+
t.Fatal(err)
27+
}
28+
t.Cleanup(func() { _ = os.Chdir(old) })
29+
return tmp
30+
}
31+
32+
/*******
33+
* Start *
34+
*******/
35+
36+
func TestStart(t *testing.T) {
37+
38+
_ = chdirTemp(t) // Change to a temporary directory
39+
40+
logger := createLoggerForTest(t)
41+
42+
// Sample data
43+
44+
var startTime int64
45+
46+
t.Run("Start (first time)", func(t *testing.T) {
47+
48+
// First start should succeed
49+
out := logger.Start()
50+
51+
if out != nil {
52+
t.Fatalf("expected nil, got %v", out)
53+
}
54+
// Capture start time
55+
startTime = logger.StartTime
56+
57+
})
58+
59+
t.Run("Start (not first time)", func(t *testing.T) {
60+
61+
// El test Start (first time) debe haber tenido éxito y haber establecido startTime
62+
if startTime == 0 {
63+
t.Fatal("precondition failed: startTime should be set from the first start")
64+
}
65+
66+
// Subsequent starts shouldn't change startTime
67+
out := logger.Start()
68+
if out != nil {
69+
t.Fatalf("expected nil, got %v", out)
70+
}
71+
if logger.StartTime != startTime {
72+
t.Fatalf("expected startTime to be %d, got %d", startTime, logger.StartTime)
73+
}
74+
})
75+
76+
}
77+
78+
/*************
79+
* Create File *
80+
*************/
81+
82+
func TestCreateFile(t *testing.T) {
83+
84+
_ = chdirTemp(t) // Change to a temporary directory
85+
logger := createLoggerForTest(t)
86+
87+
t.Run("Create File (valid path)", func(t *testing.T) {
88+
filename := "logs/testlog.txt"
89+
file, err := logger.CreateFile(filename)
90+
if err != nil {
91+
t.Fatalf("expected nil error, got %v", err)
92+
}
93+
defer file.Close()
94+
95+
// Verify file was created
96+
if _, err := os.Stat(filename); os.IsNotExist(err) {
97+
t.Fatalf("expected file %s to exist, but it does not", filename)
98+
}
99+
})
100+
101+
t.Run("Create File (invalid path)", func(t *testing.T) {
102+
// Using an invalid path (e.g., a path with illegal characters)
103+
invalidFilename := string([]byte{0}) + "invalidlog.txt"
104+
_, err := logger.CreateFile(invalidFilename)
105+
if err == nil {
106+
t.Fatal("expected an error for invalid path, got nil")
107+
}
108+
})
109+
}
110+
111+
/******
112+
* Stop *
113+
******/
114+
func TestStop(t *testing.T) {
115+
116+
_ = chdirTemp(t) // Change to a temporary directory
117+
logger := createLoggerForTest(t)
118+
119+
// Sample stop function
120+
sampleStopFunc := func() error {
121+
// Simulate some stop actions
122+
return nil
123+
}
124+
125+
t.Run("Stop (not started)", func(t *testing.T) {
126+
127+
// Stopping without starting should be a no-op
128+
out := logger.Stop(sampleStopFunc)
129+
if out != nil {
130+
t.Fatalf("expected nil, got %v", out)
131+
}
132+
})
133+
134+
t.Run("Stop (after start)", func(t *testing.T) {
135+
136+
// Start the logger first
137+
_ = logger.Start()
138+
139+
// Now stop the logger
140+
out := logger.Stop(sampleStopFunc)
141+
if out != nil {
142+
t.Fatalf("expected nil, got %v", out)
143+
}
144+
})
145+
146+
t.Run("Stop (already stopped)", func(t *testing.T) {
147+
148+
// Stopping again should be a no-op
149+
out := logger.Stop(sampleStopFunc)
150+
if out != nil {
151+
t.Fatalf("expected nil, got %v", out)
152+
}
153+
})
154+
155+
// With a function that returns an error
156+
errorStopFunc := func() error {
157+
return os.ErrInvalid
158+
}
159+
160+
t.Run("Stop (with error)", func(t *testing.T) {
161+
162+
// Start the logger first
163+
_ = logger.Start()
164+
165+
// Now stop the logger with an error-producing function
166+
out := logger.Stop(errorStopFunc)
167+
if out != os.ErrInvalid {
168+
t.Fatalf("expected os.ErrInvalid, got %v", out)
169+
}
170+
})
171+
172+
}

backend/pkg/logger/data/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
logger/

0 commit comments

Comments
 (0)