|
9 | 9 | # ./bugsnag-top.sh --all # top open error, production, all versions |
10 | 10 | # ./bugsnag-top.sh --since 2026-05-01T00:00:00Z # custom since filter |
11 | 11 | # ./bugsnag-top.sh --severity error # filter by severity |
| 12 | +# ./bugsnag-top.sh --error-id <id> # fetch a specific error by ID |
| 13 | +# ./bugsnag-top.sh --url <bugsnag_url> # fetch a specific error by Bugsnag URL |
12 | 14 |
|
13 | 15 | set -euo pipefail |
14 | 16 |
|
@@ -63,13 +65,25 @@ RELEASE_STAGE="production" |
63 | 65 | SEVERITY="" |
64 | 66 | SINCE="" |
65 | 67 | ALL_VERSIONS=false |
| 68 | +EXPLICIT_ERROR_ID="" |
66 | 69 |
|
67 | 70 | while [[ $# -gt 0 ]]; do |
68 | 71 | case "$1" in |
69 | 72 | --internal) RELEASE_STAGE="production"; SINCE=""; ALL_VERSIONS=true; shift ;; |
70 | 73 | --severity) SEVERITY="$2"; shift 2 ;; |
71 | 74 | --all) ALL_VERSIONS=true; shift ;; |
72 | 75 | --since) SINCE="$2"; shift 2 ;; |
| 76 | + --error-id) EXPLICIT_ERROR_ID="$2"; shift 2 ;; |
| 77 | + --url) |
| 78 | + # Extract error ID from a Bugsnag dashboard URL |
| 79 | + # e.g. https://app.bugsnag.com/org/project/errors/abc123def456 |
| 80 | + EXPLICIT_ERROR_ID=$(echo "$2" | grep -oE '/errors/([a-f0-9]+)' | sed 's|/errors/||') |
| 81 | + if [[ -z "$EXPLICIT_ERROR_ID" ]]; then |
| 82 | + echo "ERROR: Could not extract error ID from URL: $2" >&2 |
| 83 | + exit 1 |
| 84 | + fi |
| 85 | + shift 2 |
| 86 | + ;; |
73 | 87 | *) echo "Unknown option: $1" >&2; exit 1 ;; |
74 | 88 | esac |
75 | 89 | done |
@@ -112,30 +126,49 @@ api() { |
112 | 126 | return 1 |
113 | 127 | } |
114 | 128 |
|
115 | | -# ── Fetch top open error ────────────────────────────────────────────── |
116 | | -FILTERS="filters[error.status][]=open&filters[app.release_stage][]=${RELEASE_STAGE}" |
117 | | -if [[ -n "$SEVERITY" ]]; then |
118 | | - FILTERS="${FILTERS}&filters[event.severity][]=${SEVERITY}" |
119 | | -fi |
120 | | -if [[ -n "$SINCE" ]]; then |
121 | | - FILTERS="${FILTERS}&filters[event.since][]=${SINCE}" |
122 | | -fi |
123 | | - |
124 | | -ERRORS_URL="${API_BASE}/projects/${PROJECT_ID}/errors?${FILTERS}&sort=events&direction=desc&per_page=1" |
125 | | -ERRORS_JSON=$(api "$ERRORS_URL") |
126 | | - |
127 | | -if [[ -z "$ERRORS_JSON" ]] || ! echo "$ERRORS_JSON" | jq -e '.[0]' >/dev/null 2>&1; then |
128 | | - echo "No open errors found for release_stage=${RELEASE_STAGE}" >&2 |
129 | | - exit 1 |
| 129 | +# ── Fetch error ─────────────────────────────────────────────────────── |
| 130 | +if [[ -n "$EXPLICIT_ERROR_ID" ]]; then |
| 131 | + # Fetch a specific error by ID |
| 132 | + ERROR_URL="${API_BASE}/projects/${PROJECT_ID}/errors/${EXPLICIT_ERROR_ID}" |
| 133 | + ERROR_JSON=$(api "$ERROR_URL") |
| 134 | + |
| 135 | + if [[ -z "$ERROR_JSON" ]] || ! echo "$ERROR_JSON" | jq -e '.id' >/dev/null 2>&1; then |
| 136 | + echo "ERROR: Could not fetch error ${EXPLICIT_ERROR_ID}" >&2 |
| 137 | + exit 1 |
| 138 | + fi |
| 139 | + |
| 140 | + ERROR_ID="$EXPLICIT_ERROR_ID" |
| 141 | + TITLE=$(echo "$ERROR_JSON" | jq -r '(.error_class // "") + ": " + (.message // "")') |
| 142 | + SEVERITY_VAL=$(echo "$ERROR_JSON" | jq -r '.severity') |
| 143 | + EVENTS=$(echo "$ERROR_JSON" | jq -r '.events') |
| 144 | + USERS=$(echo "$ERROR_JSON" | jq -r '.users') |
| 145 | + FIRST_SEEN=$(echo "$ERROR_JSON" | jq -r '.first_seen') |
| 146 | +else |
| 147 | + # Fetch top open error |
| 148 | + FILTERS="filters[error.status][]=open&filters[app.release_stage][]=${RELEASE_STAGE}" |
| 149 | + if [[ -n "$SEVERITY" ]]; then |
| 150 | + FILTERS="${FILTERS}&filters[event.severity][]=${SEVERITY}" |
| 151 | + fi |
| 152 | + if [[ -n "$SINCE" ]]; then |
| 153 | + FILTERS="${FILTERS}&filters[event.since][]=${SINCE}" |
| 154 | + fi |
| 155 | + |
| 156 | + ERRORS_URL="${API_BASE}/projects/${PROJECT_ID}/errors?${FILTERS}&sort=events&direction=desc&per_page=1" |
| 157 | + ERRORS_JSON=$(api "$ERRORS_URL") |
| 158 | + |
| 159 | + if [[ -z "$ERRORS_JSON" ]] || ! echo "$ERRORS_JSON" | jq -e '.[0]' >/dev/null 2>&1; then |
| 160 | + echo "No open errors found for release_stage=${RELEASE_STAGE}" >&2 |
| 161 | + exit 1 |
| 162 | + fi |
| 163 | + |
| 164 | + ERROR_ID=$(echo "$ERRORS_JSON" | jq -r '.[0].id') |
| 165 | + TITLE=$(echo "$ERRORS_JSON" | jq -r '.[0] | (.error_class // "") + ": " + (.message // "")') |
| 166 | + SEVERITY_VAL=$(echo "$ERRORS_JSON" | jq -r '.[0].severity') |
| 167 | + EVENTS=$(echo "$ERRORS_JSON" | jq -r '.[0].events') |
| 168 | + USERS=$(echo "$ERRORS_JSON" | jq -r '.[0].users') |
| 169 | + FIRST_SEEN=$(echo "$ERRORS_JSON" | jq -r '.[0].first_seen') |
130 | 170 | fi |
131 | 171 |
|
132 | | -ERROR_ID=$(echo "$ERRORS_JSON" | jq -r '.[0].id') |
133 | | -TITLE=$(echo "$ERRORS_JSON" | jq -r '.[0] | (.error_class // "") + ": " + (.message // "")') |
134 | | -SEVERITY_VAL=$(echo "$ERRORS_JSON" | jq -r '.[0].severity') |
135 | | -EVENTS=$(echo "$ERRORS_JSON" | jq -r '.[0].events') |
136 | | -USERS=$(echo "$ERRORS_JSON" | jq -r '.[0].users') |
137 | | -FIRST_SEEN=$(echo "$ERRORS_JSON" | jq -r '.[0].first_seen') |
138 | | - |
139 | 172 | # ── Fetch latest event for this error ───────────────────────────────── |
140 | 173 | EVENTS_URL="${API_BASE}/projects/${PROJECT_ID}/errors/${ERROR_ID}/events?sort=timestamp&direction=desc&per_page=1" |
141 | 174 | EVENTS_JSON=$(api "$EVENTS_URL") |
|
0 commit comments