← Back to DevBytes

Building a Log Analysis Agent with AutoGen: Complete Guide

Introduction to Log Analysis Agents

Modern applications generate thousands of log lines every minute. From web servers and microservices to containerized workloads, logs are the primary source of truth when something goes wrong. However, manually sifting through gigabytes of log data to find the root cause of an incident is tedious, error-prone, and slow. This is where a log analysis agent comes in.

A log analysis agent is an AI-powered assistant that can ingest log files, identify anomalies, correlate events across services, summarize findings, and even propose remediation steps. By combining large language models with tool-calling capabilities, these agents transform raw log streams into actionable insights.

In this tutorial, you will learn how to build a production-grade log analysis agent using Microsoft AutoGen, a popular multi-agent conversation framework. We will cover what AutoGen is, why it is well-suited for log analysis, how to build the agent step by step, and best practices for deploying it in real environments.

What Is AutoGen?

AutoGen is an open-source framework developed by Microsoft Research for building multi-agent conversational systems. It enables developers to define agents with specific roles, personalities, and toolsets, then orchestrate conversations between them to solve complex tasks. Each agent can be backed by a different LLM, equipped with custom tools, and configured to terminate conversations based on defined conditions.

AutoGen's core building blocks include:

AutoGen supports automatic tool execution, meaning when an LLM decides it needs to run a function (for example, to read a log file), the framework handles the invocation and feeds the result back into the conversation. This makes it ideal for building agents that interact with external systems.

Why Use AutoGen for Log Analysis?

Log analysis is inherently a multi-step reasoning problem. A single agent rarely suffices because the task involves several distinct skills: parsing raw logs, detecting anomalies, correlating timestamps, querying external systems, and producing human-readable summaries. AutoGen addresses this through several key strengths:

Multi-Agent Collaboration

You can split responsibilities across specialized agents. For example, one agent can focus on parsing and filtering logs, another on anomaly detection, and a third on generating remediation suggestions. This mirrors how a real operations team works.

Tool Integration

AutoGen agents can call arbitrary Python functions. This means your agent can read files, query databases, call monitoring APIs, run shell commands, or invoke ML models for anomaly detection. The LLM decides when and how to use these tools based on the conversation context.

Human-in-the-Loop

AutoGen's UserProxyAgent can pause for human input at critical decision points. For log analysis, this is valuable when the agent identifies a potential incident but wants confirmation before triggering an alert or running a remediation script.

Code Execution

Agents can write and execute Python code on the fly. This is useful for ad-hoc log analysis — for example, generating a chart of error rates over time or computing statistics on response latencies.

Prerequisites and Setup

Before building the agent, ensure you have the following:

Start by creating a virtual environment and installing the required packages:

python -m venv venv
source venv/bin/activate  # On Windows: venv\Scripts\activate
pip install "autogen-agentchat==0.2.40" python-dotenv

Create a .env file in your project root to store your API key securely:

OPENAI_API_KEY=sk-your-api-key-here

Next, create a sample log file that we will use for testing. Save it as app.log:

2024-01-15 10:00:01 INFO  [auth-service] User login successful: user_id=1042
2024-01-15 10:00:03 INFO  [api-gateway] GET /api/users/1042 200 45ms
2024-01-15 10:00:05 WARN  [payment-service] Retry attempt 1 for transaction tx_8821
2024-01-15 10:00:06 WARN  [payment-service] Retry attempt 2 for transaction tx_8821
2024-01-15 10:00:07 ERROR [payment-service] Transaction tx_8821 failed: timeout connecting to db
2024-01-15 10:00:08 ERROR [db-service] Connection pool exhausted: active=50 max=50
2024-01-15 10:00:10 ERROR [api-gateway] POST /api/payments 500 1200ms
2024-01-15 10:00:12 INFO  [auth-service] User logout: user_id=1042
2024-01-15 10:00:15 ERROR [db-service] Connection pool exhausted: active=50 max=50
2024-01-15 10:00:18 ERROR [payment-service] Transaction tx_8822 failed: timeout connecting to db
2024-01-15 10:00:20 CRITICAL [alert-manager] Health check failed for db-service
2024-01-15 10:00:22 ERROR [api-gateway] POST /api/payments 500 980ms

This log file simulates a realistic incident: a database connection pool exhaustion cascading into payment failures and API errors.

Building the Log Analysis Agent: Step by Step

Step 1: Configuration and Imports

Create a file named log_agent.py. Begin by loading configuration and importing the necessary AutoGen components:

import os
import re
import json
from datetime import datetime
from collections import Counter
from dotenv import load_dotenv
import autogen

load_dotenv()

config_list = [
    {
        "model": "gpt-4o",
        "api_key": os.getenv("OPENAI_API_KEY"),
    }
]

llm_config = {
    "config_list": config_list,
    "temperature": 0,
    "timeout": 120,
}

Setting temperature to 0 makes the agent's responses more deterministic, which is important for log analysis where consistency matters.

Step 2: Define Log Analysis Tools

Tools are the bridge between the LLM and your actual log data. Define Python functions that the agent can call to read, filter, and analyze logs. Each function should have a clear docstring because AutoGen uses these to inform the LLM about what the tool does.

LOG_FILE = "app.log"

def read_logs(file_path: str = LOG_FILE, max_lines: int = 100) -> str:
    """Read the contents of a log file and return up to max_lines lines.
    
    Args:
        file_path: Path to the log file to read.
        max_lines: Maximum number of lines to return.
    
    Returns:
        A string containing the log lines.
    """
    try:
        with open(file_path, "r") as f:
            lines = f.readlines()
        return "".join(lines[:max_lines])
    except FileNotFoundError:
        return f"Error: File '{file_path}' not found."


def filter_logs(level: str, file_path: str = LOG_FILE) -> str:
    """Filter log entries by severity level (INFO, WARN, ERROR, CRITICAL).
    
    Args:
        level: The log level to filter by (case-insensitive).
        file_path: Path to the log file.
    
    Returns:
        A string containing all matching log lines.
    """
    try:
        with open(file_path, "r") as f:
            lines = f.readlines()
        filtered = [line for line in lines if level.upper() in line.upper()]
        return "".join(filtered) if filtered else f"No logs found with level {level}."
    except FileNotFoundError:
        return f"Error: File '{file_path}' not found."


def count_errors_by_service(file_path: str = LOG_FILE) -> str:
    """Count ERROR and CRITICAL log entries grouped by service name.
    
    Args:
        file_path: Path to the log file.
    
    Returns:
        A JSON string mapping service names to error counts.
    """
    try:
        with open(file_path, "r") as f:
            lines = f.readlines()
        
        pattern = re.compile(r'\[(\w[\w-]*)\]')
        error_counts = Counter()
        
        for line in lines:
            if "ERROR" in line or "CRITICAL" in line:
                match = pattern.search(line)
                if match:
                    error_counts[match.group(1)] += 1
        
        return json.dumps(dict(error_counts), indent=2)
    except FileNotFoundError:
        return f"Error: File '{file_path}' not found."


def extract_timestamps_for_keyword(keyword: str, file_path: str = LOG_FILE) -> str:
    """Extract timestamps of all log lines containing a specific keyword.
    
    Args:
        keyword: The keyword to search for (e.g., 'timeout', 'exhausted').
        file_path: Path to the log file.
    
    Returns:
        A string listing timestamps and matching lines.
    """
    try:
        with open(file_path, "r") as f:
            lines = f.readlines()
        
        results = []
        for line in lines:
            if keyword.lower() in line.lower():
                results.append(line.strip())
        
        return "\n".join(results) if results else f"No lines containing '{keyword}' found."
    except FileNotFoundError:
        return f"Error: File '{file_path}' not found."

Step 3: Create the Assistant Agent

Now define the main log analysis agent. The system prompt is critical — it tells the LLM what role to play, what tools are available, and how to structure its analysis.

log_analyst = autogen.AssistantAgent(
    name="LogAnalyst",
    system_message="""You are an expert DevOps log analysis agent. Your job is to analyze 
application log files and help engineers diagnose incidents.

You have access to the following tools:
- read_logs: Read the contents of a log file.
- filter_logs: Filter logs by severity level.
- count_errors_by_service: Count errors grouped by service.
- extract_timestamps_for_keyword: Find log lines containing a keyword.

When analyzing logs, follow this process:
1. Read the log file to get an overview.
2. Filter for ERROR and CRITICAL entries to identify failures.
3. Count errors by service to find the most affected component.
4. Search for specific keywords (e.g., 'timeout', 'exhausted') to find root causes.
5. Correlate timestamps to understand the sequence of events.
6. Provide a structured summary with:
   - Incident summary (what happened)
   - Root cause analysis (why it happened)
   - Affected services
   - Timeline of events
   - Recommended remediation steps

Always use the tools to gather data before drawing conclusions. Do not guess.
Reply TERMINATE when the analysis is complete.""",
    llm_config=llm_config,
)

Step 4: Create the User Proxy Agent

The UserProxyAgent represents the engineer interacting with the system. It can execute tool calls automatically and forward results back to the assistant.

user_proxy = autogen.UserProxyAgent(
    name="Engineer",
    human_input_mode="NEVER",
    max_consecutive_auto_reply=10,
    is_termination_msg=lambda msg: msg.get("content") is not None 
        and "TERMINATE" in msg["content"],
    code_execution_config=False,
)

# Register tools with both agents
user_proxy.register_function(
    function_map={
        "read_logs": read_logs,
        "filter_logs": filter_logs,
        "count_errors_by_service": count_errors_by_service,
        "extract_timestamps_for_keyword": extract_timestamps_for_keyword,
    }
)

# Register the function declarations with the assistant's LLM config
autogen.agentchat.register_function(
    read_logs,
    caller=log_analyst,
    executor=user_proxy,
    name="read_logs",
    description="Read the contents of a log file.",
)

autogen.agentchat.register_function(
    filter_logs,
    caller=log_analyst,
    executor=user_proxy,
    name="filter_logs",
    description="Filter log entries by severity level.",
)

autogen.agentchat.register_function(
    count_errors_by_service,
    caller=log_analyst,
    executor=user_proxy,
    name="count_errors_by_service",
    description="Count ERROR and CRITICAL entries grouped by service.",
)

autogen.agentchat.register_function(
    extract_timestamps_for_keyword,
    caller=log_analyst,
    executor=user_proxy,
    name="extract_timestamps_for_keyword",
    description="Extract timestamps of log lines containing a keyword.",
)

Setting human_input_mode to "NEVER" means the agent runs fully autonomously. If you want human oversight, set it to "ALWAYS" or "TERMINATE" to prompt for input at key moments.

Step 5: Initiate the Analysis

Finally, start the conversation by asking the agent to analyze the log file:

if __name__ == "__main__":
    user_proxy.initiate_chat(
        log_analyst,
        message="Please analyze the log file 'app.log' and identify any incidents, "
                "their root causes, and recommended remediation steps.",
    )

Run the script:

python log_agent.py

The agent will autonomously call the tools, gather data, and produce a structured incident report. A typical output looks like this:

Engineer (to LogAnalyst):
Please analyze the log file 'app.log' and identify any incidents...

LogAnalyst (to Engineer):
***** Suggested tool call (call_abc123): read_logs *****
Arguments: {"file_path": "app.log", "max_lines": 100}
***********************************************************

Engineer (to LogAnalyst):
***** Response from calling tool "read_logs" *****
2024-01-15 10:00:01 INFO  [auth-service] User login successful...
[full log contents]
**************************************************

LogAnalyst (to Engineer):
***** Suggested tool call (call_def456): count_errors_by_service *****
Arguments: {"file_path": "app.log"}
**********************************************************************

Engineer (to LogAnalyst):
***** Response from calling tool "count_errors_by_service" *****
{
  "payment-service": 3,
  "db-service": 2,
  "api-gateway": 2,
  "alert-manager": 1
}
****************************************************************

LogAnalyst (to Engineer):
## Incident Summary
A cascading failure occurred on 2024-01-15 starting at 10:00:07, 
originating from the database service and affecting payment processing 
and the API gateway.

## Root Cause Analysis
The root cause is a database connection pool exhaustion in db-service. 
At 10:00:08, the connection pool reached its maximum capacity (active=50, 
max=50). This caused subsequent payment transactions to time out when 
attempting to connect to the database.

## Affected Services
1. db-service — connection pool exhaustion (2 errors)
2. payment-service — transaction timeouts (3 errors)
3. api-gateway — HTTP 500 responses (2 errors)
4. alert-manager — health check failure (1 critical alert)

## Timeline of Events
- 10:00:05 — payment-service begins retrying transaction tx_8821
- 10:00:07 — transaction tx_8821 fails due to DB timeout
- 10:00:08 — db-service reports connection pool exhausted
- 10:00:10 — api-gateway returns 500 for POST /api/payments
- 10:00:15 — db-service connection pool still exhausted
- 10:00:18 — second transaction tx_8822 fails
- 10:00:20 — alert-manager reports health check failure
- 10:00:22 — api-gateway returns another 500

## Recommended Remediation
1. Increase the database connection pool max size or add connection 
   timeout and circuit breaker logic.
2. Investigate long-running queries holding connections.
3. Add autoscaling for the database tier during peak load.
4. Implement retry with exponential backoff in payment-service.
5. Set up proactive alerting when pool utilization exceeds 80%.

TERMINATE

Extending with a Multi-Agent Architecture

For more complex scenarios, you can split the analysis across multiple specialized agents using AutoGen's GroupChat. This approach is powerful when you want separation of concerns.

# Define specialized agents
parser_agent = autogen.AssistantAgent(
    name="LogParser",
    system_message="""You are a log parsing specialist. You read log files and 
extract structured information. You focus on identifying log levels, services, 
timestamps, and messages. Pass your findings to the next agent.""",
    llm_config=llm_config,
)

diagnostic_agent = autogen.AssistantAgent(
    name="Diagnostician",
    system_message="""You are an incident diagnostician. You receive parsed log 
data and identify patterns, correlations, and root causes. You focus on 
understanding the causal chain of events.""",
    llm_config=llm_config,
)

remediation_agent = autogen.AssistantAgent(
    name="Remediator",
    system_message="""You are a remediation specialist. Given a root cause 
analysis, you propose concrete, actionable remediation steps. Consider both 
immediate fixes and long-term improvements.""",
    llm_config=llm_config,
)

# Create the group chat
groupchat = autogen.GroupChat(
    agents=[user_proxy, parser_agent, diagnostic_agent, remediation_agent],
    messages=[],
    max_round=15,
)

manager = autogen.GroupChatManager(
    groupchat=groupchat,
    llm_config=llm_config,
)

# Start the group chat
user_proxy.initiate_chat(
    manager,
    message="Analyze app.log for incidents. Parser, start by reading the logs. "
            "Diagnostician, identify root causes. Remediator, propose fixes.",
)

In this setup, the GroupChatManager decides which agent speaks next based on the conversation flow. The parser reads and structures logs, the diagnostician identifies root causes, and the remediator proposes fixes. Each agent focuses on its specialty, producing higher-quality analysis.

Best Practices

Keep Tools Focused and Composable

Design each tool to do one thing well. Instead of a single monolithic analyze_logs function, provide granular tools like read_logs, filter_logs, and count_errors_by_service. This lets the LLM compose them flexibly and makes debugging easier.

Handle Large Log Files Efficiently

LLMs have context window limits. Never load an entire multi-gigabyte log file into a single tool response. Instead, implement pagination, sampling, or pre-filtering. For example:

def read_logs_paginated(file_path: str, offset: int = 0, limit: int = 50) -> str:
    """Read a page of log lines starting from a given offset.
    
    Args:
        file_path: Path to the log file.
        offset: Line number to start reading from (0-indexed).
        limit: Maximum number of lines to return.
    
    Returns:
        A string containing the requested log lines with line numbers.
    """
    with open(file_path, "r") as f:
        lines = f.readlines()
    page = lines[offset:offset + limit]
    numbered = [f"{offset + i + 1}: {line}" for i, line in enumerate(page)]
    return "".join(numbered)

Use Structured Output Formats

Return data from tools in structured formats like JSON rather than free text. This helps the LLM parse and reason about the data more reliably. The count_errors_by_service function above returns JSON, which the LLM can easily interpret.

Set Temperature Low for Analytical Tasks

Log analysis requires precision, not creativity. Use a low temperature (0 to 0.3) to reduce hallucinations and ensure the agent sticks closely to the data returned by tools.

Implement Guardrails for Destructive Actions

If your agent can execute remediation actions (restarting services, scaling infrastructure, modifying configs), always require human confirmation. Use human_input_mode="TERMINATE" or implement a confirmation step before any state-changing operation.

Log the Agent's Own Actions

For debugging and auditing, log every tool call the agent makes. AutoGen supports custom logging:

import logging

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger("log_agent")
autogen.runtime_logging.start(logger=logger, config_list=config_list)

Cache Tool Results

If the agent calls the same tool with the same arguments multiple times during a conversation, cache the results to avoid redundant file reads or API calls. This is especially important when analyzing large log files.

Validate Agent Output

LLMs can occasionally produce incorrect analysis. In production, validate the agent's conclusions against the raw data. For example, if the agent claims a service had 5 errors, run a verification query to confirm the count matches.

Conclusion

Building a log analysis agent with AutoGen brings the power of conversational AI to one of the most time-consuming tasks in software operations. By combining specialized tools for reading and filtering logs with an LLM that can reason about patterns, correlate events, and propose remediations, you create a system that dramatically reduces mean time to resolution during incidents. The multi-agent architecture takes this further by separating parsing, diagnosis, and remediation into distinct roles, mirroring how real operations teams collaborate. As you deploy such agents in production, remember to keep tools focused, handle large files efficiently, implement guardrails for any destructive actions, and always validate the agent's conclusions against the underlying data. With these practices in place, a log analysis agent becomes a reliable and powerful member of your DevOps toolkit, turning mountains of raw log data into clear, actionable insights.

— Ad —

Google AdSense will appear here after approval

← Back to all articles