← Prototype lesson
Lab

Prototype

Sign in to run your code

Read the brief and the starter here. With a free account you can edit it, run the sample, step through it and check your work, and your progress is kept.

type Condition = { metric: string; above: number };
type Labels = Record<string, string>;
// The team's on-call channel. The team owns it and renames it when the rota
// moves; rules point at it. The checker renames it in some cases.
type Channel = { name: string };

// How the checker prints labels: checker plumbing, you don't need to edit this.
const showLabels = (labels: Labels) =>
  Object.keys(labels).sort().map((key) => `${key}=${labels[key]}`).join(',');

// Pages the channel while every condition's metric is above its threshold.
class AlertRule {
  id: string;
  template: string;
  conditions: Condition[];
  labels: Labels;
  channel: Channel;
  firing: boolean;

  constructor(id: string, template: string, conditions: Condition[], labels: Labels, channel: Channel) {
    this.id = id;
    this.template = template;
    this.conditions = conditions;
    this.labels = labels;
    this.channel = channel;
    this.firing = false;
  }

  tune(index: number, above: number): void {
    this.conditions[index]!.above = above;
  }

  label(key: string, value: string): void {
    this.labels[key] = value;
  }

  fire(): void {
    this.firing = true;
  }

  // Duplicate, for now: a fresh rule from the template this one started as.
  duplicate(newId: string): AlertRule {
    return fromTemplate(this.template, newId, this.channel);
  }

  // How the checker prints a rule: you don't need to edit this.
  describe(): string {
    const conditions = this.conditions.map((c) => `${c.metric}>${c.above}`).join(',');
    const state = this.firing ? 'firing' : 'ok';
    return `${this.id}: ${conditions} [${showLabels(this.labels)}] → ${this.channel.name} ${state}`;
  }
}

// The templates new rules start from.
const templates: Record<string, { conditions: Condition[]; labels: Labels }> = {
  latency: { conditions: [{ metric: 'p99_ms', above: 800 }], labels: { severity: 'page' } },
  errors: {
    conditions: [{ metric: 'error_rate', above: 0.05 }, { metric: 'requests', above: 100 }],
    labels: { severity: 'ticket' },
  },
};

// A new rule from a template.
function fromTemplate(template: string, id: string, channel: Channel): AlertRule {
  const { conditions, labels } = templates[template]!;
  const own = conditions.map((condition) => ({ ...condition }));
  return new AlertRule(id, template, own, { ...labels }, channel);
}