Blog Post #15: Seeing the Unseen: The Critical Importance of Logging and Verbosity

Imagine trying to diagnose a patient’s illness with no tools. No stethoscope, no X-ray, no blood tests. All you can see is the final symptom—a cough. You have no idea what’s happening internally to cause it. This is what it’s like to debug an AI agent without logging.

An agent’s decision-making process, driven by a complex LLM, can often feel like a black box. When your agent produces a strange or incorrect output, simply looking at that final result is useless. You need to see the internal “chain of thought”: What was the exact prompt sent to the LLM? What was the LLM’s raw response? Which tool did it decide to use? What was the output of that tool?

Logging is the practice of recording these internal steps. It is, without question, the number one most important tool for debugging and understanding your agent’s behavior.


Why print() is Not Your Friend

When starting out, it’s tempting to just sprinkle print() statements throughout your code to see what’s happening. While useful for a quick check, this is a terrible practice for building a real application.

  • No Levels: A print() statement can’t distinguish between a fatal error and a simple status update. It’s all just text.
  • No Context: It doesn’t tell you when the message was printed, from which part of your code it came, or its severity.
  • Hard to Manage: To turn off debugging messages in a production app, you have to find and comment out every single print() statement.
  • Inflexible: print() only writes to the console. A real logging system can be configured to write to files, send alerts via email, and more.

print() is for temporary experiments. Logging is for building robust, maintainable, and debuggable applications.

Setting Up Python’s logging Module: The Professional Way

Python’s built-in logging module is powerful and easy to set up. Here’s how to configure it for your agent project.

Step 1: The Basic Configuration

At the very beginning of your main script (e.g., main.py), add this configuration block. This single setup will apply to your entire application.

import logging
import sys

# Configure the root logger
logging.basicConfig(
    level=logging.INFO,  # Set the minimum level of messages to log
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
    datefmt='%Y-%m-%d %H:%M:%S',
    stream=sys.stdout  # Direct logs to the console
)

Let’s break down the key parts:

  • level=logging.INFO: This sets the threshold. It will show INFO, WARNING, ERROR, and CRITICAL messages, but will ignore DEBUG messages. For development, you’ll often set this to logging.DEBUG to see everything.
  • format='...': This is the magic. It structures your log messages, automatically adding valuable context:
    • %(asctime)s: The timestamp when the log was created.
    • %(name)s: The name of the logger (usually the Python module).
    • %(levelname)s: The severity of the message (e.g., INFO, ERROR).
    • %(message)s: The actual message you wrote.

Step 2: Using the Logger

The best practice is to create a specific logger instance for each file in your project.

# In main.py
logger = logging.getLogger(__name__)

# In another file, say tools.py
# logger = logging.getLogger(__name__)

Using __name__ automatically names the logger after the module, so you can easily see where your log messages are coming from.

You can then log messages with different levels of severity:

logger.debug("Detailed information for diagnosing problems.")
logger.info("A high-level confirmation that things are working as expected.")
logger.warning("An indication that something unexpected happened.")
logger.error("A serious problem; the software was unable to perform a function.")
logger.critical("A very serious error, indicating the program may be unable to continue.")

Logging an Agent’s “Thoughts”: A Practical Example

Let’s see this in action by logging the internal steps of a simple agent.

import logging
import sys

# 1. Basic Configuration
logging.basicConfig(
    level=logging.DEBUG, # Set to DEBUG to see everything
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
    datefmt='%Y-%m-%d %H:%M:%S',
    stream=sys.stdout
)

# 2. Get a logger for this module
logger = logging.getLogger(__name__)

def run_agent_turn(user_query: str):
    logger.info(f"Agent turn started for query: '{user_query}'")

    # Step 1: LLM decides which tool to use
    prompt_for_tool_choice = f"Given the query '{user_query}', what tool should I use?"
    logger.debug(f"Sending tool-choice prompt to LLM: '{prompt_for_tool_choice}'")
    # --- (Simulated LLM Call) ---
    llm_tool_response = '{"tool": "search_api", "query": "latest AI research"}'
    logger.info(f"LLM decided to use tool 'search_api'")

    # Step 2: Agent uses the chosen tool
    logger.info("Executing tool 'search_api'...")
    try:
        # --- (Simulated Tool Execution) ---
        tool_output = "A new paper on 'Self-Correcting Agents' was published."
        logger.debug(f"Tool 'search_api' returned: '{tool_output}'")
    except Exception as e:
        logger.error(f"Tool 'search_api' failed!", exc_info=True)
        return "Sorry, I encountered an error."

    # Step 3: LLM generates the final response
    prompt_for_final_response = f"Based on this information: '{tool_output}', answer the user's query."
    logger.debug(f"Sending final response prompt to LLM: '{prompt_for_final_response}'")
    # --- (Simulated LLM Call) ---
    final_response = "I found a new paper on 'Self-Correcting Agents' that seems relevant to the latest AI research."
    logger.info("Successfully generated final response.")

    return final_response

# --- Run the agent ---
run_agent_turn("What's the latest in AI research?")

Your Console Output (The Agent’s Mind):

2025-09-29 12:19:29 - __main__ - INFO - Agent turn started for query: 'What's the latest in AI research?'
2025-09-29 12:19:29 - __main__ - DEBUG - Sending tool-choice prompt to LLM: 'Given the query 'What's the latest in AI research?', what tool should I use?'
2025-09-29 12:19:29 - __main__ - INFO - LLM decided to use tool 'search_api'
2025-09-29 12:19:29 - __main__ - INFO - Executing tool 'search_api'...
2025-09-29 12:19:29 - __main__ - DEBUG - Tool 'search_api' returned: 'A new paper on 'Self-Correcting Agents' was published.'
2025-09-29 12:19:29 - __main__ - DEBUG - Sending final response prompt to LLM: 'Based on this information: 'A new paper on 'Self-Correcting Agents' was published.', answer the user's query.'
2025-09-29 12:19:29 - __main__ - INFO - Successfully generated final response.

With this log, you can trace every single decision. If the agent failed, you would know exactly which step went wrong and see the exact data that caused the failure.

Conclusion

Logging is your agent’s flight recorder. Without it, a crash is a mystery. With it, a crash is a learning opportunity. Verbosity during development is your greatest asset. You can always raise the logging level to INFO or WARNING for production, but you can never recover the internal state that you failed to log in the first place. Make it the first thing you set up, and it will save you countless hours of debugging.

Author

Debjeet Bhowmik

Experienced Cloud & DevOps Engineer with hands-on experience in AWS, GCP, Terraform, Ansible, ELK, Docker, Git, GitLab, Python, PowerShell, Shell, and theoretical knowledge on Azure, Kubernetes & Jenkins. In my free time, I write blogs on ckdbtech.com

Leave a Comment