ЁЯПл The SchoolтА║ЁЯй║ ObservabilityтА║ЁЯй║ рдзрдбрд╛ 01 тАФ Observability рдХрд╛: рд╢рд╛рд│реЗрдЪрд╛ рдЖрд░реЛрдЧреНрдп рдХрдХреНрд╖
ЁЯЦ╝я╕П See the drawing + lab ЁЯПа Course home ЁЯМ┐ Branch on GitHub тЬПя╕П View source
ЁЯЦ╝я╕П рдЖрдХреГрддреА рдЖрдгрд┐ labThe drawing + lab рдкреВрд░реНрдг рдкрд╛рдирд╛рд╡рд░ рдЙрдШрдбрд╛ тЖЧOpen full page тЖЧ

ЁЯй║ рдзрдбрд╛ 01 тАФ Observability рдХрд╛: рд╢рд╛рд│реЗрдЪрд╛ рдЖрд░реЛрдЧреНрдп рдХрдХреНрд╖

ЁЯУН рддреБрдореНрд╣реА рдЗрдереЗ рдЖрд╣рд╛рдд: 12 рдкреИрдХреА рдзрдбрд╛ 01 ┬╖ рдкреБрдвреЗ: lesson-02-logs


ЁЯУж рдпрд╛ рдмреНрд░рдБрдЪрдордзреНрдпреЗ рдХрд╛рдп рдЖрд╣реЗ

рд╣рд╛ рд╕рдВрдкреВрд░реНрдг рдХреЛрд░реНрд╕ рдПрдХрд╛рдЪ рдкреНрд░рд╢реНрдирд╛рдЪреЗ рдЙрддреНрддрд░ рджреЗрддреЛ: "рдХрд╛рд╣реАрддрд░реА рдЪреБрдХрд▓реЗ рдЖрд╣реЗ тАФ рдХрд╛рдп, рдХреБрдареЗ, рдЖрдгрд┐ рдХрд╛?" рдЖрдЬ рдирд┐рдХрд╛рд▓рд╛рдЪрд╛ рджрд┐рд╡рд╕ рдЖрд╣реЗ. 11:40 рд▓рд╛ рдкрд╛рд▓рдХ рд╕рд╛рдВрдЧрддрд╛рдд рдХреА results page рддреБрдЯрд▓реЗ рдЖрд╣реЗ. System рдЖрдзреАрдЪ рдЬреЗ рд╕рд╛рдВрдЧрддреЗ рддреНрдпрд╛рд╡рд░реВрди team рдХрд╛ рддреЗ рд╕рд╛рдВрдЧреВ рд╢рдХреЗрд▓ рдХрд╛ тАФ рдирд╡рд╛ code рди рдЬреЛрдбрддрд╛ рдЖрдгрд┐ рддреЗ рдкреБрдиреНрд╣рд╛ рдмрд┐рдШрдбрдгреНрдпрд╛рдЪреА рд╡рд╛рдЯ рди рдкрд╛рд╣рддрд╛? рд╕рдВрдкреВрд░реНрдг рдХреЛрд░реНрд╕рдордзреНрдпреЗ рддреБрдореНрд╣реА рд╡рд╛рдкрд░рдгрд╛рд░ рдЕрд╕рд▓реЗрд▓реНрдпрд╛ рдЦрд▒реНрдпрд╛ files:

ЁЯОТ рд╕реБрд░реВ рдХрд░рдгреНрдпрд╛рдкреВрд░реНрд╡реА: рддреБрдореНрд╣рд╛рд▓рд╛ рдлрдХреНрдд Python 3 рд▓рд╛рдЧрддреЗ, рдмрд╛рдХреА рдХрд╛рд╣реА рдирд╛рд╣реА тАФ cloud account рдирд╛рд╣реА, pip install рдирд╛рд╣реА. рдпрд╛ lab рдордзреНрдпреЗ рдирд┐рдХрд╛рд▓рд╛рдЪреНрдпрд╛ 8 рддрд╛рд╕рд╛рдВрдЪреНрдпрд╛ рдПрдХрд╛ рджрд┐рд╡рд╕рд╛рдЪреА рд╢рд┐рдХрд╡рдгреНрдпрд╛рд╕рд╛рдареАрдЪреА models рдЖрд╣реЗрдд (рдорд┐рдирд┐рдЯрд╛рд▓рд╛ 1,000 requests, рдПрдХ slow leak, рдПрдХ рд╡рд╛рдИрдЯ deploy). рдЦрд░реА tools рдореНрд╣рдгрдЬреЗ Prometheus, Grafana, OpenTelemetry, CloudWatch рдЖрдгрд┐ Datadog тАФ рдХрд▓реНрдкрдирд╛ рдЖрдгрд┐ рдЧрдгрд┐рдд рддреЗрдЪ рдЖрд╣реЗ. On a real account рдЕрд╕реЗ рдЪрд┐рдиреНрд╣рд╛рдВрдХрд┐рдд commands рдЖрдгрд┐ files рд╕рд╛рдареА рддреА tools install рдЕрд╕рд╛рд╡реА рд▓рд╛рдЧрддрд╛рдд, рдЖрдгрд┐ рддреНрдпрд╛рддрд▓реНрдпрд╛ рдХрд╛рд╣реАрдВрдирд╛ рдкреИрд╕реЗ рд▓рд╛рдЧрддрд╛рдд.

ЁЯзТ 5 рд╡рд░реНрд╖рд╛рдВрдЪреНрдпрд╛ рдореБрд▓рд╛рд▓рд╛ рд╕рдордЬрд╛рд╡рд▓реНрдпрд╛рд╕рд╛рд░рдЦреЗ

рдкреНрд░рддреНрдпреЗрдХ рд╢рд╛рд│реЗрдд рдПрдХ рдЖрд░реЛрдЧреНрдп рдХрдХреНрд╖ ЁЯй║ рдЕрд╕рддреЛ. рд╢рд╛рд│реЗрдЪреА рдкрд░рд┐рдЪрд╛рд░рд┐рдХрд╛ рдХрддрд░рд┐рдирд╛ рддрд┐рдереЗ рдХрд╛рдо рдХрд░рддреЗ.

рдПрдЦрд╛рджреНрдпрд╛ рд╡рд┐рджреНрдпрд╛рд░реНрдереНрдпрд╛рд▓рд╛ рдмрд░реЗ рд╡рд╛рдЯрдд рдирд╕реЗрд▓, рддреЗрд╡реНрд╣рд╛ рдХрддрд░рд┐рдирд╛ рдЕрдВрджрд╛рдЬ рд▓рд╛рд╡рдд рдирд╛рд╣реА. рддрд┐рдЪреНрдпрд╛рдХрдбреЗ рддреАрди рд╕рд╛рдзрдиреЗ рдЖрд╣реЗрдд:

рдЖрддрд╛ рдЬреБрдиреА рдкрджреНрдзрдд. рдореБрдЦреНрдпрд╛рдзреНрдпрд╛рдкрд┐рдХрд╛ рджреАрдкрд┐рдХрд╛рдиреЗ рдПрдХрджрд╛ boiler рд╡рд░ рдПрдХ рдШрдВрдЯрд╛ рд▓рд╛рд╡рд▓реА. "Boiler рдЧрд░рдо рдЭрд╛рд▓рд╛ рдХреА рдШрдВрдЯрд╛ рд╡рд╛рдЬрд╡." рдШрдВрдЯрд╛ рд╕рдХрд╛рд│рднрд░ рд╡рд╛рдЬрдд рд░рд╛рд╣рд┐рд▓реА. рдХреЛрдгреАрдЪ рдЖрдЬрд╛рд░реА рдирд╡реНрд╣рддреЗ. рдЖрдгрд┐ рдЬреНрдпрд╛ рджрд┐рд╡рд╢реА рдПрдХ рд╡рд┐рджреНрдпрд╛рд░реНрдереА рдЦрд░реЛрдЦрд░ рдЖрдЬрд╛рд░реА рд╣реЛрддрд╛, рддреНрдпрд╛ рджрд┐рд╡рд╢реА рдШрдВрдЯрд╛ рд╢рд╛рдВрдд рд╣реЛрддреА тАФ boiler рдареАрдХ рд╣реЛрддрд╛.

рд╣рд╛рдЪ рдлрд░рдХ рдЖрд╣реЗ. Monitoring рдореНрд╣рдгрдЬреЗ boiler рд╡рд░рдЪреА рдШрдВрдЯрд╛: рддреБрдореНрд╣реА рдЖрдзреАрдЪ рдЕрдВрджрд╛рдЬ рдХреЗрд▓реЗрд▓реА рдПрдХрдЪ рдЧреЛрд╖реНрдЯ рддреА рдкрд╛рд╣рддреЗ. Observability рдореНрд╣рдгрдЬреЗ рдЖрд░реЛрдЧреНрдп рдХрдХреНрд╖: рджреИрдирдВрджрд┐рдиреА, рддрдХреНрддрд╛ рдЖрдгрд┐ рдорд╛рд░реНрдЧ рдХрд╛рд░реНрдбреЗ рдорд┐рд│реВрди рдХрддрд░рд┐рдирд╛рд▓рд╛ рдирд╡реЗ рдкреНрд░рд╢реНрди рд╕реЛрдбрд╡реВ рджреЗрддрд╛рдд тАФ "рдЖрдЬ 3A рд╡рд░реНрдЧ рдХрд╛ рдЖрдЬрд╛рд░реА рдЖрд╣реЗ?" тАФ рдЬреНрдпрд╛рдВрдЪрд╛ рдХреЛрдгреАрдЪ рдЖрдзреА рд╡рд┐рдЪрд╛рд░ рдХреЗрд▓рд╛ рдирд╡реНрд╣рддрд╛.

ЁЯЧ║я╕П рдЖрдХреГрддреА

flowchart LR
    q["тЭУ 11:40 тАФ 'the results page is broken'"]
    subgraph room["ЁЯй║ the health room"]
      m["ЁЯУК metrics<br/>THAT something is wrong<br/>errors 0.1% тЖТ 6%"]
      t["ЁЯЧ║я╕П traces<br/>WHERE the time went<br/>grade service: 865 of 1040 ms"]
      l["ЁЯУУ logs<br/>WHY, in detail<br/>'grade service timeout'"]
    end
    cpu["ЁЯФФ old bell: CPU > 80%<br/>64 noisy minutes"]
    q --> m --> t --> l
    q -.->|"quiet or wrong"| cpu

ЁЯЧ║я╕П рдХрд╛рдврд▓реЗрд▓реА рдЖрд╡реГрддреНрддреА + рдПрдХ lab: https://school-edh.pages.dev/observability/lesson-diagrams.html#l01

тЭУ рдХрд╛рдп

ЁЯдФ рдХрд╛

рдХрд╛рд░рдг рдЖрдзреБрдирд┐рдХ systems рдирд╡реНрдпрд╛ рдкрджреНрдзрддреАрдВрдиреА рдмрд┐рдШрдбрддрд╛рдд. рдирд┐рдХрд╛рд▓рд╛рдЪреНрдпрд╛ рджрд┐рд╡рд╢реА рдПрдХрдЪ page load рдПрдХ gateway, рдПрдХ auth service, results API, рдПрдХ database рдЖрдгрд┐ рдПрдХ grade service рдпрд╛рдВрдирд╛ рд╕реНрдкрд░реНрд╢ рдХрд░рддреЛ. рдорд╛рдЧрдЪреНрдпрд╛ рд╡рд░реНрд╖реАрдЪреНрдпрд╛ outage рд╕рд╛рдареА рдмрдирд╡рд▓реЗрд▓рд╛ dashboard рдпрд╛ рд╡рд░реНрд╖реАрдЪрд╛ outage рджрд╛рдЦрд╡рдд рдирд╛рд╣реА. рдлрдХреНрдд monitoring рдЕрд╕реЗрд▓ рддрд░ team outage рдирдВрддрд░ рдирд╡рд╛ graph рдЬреЛрдбрддреЗ рдЖрдгрд┐ рдкреБрдврдЪреНрдпрд╛ outage рдЪреА рд╡рд╛рдЯ рдкрд╛рд╣рддреЗ. Observability рдЕрд╕реЗрд▓ рддрд░ data рдЖрдзреАрдЪ рддрд┐рдереЗ рдЕрд╕рддреЛ тАФ рддреБрдореНрд╣рд╛рд▓рд╛ рдлрдХреНрдд рд╡рд┐рдЪрд╛рд░рд╛рдпрдЪреЗ рдЕрд╕рддреЗ.

рдЖрдгрд┐ рдЬреБрдиреЗ signals рдЕрдиреЗрдХрджрд╛ noise рдЕрд╕рддрд╛рдд. Lab рдордзреНрдпреЗ рджрд┐рд╡рд╕рднрд░рд╛рдд CPU 64 рдорд┐рдирд┐рдЯреЗ 80% рдЪреНрдпрд╛ рдкрд╛рд░ рдЬрд╛рддреЛ. рддреНрдпрд╛рддрд▓реЗ рдПрдХрд╣реА рдорд┐рдирд┐рдЯ рдкрд╛рд▓рдХрд╛рдВрдирд╛ рдЬрд╛рдгрд╡рдгрд╛рд▒реНрдпрд╛ рдЧреЛрд╖реНрдЯреАрдмрджреНрджрд▓ рдирд╛рд╣реА.

ЁЯФз рдХрд╕реЗ (рдпрд╛ repo рдордзреНрдпреЗ)

demo.py рдирд┐рдХрд╛рд▓рд╛рдЪрд╛ 480 рдорд┐рдирд┐рдЯрд╛рдВрдЪрд╛ рдПрдХ рджрд┐рд╡рд╕ рдмрдирд╡рддреЛ: REQ (рдорд┐рдирд┐рдЯрд╛рд▓рд╛ 1,000 requests), ERR (рдорд┐рдирд┐рдЯрд╛рд▓рд╛ errors: рд╕рд╛рдзрд╛рд░рдгрдкрдгреЗ 0.1%, рдорд┐рдирд┐рдЯреЗ 100тАУ379 рдордзреАрд▓ slow leak рджрд░рдореНрдпрд╛рди 0.9%, рдорд┐рдирд┐рдЯреЗ 400тАУ431 рдордзреАрд▓ рд╡рд╛рдИрдЯ deploy рдирдВрддрд░ 6%) рдЖрдгрд┐ CPU (рд╡реНрдпрд╕реНрдд, рдкрдг errors рд╢реА рд╕рдВрдмрдВрдз рдирд╕рд▓реЗрд▓рд╛). obs/reliability.py рдордзреАрд▓ threshold_alerts(cpu_series, limit=80) CPU рдорд░реНрдпрд╛рджреЗрдЪреНрдпрд╛ рд╡рд░ рдЕрд╕рд▓реЗрд▓реЗ рдкреНрд░рддреНрдпреЗрдХ рдорд┐рдирд┐рдЯ рдкрд░рдд рдХрд░рддреЗ тАФ рдореНрд╣рдгрдЬреЗрдЪ "boiler рд╡рд░рдЪреА рдШрдВрдЯрд╛". why() рдЧреЛрд╖реНрдЯ print рдХрд░рддреЗ рдЖрдгрд┐ рддреА рдорд┐рдирд┐рдЯреЗ рдореЛрдЬрддреЗ.

ЁЯзк рдХрд░реВрди рдкрд╛рд╣рд╛

python3 obs/demo.py why
python3 - <<'EOF'
import sys; sys.path.insert(0, "obs"); from demo import CPU, ERR, REQ; from reliability import threshold_alerts
for limit in (70, 80, 90):
    print(f"alert when CPU > {limit}% тЖТ {len(threshold_alerts(CPU, limit)):>3} minutes of alerts")
bad = [m for m in range(len(ERR)) if ERR[m] / REQ[m] > 0.05]
cpu = threshold_alerts(CPU)
print(f"minutes when parents saw >5% errors: {len(bad)} ┬╖ CPU alerts in those minutes: {len(set(bad) & set(cpu))}")
print(f"CPU during the bad deploy: min {min(CPU[400:432])}% ┬╖ max {max(CPU[400:432])}% ┬╖ on a calm minute (10): {CPU[10]}%")
EOF
python3 obs/test_obs.py

тЬЕ рддрдкрд╛рд╕рд╛ тАФ рддреБрдореНрд╣рд╛рд▓рд╛ рдХрд╛рдп рджрд┐рд╕рд╛рдпрд▓рд╛ рд╣рд╡реЗ

why рд╣реЗ print рдХрд░рддреЗ:

тФАтФА results day, 11:40: 'parents say the results page is broken' тАФ can we answer WHY without adding code?
   monitoring: dashboards for failures you predicted (CPU, disk, 5xx)
   observability: ask NEW questions of the system from what it already emits тАФ logs, metrics, traces
   this morning: CPU crossed 80% in 64 minutes тАФ but CPU is not what parents feel
   the three signals: metrics say THAT something is wrong ┬╖ traces say WHERE ┬╖ logs say WHY

рддреБрдордЪрд╛ snippet рд╣реЗ print рдХрд░рддреЛ:

alert when CPU > 70% тЖТ 224 minutes of alerts
alert when CPU > 80% тЖТ  64 minutes of alerts
alert when CPU > 90% тЖТ   0 minutes of alerts
minutes when parents saw >5% errors: 32 ┬╖ CPU alerts in those minutes: 4
CPU during the bad deploy: min 55% ┬╖ max 84% ┬╖ on a calm minute (10): 65%

Tests рд╢реЗрд╡рдЯреА 12/12 passed рджрд╛рдЦрд╡рддрд╛рдд.

ЁЯПБ рддреБрдореНрд╣реА рдЖрддреНрддрд╛рдЪ рдХрд╛рдп рд╕рд┐рджреНрдз рдХреЗрд▓реЗ

CPU alarm рдПрдХрддрд░ рдЦреВрдк рдореЛрдареНрдпрд╛рдиреЗ рд╡рд╛рдЬрддреЛ (70% рд▓рд╛ 224 рдорд┐рдирд┐рдЯреЗ) рдХрд┐рдВрд╡рд╛ рдмрд╣рд┐рд░рд╛ рдЕрд╕рддреЛ (90% рд▓рд╛ 0 рдорд┐рдирд┐рдЯреЗ). 80% рд▓рд╛, рдкрд╛рд▓рдХрд╛рдВрдирд╛ рдЦрд░реЛрдЦрд░ errors рджрд┐рд╕рд▓реЗ рддреНрдпрд╛ 32 рдорд┐рдирд┐рдЯрд╛рдВрдкреИрдХреА рдлрдХреНрдд 4 рдорд┐рдирд┐рдЯрд╛рдВрдд рддреЛ рд╡рд╛рдЬрд▓рд╛ тАФ рдЖрдгрд┐ рддреНрдпрд╛рдВрдирд╛ errors рджрд┐рд╕рдд рдирд╡реНрд╣рддреЗ рдЕрд╢рд╛ 60 рдорд┐рдирд┐рдЯрд╛рдВрдд рд╡рд╛рдЬрд▓рд╛. рд╡рд╛рдИрдЯ deploy рджрд░рдореНрдпрд╛рдирдЪрд╛ CPU рдЗрддрд░ рдХреЛрдгрддреНрдпрд╛рд╣реА рддрд╛рд╕рд╛рд╕рд╛рд░рдЦрд╛рдЪ рджрд┐рд╕рдд рд╣реЛрддрд╛. рдорд╣рддреНрддреНрд╡рд╛рдЪрд╛ signal рдореНрд╣рдгрдЬреЗ рдЬреЛ users рдирд╛ рдЬрд╛рдгрд╡рддреЛ: errors рдЖрдгрд┐ рд╣рд│реВрдкрдгрд╛. рдЙрд░рд▓реЗрд▓рд╛ рдХреЛрд░реНрд╕ рддреЛ signal рдЯрдкреНрдкреНрдпрд╛рдЯрдкреНрдкреНрдпрд╛рдиреЗ рддрдпрд╛рд░ рдХрд░рддреЛ.

тЪая╕П рдиреЗрд╣рдореАрдЪреНрдпрд╛ рдЪреБрдХрд╛

ЁЯПн рдкреНрд░рддреНрдпрдХреНрд╖ рд╡рд╛рдкрд░рд╛рдд

On a real account тАФ рдиреЗрд╣рдореАрдЪреНрдпрд╛ stacks рдордзрд▓реЗ рддреЗрдЪ рддреАрди signals:

Signal Open source AWS Datadog
ЁЯУК Metrics Prometheus + Grafana CloudWatch Metrics Datadog Metrics
ЁЯУУ Logs Loki, OpenSearch CloudWatch Logs + Logs Insights Datadog Logs
ЁЯЧ║я╕П Traces Tempo, Jaeger AWS X-Ray (CloudWatch) Datadog APM
ЁЯФн рдЧреЛрд│рд╛ рдХрд░рдгреЗ OpenTelemetry SDK + Collector (рдзрдбрд╛ 06) ADOT (AWS Distro for OpenTelemetry) Datadog Agent (OTLP рд╕реНрд╡реАрдХрд╛рд░рддреЛ)

рдХреЛрдгрддреНрдпрд╛рд╣реА service рдЪреА рдкрд╣рд┐рд▓реА рдкреНрд░рд╛рдорд╛рдгрд┐рдХ рддрдкрд╛рд╕рдгреА: рддреА рдЖрдзреАрдЪ рдЬреЗ рдмрд╛рд╣реЗрд░ рдЯрд╛рдХрддреЗ рддреНрдпрд╛рд╡рд░реВрди, рдкрд╛рдЪ рдорд┐рдирд┐рдЯрд╛рдВрдЪреНрдпрд╛ рдЖрдд рддреБрдореНрд╣реА рд╣реЗ рддреАрди рдкреНрд░рд╢реНрди рд╕реЛрдбрд╡реВ рд╢рдХрддрд╛ рдХрд╛?

1. What share of requests failed in the last 15 minutes?     (metrics)
2. For one failed request, which service spent the time?     (traces)
3. What did that service say about it, in detail?            (logs, joined by trace id)

ЁЯПн Production рдордзреНрдпреЗ рд╣реЗ рдХрд╛ рдорд╣рддреНрддреНрд╡рд╛рдЪреЗ: рдЖрдзреА рдкреНрд░рд╢реНрди рд▓рд┐рд╣рд╛, рдордЧ telemetry. рдЬреА service рд╣реЗ рддреАрди рдкреНрд░рд╢реНрди рд╕реЛрдбрд╡реВ рд╢рдХрдд рдирд╛рд╣реА рддреА рдирд┐рдХрд╛рд▓рд╛рдЪреНрдпрд╛ рджрд┐рд╡рд╕рд╛рд╕рд╛рдареА рддрдпрд╛рд░ рдирд╛рд╣реА.

тПня╕П рдкреБрдвреЗ

рдЖрд░реЛрдЧреНрдп рдХрдХреНрд╖рд╛рддрд▓реЗ рдкрд╣рд┐рд▓реЗ рд╕рд╛рдзрди: рджреИрдирдВрджрд┐рдиреА. рдкреНрд░рддреНрдпреЗрдХ рдШрдЯрдиреЗрд╕рд╛рдареА рдПрдХ рдУрд│, рдЕрд╢реА рд▓рд┐рд╣рд┐рд▓реЗрд▓реА рдХреА machine рддреА рд╢реЛрдзреВ рд╢рдХреЗрд▓.

git checkout lesson-02-logs

ЁЯй║ Lesson 01 тАФ Why observability: the school health room

ЁЯУН You are here: Lesson 01 of 12 ┬╖ Next: lesson-02-logs


ЁЯУж What's in this branch

The one question this whole course answers: "Something is wrong тАФ what, where, and why?" It is results day. At 11:40 parents say the results page is broken. Can the team answer why from what the system already tells them тАФ without adding new code and waiting for it to break again? Real files you will use all the way through:

ЁЯОТ Before you start: you need Python 3 and nothing else тАФ no cloud account, no pip install. The lab holds teaching models of one 8-hour results day (1,000 requests a minute, a slow leak, a bad deploy). The real tools are Prometheus, Grafana, OpenTelemetry, CloudWatch and Datadog тАФ the ideas and the maths are the same. Commands and files marked on a real account need those tools installed, and some of them cost money.

ЁЯзТ Explain like I'm 5

Every school has a health room ЁЯй║. Katrina, the school nurse, works there.

When a pupil feels ill, Katrina does not guess. She has three tools:

Now the old way. The head teacher, Dipika, once put a bell on the boiler. "If the boiler gets hot, ring the bell." The bell rang all morning. Nobody was ill. And the day a pupil really was ill, the bell was quiet тАФ the boiler was fine.

That is the difference. Monitoring is the bell on the boiler: it watches the one thing you guessed in advance. Observability is the health room: the diary, the chart and the route cards together let Katrina answer new questions тАФ "why is class 3A ill today?" тАФ that nobody planned for.

ЁЯЧ║я╕П Diagram

flowchart LR
    q["тЭУ 11:40 тАФ 'the results page is broken'"]
    subgraph room["ЁЯй║ the health room"]
      m["ЁЯУК metrics<br/>THAT something is wrong<br/>errors 0.1% тЖТ 6%"]
      t["ЁЯЧ║я╕П traces<br/>WHERE the time went<br/>grade service: 865 of 1040 ms"]
      l["ЁЯУУ logs<br/>WHY, in detail<br/>'grade service timeout'"]
    end
    cpu["ЁЯФФ old bell: CPU > 80%<br/>64 noisy minutes"]
    q --> m --> t --> l
    q -.->|"quiet or wrong"| cpu

ЁЯЧ║я╕П Drawn version + a lab: https://school-edh.pages.dev/observability/lesson-diagrams.html#l01

тЭУ What

ЁЯдФ Why

Because modern systems fail in new ways. One page load on results day touches a gateway, an auth service, the results API, a database and a grade service. A dashboard built for last year's outage does not show this year's. With only monitoring, the team adds a new graph after the outage and waits for the next one. With observability, the data is already there тАФ you only need to ask.

And the old signals are often noise. In the lab, CPU crosses 80% in 64 minutes of the day. None of those minutes are about what parents feel.

ЁЯФз How (in this repo)

demo.py builds one results day of 480 minutes: REQ (1,000 requests a minute), ERR (errors per minute: 0.1% normally, 0.9% during a slow leak in minutes 100тАУ379, 6% after a bad deploy in minutes 400тАУ431) and CPU (busy, but not linked to errors). threshold_alerts(cpu_series, limit=80) in obs/reliability.py returns every minute where CPU is above the limit тАФ the "bell on the boiler". why() prints the story and counts those minutes.

ЁЯзк Try it

python3 obs/demo.py why
python3 - <<'EOF'
import sys; sys.path.insert(0, "obs"); from demo import CPU, ERR, REQ; from reliability import threshold_alerts
for limit in (70, 80, 90):
    print(f"alert when CPU > {limit}% тЖТ {len(threshold_alerts(CPU, limit)):>3} minutes of alerts")
bad = [m for m in range(len(ERR)) if ERR[m] / REQ[m] > 0.05]
cpu = threshold_alerts(CPU)
print(f"minutes when parents saw >5% errors: {len(bad)} ┬╖ CPU alerts in those minutes: {len(set(bad) & set(cpu))}")
print(f"CPU during the bad deploy: min {min(CPU[400:432])}% ┬╖ max {max(CPU[400:432])}% ┬╖ on a calm minute (10): {CPU[10]}%")
EOF
python3 obs/test_obs.py

тЬЕ Verify тАФ what you should see

why prints:

тФАтФА results day, 11:40: 'parents say the results page is broken' тАФ can we answer WHY without adding code?
   monitoring: dashboards for failures you predicted (CPU, disk, 5xx)
   observability: ask NEW questions of the system from what it already emits тАФ logs, metrics, traces
   this morning: CPU crossed 80% in 64 minutes тАФ but CPU is not what parents feel
   the three signals: metrics say THAT something is wrong ┬╖ traces say WHERE ┬╖ logs say WHY

Your snippet prints:

alert when CPU > 70% тЖТ 224 minutes of alerts
alert when CPU > 80% тЖТ  64 minutes of alerts
alert when CPU > 90% тЖТ   0 minutes of alerts
minutes when parents saw >5% errors: 32 ┬╖ CPU alerts in those minutes: 4
CPU during the bad deploy: min 55% ┬╖ max 84% ┬╖ on a calm minute (10): 65%

The tests end with 12/12 passed.

ЁЯПБ What you just proved

A CPU alarm is either too loud (224 minutes at 70%) or deaf (0 minutes at 90%). At 80% it fired in only 4 of the 32 minutes when parents really saw errors тАФ and in 60 minutes when they did not. CPU during the bad deploy looked like any other hour. The signal that matters is the one users feel: errors and slowness. The rest of the course builds that signal, step by step.

тЪая╕П Common mistakes

ЁЯПн In production

On a real account тАФ the same three signals in the common stacks:

Signal Open source AWS Datadog
ЁЯУК Metrics Prometheus + Grafana CloudWatch Metrics Datadog Metrics
ЁЯУУ Logs Loki, OpenSearch CloudWatch Logs + Logs Insights Datadog Logs
ЁЯЧ║я╕П Traces Tempo, Jaeger AWS X-Ray (CloudWatch) Datadog APM
ЁЯФн Collecting OpenTelemetry SDK + Collector (lesson 06) ADOT (AWS Distro for OpenTelemetry) Datadog Agent (accepts OTLP)

A first honest check on any service: can you answer these three questions in under five minutes, from what it already emits?

1. What share of requests failed in the last 15 minutes?     (metrics)
2. For one failed request, which service spent the time?     (traces)
3. What did that service say about it, in detail?            (logs, joined by trace id)

ЁЯПн Why this matters in production: write the questions first, then the telemetry. A service that cannot answer those three questions is not ready for results day.

тПня╕П Next

The first tool in the health room: the diary. One line per event, written so a machine can search it.

git checkout lesson-02-logs
тЖР Course homeall lessonsNext тЖТlogs

This page is the lesson's README from the lesson-01-why-observability branch, shown here so the whole School stays on one site. Code files open on GitHub at the same branch.