When a request flows through a distributed system, it touches many services: an API gateway, a few backend services, a cache, a database. A span captures one of those steps. It is the basic building block of distributed tracing, the same way a single line is the building block of a log file.
Every span carries a small set of standard fields. It has a name that describes the operation (for example GET /checkout or SELECT orders), a start timestamp, a duration, a span ID that uniquely identifies it, and a trace ID shared by every span in the same request. Most spans also have a parent span ID that points to the span that triggered them, which is how the tree gets built.
On top of those core fields, a span holds attributes (key-value tags like http.status_code=200 or db.system=postgresql), events (timestamped notes such as an exception being thrown), and a status that marks whether the operation succeeded or failed. In OpenTelemetry, which is the standard most tools now follow, all of this is defined in the span data model.