Logging Configuration

Control PraisonAI log output from the CLI or your own scripts

python
from praisonaiagents import Agent

agent = Agent(
    name="logged-agent",
    instructions="Process tasks with full logging enabled.",
    output="verbose",
)
agent.start("Run this task with detailed logging.")

Control how PraisonAI logs run-time information from the CLI or your own Python scripts.

The user runs an agent with verbose logging; PraisonAI emits structured lines to stderr for debugging.

Diagram

Logging Flow

configures

📝 Code

🔍 praisonai.* logger

📋 root logger

📤 stderr

🖥️ CLI

Quick Start

  1. CLI Users

    Set LOGLEVEL=INFO (or DEBUG) before running PraisonAI commands to see more output.

    bash
    export LOGLEVEL=INFO
    praisonai agents.yaml
  2. Script Users

    Call configure_cli_logging("INFO") once at app start, or wire your own logging.basicConfig().

    python
    from praisonai import PraisonAI
    from praisonai._logging import configure_cli_logging
    
    configure_cli_logging("INFO")  # opt in to root-logger setup
    PraisonAI(agent_file="agents.yaml").run()

How It Works

Diagram
OutputLoggingScriptCLIOutputLoggingScriptCLICLI vs Library Import Pathsconfigure_cli_logging()Root logger configuredimport praisonai (no auto-config)configure_cli_logging() (optional)Only if explicitly called
Import TypeRoot Logger ConfigurationDefault Level
CLI (praisonai command)✅ Automatic via configure_cli_logging()WARNING
Library (from praisonai import)❌ No automatic configurationN/A

Configuration Options

OptionTypeDefaultDescription
LOGLEVEL env varstrWARNINGRead by configure_cli_logging(). Accepts standard Python levels.
configure_cli_logging(level)`str \int \None`None (uses LOGLEVEL or WARNING)Idempotent; only the first call configures the root logger.
get_logger(name)`str \None`None (returns praisonai)Returns a namespaced praisonai.<name> logger; never mutates root.

Common Patterns

Quieting PraisonAI in a Larger App

python
import logging
from praisonai import PraisonAI

# Set only the praisonai logger to WARNING
logging.getLogger("praisonai").setLevel(logging.WARNING)

# Your app's logging remains untouched
praisonai = PraisonAI(agent_file="agents.yaml")
praisonai.run()

Routing PraisonAI Logs to a File

python
import logging
from praisonai import PraisonAI

# Create file handler for praisonai logs only
handler = logging.FileHandler("praisonai.log")
handler.setFormatter(logging.Formatter("%(asctime)s - %(levelname)s - %(message)s"))

# Attach to praisonai logger tree
praisonai_logger = logging.getLogger("praisonai")
praisonai_logger.addHandler(handler)
praisonai_logger.setLevel(logging.INFO)

praisonai = PraisonAI(agent_file="agents.yaml")
praisonai.run()

One-off CLI Debugging

bash
# Debug a specific run
LOGLEVEL=DEBUG praisonai agents.yaml

# Back to quiet mode
praisonai agents.yaml


Import-time behaviour (PR #5219)

import praisonaiagents no longer overwrites host environment variables or silences the host’s asyncio logger.

Reference: PraisonAI PR #5219, fixes #5162. For the full fork-safety story, see Python Import Safety & Fork Behaviour.

Environment variables: setdefault, not overwrite

praisonaiagents._logging._configure_environment() now uses os.environ.setdefault(key, value) instead of an unconditional assignment. A value the host exported before launch is preserved and no longer leaks a different value into any subprocess spawned afterwards.

Host exports its own value
# The host sets LITELLM_LOG before launching your script.
export LITELLM_LOG=DEBUG
python my_script.py     # imports praisonaiagents
After PR #5219 (preserved)
import os
from praisonaiagents import Agent  # env defaults applied when the LLM layer loads

# The host's DEBUG value is kept — setdefault does not overwrite it.
assert os.environ["LITELLM_LOG"] == "DEBUG"

When the host has not set a value, the SDK still fills these in once praisonaiagents.llm is imported (since PR #6135, not on bare import praisonaiagents):

VariableDefault set when unset
LITELLM_TELEMETRYFalse
LITELLM_DROP_PARAMSTrue
LITELLM_LOGERROR
LITELLM_DEBUGFalse
LITELLM_SUPPRESS_DEBUG_INFOTrue
LITELLM_VERBOSEFalse
LITELLM_SET_VERBOSEFalse
HTTPX_DISABLE_WARNINGSTrue
HTTPX_LOG_LEVELERROR
PYDANTIC_WARNINGS_ENABLEDFalse

asyncio logger is no longer suppressed

"asyncio" has been removed from the SDK’s noisy-logger list, so import praisonaiagents no longer forces logging.getLogger("asyncio") to CRITICAL or clears its handlers. Host application asyncio errors — Task exception was never retrieved, coroutine-scheduling failures, and similar — surface again as your own logging config intends.

If you relied on the old import-time behaviour to hide those messages, set the level yourself in your own code:

python
import logging
import praisonaiagents  # no longer touches the asyncio logger

# Opt back into suppression explicitly if you want it.
logging.getLogger("asyncio").setLevel(logging.CRITICAL)

When the host has already configured logging

The SDK detects host-installed root handlers and leaves logging alone — your Django/FastAPI/gunicorn setup is preserved as-is.

python
import logging

logging.basicConfig(level=logging.INFO, format="%(levelname)s %(name)s %(message)s")

from praisonaiagents import Agent  # root handlers, level, and httpx/openai loggers untouched

agent = Agent(instructions="You are a helpful assistant")
agent.start("Hello")

Since PR #6135, the SDK’s logger setup checks logging.getLogger().handlers first and returns early if any handler exists. force=True was removed, so basicConfig no longer replaces host handlers. LOGLEVEL and noisy-logger silencing only apply when the host has not configured logging.

Diagram

Yes

No

import praisonaiagents

Root handlers
already installed?

Skip configure_root_logger
Skip _configure_loggers
Host logs preserved

Apply LOGLEVEL
Silence noisy loggers

See Python Import Safety → Host logging, warnings, and env on import for the related warnings.warn and env guarantees.


Best Practices

Use namespaced loggers in library code

Always use get_logger("module") instead of the root logger when writing library code.

python
from praisonai._logging import get_logger

logger = get_logger("mymodule")  # Creates praisonai.mymodule logger
logger.info("This won't interfere with the user's logging")
Do not call basicConfig from libraries

Libraries should never call logging.basicConfig() as it mutates global state. Let applications control their logging setup.

python
# ❌ Bad - mutates global logger
import logging
logging.basicConfig(level=logging.INFO)

# ✅ Good - use namespaced logger
from praisonai._logging import get_logger
logger = get_logger("mylibrary")
Prefer LOGLEVEL for one-shot debugging

Use the environment variable for temporary debugging instead of changing code.

bash
# Quick debug session
LOGLEVEL=DEBUG praisonai agents.yaml

# Production run
praisonai agents.yaml
Attach handlers to praisonai not root

When customizing PraisonAI logging, attach handlers to the praisonai logger tree rather than the root logger.

python
import logging

# ✅ Good - only affects praisonai
praisonai_logger = logging.getLogger("praisonai")
praisonai_logger.addHandler(my_handler)

# ❌ Bad - affects all logging
root_logger = logging.getLogger()
root_logger.addHandler(my_handler)

Related