barnesbiz/garmin_exporter

By barnesbiz

Updated 16 days ago

OTel-native Prometheus exporter for Garmin Connect.

Image
Internet of things
Monitoring & observability
1

690

barnesbiz/garmin_exporter repository overview

Garmin Exporter

GitHub Release Build Status Go Report Card GHCR Docker Hub

OTel-native Prometheus exporter for Garmin Connect.

Listens on port 10045 by default. Authenticates with Garmin Connect via username and password (with MFA support), caches the OAuth2 token to disk, and refreshes it automatically. Exposes metrics at /metrics, and can additionally push metrics, traces, and logs to an OTLP endpoint.

If this project is useful to you, a star on the repo would be appreciated.

Quick start

Docker
  docker run -d -p 10045:10045 \
    -v garmin_data:/data \
    -e [email protected] \
    -e GARMIN_PASSWORD=yourpassword \
    ghcr.io/barnes-c/garmin_exporter:latest \
    --token-file=/data/garmin_token.json
Binary

  make build
  [email protected] GARMIN_PASSWORD=yourpassword
  ./garmin_exporter

Scrape: curl localhost:10045/metrics. Probes: /healthz, /readyz.

First login: if your account has MFA enabled, the exporter prompts for a one-time code on stdin. Run it interactively once (add stdin_open: true and tty: true in Compose); once the token is cached to --token-file, subsequent restarts are unattended. Prefer the GARMIN_USERNAME / GARMIN_PASSWORD environment variables over their flags. Flag values are visible to other users on the host via ps.

Examples

Checkout the examples in examples/:

Configuration

Key flags (full list via --help):

FlagEnv varDefaultPurpose
--cache.ttlGARMIN_CACHE_TTL1hGarmin API refresh interval; independent of scrape interval
--activity-limitGARMIN_ACTIVITY_LIMIT30Number of recent activities to fetch per refresh
--passwordGARMIN_PASSWORD(required)Garmin Connect password
--token-fileGARMIN_TOKEN_FILEgarmin_token.jsonPath to the cached OAuth2 token file
--usernameGARMIN_USERNAME(required)Garmin Connect email address
--log.levelGARMIN_LOG_LEVELinfoLog level (debug, info, warn, error)
--web.health-pathGARMIN_WEB_HEALTH_PATH/healthzLiveness probe path
--web.listen-addressGARMIN_WEB_LISTEN_ADDRESS:10045Listen address
--web.prometheusGARMIN_WEB_PROMETHEUStrueDisable for OTLP-push-only deployments
--web.ready-pathGARMIN_WEB_READY_PATH/readyzReadiness probe path
--web.telemetry-pathGARMIN_WEB_TELEMETRY_PATH/metricsPrometheus endpoint
OTel pipeline

The OTel pipeline is entirely environment-driven; see the OTel SDK env var spec for the full list. /metrics is always served unless --web.prometheus=false.

VariablePurpose
OTEL_METRICS_EXPORTERComma-separated push exporters: otlp, console, none (default none)
OTEL_TRACES_EXPORTERTraces exporter: otlp, console, none (default none)
OTEL_LOGS_EXPORTERLogs exporter: otlp, console, none (default none)
OTEL_EXPORTER_OTLP_ENDPOINTCollector endpoint, e.g. localhost:4317
OTEL_EXPORTER_OTLP_PROTOCOLgrpc or http/protobuf
OTEL_METRIC_EXPORT_INTERVALOTLP metric push interval, in ms
OTEL_TRACES_SAMPLERe.g. parentbased_traceidratio
OTEL_TRACES_SAMPLER_ARGSampler argument (e.g. 0.1)
OTEL_SERVICE_NAMEResource service.name (default garmin_exporter)
OTEL_CONFIG_FILEPath to otelconf YAML; overrides all other OTEL_* vars

The three exporter selectors default to none instead of the spec default otlp. The OTel exporters stays silent until OTLP is opted in.

Metrics

All instruments are observable gauges. Naming follows garmin.<area>.<name>. Attributes are noted in parentheses.

MetricCollector
garmin.activity.count (type)activities
garmin.activity.duration_seconds_total (type)activities
garmin.activity.distance_meters_total (type)activities
garmin.activity.calories_total (type)activities
garmin.activity.last_timestamp_seconds (type)activities
garmin.activity.lifetime_countactivities
garmin.blood_pressure.systolic_mmhgblood_pressure
garmin.blood_pressure.diastolic_mmhgblood_pressure
garmin.blood_pressure.pulse_bpmblood_pressure
garmin.body.weight_gramsbody
garmin.body.bmibody
garmin.body.fat_percentbody
garmin.body.water_percentbody
garmin.body.bone_mass_gramsbody
garmin.body.muscle_mass_gramsbody
garmin.body.visceral_fatbody
garmin.body.metabolic_age_yearsbody
garmin.body_composition.weight_grams_avgbody_composition
garmin.body_composition.bmi_avgbody_composition
garmin.body_composition.fat_percent_avgbody_composition
garmin.body_composition.water_percent_avgbody_composition
garmin.body_composition.bone_mass_grams_avgbody_composition
garmin.body_composition.muscle_mass_grams_avgbody_composition
garmin.body_composition.visceral_fat_avgbody_composition
garmin.body_composition.metabolic_age_years_avgbody_composition
garmin.cycling.ftp_wattscycling
garmin.device.countdevices
garmin.device.info (device_id, name, status)devices
garmin.gear.max_meters (gear_name, gear_type)gear
garmin.gear.notified_at_meters (gear_name, gear_type)gear
garmin.gear.active (gear_name, gear_type)gear
garmin.goals.active_totalgoals
garmin.goals.earned_badges_totalgoals
garmin.golf.last_round_scoregolf
garmin.golf.last_round_to_pargolf
garmin.heartrate.resting_bpmheartrate
garmin.heartrate.min_bpmheartrate
garmin.heartrate.max_bpmheartrate
garmin.heartrate.seven_day_avg_resting_bpmheartrate
garmin.hydration.intake_mlhydration
garmin.hydration.goal_mlhydration
garmin.hydration.daily_avg_mlhydration
garmin.hydration.sweat_loss_mlhydration
garmin.hydration.activity_intake_mlhydration
garmin.intensity.weekly_goal_minutesintensity
garmin.intensity.moderate_minutes_totalintensity
garmin.intensity.vigorous_minutes_totalintensity
garmin.lactatethreshold.running_speed_mpslactatethreshold
garmin.lactatethreshold.running_heart_rate_bpmlactatethreshold
garmin.lactatethreshold.cycling_heart_rate_bpmlactatethreshold
garmin.personalrecords.value (pr_type, name)personalrecords
garmin.respiration.avg_waking_bpmrespiration
garmin.respiration.highest_bpmrespiration
garmin.respiration.lowest_bpmrespiration
garmin.runningtolerance.scorerunningtolerance
garmin.runningtolerance.levelrunningtolerance
garmin.sleep.total_secondssleep
garmin.sleep.deep_secondssleep
garmin.sleep.light_secondssleep
garmin.sleep.rem_secondssleep
garmin.sleep.awake_secondssleep
garmin.sleep.nap_secondssleep
garmin.sleep.restless_moments_totalsleep
garmin.sleep.avg_respiration_bpmsleep
garmin.sleep.highest_respiration_bpmsleep
garmin.sleep.lowest_respiration_bpmsleep
garmin.sleep.avg_stresssleep
garmin.sleep.hrv_last_night_mssleep
garmin.sleep.hrv_weekly_avg_mssleep
garmin.sleep.hrv_baseline_low_upper_mssleep
garmin.sleep.hrv_baseline_balanced_low_mssleep
garmin.sleep.hrv_baseline_balanced_upper_mssleep
garmin.spo2.avg_percentspo2
garmin.spo2.lowest_percentspo2
garmin.spo2.seven_day_avg_percentspo2
garmin.stress.avg_levelstress
garmin.stress.max_levelstress
garmin.training.readiness_scoretraining
garmin.training.readiness_sleep_scoretraining
garmin.training.readiness_recovery_minutestraining
garmin.training.readiness_hrv_weekly_avg_mstraining
garmin.training.vo2max_generictraining
garmin.training.vo2max_cyclingtraining
garmin.training.fitness_age_yearstraining
garmin.training.race_prediction_5k_secondstraining
garmin.training.race_prediction_10k_secondstraining
garmin.training.race_prediction_half_marathon_secondstraining
garmin.training.race_prediction_marathon_secondstraining
garmin.training.endurance_scoretraining
garmin.training.hill_scoretraining
garmin.trainingstatus.statustrainingstatus
garmin.trainingstatus.weekly_training_loadtrainingstatus
garmin.trainingstatus.acwr_percenttrainingstatus
garmin.trainingstatus.acwr_ratiotrainingstatus
garmin.trainingstatus.aerobic_low_monthly_loadtrainingstatus
garmin.trainingstatus.aerobic_high_monthly_loadtrainingstatus
garmin.trainingstatus.anaerobic_monthly_loadtrainingstatus
garmin.wellness.total_stepswellness
garmin.wellness.step_goalwellness
garmin.wellness.total_distance_meterswellness
garmin.wellness.total_kilocalorieswellness
garmin.wellness.active_kilocalorieswellness
garmin.wellness.bmr_kilocalorieswellness
garmin.wellness.active_secondswellness
garmin.wellness.highly_active_secondswellness
garmin.wellness.sedentary_secondswellness
garmin.wellness.sleeping_secondswellness
garmin.wellness.floors_ascendedwellness
garmin.wellness.floors_descendedwellness
garmin.wellness.floors_ascended_goalwellness
garmin.wellness.resting_heart_rate_bpmwellness
garmin.wellness.min_heart_rate_bpmwellness
garmin.wellness.max_heart_rate_bpmwellness
garmin.wellness.body_battery_latestwellness
garmin.wellness.body_battery_highestwellness
garmin.wellness.body_battery_lowestwellness
garmin.wellness.body_battery_chargedwellness
garmin.wellness.body_battery_drainedwellness
garmin.wellness.avg_waking_respiration_bpmwellness
garmin.wellness.highest_respiration_bpmwellness
garmin.wellness.lowest_respiration_bpmwellness
garmin.wellness.avg_stress_duration_secondswellness
garmin.wellness.rest_stress_duration_secondswellness
garmin.wellness.low_stress_duration_secondswellness
garmin.wellness.high_stress_duration_secondswellness
garmin.wellness.moderate_intensity_minuteswellness
garmin.wellness.vigorous_intensity_minuteswellness
garmin.collector.up (collector)

See collector/ for per-collector implementation.

Development

make all       # fmt, vet, lint, build, test
make test      # go test -race ./...
make snapshot  # local goreleaser build

License

Apache-2.0

Tag summary

Content type

Image

Digest

sha256:818e87b79

Size

1.1 MB

Last updated

16 days ago

docker pull barnesbiz/garmin_exporter:sha256-49952d346cb0a2ce13e661c0a849ae5511dee7de2108caeca7f73bf4516d5c83.att