DEV Community

Cover image for Strategic Logging: The Debugging Skill Nobody Taught Me
ZIKORA CHUKWUKA
ZIKORA CHUKWUKA

Posted on

Strategic Logging: The Debugging Skill Nobody Taught Me

When something breaks in production, most developers do one of two things.

They either guess- changing things randomly and hoping something works. Or they panic- opening every tab, reading every Stack Overflow answer, going in circles.

Or more recently paste tracebacks into an AI.

I have done all versions.

I recently realized something from my work building production software.

I realized I was missing a systematic way to see exactly what my code was doing at every step.

Not just when it crashed, but before it crashed. During the journey from request to response, something was going wrong and I had no visibility into where.

All of that changed after I learnt about strategic logging.


What is Strategic Logging?

To understand strategic logging, we first have to understand logging.

Logging is the practice of recording structured events from your code to capture the precise application state, execution path, and environmental context at a specific point in time.

It is like leaving a trail of breadcrumbs in your code. Each breadcrumb tells you exactly where the program went, what data it was holding, and what the environment looked like at that exact moment.

You have probably seen this before:

console.log("here")
Enter fullscreen mode Exit fullscreen mode

That is logging. But it is not strategic logging.

Strategic logging is intentional. It tells you not just that your code reached a certain point, but what the state of your data was at that point, what action was being taken, and what the result was.

The difference looks like this:

// Not strategic
console.log("here")

// Strategic
console.log("Login attempt started", { email: user.email, timestamp: new Date().toISOString() })
console.log("Token received from API", { tokenExists: !!token, status: response.status })
console.log("Cookie being set", { httpOnly: true, path: "/" })
Enter fullscreen mode Exit fullscreen mode

Can you see the difference? The strategic version tells a story. The first version tells you nothing.


My Production Bug

I was building the frontend for an AI startup as the only frontend engineer on the team, consuming a FastAPI backend being built by another engineer.

Auth was not working properly after deploying to staging.

My first instinct was to assume the problem was on my end. I had recently implemented HttpOnly Cookies for session management and there were a lot of moving parts - server actions, middleware, cookie flags. Any one of them could have been the culprit.

So I added logs at every step of the auth flow.

console.log("Server action called with credentials", { emailProvided: !!email, passwordProvided: !!password })

console.log("Calling API login endpoint")
const response = await fetch(`${process.env.API_URL}/auth/login`, {
  method: "POST",
  body: JSON.stringify({ email, password })
})

console.log("API response received", { 
  status: response.status, 
  ok: response.ok 
})

const data = await response.json()
console.log("Response data", { 
  tokenExists: !!data.token, 
  error: data.error || null 
})
Enter fullscreen mode Exit fullscreen mode

What came back stopped me immediately.

The API response status was 500. The token did not exist. The error field pointed to the backend.

The problem was not in my frontend at all. The logs had traced the issue directly to the backend where an incomplete database migration was causing the API to crash silently on every login attempt.

Without those logs, I could have spent days ripping apart my frontend code looking for a bug that was never there.

Instead I had a clear answer in minutes and a productive conversation with the backend engineer to resolve it fast.


What Good Logs Actually Look Like

Through this experience and further, I have come to understand that good logs share a few things in common.

They are contextual.

A good log does not just say something happened. It says what happened, with what data, and what the outcome was.

// Weak
console.log("API call made")

// Strong  
console.log("API call made", { 
  endpoint: "/auth/login", 
  method: "POST",
  status: response.status,
  duration: `${Date.now() - startTime}ms`
})
Enter fullscreen mode Exit fullscreen mode

They follow the journey.

Think of your code as a journey from request to response.

Log at the beginning of each significant step and at the end. That way when something breaks you can see exactly where the journey stopped.

They are removed after debugging.

Very Important.

Production logs that are too verbose can expose sensitive data and slow down your application. The logs I write for debugging are temporary. Once I understand the problem and fix it, I clean them out. What stays in production should be intentional, not accidental.

They never log sensitive data.

This is important. Never log passwords, tokens, full credit card numbers, or any personally identifiable information you do not need. A log file in the wrong hands becomes a security problem.

// Never do this
console.log("User login", { email, password })

// Do this instead
console.log("User login attempt", { email, passwordProvided: !!password })
Enter fullscreen mode Exit fullscreen mode

A Simple Framework for Debugging with Logs

When something breaks and I do not know why, I now follow a simple process.

First I identify the flow. I trace the journey from where the user action starts to where the expected outcome should be. In my case it was: form submission, server action, API call, cookie set, redirect.

Then I add a log at the start of each step. Not inside the step yet. Just at the entrance so I can see how far the request is getting before it fails.

Then I run it and see where the logs stop. The last log that appears before silence or an error is your crime scene. That is where to look.

Then I go deeper into that specific step. Add more logs inside it. Narrow the problem down until you can see exactly what is wrong.

Then I fix it, verify with the logs, and remove the debugging logs once the problem is resolved.


What I Learned

The most valuable thing about this experience was not the fix itself. It was realising that debugging is a skill, not a talent.

Some developers seem to find bugs quickly and others seem to struggle forever.

The difference is usually not intelligence. It is methodology. Strategic logging is one of the most important tools in that methodology.

I also learned something about working on a team.

Without those logs, I might have spent days convinced the problem was mine. The logs gave me evidence. Evidence made the conversation with the backend engineer fast and productive. Nobody was defensive. We just looked at the data together.

That is what good debugging does. It removes the guesswork and replaces it with clarity.

I am actively learning about logging and observability.

This article reflects my current understanding of the subject from real experience.

If you have feedback or see something I can improve, please leave a comment. I am here to learn.

Top comments (0)