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.util.Profiler; 023 024import java.io.PrintStream; 025import java.util.Set; 026 027/** Markdown renderer for {@link Profiler} traces, emitted as a fenced code block. */ 028public final class ProfilerMarkdownRenderer implements LogRenderer<Profiler> { 029 /** Default constructor. */ 030 public ProfilerMarkdownRenderer() { 031 } 032 033 @Override 034 public void render(Profiler prof, PrintStream ps, String indent) { 035 var events = prof.getEvents(); 036 int width = maxLength(events.keySet()); 037 final String fmt = "| %-" + width + "s | %10.10s | %10.10s |%n"; 038 ps.print (row(fmt, "Checkpoint", "Elapsed", "Total")); 039 ps.print( 040 row(fmt, "-".repeat(width), "---------:", "-------:") 041 ); 042 StringBuilder graph = new StringBuilder(); 043 events.forEach((key, v) -> { 044 ps.print( 045 row(fmt, v.getEventName(), toMillis(v.getDurationInNanos()), toMillis(v.getTotalDurationInNanos())) 046 ); 047 graph.append (" \"%s\" : %s%n".formatted(key, toMillis(v.getDurationInNanos()))); 048 }); 049 ps.println(); 050 ps.println ("```mermaid"); 051 ps.println ("pie title Profiler"); 052 ps.println (graph); 053 ps.println ("```"); 054 055 } 056 public Class<?> clazz() { 057 return Profiler.class; 058 } 059 060 public Type type() { 061 return Type.MARKDOWN; 062 } 063 private String row (String fmt, String c1, String c2, String c3) { 064 return fmt.formatted(c1, c2, c3); 065 } 066 067 private String toMillis(long nanos) { 068 long millis = nanos / Profiler.TO_MILLIS; 069 long fractional = (nanos % Profiler.TO_MILLIS) / (Profiler.TO_MILLIS / 1000); 070 return String.format("%d.%03d", millis, fractional); 071 } 072 private int maxLength (Set<String> keys) { 073 return keys.stream() 074 .mapToInt(String::length) 075 .max() 076 .orElse(0); // R 077 } 078}