Exercise 1: A Counter for Failed Login Attempts — Possible Solution ==================================================================== # HELP failed_login_attempts_total Total failed login attempts # TYPE failed_login_attempts_total counter failed_login_attempts_total{reason="bad_password"} 342 failed_login_attempts_total{reason="account_locked"} 17 -- Why a counter, not a gauge? -- -- -- "Total failed login attempts" is inherently a running, cumulative -- count that only ever grows over the life of the process -- every -- new failed attempt adds one more to the total, and the number -- should never legitimately decrease (short of a process restart, -- which counters explicitly account for as a reset back to zero). -- That's exactly the counter contract: monotonically increasing, -- meant to be turned into a meaningful per-second rate later via -- rate() rather than read as a raw cumulative number directly. A -- gauge would be the wrong choice here because gauges are meant for -- values that can freely rise AND fall -- there's no real-world -- sense in which "failed login attempts so far" should ever go back -- down while the process keeps running, the way a gauge like -- "current active connections" legitimately does. WHY THIS WORKS AS AN ANSWER ------------------------------ This writes the metric in the chapter's own exposition format with a correctly bounded label (a small, fixed set of failure reasons, not an unbounded value), then explains the counter choice by tying it directly to the counter's own defining property -- monotonic, cumulative, reset-on-restart -- rather than just asserting "it should be a counter."