-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
695636e
commit 6212495
Showing
5 changed files
with
279 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
package egym | ||
|
||
import ( | ||
"encoding/json" | ||
"fmt" | ||
"time" | ||
) | ||
|
||
func (c *EgymClient) GetWorkoutsInPeriod(startDate, endDate time.Time) (*[]Workout, error) { | ||
url := fmt.Sprintf( | ||
"%s/workouts/api/workouts/v2.3/exercisers/%s/workouts?completedAfter=%s&completedBefore=%s", | ||
c.brandApiUrl, | ||
c.userId, | ||
startDate.Format(time.RFC3339), | ||
endDate.Format(time.RFC3339), | ||
) | ||
body, err := c.fetch(url, 1) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
var response GetWorkoutsResponse | ||
err = json.Unmarshal(body, &response) | ||
if err != nil { | ||
return nil, err | ||
} | ||
return &response.Workouts, nil | ||
} | ||
|
||
type GetWorkoutsResponse struct { | ||
Workouts []Workout `json:"workouts"` | ||
} | ||
|
||
type Workout struct { | ||
Code string `json:"code"` | ||
Exercises []Exercise `json:"exercises"` | ||
CreatedAt string `json:"createdAt"` | ||
UpdatedAt string `json:"updatedAt"` | ||
CompletedAt string `json:"completedAt"` | ||
Timezone string `json:"timezone"` | ||
WorkoutPlanCode string `json:"workoutPlanCode"` | ||
WorkoutPlanLabel string `json:"workoutPlanLabel"` | ||
WorkoutPlanImageUrl string `json:"workoutPlanImageUrl"` | ||
WorkoutPlanGroupType string `json:"workoutPlanGroupType"` | ||
} | ||
|
||
type Exercise struct { | ||
Code string `json:"code"` | ||
ExerciseCode string `json:"exerciseCode"` | ||
LibraryCode string `json:"libraryCode"` | ||
Source struct { | ||
Label string `json:"label"` | ||
Code string `json:"code"` | ||
} `json:"source"` | ||
Exercise struct { | ||
Label string `json:"label"` | ||
Code string `json:"code"` | ||
Icons []string `json:"icons"` | ||
Videos []string `json:"videos"` | ||
Previews []string `json:"previews"` | ||
Description string `json:"description"` | ||
Synonyms []string `json:"synonyms"` | ||
Category struct { | ||
Code string `json:"code"` | ||
Label string `json:"label"` | ||
} `json:"category"` | ||
MachineBased bool `json:"machineBased"` | ||
} `json:"exercise"` | ||
Attributes struct { | ||
Distance *ValueWithUnit `json:"distance"` | ||
Duration *ValueWithUnit `json:"duration"` | ||
Calories *ValueWithUnit `json:"calories"` | ||
ActivityPoints *ValueWithUnit `json:"activity_points"` | ||
AverageSpeed *ValueWithUnit `json:"average_speed"` | ||
Sets []struct { | ||
Reps *ValueWithUnit `json:"reps"` | ||
Duration *ValueWithUnit `json:"duration"` | ||
Weight *ValueWithUnit `json:"weight"` | ||
} `json:"sets_of_reps_and_weight_or_duration_and_weight"` | ||
} `json:"attributes"` | ||
Name string `json:"name"` | ||
Editable bool `json:"editable"` | ||
Deletable bool `json:"deletable"` | ||
CreatedAt string `json:"createdAt"` | ||
UpdatedAt string `json:"updatedAt"` | ||
CompletedAt string `json:"completedAt"` | ||
Timezone string `json:"timezone"` | ||
Origin string `json:"origin"` | ||
} | ||
|
||
type ValueWithUnit struct { | ||
Unit string `json:"unit"` | ||
Value float64 `json:"value"` | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,165 @@ | ||
package exporter | ||
|
||
import ( | ||
"github.com/prometheus/client_golang/prometheus" | ||
"github.com/soerenuhrbach/egym-exporter/internal/egym" | ||
|
||
"time" | ||
|
||
log "github.com/sirupsen/logrus" | ||
) | ||
|
||
const exerciseNamespace = "exercise" | ||
|
||
var ( | ||
exerciseLabels = []string{"exercise", "code", "completed_at", "source", "source_label", "unit", "workout"} | ||
|
||
exerciseActivityPoints = prometheus.NewDesc( | ||
prometheus.BuildFQName(namespace, exerciseNamespace, "activity_points"), | ||
"Activity points of the exercise", | ||
append(labels, exerciseLabels...), | ||
nil, | ||
) | ||
exerciseDistance = prometheus.NewDesc( | ||
prometheus.BuildFQName(namespace, exerciseNamespace, "distance"), | ||
"Distance of the exercise", | ||
append(labels, exerciseLabels...), | ||
nil, | ||
) | ||
exerciseDuration = prometheus.NewDesc( | ||
prometheus.BuildFQName(namespace, exerciseNamespace, "duration"), | ||
"Training duration of the exercise", | ||
append(labels, exerciseLabels...), | ||
nil, | ||
) | ||
exerciseCalories = prometheus.NewDesc( | ||
prometheus.BuildFQName(namespace, exerciseNamespace, "calories"), | ||
"Burned calories with the exercise", | ||
append(labels, exerciseLabels...), | ||
nil, | ||
) | ||
exerciseAverageSpeed = prometheus.NewDesc( | ||
prometheus.BuildFQName(namespace, exerciseNamespace, "average_speed"), | ||
"Average speed of the exercise", | ||
append(labels, exerciseLabels...), | ||
nil, | ||
) | ||
exerciseSets = prometheus.NewDesc( | ||
prometheus.BuildFQName(namespace, exerciseNamespace, "sets"), | ||
"Number of sets of the exercise", | ||
append(labels, exerciseLabels...), | ||
nil, | ||
) | ||
exerciseReps = prometheus.NewDesc( | ||
prometheus.BuildFQName(namespace, exerciseNamespace, "reps"), | ||
"Total number of reps over all sets of the exercise", | ||
append(labels, exerciseLabels...), | ||
nil, | ||
) | ||
exerciseWeightPerRep = prometheus.NewDesc( | ||
prometheus.BuildFQName(namespace, exerciseNamespace, "weight_per_rep"), | ||
"Average weight per rep of the exercise", | ||
append(labels, exerciseLabels...), | ||
nil, | ||
) | ||
exerciseTotalWeight = prometheus.NewDesc( | ||
prometheus.BuildFQName(namespace, exerciseNamespace, "weight_total"), | ||
"Total weight across all reps of all sets of the exercise", | ||
append(labels, exerciseLabels...), | ||
nil, | ||
) | ||
) | ||
|
||
func (c *EgymExporter) describeExerciseMetrics(ch chan<- *prometheus.Desc) { | ||
ch <- exerciseActivityPoints | ||
} | ||
|
||
func (c *EgymExporter) collectExerciseMetrics(ch chan<- prometheus.Metric) { | ||
now := time.Now().UTC() | ||
today := time.Date( | ||
now.Year(), | ||
now.Month(), | ||
now.Day(), | ||
int(0), | ||
int(0), | ||
int(0), | ||
int(0), | ||
now.Location(), | ||
) | ||
endOfDay := time.Date( | ||
now.Year(), | ||
now.Month(), | ||
now.Day(), | ||
int(23), | ||
int(59), | ||
int(59), | ||
int(59), | ||
now.Location(), | ||
) | ||
|
||
workouts, err := c.client.GetWorkoutsInPeriod(today, endOfDay) | ||
if err != nil { | ||
log.Error("could not retrieve exercise data!", err) | ||
return | ||
} | ||
|
||
for _, workout := range *workouts { | ||
for _, exercise := range workout.Exercises { | ||
|
||
if exercise.Attributes.ActivityPoints != nil && exercise.Attributes.ActivityPoints.Value > 0 { | ||
ch <- c.createExerciseMetric(exerciseActivityPoints, workout, exercise, exercise.Attributes.ActivityPoints.Value, exercise.Attributes.ActivityPoints.Unit) | ||
} | ||
if exercise.Attributes.Distance != nil && exercise.Attributes.Distance.Value > 0 { | ||
ch <- c.createExerciseMetric(exerciseDistance, workout, exercise, exercise.Attributes.Distance.Value, exercise.Attributes.Distance.Unit) | ||
} | ||
if exercise.Attributes.Duration != nil && exercise.Attributes.Duration.Value > 0 { | ||
ch <- c.createExerciseMetric(exerciseDuration, workout, exercise, exercise.Attributes.Duration.Value, exercise.Attributes.Duration.Unit) | ||
} | ||
if exercise.Attributes.Calories != nil && exercise.Attributes.Calories.Value > 0 { | ||
ch <- c.createExerciseMetric(exerciseCalories, workout, exercise, exercise.Attributes.Calories.Value, exercise.Attributes.Calories.Unit) | ||
} | ||
if exercise.Attributes.AverageSpeed != nil && exercise.Attributes.AverageSpeed.Value > 0 { | ||
ch <- c.createExerciseMetric(exerciseAverageSpeed, workout, exercise, exercise.Attributes.AverageSpeed.Value, exercise.Attributes.AverageSpeed.Unit) | ||
} | ||
|
||
if exercise.Attributes.Sets != nil && len(exercise.Attributes.Sets) > 0 { | ||
sets := float64(len(exercise.Attributes.Sets)) | ||
reps := float64(0) | ||
weight := float64(0) | ||
|
||
for _, set := range exercise.Attributes.Sets { | ||
if set.Reps != nil { | ||
reps += set.Reps.Value | ||
} | ||
|
||
if set.Weight != nil { | ||
weight += set.Weight.Value | ||
} | ||
} | ||
|
||
weight = weight / sets | ||
|
||
ch <- c.createExerciseMetric(exerciseSets, workout, exercise, sets, "") | ||
ch <- c.createExerciseMetric(exerciseReps, workout, exercise, reps, "") | ||
ch <- c.createExerciseMetric(exerciseWeightPerRep, workout, exercise, weight, "kg") | ||
ch <- c.createExerciseMetric(exerciseTotalWeight, workout, exercise, weight*reps, "kg") | ||
} | ||
} | ||
} | ||
} | ||
|
||
func (c *EgymExporter) createExerciseMetric(desc *prometheus.Desc, workout egym.Workout, exercise egym.Exercise, value float64, unit string) prometheus.Metric { | ||
return prometheus.MustNewConstMetric( | ||
desc, | ||
prometheus.CounterValue, | ||
value, | ||
c.client.Username, | ||
exercise.Exercise.Label, | ||
exercise.Exercise.Code, | ||
exercise.CompletedAt, | ||
exercise.Source.Code, | ||
exercise.Source.Label, | ||
unit, | ||
workout.Code, | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters