phase 4 planning
This commit is contained in:
@@ -0,0 +1,198 @@
|
||||
---
|
||||
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>
|
||||
Reference in New Issue
Block a user