What is Gemini CLI?

Google officially launched Gemini CLI on June 25, 2025. Basically, it’s a CLI that allows me to interact with Gemini right from the terminal.

While reading the documentation, I was quite impressed with its features:

  • ReAct-style Reasoning: It doesn’t just provide mechanical answers but can “think-act-observe” to solve problems.
  • 1 Million Token Context: The ability to “remember” an entire massive codebase or digest a large set of documents for Q&A.
  • Sandbox Execution: It can run code or shell commands safely in a sandbox, with our supervision (Human-in-the-Loop).
  • Integration: It can independently use Google Search to find the latest information and connect with other systems via the Model Context Protocol (MCP).

Detailed documentation: Gemini CLI

Vibe coding with gemini - What is Gemini CLI?

To test its “Vibe Coding” capabilities against other tools, I decided to apply it to a real-world project. Since I haven’t had much time for personal projects lately, I’m using it for a task at my company. The plan is to build a script to aggregate error logs.

Specifically, this script will:

  1. Automatically aggregate error log files.
  2. Feed the log content to Gemini CLI for analysis and assessment.
  3. Send the analysis results to our team’s Discord channel.

Vibe coding with gemini - Script calling Gemini CLI to aggregate logs and send a report

In this script, I’ll leverage Gemini CLI to “Vibe Code” the script itself, and the script will also contain a section that asks Gemini to analyze errors. This is just a basic implementation; more complex scenarios are certainly possible, such as asking it to automatically execute another script upon detecting an issue.

Vibe Coding with Gemini CLI

According to the Gemini CLI GitHub documentation, we need a settings.json file in the project’s .gemini directory. You can find more details in the Gemini CLI configuration docs. In my .gemini folder, I also added a prompt.md file to write my prompts, as my terminal doesn’t support Vietnamese input.

.gemini/
├── prompt.md
└── settings.json

Here’s a screenshot of me asking Gemini CLI to code the script. Vibe coding with gemini - Working with Gemini CLI

I asked Gemini CLI to write this script in two versions: one for Windows (PowerShell) and one for Linux (bash).

Surprisingly, the PowerShell script it generated ran perfectly on the first try. However, the bash version had errors, and I had to ask Claude to fix it.

The problem lies with Gemini CLI’s automatic fallback mechanism, which is clearly documented. When the gemini-1.5-pro model is overloaded, it switches to gemini-1.5-flash. And sure enough, when I requested the bash script, I was switched to the “weaker” model.

Tip: According to the documentation, if you want to force it to always use gemini-1.5-pro, you need to configure your own GOOGLE_API_KEY.

The final result - a notification sent via Discord (the screenshot is a bit blurry, so here’s the text):

✨ IoT & API System Status
❌ Critical - Severe access level error affecting multiple core services.
---
🚨 Issues in the Last Hour
Detected a recurring "Fatal error: Access level to Mita\UranusIoT\Tasks\" in logs: `rule-chain-system`, `mqtt-collector`, `websocket-publisher`, `socket-server`. Error is related to PHP-DI in `embedding-job.log`.
---
📊 Diagnosis & Analysis
The "Access level" error is widespread, indicating a configuration or permission issue with a PHP class in the `Mita\UranusIoT\Tasks` namespace. The appearance of a PHP-DI error in `embedding-job` reinforces the hypothesis of a problem with the Dependency Injection container or class definitions. Despite the errors, tasks are reporting "Running," which could mean the error is non-blocking or the tasks are self-recovering.
---
🚀 Performance & Statistics
High frequency of "Fatal error: Access level" across most IoT services. Affected services: `rule-chain-system`, `mqtt-collector`, `websocket-publisher`, `socket-server`, `embedding-job`.
---
🛠️ Recommended Actions
1. Check the detailed PHP logs for a full stack trace of the "Access level" error.
2. Review the PHP class definitions in `Mita\UranusIoT\Tasks\` for access modifiers (public/protected/private).
3. Inspect the PHP-DI configuration for the `Mita\UranusIoT\Tasks\` namespace.
4. Verify file/directory permissions for `Mita\UranusIoT\Tasks\`.
5. Restart the affected services.

Conclusion

Compared to other AI coding tools I’ve used, like Claude or Cursor, Gemini CLI has its own unique strengths:

  • Deep terminal integration: No need to switch context between an editor and a browser.
  • ReAct reasoning: It can “think” and create a plan before coding.
  • Sandbox execution: Safer for testing code.

However, it still has some limitations:

  • UI/UX: The diff view in the terminal is difficult to use.
  • Model switching: Automatic fallback can reduce output quality.
  • Context management: There’s no effective way to manage conversation history yet.

Overall, Gemini CLI is a highly promising tool for DevOps and automation workflows. With some UX improvements, it could become a powerful alternative to current AI coding assistants.

Below is the script content. This script can be customized to fit specific project needs. The key is that it demonstrates Gemini CLI’s ability to automatically analyze logs and generate intelligent reports.

#!/bin/bash
# ==============================================================================
# This script automates the process of monitoring log files from a project.
# It performs the following steps:
#   1. Aggregates and filters recent log entries, focusing on warnings/errors.
#   2. Uses the Gemini CLI to analyze the aggregated logs and generate a
#      concise, structured report in English.
#   3. Sends the generated report to a specified Discord webhook.
#
# Author:  MiTaDev.Blog Shared for the community
# Version:  1.0.0
#
# Prerequisites:
#   - bash
#   - gemini-cli (https://github.com/google-gemini/gemini-cli)
#   - jq (A lightweight command-line JSON processor)
#     On Debian/Ubuntu: sudo apt-get install jq
#
# ==============================================================================

# --- 🔧 CONFIGURATION - YOU MUST CHANGE THE VALUES BELOW 🔧 ---

# 1. Path to the root directory of the project you want to monitor.
#    Example: "/var/www/my-project"
PROJECT_DIR="\/PATH\/TO\/YOUR\/PROJECT"

# 2. The Discord Webhook URL to receive reports.
#    Get it from: Server Settings -> Integrations -> Webhooks -> New Webhook
DISCORD_WEBHOOK_URL="YOUR_DISCORD_WEBHOOK_URL_HERE"

# 3. Log type configuration (Advanced options)
#    Change these values if your log structure differs from the description.

#    Structured logs (e.g., Monolog/LineFormatter)
#    The script will filter for lines containing "WARNING" or "ERROR".
STRUCTURED_LOG_DIR="${PROJECT_DIR}/storage/logs/app"
STRUCTURED_LOG_PATTERN="*$(date +"%Y-%m-%d").log" # Today's log file pattern

#    Unstructured logs (e.g., stdout/stderr from supervisord)
#    The script will get the last lines of the file.
UNSTRUCTURED_LOG_DIR="${PROJECT_DIR}/storage/logs"

# --- END OF CONFIGURATION ---


# Exit immediately if a command exits with a non-zero status.
set -e
# Treat unset variables as an error.
set -u
# Pipes return the exit code of the last command to exit with a non-zero status.
set -o pipefail


main() {
    # --- 1. VALIDATE CONFIGURATION & PREREQUISITES ---
    echo "🔎 Validating configuration and prerequisites..."

    if [[ "$PROJECT_DIR" == *"\/PATH\/TO\/YOUR\/PROJECT"* || "$DISCORD_WEBHOOK_URL" == *"YOUR_DISCORD_WEBHOOK_URL"* ]]; then
        echo "❌ Configuration Error: Please edit this script and update the 'PROJECT_DIR' and 'DISCORD_WEBHOOK_URL' variables." >&2
        exit 1
    fi

    if ! command -v gemini &> /dev/null || ! command -v jq &> /dev/null; then
        echo "❌ Missing Tools Error: 'gemini' and 'jq' are required." >&2
        echo "Please install them to continue. On Ubuntu: sudo apt-get install jq" >&2
        exit 1
    fi

    # --- 2. SETUP & CLEANUP ---
    # Create temporary files for processing
    local temp_log_file
    temp_log_file=$(mktemp)
    
    # Setup a trap to automatically clean up temporary files on exit
    trap 'rm -f "$temp_log_file"' EXIT

    # --- 3. AGGREGATE LOGS ---
    echo "🔄 Aggregating log files..."
    
    local all_log_entries=""
    
    # Process structured logs (e.g., Monolog)
    if [ -d "$STRUCTURED_LOG_DIR" ]; then
        while read -r file; do
            # Filter for WARNING/ERROR, get last 20 lines, truncate each line to 150 chars
            local filtered_content
            filtered_content=$(grep -E "WARNING|ERROR" "$file" 2>/dev/null | tail -n 20 | cut -c 1-150 || true)
            
            if [ -n "$filtered_content" ]; then
                all_log_entries+="==== $(basename "$file") ====\n${filtered_content}\n\n"
            fi
        done < <(find "$STRUCTURED_LOG_DIR" -type f -name "$STRUCTURED_LOG_PATTERN" 2>/dev/null || true)
    fi

    # Process unstructured logs (e.g., supervisord stdout)
    if [ -d "$UNSTRUCTURED_LOG_DIR" ]; then
        while read -r file; do
            # Get last 10 lines, truncate each line to 80 chars
            local content
            content=$(tail -n 10 "$file" 2>/dev/null | cut -c 1-80 || true)
            
            if [ -n "$content" ]; then
                all_log_entries+="==== $(basename "$file") ====\n${content}\n\n"
            fi
        done < <(find "$UNSTRUCTURED_LOG_DIR" -maxdepth 1 -type f -name "*.log" 2>/dev/null || true)
    fi

    local log_data
    if [ -z "$all_log_entries" ]; then
        echo "✅ No relevant log entries found. System appears healthy." >&2
        log_data="No new WARNING or ERROR logs were found in this check."
    else
        log_data="$all_log_entries"
    fi
    
    # --- 4. GENERATE REPORT WITH GEMINI ---
    echo "🤖 Building prompt and calling Gemini API..."

    # The prompt guides the AI to create a high-quality, structured report.
    read -r -d '' GEMINI_PROMPT <<EOF
You are a professional DevOps engineer. Your task is to analyze log data from a system and generate a concise, structured status report in English for the monitoring team.

**Raw Log Data:**
\`\`\`
${log_data}
\`\`\`

**Report Formatting Requirements (Use Markdown for Discord):**

✨ **System Status**
_Updated at: $(date +"%H:%M:%S %d-%m-%Y")_
[Fill in one of three statuses: ✅ **Stable**, ⚠️ **Warning**, or ❌ **Critical**] Followed by a one-sentence overview.

---
🚨 **Key Issues**
- [List the most specific and noteworthy errors or warnings. If none, write: "No new issues detected."]

---
📊 **Diagnosis & Analysis**
- [This is the most crucial part. AI's analysis: group similar errors, identify recurring patterns, and propose hypotheses about the root cause. Provide insights a human might miss.]

---
🛠️ **Recommended Actions**
- [Provide specific, actionable recommendations. If none are needed, write: "No immediate action required at this time."]
EOF

    # Call Gemini and save the raw output
    local gemini_raw_output
    if ! gemini_raw_output=$(gemini <<<"$GEMINI_PROMPT"); then
        echo "❌ Error calling Gemini CLI. Generating manual report." >&2
        gemini_raw_output="⚠️ **Reporting System Error**: Could not connect to or execute Gemini CLI. Please check the server's configuration and network connection."
    fi

    # Clean the report from any potential CLI artifacts
    local final_report
    final_report=$(echo "$gemini_raw_output" | sed 's/\\n/\n/g') # Ensure newlines are rendered correctly

    if [ -z "$final_report" ]; then
        final_report="⚠️ **Warning**: Gemini CLI ran but did not produce any report content. This can happen when there are no new errors or the logs lack sufficient information."
    fi

    # --- 5. SEND REPORT TO DISCORD ---
    echo "🚀 Sending report to Discord..."

    # Discord has a 2000 character limit per message. Truncate if necessary.
    if [ ${#final_report} -gt 1900 ]; then
        echo "⚠️ Report is too long (${#final_report} chars), truncating..." >&2
        final_report="${final_report:0:1850}...\n\n**(Report was truncated due to length limit)**"
    fi

    # Create a valid JSON payload for the Discord webhook
    local json_payload
    json_payload=$(jq -n --arg content "$final_report" '{"content": $content, "username": "System Monitor", "avatar_url": "https://i.imgur.com/g8vB3v6.png"}')

    # Send the report via curl
    if curl -s -S -H "Content-Type: application/json" -X POST -d "$json_payload" "$DISCORD_WEBHOOK_URL"; then
        echo "✅ Report sent successfully!"
    else
        echo "❌ Failed to send report to Discord. Please check the Webhook URL and network connection." >&2
        exit 1
    fi
}

# Run the main function with all script arguments
main "$@"

Bình luận

Đang tải bình luận...