Free preview

Requirements, Building Blocks, and the API

In one line: this design is unusual in the course — it is assembled almost entirely from earlier building blocks. Pub-sub, distributed search, and blob store do most of the work, which is itself the lesson.

Functional requirements

RequirementDetail
Writing logsServices within the distributed system must be able to write to the logging system
Searchable logsUsers must be able to search logs effortlessly and track the application flow end to end
Storing logsLogs must reside in distributed storage for easy access
Centralized logging visualizerThe system must provide a unified view of globally distributed services

'Track the application flow end to end' is the requirement that makes this hard

Three of the four requirements are ordinary: write, store, display. "Track the application flow end to end" is the one that carries Lesson 2's real problem.

Searching logs is easy — that is a text search over documents, and the inverted-index pattern already built it. Reconstructing one request's path across a dozen services is not, because it requires the logs to carry something that links them, and it requires that something to preserve order.

Nothing in the storage or search machinery provides that. It has to be designed in at the producer, which is why Lesson 9's sequencer-issued request ID exists. If you only take one requirement seriously in this chapter, take this one — it is what distinguishes a log store from a log system.

Non-functional requirements

RequirementDetail
Low latencyLogging is an I/O-intensive operation. It must not block the application's critical path
ScalabilityHandle increasing log volumes and a growing number of concurrent users
AvailabilityThe logging system must be highly available

'Must not block the critical path' is the sharpest constraint here

This is a stronger statement than "should be fast." It means the logging system's latency must be invisible to the application, and it has a hard consequence: the application cannot wait for logging to succeed.

Which in turn means logging cannot be reliably durable from the application's point of view. If you do not wait for the write, you do not know whether it happened.

That is a genuine and deliberate trade, and it inverts the priorities of most components in this course. The Distributed Messaging Queue chapter would not acknowledge a message until it was durable. Here, the application fires and forgets, accepting that some logs are lost, because a logging system that slows down the product has failed at its job — logging is diagnostics, not the product.

Lesson 7 states the trade explicitly: "a trade-off between latency and guarantees of persistence." Being able to say "we deliberately chose lossy logging over slow requests" is the senior framing.

Availability of a logging system means something specific

The logging system being down must not take the application down — which follows from the same fire-and-forget property. If the application blocked on logging, an outage in the log pipeline would become an outage in the product, which would be an absurd way to lose availability.

But there is a second, subtler requirement: the logging system must be most available exactly when the application is least healthy. Incidents are when log volume spikes — errors multiply, retries fire, debug levels get raised — and it is precisely then that you need the pipeline working.

So the logging system must be sized for incident-time volume, not steady-state. A pipeline that saturates during an outage goes blind at the only moment it matters, which is why Lesson 8 puts a horizontally scalable pub-sub tier at its centre.

Building blocks

Building blockUsed for
Pub-sub systemHandles the massive volume of logs
Distributed searchEnables efficient log querying

Plus blob storage for the accumulated logs, from object storage.

This chapter is mostly composition — and that is the point

Look at what is actually new here. Pub-sub absorbs the write volume and fans it out to multiple consumers. Distributed search makes the logs queryable. Blob storage holds them durably and cheaply.

The genuinely new components are small: a log accumulator on each node, a filterer, two aggregators, and an expiration checker. Everything heavy is reused.

That is worth noticing as a general skill. A strong system design answer often looks like "pub-sub here, search there, blob store underneath" rather than novel machinery — and the value is in choosing the right blocks and knowing why each fits, not in inventing storage.

Note how well each fits: logs are high-volume, immutable, write-once-read-many, multi-consumer — which is the pub-sub profile exactly, and the blob store profile exactly.

API design

write(unique_ID, message_to_be_logged)
ParameterDescription
unique_IDA numeric ID containing application-id, service-id, and a timestamp
message_to_be_loggedThe log message stored against a unique key
searching(keyword)

Returns a list of logs containing the specified keyword.

ParameterDescription
keywordUsed for finding the logs containing the keyword

The unique_ID's three parts each do a different job

application-id + service-id + timestamp is a compact design worth unpacking:

  • application-id identifies which application produced it — used by Lesson 8's filterer to route logs into the right per-application blob storage, and it is what makes multi-tenant separation possible.
  • service-id identifies which microservice within that application — the axis you filter on to look at one service's behaviour.
  • timestamp orders events.

The gap is that this ID identifies the producer, not the request. Two log lines from the same service handling two different user requests get IDs that differ only by timestamp, so you cannot separate the two requests' stories.

That is exactly the hole Lesson 9 fills with a separate, sequencer-issued request ID propagated across services. Worth noticing now: the API as written satisfies "storing logs" but not yet "track the application flow end to end."

Key takeaway

Four functional requirements, of which "track the application flow end to end" is the hard one. "Must not block the critical path" forces fire-and-forget, which means deliberately lossy logging — an inversion of the durability priorities elsewhere in this course. And the design is mostly composition: pub-sub for volume, distributed search for querying, blob store for durability.

Interview signal by level

LevelWhat a strong answer sounds like
L4"Write logs, store them, and make them searchable."
L5Names the composition: "pub-sub to absorb the write volume, blob storage for durability, and the distributed search building block to make them queryable."
Staff+States the deliberate trade: "'must not block the critical path' means the application can't wait for logging, which means we can't guarantee logs are durable — we're choosing lossy logging over slow requests, which inverts the priorities of most components here. And availability has a twist: log volume spikes during incidents, so the pipeline has to be sized for incident-time load or it goes blind exactly when it matters."

Next: the first architecture, and where it breaks.

Enjoying the preview?

Create a free account to unlock the rest of this course, the in-browser judge, and live AI mock interviews.

Sign up free to continue