---
title: "Caine Nielsen • Log Challenge | Caine&#x27;s home base"
canonical_url: "https://cainenielsen.com/projects/log-challenge"
last_updated: "2026-09-03T17:15:53.347Z"
meta:
  author: "Caine Nielsen"
  description: "Log Challenge"
  "og:description": "Log Challenge"
  "og:title": "Caine Nielsen • Log Challenge"
  "twitter:description": "Log Challenge"
  "twitter:title": "Caine Nielsen • Log Challenge"
---

# Log Challenge

Caine Nielsen · August 14, 2026

As a support-oriented engineering exercise, I wanted to build something that puts a candidate in the shoes of a real support engineer: staring down a stack of tickets with only a log stream and a database to work from. That's what Log Challenge is — a self-contained, client-side debugging exercise built around a Datadog-style Lucene log search UI and a read-only SQL database browser, all running against a SQLite file with nothing on the backend.

Repo: [github.com/cainenielsen/log-challenge](https://github.com/cainenielsen/log-challenge)

Live: [cainenielsen.github.io/log-challenge](https://cainenielsen.github.io/log-challenge/)

## How it works

The app has three tabs: Challenge (the brief, where candidates land), Log Explorer, and Database Admin.

### Data

public/data.db is a plain SQLite database with four tables — users, accounts, transactions, logs — generated by a small, deterministic, stdlib-only Python script. Because the seed is fixed, regenerating the database keeps the ticket text and the answer key in sync without me having to hand-edit either one. The generator embeds several deliberate incidents that the tickets are built around: a declined charge, a duplicate charge, an account lockout, an unhandled-exception stack trace, a silent failure with no error log, and a systemic outage window.

### Runtime

Everything runs in the browser. sql.js compiles SQLite to WebAssembly, so the app loads data.db and runs real SQL against it in memory — nothing is written back. I opened the connection with PRAGMA query\_only = ON as a second line of defense on top of the UI's own statement allowlist, so there's no path to mutating the data even if someone gets creative in the SQL box.

### Log Explorer

This was the fun part to build: a hand-rolled Lucene/Datadog-style query parser supporting field:value, quoted phrases, wildcards, AND / OR / NOT, parentheses, and numeric ranges and comparisons. It filters the logs table client-side and pairs with a facet sidebar (service, level, time range) and a detail panel where clickable IDs jump straight to the matching row in Database Admin or re-scope the search to a trace\_id — mimicking the kind of pivoting a support engineer actually does when chasing an incident.

### Database Admin

A table and schema browser plus a SQL box restricted to SELECT / WITH / EXPLAIN, with a live-highlighted editor using real Shiki syntax highlighting.

## The answer key

The answer key lives at answers.html, a separate page that nothing in the app links to. It's committed to the repo — so it travels with it and stays in sync with the generated data — but it's kept off the candidate-facing surface: noindex'd and reachable only if you type the exact path. Since GitHub Pages serves the whole build output, it's technically reachable, just not discoverable. That's obscurity, not access control, so I'm treating the repo itself as the real gate.

## Stack & deployment

Built with Vite, deployed to GitHub Pages via GitHub Actions — every push to main runs the build and publishes dist/ through GitHub's official Pages actions. Nothing about this needed a server: static hosting, a WASM SQLite engine, and a bit of hand-rolled query parsing was enough to make something that feels a lot like a real support tool.

## Conclusion

Log Challenge scratched an itch I've had for a while: most take-home debugging exercises either hand candidates a wall of static text or require standing up real infrastructure just to run a simple evaluation. This sits in between — a realistic-feeling tool, zero backend, fully reproducible, and easy to reset or extend.

As always, thank you for reading. I really appreciate it. 💖