@@ -12,6 +12,7 @@ import (
1212 "github.com/hhftechnology/traefik-log-dashboard/agent/pkg/logs"
1313 "github.com/hhftechnology/traefik-log-dashboard/agent/pkg/system"
1414 "github.com/hhftechnology/traefik-log-dashboard/agent/pkg/location"
15+ "github.com/hhftechnology/traefik-log-dashboard/agent/pkg/logger"
1516)
1617
1718// Handler manages HTTP routes and dependencies
@@ -24,10 +25,88 @@ type Handler struct {
2425
2526// NewHandler creates a new Handler with the given configuration
2627func NewHandler (cfg * config.Config ) * Handler {
27- return & Handler {
28+ h := & Handler {
2829 config : cfg ,
2930 positions : make (map [string ]int64 ),
3031 }
32+
33+ // ADDED: Load positions from file on startup
34+ if err := h .loadPositions (); err != nil {
35+ logger .Log .Printf ("Warning: Could not load positions from file: %v" , err )
36+ }
37+
38+ return h
39+ }
40+
41+ // ADDED: loadPositions loads position data from the position file
42+ func (h * Handler ) loadPositions () error {
43+ if h .config .PositionFile == "" {
44+ return nil
45+ }
46+
47+ // Check if file exists
48+ if _ , err := os .Stat (h .config .PositionFile ); os .IsNotExist (err ) {
49+ logger .Log .Printf ("Position file does not exist yet: %s" , h .config .PositionFile )
50+ return nil
51+ }
52+
53+ // Read file
54+ data , err := os .ReadFile (h .config .PositionFile )
55+ if err != nil {
56+ return err
57+ }
58+
59+ // Parse JSON
60+ var positions map [string ]int64
61+ if err := json .Unmarshal (data , & positions ); err != nil {
62+ return err
63+ }
64+
65+ h .positionMutex .Lock ()
66+ h .positions = positions
67+ h .positionMutex .Unlock ()
68+
69+ logger .Log .Printf ("Loaded %d position(s) from %s" , len (positions ), h .config .PositionFile )
70+ return nil
71+ }
72+
73+ // ADDED: savePositions persists position data to the position file
74+ func (h * Handler ) savePositions () error {
75+ if h .config .PositionFile == "" {
76+ return nil
77+ }
78+
79+ h .positionMutex .RLock ()
80+ positions := make (map [string ]int64 , len (h .positions ))
81+ for k , v := range h .positions {
82+ positions [k ] = v
83+ }
84+ h .positionMutex .RUnlock ()
85+
86+ // Marshal to JSON
87+ data , err := json .MarshalIndent (positions , "" , " " )
88+ if err != nil {
89+ return err
90+ }
91+
92+ // Ensure directory exists
93+ dir := filepath .Dir (h .config .PositionFile )
94+ if err := os .MkdirAll (dir , 0755 ); err != nil {
95+ return err
96+ }
97+
98+ // Write to file atomically (write to temp file, then rename)
99+ tmpFile := h .config .PositionFile + ".tmp"
100+ if err := os .WriteFile (tmpFile , data , 0644 ); err != nil {
101+ return err
102+ }
103+
104+ if err := os .Rename (tmpFile , h .config .PositionFile ); err != nil {
105+ os .Remove (tmpFile ) // Clean up temp file on error
106+ return err
107+ }
108+
109+ return nil
31110}
32111
33112// getFilePosition gets the tracked position for a file
@@ -43,8 +122,15 @@ func (h *Handler) getFilePosition(path string) int64 {
43122// setFilePosition updates the tracked position for a file
44123func (h * Handler ) setFilePosition (path string , position int64 ) {
45124 h .positionMutex .Lock ()
46- defer h .positionMutex .Unlock ()
47125 h .positions [path ] = position
126+ h .positionMutex .Unlock ()
127+
128+ // ADDED: Save to disk asynchronously to avoid blocking
129+ go func () {
130+ if err := h .savePositions (); err != nil {
131+ logger .Log .Printf ("Error saving positions to file: %v" , err )
132+ }
133+ }()
48134}
49135
50136// HandleAccessLogs handles requests for access logs
0 commit comments