From 43deee0c90878f7ea4a71b02b44b6b2b3c68d81b Mon Sep 17 00:00:00 2001 From: Mark Lee Date: Thu, 16 Apr 2026 18:35:51 -0700 Subject: [PATCH 1/2] feat(mise): opt-in Datadog metrics for app token usage --- shell/lib/mise.sh | 80 ++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 75 insertions(+), 5 deletions(-) diff --git a/shell/lib/mise.sh b/shell/lib/mise.sh index 66be26ad..c571c93d 100644 --- a/shell/lib/mise.sh +++ b/shell/lib/mise.sh @@ -242,19 +242,89 @@ mise_manages_tool_versions() { # `wait-for-gh-rate-limit` is installed, makes sure that the token # isn't rate limited before calling `mise`. run_mise() { - local mise_path - mise_path="$(find_mise)" + local exitCode ghToken misePath + misePath="$(find_mise)" if in_ci_environment && [[ -n ${MISE_GITHUB_TOKEN:-} || -n ${GITHUB_TOKEN:-} ]]; then - local ghToken="${MISE_GITHUB_TOKEN:-$GITHUB_TOKEN}" + ghToken="${MISE_GITHUB_TOKEN:-$GITHUB_TOKEN}" GITHUB_TOKEN="$ghToken" wait_for_gh_rate_limit fi if mise_manages_tool_versions; then - "$mise_path" "$@" + "$misePath" "$@" || exitCode=$? else - MISE_OVERRIDE_TOOL_VERSIONS_FILENAMES=none "$mise_path" "$@" + MISE_OVERRIDE_TOOL_VERSIONS_FILENAMES=none "$misePath" "$@" || exitCode=$? fi + exitCode=${exitCode:-0} + + if [[ -n ${ghToken:-} ]]; then + GITHUB_TOKEN="$ghToken" report_gh_rate_limit_to_datadog "${1:-unknown}" + fi + + return "$exitCode" +} + +# report_gh_rate_limit_to_datadog MISE_COMMAND +# +# Best-effort submission of the current GitHub API rate-limit state +# as Datadog gauge metrics, tagged with the mise subcommand, repo, and +# CI job. Silently no-ops when not in CI, when DATADOG_API_KEY is unset, +# when `gh` or `gojq` are unavailable, or when the rate-limit query +# fails. Never returns a non-zero exit code. +report_gh_rate_limit_to_datadog() { + local ddPayload miseCommand now rateLimit remaining tags used + miseCommand="$1" + + if ! in_ci_environment || [[ -z ${DATADOG_API_KEY:-} ]] || ! command_exists gh || ! command_exists gojq; then + return 0 + fi + + rateLimit="$(gh api /rate_limit --jq .rate 2>/dev/null || true)" + if [[ -z $rateLimit ]]; then return 0; fi + # Validate JSON before feeding to --argjson; a malformed response would + # otherwise make gojq exit non-zero and, under `set -e` in callers, kill + # the parent script. + if ! gojq --exit-status . <<<"$rateLimit" >/dev/null 2>&1; then return 0; fi + + # Why: jq vars, not shell vars + # shellcheck disable=SC2016 + used="$(gojq --null-input --argjson r "$rateLimit" '$r.used')" + # Why: jq vars, not shell vars + # shellcheck disable=SC2016 + remaining="$(gojq --null-input --argjson r "$rateLimit" '$r.remaining')" + now="$(date +%s)" + # Why: jq vars, not shell vars + # shellcheck disable=SC2016 + tags="$(gojq --null-input --compact-output \ + --arg c "$miseCommand" \ + --arg r "${CIRCLE_PROJECT_REPONAME:-unknown}" \ + --arg j "${CIRCLE_JOB:-unknown}" \ + '["mise_command:" + $c, "repo:" + $r, "ci_job:" + $j]')" + # type=3 is gauge + ddPayload=$( + cat </dev/null || true } # If `wait-for-gh-rate-limit` is installed, runs it to wait for From 0ad2d73f0014e0d857da6a4dc318bfcb9e33eabb Mon Sep 17 00:00:00 2001 From: Mark Lee Date: Thu, 16 Apr 2026 18:42:53 -0700 Subject: [PATCH 2/2] Better debugging --- shell/lib/mise.sh | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/shell/lib/mise.sh b/shell/lib/mise.sh index c571c93d..7c38d7fc 100644 --- a/shell/lib/mise.sh +++ b/shell/lib/mise.sh @@ -280,11 +280,17 @@ report_gh_rate_limit_to_datadog() { fi rateLimit="$(gh api /rate_limit --jq .rate 2>/dev/null || true)" - if [[ -z $rateLimit ]]; then return 0; fi + if [[ -z $rateLimit ]]; then + warn "Could not get rate limit from GitHub API, skipping" >&2 + return 0 + fi # Validate JSON before feeding to --argjson; a malformed response would # otherwise make gojq exit non-zero and, under `set -e` in callers, kill # the parent script. - if ! gojq --exit-status . <<<"$rateLimit" >/dev/null 2>&1; then return 0; fi + if ! gojq --exit-status . <<<"$rateLimit" >/dev/null 2>&1; then + warn "Returned rate limit is not valid JSON, skipping" >&2 + return 0 + fi # Why: jq vars, not shell vars # shellcheck disable=SC2016