Module: HeapScope::Report::Markdown

Defined in:
lib/heapscope/report/markdown.rb

Class Method Summary collapse

Class Method Details

.mb(n) ⇒ Object



71
72
73
74
75
# File 'lib/heapscope/report/markdown.rb', line 71

def mb(n)
  return "n/a" if n.nil?

  format("%.2f MB", n.to_f / (1024 * 1024))
end

.render(report) ⇒ Object



8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
# File 'lib/heapscope/report/markdown.rb', line 8

def render(report)
  lines = []
  lines << "# HeapScope Report"
  lines << ""
  lines << "- **Version:** #{report.heapscope_version}"
  lines << "- **Ruby:** #{report.runtime_info[:ruby]} (#{report.runtime_info[:engine]})"
  lines << "- **Result:** #{report.summary[:healthy] ? "HEALTHY" : "ATTENTION"}"
  lines << ""
  if report.before && report.after
    lines << "## Memory"
    lines << ""
    lines << "| Metric | Before | After | Delta |"
    lines << "|--------|--------|-------|-------|"
    lines << "| RSS | #{mb(report.before.rss_bytes)} | #{mb(report.after.rss_bytes)} | #{mb(report.diff&.rss_delta)} |"
    lines << "| Live slots | #{report.before.heap_live_slots} | #{report.after.heap_live_slots} | #{report.diff&.heap_live_delta} |"
    lines << ""
  end
  if report.diff
    lines << "## Top class growth"
    lines << ""
    lines << "| Class | Before | After | Delta | Bytes Δ |"
    lines << "|-------|--------|-------|-------|---------|"
    report.diff.growing_classes(15).each do |c|
      lines << "| `#{c[:name]}` | #{c[:before_count]} | #{c[:after_count]} | #{c[:delta_count]} | #{mb(c[:delta_bytes])} |"
    end
    lines << ""
  end
  unless report.findings.empty?
    lines << "## Findings"
    lines << ""
    report.findings.each do |f|
      lines << "### #{f.code}#{f.title} (`#{f.severity}`)"
      f.facts.each { |fact| lines << "- Fact: #{fact}" }
      f.derived.each { |d| lines << "- Derived: #{d}" }
      lines << "- Hypothesis: #{f.hypothesis}" if f.hypothesis
      lines << "- Suspected cause: #{f.suspected_cause}" if f.suspected_cause
      lines << ""
    end
  end
  if report.reproduction
    lines << "## Reproduction"
    lines << ""
    lines << "```bash"
    lines << report.reproduction[:command].to_s
    lines << "```"
    lines << ""
  end
  steps = Suggest.next_steps(report)
  unless steps.empty?
    lines << "## Next steps"
    lines << ""
    steps.each_with_index do |step, i|
      tag = step[:code] || "hint"
      lines << "#{i + 1}. **[#{tag}]** #{step[:action]}"
    end
    lines << ""
  end
  lines << "_Privacy: object values are not serialized by default._"
  lines << ""
  lines << "_#{Branding.report_footer}_"
  lines.join("\n")
end