21e888c1ce
- Remove Claude API integration and intent parsing (04-02-PLAN) - REQ-08 (conversational queries) moved to out of scope - Phase 4 renamed from "Logs & Intelligence" to "Logs" (complete) - v1.0 now focuses on keyword-based container control Simple substring matching works well for container management. NLU adds complexity without proportional value for v1. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
199 lines
6.6 KiB
Markdown
199 lines
6.6 KiB
Markdown
---
|
|
phase: 04-logs-intelligence
|
|
plan: 01
|
|
type: execute
|
|
wave: 1
|
|
depends_on: []
|
|
files_modified: [n8n-workflow.json]
|
|
autonomous: true
|
|
|
|
user_setup:
|
|
- service: anthropic
|
|
why: "Claude API for natural language understanding"
|
|
env_vars:
|
|
- name: ANTHROPIC_API_KEY
|
|
source: "Anthropic Console -> API Keys -> Create Key"
|
|
dashboard_config: []
|
|
|
|
must_haves:
|
|
truths:
|
|
- "User can request logs for a container by name"
|
|
- "User can specify number of log lines (default 50)"
|
|
- "Logs are returned in readable format in Telegram"
|
|
artifacts:
|
|
- path: "n8n-workflow.json"
|
|
provides: "Logs command routing and Docker API integration"
|
|
contains: "logs"
|
|
key_links:
|
|
- from: "Switch node"
|
|
to: "Docker logs API call"
|
|
via: "logs command pattern match"
|
|
pattern: "logs|show logs"
|
|
- from: "Docker API response"
|
|
to: "Telegram reply"
|
|
via: "log formatting code node"
|
|
---
|
|
|
|
<objective>
|
|
Implement container log retrieval via Telegram commands.
|
|
|
|
Purpose: Delivers REQ-07 (view logs with configurable line count) - users can troubleshoot containers directly from their phone by viewing recent logs.
|
|
|
|
Output: Extended n8n workflow with logs command routing, Docker logs API call, and formatted log response.
|
|
</objective>
|
|
|
|
<execution_context>
|
|
@/home/luc/.claude/get-shit-done/workflows/execute-plan.md
|
|
@/home/luc/.claude/get-shit-done/templates/summary.md
|
|
</execution_context>
|
|
|
|
<context>
|
|
@.planning/PROJECT.md
|
|
@.planning/ROADMAP.md
|
|
@.planning/STATE.md
|
|
@.planning/phases/04-logs-intelligence/04-RESEARCH.md
|
|
@.planning/phases/02-docker-integration/02-02-SUMMARY.md
|
|
@n8n-workflow.json
|
|
</context>
|
|
|
|
<tasks>
|
|
|
|
<task type="auto">
|
|
<name>Task 1: Add logs command routing to workflow</name>
|
|
<files>n8n-workflow.json</files>
|
|
<action>
|
|
Extend the main Switch node to detect logs commands. Pattern: "logs <container>" or "show logs <container>" with optional line count.
|
|
|
|
Add new route in Switch node:
|
|
- Condition: message matches /^(show\s+)?logs\s+/i
|
|
- Route to new "Parse Logs Command" Code node
|
|
|
|
Create "Parse Logs Command" Code node:
|
|
- Extract container name from message
|
|
- Extract line count if specified (e.g., "logs plex 100"), default to 50
|
|
- Return: { container: string, lines: number }
|
|
|
|
Example inputs to handle:
|
|
- "logs plex" -> { container: "plex", lines: 50 }
|
|
- "show logs sonarr" -> { container: "sonarr", lines: 50 }
|
|
- "logs nginx 100" -> { container: "nginx", lines: 100 }
|
|
- "show logs radarr last 200" -> { container: "radarr", lines: 200 }
|
|
</action>
|
|
<verify>
|
|
In n8n workflow editor, send message "logs test" - should route to Parse Logs Command node (visible in execution view). Check output includes container and lines fields.
|
|
</verify>
|
|
<done>Logs commands route to dedicated branch with parsed container name and line count.</done>
|
|
</task>
|
|
|
|
<task type="auto">
|
|
<name>Task 2: Implement Docker logs API call with formatting</name>
|
|
<files>n8n-workflow.json</files>
|
|
<action>
|
|
After Parse Logs Command, add container matching (reuse existing fuzzy match pattern from actions branch).
|
|
|
|
Create "Build Logs Command" Code node:
|
|
- Input: matched container ID and requested line count
|
|
- Build curl command:
|
|
```
|
|
curl -s --unix-socket /var/run/docker.sock "http://localhost/v1.53/containers/CONTAINER_ID/logs?stdout=1&stderr=1&tail=LINES×tamps=1"
|
|
```
|
|
- Note: Docker logs API returns binary stream with 8-byte header per line. First byte indicates stream (1=stdout, 2=stderr).
|
|
|
|
Create "Execute Logs" Execute Command node:
|
|
- Run the curl command
|
|
|
|
Create "Format Logs" Code node:
|
|
- Parse Docker log stream format (strip 8-byte headers from each line)
|
|
- Format for Telegram:
|
|
- Truncate if > 4000 chars (Telegram message limit)
|
|
- Add header: "Logs for <container> (last N lines):"
|
|
- Use monospace formatting with <pre> tags (HTML parse mode already enabled)
|
|
- Handle empty logs gracefully: "No logs available for <container>"
|
|
- Handle errors: "Could not retrieve logs for <container>: <error>"
|
|
|
|
Wire to Telegram Send Message node for reply.
|
|
</action>
|
|
<verify>
|
|
Test via Telegram:
|
|
1. "logs n8n" - should return recent n8n container logs in monospace format
|
|
2. "logs n8n 10" - should return only 10 lines
|
|
3. "logs nonexistent" - should return friendly "no container found" message
|
|
</verify>
|
|
<done>Users can retrieve container logs via Telegram with configurable line count, formatted for readability.</done>
|
|
</task>
|
|
|
|
<task type="auto">
|
|
<name>Task 3: Handle Docker log stream binary format</name>
|
|
<files>n8n-workflow.json</files>
|
|
<action>
|
|
The Docker logs API returns a multiplexed stream with 8-byte headers. Each frame:
|
|
- Byte 0: stream type (1=stdout, 2=stderr)
|
|
- Bytes 1-3: reserved (zeros)
|
|
- Bytes 4-7: frame size (big-endian uint32)
|
|
- Remaining bytes: log content
|
|
|
|
Update "Format Logs" Code node to properly decode this:
|
|
|
|
```javascript
|
|
// Docker logs binary stream decoder
|
|
const rawOutput = $input.item.json.stdout || '';
|
|
|
|
// Docker API with timestamps returns text lines when using tail parameter
|
|
// But may have 8-byte binary headers we need to strip
|
|
const lines = rawOutput.split('\n')
|
|
.filter(line => line.length > 0)
|
|
.map(line => {
|
|
// Check if line starts with binary header (non-printable chars in first 8 bytes)
|
|
if (line.length > 8 && line.charCodeAt(0) <= 2) {
|
|
return line.substring(8);
|
|
}
|
|
return line;
|
|
})
|
|
.join('\n');
|
|
|
|
// Truncate for Telegram (4096 char limit, leave room for header)
|
|
const maxLen = 3800;
|
|
const truncated = lines.length > maxLen
|
|
? lines.substring(0, maxLen) + '\n... (truncated)'
|
|
: lines;
|
|
|
|
return {
|
|
formatted: truncated,
|
|
lineCount: lines.split('\n').length
|
|
};
|
|
```
|
|
|
|
Add error indicator prefix for stderr lines if desired (optional enhancement).
|
|
</action>
|
|
<verify>
|
|
Test with a container known to have logs:
|
|
1. Send "logs n8n 20" via Telegram
|
|
2. Verify output is readable text (no garbled binary characters)
|
|
3. Verify timestamps appear if container outputs them
|
|
</verify>
|
|
<done>Docker log binary stream format properly decoded into readable text.</done>
|
|
</task>
|
|
|
|
</tasks>
|
|
|
|
<verification>
|
|
After all tasks:
|
|
1. Send "logs n8n" - returns formatted logs
|
|
2. Send "logs plex 100" - returns up to 100 lines
|
|
3. Send "show logs sonarr" - alternative syntax works
|
|
4. Send "logs nonexistent" - friendly error message
|
|
5. Logs display in monospace (preformatted) in Telegram
|
|
</verification>
|
|
|
|
<success_criteria>
|
|
- REQ-07 delivered: Users can view container logs with configurable line count
|
|
- Default 50 lines when not specified
|
|
- Multiple syntax variations supported (logs X, show logs X)
|
|
- Binary stream format properly decoded
|
|
- Output formatted for Telegram readability (monospace, truncated if needed)
|
|
</success_criteria>
|
|
|
|
<output>
|
|
After completion, create `.planning/phases/04-logs-intelligence/04-01-SUMMARY.md`
|
|
</output>
|