Skip to content

Commit b0e36a6

Browse files
committed
feat: prometheus metric collection
1 parent 5b5516a commit b0e36a6

File tree

4 files changed

+108
-10
lines changed

4 files changed

+108
-10
lines changed

fly.toml

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,18 @@ primary_region = 'fra'
99
[build]
1010

1111
[http_service]
12-
internal_port = 8080
13-
force_https = true
14-
auto_stop_machines = 'suspend'
15-
auto_start_machines = true
16-
min_machines_running = 0
17-
processes = ['app']
12+
internal_port = 8080
13+
force_https = true
14+
auto_stop_machines = 'suspend'
15+
auto_start_machines = true
16+
min_machines_running = 0
17+
processes = ['app']
18+
19+
[metrics]
20+
port = 8080
21+
path = "/metrics"
1822

1923
[[vm]]
20-
memory = '1gb'
21-
cpu_kind = 'shared'
22-
cpus = 2
24+
memory = '1gb'
25+
cpu_kind = 'shared'
26+
cpus = 2

go.mod

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,18 @@
11
module github.com/TinyTapeout/vga-playground/server
22

3-
go 1.21
3+
go 1.23.0
44

55
require github.com/google/uuid v1.6.0
6+
7+
require (
8+
github.com/beorn7/perks v1.0.1 // indirect
9+
github.com/cespare/xxhash/v2 v2.3.0 // indirect
10+
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
11+
github.com/prometheus/client_golang v1.23.2 // indirect
12+
github.com/prometheus/client_model v0.6.2 // indirect
13+
github.com/prometheus/common v0.66.1 // indirect
14+
github.com/prometheus/procfs v0.16.1 // indirect
15+
go.yaml.in/yaml/v2 v2.4.2 // indirect
16+
golang.org/x/sys v0.35.0 // indirect
17+
google.golang.org/protobuf v1.36.8 // indirect
18+
)

go.sum

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,23 @@
1+
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
2+
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
3+
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
4+
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
15
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
26
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
7+
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
8+
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
9+
github.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h0RJWRi/o0o=
10+
github.com/prometheus/client_golang v1.23.2/go.mod h1:Tb1a6LWHB3/SPIzCoaDXI4I8UHKeFTEQ1YCr+0Gyqmg=
11+
github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk=
12+
github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE=
13+
github.com/prometheus/common v0.66.1 h1:h5E0h5/Y8niHc5DlaLlWLArTQI7tMrsfQjHV+d9ZoGs=
14+
github.com/prometheus/common v0.66.1/go.mod h1:gcaUsgf3KfRSwHY4dIMXLPV0K/Wg1oZ8+SbZk/HH/dA=
15+
github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg=
16+
github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is=
17+
go.yaml.in/yaml/v2 v2.4.2 h1:DzmwEr2rDGHl7lsFgAHxmNz/1NlQ7xLIrlN2h5d1eGI=
18+
go.yaml.in/yaml/v2 v2.4.2/go.mod h1:081UH+NErpNdqlCXm3TtEran0rJZGxAYx9hb/ELlsPU=
19+
golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI=
20+
golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
21+
google.golang.org/protobuf v1.36.8 h1:xHScyCOEuuwZEc6UtSOvPbAT4zRh0xcNRYekJwfqyMc=
22+
google.golang.org/protobuf v1.36.8/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
23+
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=

main.go

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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

2224
type 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+
3578
func 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

231286
func 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

Comments
 (0)