@@ -17,6 +17,8 @@ import (
1717 "time"
1818
1919 "github.com/google/uuid"
20+ "github.com/prometheus/client_golang/prometheus"
21+ "github.com/prometheus/client_golang/prometheus/promhttp"
2022)
2123
2224type CompileRequest struct {
@@ -32,9 +34,51 @@ type StreamMessage struct {
3234 Message string `json:"message,omitempty"`
3335}
3436
37+ var (
38+ compilationRequestsTotal = prometheus .NewCounterVec (
39+ prometheus.CounterOpts {
40+ Name : "fpga_compilation_requests_total" ,
41+ Help : "Total number of FPGA compilation requests" ,
42+ },
43+ []string {"status" }, // "success" or "error"
44+ )
45+
46+ compilationDuration = prometheus .NewHistogram (
47+ prometheus.HistogramOpts {
48+ Name : "fpga_compilation_duration_seconds" ,
49+ Help : "Duration of FPGA compilation requests in seconds" ,
50+ Buckets : prometheus .ExponentialBuckets (1 , 2 , 10 ), // 1s, 2s, 4s, 8s, ... up to ~512s
51+ },
52+ )
53+
54+ compilationInProgress = prometheus .NewGauge (
55+ prometheus.GaugeOpts {
56+ Name : "fpga_compilation_in_progress" ,
57+ Help : "Number of FPGA compilations currently in progress" ,
58+ },
59+ )
60+
61+ commandExecutionDuration = prometheus .NewHistogramVec (
62+ prometheus.HistogramOpts {
63+ Name : "fpga_command_execution_duration_seconds" ,
64+ Help : "Duration of individual FPGA toolchain command execution in seconds" ,
65+ Buckets : prometheus .ExponentialBuckets (0.1 , 2 , 10 ), // 0.1s, 0.2s, 0.4s, ... up to ~51s
66+ },
67+ []string {"command" }, // "yosys", "nextpnr-ice40", "icepack"
68+ )
69+ )
70+
71+ func init () {
72+ prometheus .MustRegister (compilationRequestsTotal )
73+ prometheus .MustRegister (compilationDuration )
74+ prometheus .MustRegister (compilationInProgress )
75+ prometheus .MustRegister (commandExecutionDuration )
76+ }
77+
3578func main () {
3679 http .HandleFunc ("/api/compile" , loggingMiddleware (corsMiddleware (handleCompile )))
3780 http .HandleFunc ("/health" , loggingMiddleware (handleHealth ))
81+ http .Handle ("/metrics" , promhttp .Handler ())
3882
3983 port := os .Getenv ("PORT" )
4084 if port == "" {
@@ -117,6 +161,16 @@ func handleCompile(w http.ResponseWriter, r *http.Request) {
117161 return
118162 }
119163
164+ // Start metrics tracking
165+ startTime := time .Now ()
166+ compilationInProgress .Inc ()
167+ status := "error" // Default to error, set to success on completion
168+ defer func () {
169+ compilationInProgress .Dec ()
170+ compilationDuration .Observe (time .Since (startTime ).Seconds ())
171+ compilationRequestsTotal .WithLabelValues (status ).Inc ()
172+ }()
173+
120174 // Set up SSE
121175 w .Header ().Set ("Content-Type" , "text/event-stream" )
122176 w .Header ().Set ("Cache-Control" , "no-cache" )
@@ -222,13 +276,19 @@ func handleCompile(w http.ResponseWriter, r *http.Request) {
222276 }
223277
224278 // Send success message with bitstream as base64
279+ status = "success"
225280 sendSSE (w , flusher , StreamMessage {
226281 Type : "success" ,
227282 Data : fmt .Sprintf ("base64:%s" , base64 .StdEncoding .EncodeToString (bitstream )),
228283 })
229284}
230285
231286func runCommand (w http.ResponseWriter , flusher http.Flusher , workDir , command string , args []string ) bool {
287+ startTime := time .Now ()
288+ defer func () {
289+ commandExecutionDuration .WithLabelValues (command ).Observe (time .Since (startTime ).Seconds ())
290+ }()
291+
232292 sendSSE (w , flusher , StreamMessage {
233293 Type : "command" ,
234294 Command : command ,
0 commit comments