Skip to content

Chapter 16: Output Formats

Overview

melisai produces three output types: structured JSON, SVG flame graphs, and AI prompts. The output package (internal/output/) handles formatting and writing.

Source Files: output/ (5 files)

File Lines Purpose
json.go ~106 JSON serialization to file or stdout
flamegraph.go ~106 SVG flame graph from folded stacks
ai_prompt.go ~103 AI/LLM analysis prompt (see Chapter 13)
progress.go ~53 Collection progress display

JSON Output

WriteJSON()

func WriteJSON(report *model.Report, path string) error {
    data, err := json.MarshalIndent(report, "", "  ")

    if path == "" || path == "-" {
        os.Stdout.Write(data)
    } else {
        // Atomic write: write to temp file, then rename
        tmpFile := path + ".tmp"
        os.WriteFile(tmpFile, data, 0644)
        os.Rename(tmpFile, path)
    }
}

Atomic write pattern: Writing to a temporary file and renaming prevents partial writes if melisai is killed mid-write. os.Rename is atomic on the same filesystem.

JSON Schema

The complete JSON output follows this structure:

{
  "metadata": {
    "tool": "melisai",
    "version": "0.2.0",
    "hostname": "...",
    "timestamp": "...",
    "profile": "standard",
    "duration_seconds": 30
  },
  "system": {
    "os": "Ubuntu 22.04",
    "kernel": "5.15.0-91-generic",
    "uptime_seconds": 1234567,
    "boot_params": "...",
    "filesystems": [...],
    "block_devices": [...],
    "dmesg_errors": [...]
  },
  "categories": {
    "cpu": [{"collector": "cpu_utilization", "tier": 1, "data": {...}}],
    "memory": [...],
    "disk": [...],
    "network": [...],
    "process": [...],
    "system": [...]
  },
  "summary": {
    "health_score": 78,
    "resources": {
      "cpu": {"utilization": 45.2, "saturation": 12.3, "errors": 0},
      "memory": {"utilization": 67.8, "saturation": 5.0, "errors": 123}
    },
    "anomalies": [...],
    "recommendations": [...]
  }
}

Flame Graph Generator

WriteFlamegraph()

func WriteFlamegraph(stacks []model.StackTrace, outputPath string) error {
    // 1. Convert stacks to folded format
    //    "main;handleRequest;db.Query 42"
    //    "main;handleRequest;json.Marshal 15"
    // 2. Generate SVG using flame graph algorithm
    // 3. Write to output file
}

Flame graphs visualize CPU profiling data:

┌──────────────────────────────────────────────────────────┐
│ root                                                      │
├──────────┬───────────────────────────┬───────────────────┤
│ goroutine│ goroutine 2               │ goroutine 3       │
│ 1        │                           │                   │
│          ├───────────┬───────────────┤                   │
│          │handleReq  │other          │                   │
│          ├─────┬─────┤               │                   │
│          │json │ db  │               │                   │
│          │     │Query│               │                   │
└── ── ── ─┴─────┴─────┴── ── ── ── ──┴── ── ── ── ── ──┘
Width = proportion of CPU time
  • Wide bars = hot functions consuming lots of CPU
  • Vertical stacking = call chain
  • Read bottom-to-top: caller → callee

Progress Reporter

type ProgressReporter struct {
    quiet bool
}

func (p *ProgressReporter) Start(name string) {
    if !p.quiet {
        fmt.Fprintf(os.Stderr, "  %-30s ", name)
    }
}

func (p *ProgressReporter) Done(duration time.Duration) {
    if !p.quiet {
        fmt.Fprintf(os.Stderr, "✓ %s\n", duration.Round(time.Millisecond))
    }
}

Output during collection:

melisai v0.2.0 — collecting with standard profile (30s)
  cpu_utilization               ✓ 1.003s
  memory_info                   ✓ 12ms
  disk_io                       ✓ 1.001s
  network_stats                 ✓ 45ms
  process_top                   ✓ 1.005s
  container_info                ✓ 3ms
  system_info                   ✓ 218ms


Next: Chapter 17 — Appendix