- Add API server with WebSocket support and REST endpoints - Implement authentication system with API keys and permissions - Add task queue system with Redis backend and error handling - Include storage layer with database migrations and schemas - Add comprehensive logging, metrics, and telemetry - Implement security middleware and network utilities - Add experiment management and container orchestration - Include configuration management with smart defaults
77 lines
1.6 KiB
Go
77 lines
1.6 KiB
Go
package telemetry
|
|
|
|
import (
|
|
"bufio"
|
|
"os"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/jfraeys/fetch_ml/internal/logging"
|
|
)
|
|
|
|
type IOStats struct {
|
|
ReadBytes uint64
|
|
WriteBytes uint64
|
|
}
|
|
|
|
func ReadProcessIO() (IOStats, error) {
|
|
f, err := os.Open("/proc/self/io")
|
|
if err != nil {
|
|
return IOStats{}, err
|
|
}
|
|
defer f.Close()
|
|
|
|
var stats IOStats
|
|
scanner := bufio.NewScanner(f)
|
|
for scanner.Scan() {
|
|
line := scanner.Text()
|
|
if strings.HasPrefix(line, "read_bytes:") {
|
|
stats.ReadBytes = parseUintField(line)
|
|
}
|
|
if strings.HasPrefix(line, "write_bytes:") {
|
|
stats.WriteBytes = parseUintField(line)
|
|
}
|
|
}
|
|
if err := scanner.Err(); err != nil {
|
|
return IOStats{}, err
|
|
}
|
|
return stats, nil
|
|
}
|
|
|
|
func DiffIO(before, after IOStats) IOStats {
|
|
var delta IOStats
|
|
if after.ReadBytes >= before.ReadBytes {
|
|
delta.ReadBytes = after.ReadBytes - before.ReadBytes
|
|
}
|
|
if after.WriteBytes >= before.WriteBytes {
|
|
delta.WriteBytes = after.WriteBytes - before.WriteBytes
|
|
}
|
|
return delta
|
|
}
|
|
|
|
func parseUintField(line string) uint64 {
|
|
parts := strings.Split(line, ":")
|
|
if len(parts) != 2 {
|
|
return 0
|
|
}
|
|
value, err := strconv.ParseUint(strings.TrimSpace(parts[1]), 10, 64)
|
|
if err != nil {
|
|
return 0
|
|
}
|
|
return value
|
|
}
|
|
|
|
func ExecWithMetrics(logger *logging.Logger, description string, threshold time.Duration, fn func() (string, error)) (string, error) {
|
|
start := time.Now()
|
|
out, err := fn()
|
|
duration := time.Since(start)
|
|
if duration > threshold {
|
|
fields := []any{"latency_ms", duration.Milliseconds(), "command", description}
|
|
if err != nil {
|
|
fields = append(fields, "error", err)
|
|
}
|
|
logger.Debug("ssh exec", fields...)
|
|
}
|
|
return out, err
|
|
}
|