forked from ronnynth/aztecmonitor
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmain.go
More file actions
195 lines (161 loc) · 4.54 KB
/
main.go
File metadata and controls
195 lines (161 loc) · 4.54 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
package main
import (
"context"
"flag"
"fmt"
"net/http"
_ "net/http/pprof"
"os"
"os/signal"
"syscall"
"time"
_ "aztecmonitor/base"
"aztecmonitor/conf"
"aztecmonitor/sched"
"github.com/golang/glog"
"github.com/prometheus/client_golang/prometheus/promhttp"
"gopkg.in/yaml.v2"
)
var (
confPath string
ac = conf.NodeConfig{}
)
func init() {
// Initialize command line flags
flag.StringVar(&confPath, "conf", "./config.yaml", "config file path")
flag.Parse()
}
func loadConf(path string) error {
yamlFile, err := os.ReadFile(path)
if err != nil {
return fmt.Errorf("failed to read config file %s: %w", path, err)
}
if err := yaml.Unmarshal(yamlFile, &ac); err != nil {
return fmt.Errorf("failed to parse config file %s: %w", path, err)
}
// Validate configuration
if err := validateConfig(&ac); err != nil {
return fmt.Errorf("invalid config: %w", err)
}
return nil
}
func validateConfig(config *conf.NodeConfig) error {
if len(config.Aztec) == 0 {
return fmt.Errorf("no monitoring targets configured")
}
// Set default server configuration if not provided
if config.Server == nil {
config.Server = &conf.ServerConfig{
HTTPPort: 3008,
PprofPort: 6068,
}
} else {
if config.Server.HTTPPort == 0 {
config.Server.HTTPPort = 3008
}
if config.Server.PprofPort == 0 {
config.Server.PprofPort = 6068
}
}
// Validate Aztec configurations
for i, aztec := range config.Aztec {
if aztec.HostName == "" {
return fmt.Errorf("aztec[%d]: host_name is required", i)
}
if aztec.HostIP == "" {
return fmt.Errorf("aztec[%d]: host_ip is required", i)
}
if aztec.RPCPort == 0 {
return fmt.Errorf("aztec[%d]: rpc_port is required", i)
}
if aztec.TCPPort == 0 {
return fmt.Errorf("aztec[%d]: tcp_port is required", i)
}
if aztec.L1ChainRPC == "" {
return fmt.Errorf("aztec[%d]: l1_chain_rpc is required", i)
}
if aztec.Address == "" {
return fmt.Errorf("aztec[%d]: address is required", i)
}
}
return nil
}
func setupHTTPServer(port int) *http.Server {
mux := http.NewServeMux()
mux.Handle("/metrics", promhttp.Handler())
mux.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
w.Write([]byte("OK"))
})
return &http.Server{
Addr: fmt.Sprintf(":%d", port),
Handler: mux,
ReadTimeout: 10 * time.Second,
WriteTimeout: 10 * time.Second,
IdleTimeout: 30 * time.Second,
}
}
func startPprofServer(port int) {
pprofServer := &http.Server{
Addr: fmt.Sprintf("localhost:%d", port),
ReadTimeout: 5 * time.Second,
WriteTimeout: 5 * time.Second,
IdleTimeout: 15 * time.Second,
}
go func() {
if err := pprofServer.ListenAndServe(); err != http.ErrServerClosed {
glog.Errorf("pprof server error: %v", err)
}
}()
}
func gracefulShutdown(ctx context.Context, cancel context.CancelFunc, controller *sched.Controller, server *http.Server) {
// Wait for interrupt signals
term := make(chan os.Signal, 1)
signal.Notify(term, os.Interrupt, syscall.SIGTERM, syscall.SIGQUIT)
sig := <-term
glog.Infof("Received signal %v, starting graceful shutdown...", sig)
// Create shutdown timeout context
shutdownCtx, shutdownCancel := context.WithTimeout(context.Background(), 30*time.Second)
defer shutdownCancel()
// Stop controller
glog.Info("Stopping controller...")
controller.Stop()
// Cancel application context
cancel()
// Shutdown HTTP server
glog.Info("Shutting down HTTP server...")
if err := server.Shutdown(shutdownCtx); err != nil {
glog.Errorf("Error during server shutdown: %v", err)
} else {
glog.Info("HTTP server shutdown completed")
}
}
func main() {
defer glog.Flush()
// Load configuration
if err := loadConf(confPath); err != nil {
glog.Fatalf("Failed to load config: %v", err)
}
glog.Infof("Loaded config from %s", confPath)
glog.Infof("Monitoring %d Aztec nodes", len(ac.Aztec))
// Create application context
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
// Create controller
controller := sched.NewController(ctx, &ac)
// Setup HTTP server
server := setupHTTPServer(ac.Server.HTTPPort)
// Start pprof server
startPprofServer(ac.Server.PprofPort)
// Start graceful shutdown handler
go gracefulShutdown(ctx, cancel, controller, server)
// Start controller
glog.Info("Starting blockchain monitor...")
controller.Start()
// Start HTTP server
glog.Infof("HTTP server listening on %s", server.Addr)
if err := server.ListenAndServe(); err != http.ErrServerClosed {
glog.Errorf("HTTP server error: %v", err)
}
glog.Info("Application shutdown completed")
}