Coding problem · Medium · Data Processing

Top Endpoints from Access Logs

Medium Practical tasks Seen at Datadog, Cloudflare, Shopify, Amazon

You are given lines from an HTTP access log in the common format:

203.0.113.9 - - [11/Oct/2026:10:00:01 +0000] "GET /api/users?page=2 HTTP/1.1" 200 512

Return the k most requested paths:

  • the path is the request target without its query string (/api/users?page=2 → /api/users);
  • count every well-formed request regardless of method or status;
  • skip malformed lines (no quoted "METHOD path PROTOCOL" part);
  • order by count descending, then by path ascending; return fewer than k paths if there aren't enough.

Example 1

Input: lines = (7 sample lines), k = 2
Output: ["/api/users","/api/orders"]
Explanation: /api/users appears 3 times, /api/orders twice.

Hints

Hint 1

A regex like "[A-Z]+ (\S+) [^"]*" extracts the request target.

Hint 2

Strip the query string, count with a hash map, then sort by (−count, path).

Write and run your solution

Loading the editor… (JavaScript is required to run code in your browser.)

Solution and explanation

Show the solution

Time O(n + p log p) for p distinct paths · Space O(p)

One pass: match each line against a regex that captures the request target, drop malformed lines, cut the query string at ?, and count in a hash map. Sorting distinct paths by (-count, path) gives a deterministic order. For huge logs you'd stream the file and keep a size-k heap instead of sorting every path.

Reference solution

function topEndpoints(lines, k) {
  const counts = new Map();
  for (const line of lines) {
    const m = line.match(/"[A-Z]+ (\S+) [^"]*"/);
    if (!m) continue;
    const path = m[1].split("?")[0];
    counts.set(path, (counts.get(path) ?? 0) + 1);
  }
  return [...counts.entries()]
    .sort((a, b) => b[1] - a[1] || (a[0] < b[0] ? -1 : 1))
    .slice(0, k)
    .map(([path]) => path);
}

Common mistakes

  • Counting /api/users and /api/users?page=2 as different endpoints.
  • Unstable ordering for ties — always define a tie-breaker.
  • Crashing on a malformed line instead of skipping it.

Follow-up questions

  • Group by route template (/users/123 → /users/:id).
  • Compute p95 latency per endpoint.
  • Process a multi-GB file with constant memory.