In modern software development, especially with the rise of microservices and complex distributed systems, understanding what's happening inside your application can feel like navigating a maze in the dark. To find our way, we rely on observability. But true observability isn't just about collecting data; it's about understanding the story that data tells.
This story is written using the three pillars of observability: Logs, Metrics, and Traces.
For years, developers and SREs have treated these as separate tools for separate jobs. You check a metrics dashboard for high-level health, dig through logs to find specific errors, and (if you’re lucky) look at a trace to understand a request flow. This constant context-switching is slow, inefficient, and frustrating.
What if you could have all three, perfectly correlated, in a single, unified view? The real power isn't in having the pillars, but in bringing them together.
Before we unify them, let's quickly recap what each pillar represents.
Logs are timestamped, structured or unstructured text records of discrete events. They are the most granular form of insight into your application.
Metrics are numerical measurements aggregated over time. They provide a high-level, quantitative view of your system's health and performance.
A distributed trace represents the end-to-end journey of a single request as it travels through multiple services, queues, and databases in your system. Each step in the journey is a "span."
Imagine an alert fires: "API p99 latency is over 2 seconds!"
Your current workflow might look like this:
This frantic shuffle between tabs is where precious time is lost. The clues are scattered, and it's up to you to piece the puzzle together.
The solution isn't a better logging tool or a prettier metrics dashboard. The solution is to tear down the walls between them. This is where trace.do changes the game by treating Observability as Code.
Instead of retrofitting observability with separate agents and complex configurations, trace.do allows you to define it programmatically within your application logic. The result? Logs, metrics, and traces that are inherently connected from the moment they are created.
Let's look at how this works. With a simple API wrapper, you can instrument a function and get all three pillars automatically.
import { trace } from '@do/trace';
async function processOrder(orderId: string) {
// This automatically creates a TRACE SPAN for the entire function
return trace.span('processOrder', async (span) => {
// This attribute acts like a STRUCTURED LOG and can be aggregated into a METRIC
span.setAttribute('order.id', orderId);
// Context is automatically passed to downstream calls
const payment = await completePayment(orderId);
// This is a time-stamped LOG event tied directly to this trace
span.addEvent('Payment processed', { paymentId: payment.id });
await dispatchShipment(orderId);
span.addEvent('Shipment dispatched');
return { success: true };
});
}
In this single block of code:
Built on the open standard of OpenTelemetry (OTel), trace.do ensures you're not locked into a proprietary ecosystem. It works with your existing frameworks and can export data to platforms you already use, like Jaeger, Prometheus, or Datadog.
Unifying the three pillars transforms your debugging workflow from a reactive scavenger hunt to a proactive investigation. The journey becomes:
Stop juggling tabs and start solving problems. When logs, metrics, and traces are born together, they tell a single, coherent story—one that leads you directly to the solution.
Ready to achieve effortless observability and complete clarity? Discover how trace.do can unify your observability stack today.