View Javadoc
1   package com.guinetik.hexafun.examples.sysmon;
2   
3   import java.util.function.Function;
4   
5   import static com.guinetik.hexafun.examples.tui.Ansi.*;
6   import static com.guinetik.hexafun.examples.tui.Widgets.*;
7   
8   /**
9    * Output adapters for SystemMetrics - transforms domain data to presentation formats.
10   *
11   * <p>This is where the hexagonal architecture shines: same domain object,
12   * four completely different presentations. The domain knows nothing about
13   * how it will be displayed.</p>
14   *
15   * <h2>Available Formats</h2>
16   * <ul>
17   *   <li><b>TUI</b> - Colorful progress bars with warnings</li>
18   *   <li><b>CLI</b> - Plain text for scripting</li>
19   *   <li><b>JSON</b> - Machine-readable</li>
20   *   <li><b>Prometheus</b> - Metrics exposition format</li>
21   * </ul>
22   */
23  public final class SysmonAdapters {
24  
25      private SysmonAdapters() {}
26  
27      private static final int BAR_WIDTH = 20;
28      private static final int BOX_WIDTH = 36;
29  
30      // ═══════════════════════════════════════════════════════════════════
31      //  TUI ADAPTER - Colorful gauges with box drawing
32      // ═══════════════════════════════════════════════════════════════════
33  
34      /**
35       * TUI format with colorful progress bars and warning indicators.
36       *
37       * <pre>
38       * ┌─ System Monitor ─────────────────┐
39       * │ CPU  [████████░░░░░░░░░░░░] 67%  │
40       * │ MEM  [██████████░░░░░░░░░░] 52%  │
41       * │ DISK [██████████████████░░] 91% ⚠│
42       * └──────────────────────────────────┘
43       * </pre>
44       */
45      public static final Function<SystemMetrics, String> TUI_ADAPTER = metrics -> {
46          StringBuilder sb = new StringBuilder();
47          String indent = "  ";
48  
49          // Header
50          sb.append(indent).append(color(BOX_TOP_LEFT + "─ System Monitor " +
51              repeat(BOX_HORIZONTAL, BOX_WIDTH - 19) + BOX_TOP_RIGHT, CYAN)).append("\n");
52  
53          // CPU gauge
54          sb.append(indent).append(color(BOX_VERTICAL, CYAN))
55            .append(gauge("CPU ", metrics.cpu(), metrics.cpuWarning()))
56            .append(color(BOX_VERTICAL, CYAN)).append("\n");
57  
58          // Memory gauge
59          sb.append(indent).append(color(BOX_VERTICAL, CYAN))
60            .append(gauge("MEM ", metrics.memory(), metrics.memoryWarning()))
61            .append(color(BOX_VERTICAL, CYAN)).append("\n");
62  
63          // Disk gauge
64          sb.append(indent).append(color(BOX_VERTICAL, CYAN))
65            .append(gauge("DISK", metrics.disk(), metrics.diskWarning()))
66            .append(color(BOX_VERTICAL, CYAN)).append("\n");
67  
68          // Footer
69          sb.append(indent).append(color(BOX_BOTTOM_LEFT + repeat(BOX_HORIZONTAL, BOX_WIDTH - 2) +
70              BOX_BOTTOM_RIGHT, CYAN)).append("\n");
71  
72          return sb.toString();
73      };
74  
75      /**
76       * Build a single gauge line with color-coded bar.
77       */
78      private static String gauge(String label, double percent, boolean warning) {
79          int filled = (int) ((BAR_WIDTH * percent) / 100);
80          int empty = BAR_WIDTH - filled;
81  
82          String barColor = warning ? RED : GREEN;
83          String warnIcon = warning ? color(" ⚠", YELLOW) : "  ";
84  
85          return " " + color(label, BOLD) + " " +
86              color("[", DIM) +
87              color(repeat(BLOCK_FULL, filled), barColor) +
88              color(repeat(BLOCK_LIGHT, empty), BRIGHT_BLACK) +
89              color("]", DIM) +
90              color(String.format(" %3.0f%%", percent), warning ? RED : WHITE) +
91              warnIcon + " ";
92      }
93  
94      // ═══════════════════════════════════════════════════════════════════
95      //  CLI ADAPTER - Plain text for scripting
96      // ═══════════════════════════════════════════════════════════════════
97  
98      /**
99       * CLI format - simple key: value pairs for shell scripts.
100      *
101      * <pre>
102      * cpu: 67%
103      * mem: 52%
104      * disk: 91%
105      * </pre>
106      */
107     public static final Function<SystemMetrics, String> CLI_ADAPTER = metrics ->
108         String.format("cpu: %.0f%%\nmem: %.0f%%\ndisk: %.0f%%\n",
109             metrics.cpu(), metrics.memory(), metrics.disk());
110 
111     // ═══════════════════════════════════════════════════════════════════
112     //  JSON ADAPTER - Machine readable
113     // ═══════════════════════════════════════════════════════════════════
114 
115     /**
116      * JSON format for APIs and data interchange (pretty-printed).
117      *
118      * <pre>
119      * {
120      *   "cpu": 67.0,
121      *   "memory": 52.0,
122      *   "disk": 91.0,
123      *   "warnings": ["disk"]
124      * }
125      * </pre>
126      */
127     public static final Function<SystemMetrics, String> JSON_ADAPTER = metrics -> {
128         StringBuilder warnings = new StringBuilder("[");
129         boolean first = true;
130         if (metrics.cpuWarning()) {
131             warnings.append("\"cpu\"");
132             first = false;
133         }
134         if (metrics.memoryWarning()) {
135             if (!first) warnings.append(", ");
136             warnings.append("\"memory\"");
137             first = false;
138         }
139         if (metrics.diskWarning()) {
140             if (!first) warnings.append(", ");
141             warnings.append("\"disk\"");
142         }
143         warnings.append("]");
144 
145         return String.format(
146             "{\n  \"cpu\": %.1f,\n  \"memory\": %.1f,\n  \"disk\": %.1f,\n  \"warnings\": %s\n}\n",
147             metrics.cpu(), metrics.memory(), metrics.disk(), warnings
148         );
149     };
150 
151     // ═══════════════════════════════════════════════════════════════════
152     //  PROMETHEUS ADAPTER - Metrics exposition format
153     // ═══════════════════════════════════════════════════════════════════
154 
155     /**
156      * Prometheus exposition format for monitoring systems.
157      *
158      * <pre>
159      * # HELP system_cpu_percent Current CPU usage percentage
160      * # TYPE system_cpu_percent gauge
161      * system_cpu_percent 67.0
162      * # HELP system_memory_percent Current memory usage percentage
163      * # TYPE system_memory_percent gauge
164      * system_memory_percent 52.0
165      * # HELP system_disk_percent Current disk usage percentage
166      * # TYPE system_disk_percent gauge
167      * system_disk_percent 91.0
168      * </pre>
169      */
170     public static final Function<SystemMetrics, String> PROMETHEUS_ADAPTER = metrics -> {
171         StringBuilder sb = new StringBuilder();
172 
173         sb.append("# HELP system_cpu_percent Current CPU usage percentage\n");
174         sb.append("# TYPE system_cpu_percent gauge\n");
175         sb.append(String.format("system_cpu_percent %.1f\n", metrics.cpu()));
176 
177         sb.append("# HELP system_memory_percent Current memory usage percentage\n");
178         sb.append("# TYPE system_memory_percent gauge\n");
179         sb.append(String.format("system_memory_percent %.1f\n", metrics.memory()));
180 
181         sb.append("# HELP system_disk_percent Current disk usage percentage\n");
182         sb.append("# TYPE system_disk_percent gauge\n");
183         sb.append(String.format("system_disk_percent %.1f\n", metrics.disk()));
184 
185         return sb.toString();
186     };
187 }