Practice problem · Eightfold · Hard

API Log Insights: Formats, Limits, Live Updates

A cloud provider's API traffic is logged by many sources, each writing files in its own shape into input/<source/: an edge server writes JSON Lines with api_key and latency_ms, a microservice writes CSV with client_id and response_time_ms. 3 stages in Python with an AI assistant. Pro.

Stage 1 of 3: Two formats, one record, insights per source

Background. A cloud provider's API traffic is logged by many sources, each writing files in its own shape into input/<source>/: an edge server writes JSON Lines with api_key and latency_ms, a microservice writes CSV with client_id and response_time_ms. The service you are building reads those files, maps every entry onto one record (records.py), computes usage insights per source, and writes them to output/<source>/insights.json. sources.json says which format each source uses and how its field names map onto the record's (config.py reads and validates it). test_helpers.py builds a scratch workspace with both.

Implement parse in parsers.py and Engine in engine.py (metrics.py is yours to organise).

  • parse(text, config, header=None) returns (records, skipped, header). jsonl: one JSON object per line, either a single entry or {"records": [...]} holding several; blank lines are nothing. csv: a header row names the columns, then one entry per row; pass the returned header back in when text continues a file whose header was already read, and the rows are then rows; for jsonl the returned header is None, for csv it is the list of column names. A records value that is not a list is one bad entry. An entry becomes a Record through the mapping; latency_ms and status must be integers, negative ones included (a digit string with an optional leading minus counts; floats, booleans, spaces and + do not); timestamp, client, endpoint and method must be strings (a null or a number is a missing field); the timestamp an ISO 8601 date-time with a UTC offset, kept as written. Anything that cannot become a record is one skipped: an unreadable line, a batch item, a CSV row with more or fewer cells than the header, a missing mapped field.
  • Engine(input_dir, output_dir, sources_path, limits_path=None); run_once() reads every file of every configured source whose folder exists, and returns {source: insights} after writing each to output/<source>/insights.json. A folder with no configuration is ignored; a configured source with no folder is skipped; a bad configuration raises ValueError.
  • Insights: {"source", "records", "skipped", "clients", "top_endpoints"}. clients maps each client id, in sorted order, to {"requests": n, "avg_latency_ms": sum / n} (a float). top_endpoints lists at most five {"endpoint", "requests"}, most requests first, equal counts by endpoint name. Clients and endpoints are per source.

Example

ws = Workspace()                                      # input/, output/, sources.json
ws.write_jsonl("EdgeServer", "log1.json", [edge_entry(), edge_entry(key="xyz789", latency=250)])
Engine(ws.input, ws.output, ws.sources_path).run_once()["EdgeServer"]
# {"source": "EdgeServer", "records": 2, "skipped": 0,
#  "clients": {"abc123": {"requests": 1, "avg_latency_ms": 120.0}, "xyz789": {"requests": 1, "avg_latency_ms": 250.0}},
#  "top_endpoints": [{"endpoint": "/v1/users", "requests": 2}]}

Done when Submit goes green.

Constraints

  • Python 3.12+ standard library only
  • Time limit: 10 seconds per test file
  • Editable: parsers.py, metrics.py, engine.py, limits.py
  • Read-only: records.py, config.py, test_helpers.py and all tests/test_*.py files

What comes after stage 1

The next stages open once the tests for the one before them pass. Each raises the bar, the way an interviewer does in the room.

  1. Stage 2: Dynamic rate limits. A limits file that changes under you, fixed clock windows, and a flag on every client who went over.
  2. Stage 3: Files that grow, sources that come and go. Read only what is new, remember what you read, and forget what disappeared, fast enough to run every few seconds.

The files you get

  • Yours to edit: parsers.py, metrics.py, engine.py, limits.py.
  • Read-only: records.py, config.py, test_helpers.py, tests/__init__.py.
  • Tests you can read and run: tests/test_part1_parse_and_metrics.py. Hidden tests run on Submit.

The round: an agent in the editor

The assistant here works like the one in the interview IDE. It reads your files, runs code and proposes changes, and you accept or reject each one. It doesn't volunteer ideas, so what gets built is what you asked for. Along the way the interviewer asks about your decisions, and at the end the report says what you checked and what you accepted unread.

Frequently asked, briefly answered

Is API Log Insights: Formats, Limits, Live Updates free?

It is a Pro problem. Free plan includes one complete problem, plus the first stage of several more, so you can see how a round works before you pay.

Which company asks something like this?

Eightfold. It is modelled on Eightfold's round: AI-assisted coding round for senior engineers: a system-sized problem statement, your own IDE and AI assistant, graded on whether it runs.

Do I bring my own AI tool?

No. The assistant is in the editor, same as in the interview IDEs at Meta, Stripe and Amazon. What you choose at Begin is the format: an agent that proposes changes you accept or reject, an answer-only assistant that can't write code, or no assistant at all.

What does the interviewer ask?

3 questions along the way about your own code, and one at the end about the whole session. A weak answer gets one follow up. The answers go into the report, which ends with a hire or no hire verdict.

Start the problem

Sign in and the problem opens where you left it. New here? An account takes a minute to create, and the Pro plan starts at the first stage of this problem.

Start this problem → Sign in

More like it: every practice problem, how Eightfold runs its AI round, the AI coding interview guide.