diff --git a/README.md b/README.md new file mode 100644 index 0000000..293990b --- /dev/null +++ b/README.md @@ -0,0 +1,100 @@ +# Träwelling Prometheus Exporter + +## Beschreibung + +Dieser Prometheus Exporter sammelt Daten von der Träwelling API und stellt sie als Prometheus-Metriken zur Verfügung. Er bietet detaillierte Informationen über Fahrten, einschließlich Gesamtfahrzeit, Gesamtpunkte und Gesamtentfernung für jeden Benutzer. + +## Funktionen + +- Abfrage der Träwelling API für aktuelle Fahrtdaten +- Bereitstellung von Prometheus-Metriken für: + - Gesamtfahrzeit pro Benutzer + - Gesamtpunkte pro Benutzer + - Gesamtentfernung pro Benutzer +- Konsolenausgabe detaillierter Fahrtinformationen +- Regelmäßige Aktualisierung der Daten (alle 5 Minuten) + +## Voraussetzungen + +- Go 1.15 oder höher +- Docker und Docker Compose (für containerisierte Ausführung) +- Gültiger Träwelling API-Token + +## Installation + +1. Klone das Repository: + ``` + git clone https://github.com/yourusername/traewelling-prometheus-exporter.git + cd traewelling-prometheus-exporter + ``` + +2. Installiere die erforderlichen Go-Pakete: + ``` + go get github.com/prometheus/client_golang/prometheus + go get github.com/prometheus/client_golang/prometheus/promauto + go get github.com/prometheus/client_golang/prometheus/promhttp + ``` + +3. Erstelle eine `.env` Datei im Projektverzeichnis und füge deinen Träwelling API-Token hinzu: + ``` + TRAEWELLING_TOKEN=your_token_here + ``` + +## Ausführung + +### Lokale Ausführung + +1. Baue die Anwendung: + ``` + go build -o traewelling-exporter + ``` + +2. Führe die Anwendung aus: + ``` + ./traewelling-exporter + ``` + +### Mit Docker + +1. Baue das Docker-Image: + ``` + docker-compose build + ``` + +2. Starte den Container: + ``` + docker-compose up -d + ``` + +## Verwendung + +Nach dem Start ist der Exporter unter `http://localhost:8080/metrics` erreichbar. Prometheus kann so konfiguriert werden, dass es diese Endpunkt abfragt. + +## Prometheus Konfiguration + +Füge folgende Job-Konfiguration zu deiner `prometheus.yml` hinzu: + +``` +scrape_configs: + - job_name: 'traewelling' + static_configs: + - targets: ['localhost:8080'] +``` + +## Metriken + +- `traewelling_total_trip_duration_minutes`: Gesamtfahrzeit eines Benutzers in Minuten +- `traewelling_total_trip_points`: Gesamtpunkte eines Benutzers +- `traewelling_total_trip_distance_km`: Gesamtentfernung eines Benutzers in Kilometern + +## Beitragen + +Beiträge sind willkommen! Bitte erstelle ein Issue oder einen Pull Request für Verbesserungsvorschläge oder Fehlerbehebungen. + +## Lizenz + +[MIT License](LICENSE) + +## Kontakt + +Bei Fragen oder Problemen erstelle bitte ein GitHub Issue oder kontaktiere [dein-kontakt@example.com](mailto:dein-kontakt@example.com). diff --git a/go/main.go b/go/main.go index 785efd6..35d50de 100644 --- a/go/main.go +++ b/go/main.go @@ -12,41 +12,59 @@ import ( "github.com/prometheus/client_golang/prometheus/promhttp" ) -var ( - totalTrips = promauto.NewGauge(prometheus.GaugeOpts{ - Name: "traewelling_total_trips", - Help: "Gesamtanzahl der Fahrten", - }) - totalDistance = promauto.NewGauge(prometheus.GaugeOpts{ - Name: "traewelling_total_distance_km", - Help: "Gesamtdistanz aller Fahrten in Kilometern", - }) - averageDuration = promauto.NewGauge(prometheus.GaugeOpts{ - Name: "traewelling_average_duration_minutes", - Help: "Durchschnittliche Dauer der Fahrten in Minuten", - }) -) - type DashboardResponse struct { Data []struct { ID int `json:"id"` + User struct { + DisplayName string `json:"displayName"` + Username string `json:"username"` + } `json:"userDetails"` Train struct { Trip int `json:"trip"` - Distance float64 `json:"distance"` - Duration int `json:"duration"` Category string `json:"category"` LineName string `json:"lineName"` JourneyNumber int `json:"journeyNumber"` + Distance float64 `json:"distance"` + Duration int `json:"duration"` + Points int `json:"points"` Origin struct { - Name string `json:"name"` + Name string `json:"name"` + DeparturePlanned string `json:"departurePlanned"` + DepartureReal string `json:"departureReal"` } `json:"origin"` Destination struct { - Name string `json:"name"` + Name string `json:"name"` + ArrivalPlanned string `json:"arrivalPlanned"` + ArrivalReal string `json:"arrivalReal"` } `json:"destination"` } `json:"train"` } `json:"data"` } +var ( + totalTripDuration = promauto.NewGaugeVec( + prometheus.GaugeOpts{ + Name: "traewelling_total_trip_duration_minutes", + Help: "Gesamtfahrzeit eines Benutzers in Minuten", + }, + []string{"username"}, + ) + totalTripPoints = promauto.NewGaugeVec( + prometheus.GaugeOpts{ + Name: "traewelling_total_trip_points", + Help: "Gesamtpunkte eines Benutzers", + }, + []string{"username"}, + ) + totalTripDistance = promauto.NewGaugeVec( + prometheus.GaugeOpts{ + Name: "traewelling_total_trip_distance_km", + Help: "Gesamtentfernung eines Benutzers in Kilometern", + }, + []string{"username"}, + ) +) + func fetchTraewellingData() (*DashboardResponse, error) { url := "https://traewelling.de/api/v1/dashboard" client := &http.Client{Timeout: 10 * time.Second} @@ -81,35 +99,60 @@ func fetchTraewellingData() (*DashboardResponse, error) { return &apiResponse, nil } +func processAndPrintTripDetails(data *DashboardResponse) { + fmt.Println("Fahrtdetails der Benutzer:") + fmt.Println("==========================") + + userStats := make(map[string]struct { + TotalDuration float64 + TotalPoints int + TotalDistance float64 + }) + + for _, trip := range data.Data { + fmt.Printf("Benutzer: %s (@%s)\n", trip.User.DisplayName, trip.User.Username) + fmt.Printf("Fahrt-ID: %d\n", trip.Train.Trip) + fmt.Printf("Kategorie: %s\n", trip.Train.Category) + fmt.Printf("Linie: %s (Nummer: %d)\n", trip.Train.LineName, trip.Train.JourneyNumber) + fmt.Printf("Startbahnhof: %s\n", trip.Train.Origin.Name) + fmt.Printf("\tGeplante Abfahrt: %s\n", trip.Train.Origin.DeparturePlanned) + fmt.Printf("\tTatsächliche Abfahrt: %s\n", trip.Train.Origin.DepartureReal) + fmt.Printf("Zielbahnhof: %s\n", trip.Train.Destination.Name) + fmt.Printf("\tGeplante Ankunft: %s\n", trip.Train.Destination.ArrivalPlanned) + fmt.Printf("\tTatsächliche Ankunft: %s\n", trip.Train.Destination.ArrivalReal) + fmt.Printf("Dauer: %d Minuten\n", trip.Train.Duration) + fmt.Printf("Entfernung: %.2f km\n", trip.Train.Distance/1000) + fmt.Printf("Punkte: %d\n", trip.Train.Points) + fmt.Println("--------------------------") + + stats := userStats[trip.User.Username] + stats.TotalDuration += float64(trip.Train.Duration) + stats.TotalPoints += trip.Train.Points + stats.TotalDistance += trip.Train.Distance / 1000 + userStats[trip.User.Username] = stats + } + + for username, stats := range userStats { + totalTripDuration.WithLabelValues(username).Set(stats.TotalDuration) + totalTripPoints.WithLabelValues(username).Set(float64(stats.TotalPoints)) + totalTripDistance.WithLabelValues(username).Set(stats.TotalDistance) + } +} + func updateMetrics() { data, err := fetchTraewellingData() if err != nil { fmt.Printf("Fehler beim Abrufen der Daten: %v\n", err) return } - - var totalTripsCount int - var totalDistanceSum float64 - var totalDurationSum int - - for _, trip := range data.Data { - totalTripsCount++ - totalDistanceSum += trip.Train.Distance / 1000 - totalDurationSum += trip.Train.Duration - } - - totalTrips.Set(float64(totalTripsCount)) - totalDistance.Set(totalDistanceSum) - if totalTripsCount > 0 { - averageDuration.Set(float64(totalDurationSum) / float64(totalTripsCount)) - } + processAndPrintTripDetails(data) } func main() { go func() { for { updateMetrics() - time.Sleep(30 * time.Second) + time.Sleep(5 * time.Minute) } }()