001/* 002 * jPOS Project [http://jpos.org] 003 * Copyright (C) 2000-2026 jPOS Software SRL 004 * 005 * This program is free software: you can redistribute it and/or modify 006 * it under the terms of the GNU Affero General Public License as 007 * published by the Free Software Foundation, either version 3 of the 008 * License, or (at your option) any later version. 009 * 010 * This program is distributed in the hope that it will be useful, 011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 013 * GNU Affero General Public License for more details. 014 * 015 * You should have received a copy of the GNU Affero General Public License 016 * along with this program. If not, see <http://www.gnu.org/licenses/>. 017 */ 018 019package org.jpos.log.render.markdown; 020 021import org.jpos.log.LogRenderer; 022import org.jpos.log.evt.KV; 023import org.jpos.log.evt.ProcessOutput; 024import org.jpos.log.evt.SysInfo; 025 026import java.io.PrintStream; 027import java.lang.reflect.InvocationTargetException; 028import java.lang.reflect.Method; 029import java.lang.reflect.RecordComponent; 030import java.util.List; 031import java.util.Map; 032import java.util.stream.Collectors; 033import java.util.stream.Stream; 034 035 036public final class SysInfoMarkdownRenderer implements LogRenderer<SysInfo> { 037 038 @Override 039 public void render(SysInfo sysinfo, PrintStream ps, String indent) { 040 Map<String,Object> entries = extractEntriesToMap(sysinfo); 041 int width = maxLength(entries); 042 final String fmt = "| %-" + width + "s | %s |%n"; 043 ps.println ("### SystemMonitor"); 044 ps.print (row(fmt, "id", "value")); 045 ps.print (row(fmt, "-".repeat(width), "-----")); 046 entries.forEach((k, v) -> { 047 switch (k) { 048 case "nameRegistrarEntries": 049 case "threads": 050 case "scripts": 051 break; 052 default: 053 ps.print( 054 row(fmt, k, v.toString()) 055 ); 056 } 057 }); 058 renderNameRegistrar(sysinfo.nameRegistrarEntries(), ps, fmt, width); 059 renderThreads(sysinfo.threads(), ps, fmt, width); 060 renderScripts(sysinfo.scripts(), ps); 061 } 062 public Class<?> clazz() { 063 return SysInfo.class; 064 } 065 public Type type() { 066 return Type.MARKDOWN; 067 } 068 069 private void renderNameRegistrar(List<KV> entries, PrintStream ps, String fmt, int width) { 070 ps.println ("#### NameRegistrar"); 071 ps.print (row(fmt, "id", "component")); 072 ps.print (row(fmt, "-".repeat(width), "---------")); 073 entries.forEach(kv -> { 074 ps.print( 075 row(fmt, kv.key(), kv.value())); 076 }); 077 } 078 079 private void renderThreads(List<KV> entries, PrintStream ps, String fmt, int width) { 080 ps.println ("#### Threads"); 081 ps.print (row(fmt, "thread", "info")); 082 ps.print (row(fmt, "-".repeat(width), "----")); 083 entries.forEach(kv -> { 084 ps.print( 085 row(fmt, kv.key(), kv.value())); 086 }); 087 } 088 089 private void renderScripts(List<ProcessOutput> entries, PrintStream ps) { 090 entries.forEach (processOutput -> { 091 ps.printf ("#### %s%n", processOutput.name()); 092 if (!processOutput.stdout().isEmpty()) { 093 ps.println ("```"); 094 ps.println (processOutput.stdout()); 095 ps.println ("```"); 096 } 097 if (processOutput.stderr() != null) { 098 ps.println ("```"); 099 ps.println (processOutput.stderr()); 100 ps.println ("```"); 101 } 102 }); 103 } 104 105 106 private String row (String fmt, String c1, String c2) { 107 return fmt.formatted(c1, c2); 108 } 109 110 private int maxLength(Map<String, Object> map) { 111 return map.keySet().stream() 112 .map(String::length) 113 .max(Integer::compareTo).orElse(0); 114 } 115 116 private Map<String, Object> extractEntriesToMap(SysInfo record) { 117 return Stream.of(record.getClass().getRecordComponents()) 118 .collect(Collectors.toMap( 119 RecordComponent::getName, 120 component -> { 121 try { 122 Method accessor = component.getAccessor(); 123 return accessor.invoke(record); 124 } catch (IllegalAccessException | InvocationTargetException e) { 125 return "%s:%s".formatted(e.getClass().getSimpleName(), e.getMessage()); 126 } 127 } 128 )); 129 } 130}