001/* 002 * Logback: the reliable, generic, fast and flexible logging framework. 003 * Copyright (C) 1999-2024, QOS.ch. All rights reserved. 004 * 005 * This program and the accompanying materials are dual-licensed under 006 * either the terms of the Eclipse Public License v1.0 as published by 007 * the Eclipse Foundation 008 * 009 * or (per the licensee's choosing) 010 * 011 * under the terms of the GNU Lesser General Public License version 2.1 012 * as published by the Free Software Foundation. 013 */ 014 015package ch.qos.logback.core.util; 016 017import ch.qos.logback.core.Context; 018import ch.qos.logback.core.CoreConstants; 019import ch.qos.logback.core.helpers.ThrowableToStringArray; 020import ch.qos.logback.core.status.ErrorStatus; 021import ch.qos.logback.core.status.Status; 022import ch.qos.logback.core.status.StatusManager; 023import ch.qos.logback.core.status.StatusUtil; 024 025import java.io.PrintStream; 026import java.util.Iterator; 027import java.util.List; 028 029import static ch.qos.logback.core.status.StatusUtil.filterStatusListByTimeThreshold; 030 031/** 032 * 033 * Same as StatusPrinter but with instance methods instead of static. 034 * 035 * @since 1.5.4 036 */ 037public class StatusPrinter2 { 038 039 040 private PrintStream ps = System.out; 041 042 static CachingDateFormatter cachingDateFormat = new CachingDateFormatter("HH:mm:ss,SSS"); 043 044 public void setPrintStream(PrintStream printStream) { 045 ps = printStream; 046 } 047 048 /** 049 * Print the contents of the context statuses, but only if they contain warnings 050 * or errors. 051 * 052 * @param context a context to print 053 */ 054 public void printInCaseOfErrorsOrWarnings(Context context) { 055 printInCaseOfErrorsOrWarnings(context, 0); 056 } 057 058 /** 059 * Print the contents of the context status, but only if they contain warnings 060 * or errors occurring later than the threshold. 061 * 062 * @param context a context to print 063 * @param threshold filter events later than the threshold 064 */ 065 public void printInCaseOfErrorsOrWarnings(Context context, long threshold) { 066 if (context == null) { 067 throw new IllegalArgumentException("Context argument cannot be null"); 068 } 069 070 StatusManager sm = context.getStatusManager(); 071 if (sm == null) { 072 ps.println("WARN: Context named \"" + context.getName() + "\" has no status manager"); 073 } else { 074 StatusUtil statusUtil = new StatusUtil(context); 075 if (statusUtil.getHighestLevel(threshold) >= ErrorStatus.WARN) { 076 print(sm, threshold); 077 } 078 } 079 } 080 081 /** 082 * Print the contents of the context statuses, but only if they contain errors. 083 * 084 * @param context a context to print 085 */ 086 public void printIfErrorsOccured(Context context) { 087 if (context == null) { 088 throw new IllegalArgumentException("Context argument cannot be null"); 089 } 090 091 StatusManager sm = context.getStatusManager(); 092 if (sm == null) { 093 ps.println("WARN: Context named \"" + context.getName() + "\" has no status manager"); 094 } else { 095 StatusUtil statusUtil = new StatusUtil(context); 096 if (statusUtil.getHighestLevel(0) == ErrorStatus.ERROR) { 097 print(sm); 098 } 099 } 100 } 101 102 /** 103 * Print the contents of the context's status data. 104 * 105 * @param context a context to print 106 */ 107 public void print(Context context) { 108 print(context, 0); 109 } 110 111 /** 112 * Print context's status data with a timestamp higher than the threshold. 113 * 114 * @param context a context to print 115 */ 116 public void print(Context context, long threshold) { 117 if (context == null) { 118 throw new IllegalArgumentException("Context argument cannot be null"); 119 } 120 121 StatusManager sm = context.getStatusManager(); 122 if (sm == null) { 123 ps.println("WARN: Context named \"" + context.getName() + "\" has no status manager"); 124 } else { 125 print(sm, threshold); 126 } 127 } 128 129 public void print(StatusManager sm) { 130 print(sm, 0); 131 } 132 133 public void print(StatusManager sm, long threshold) { 134 StringBuilder sb = new StringBuilder(); 135 List<Status> filteredList = filterStatusListByTimeThreshold(sm.getCopyOfStatusList(), threshold); 136 buildStrFromStatusList(sb, filteredList); 137 ps.println(sb.toString()); 138 } 139 140 public void print(List<Status> statusList) { 141 StringBuilder sb = new StringBuilder(); 142 buildStrFromStatusList(sb, statusList); 143 ps.println(sb.toString()); 144 } 145 146 private void buildStrFromStatusList(StringBuilder sb, List<Status> statusList) { 147 if (statusList == null) 148 return; 149 for (Status s : statusList) { 150 buildStr(sb, "", s); 151 } 152 } 153 154 private void appendThrowable(StringBuilder sb, Throwable t) { 155 String[] stringRep = ThrowableToStringArray.convert(t); 156 157 for (String s : stringRep) { 158 if (s.startsWith(CoreConstants.CAUSED_BY)) { 159 // nothing 160 } else if (Character.isDigit(s.charAt(0))) { 161 // if line resembles "48 common frames omitted" 162 sb.append("\t... "); 163 } else { 164 // most of the time. just add a tab+"at" 165 sb.append("\tat "); 166 } 167 sb.append(s).append(CoreConstants.LINE_SEPARATOR); 168 } 169 } 170 171 public void buildStr(StringBuilder sb, String indentation, Status s) { 172 String prefix; 173 if (s.hasChildren()) { 174 prefix = indentation + "+ "; 175 } else { 176 prefix = indentation + "|-"; 177 } 178 179 if (cachingDateFormat != null) { 180 String dateStr = cachingDateFormat.format(s.getTimestamp()); 181 sb.append(dateStr).append(" "); 182 } 183 sb.append(prefix).append(s).append(CoreConstants.LINE_SEPARATOR); 184 185 if (s.getThrowable() != null) { 186 appendThrowable(sb, s.getThrowable()); 187 } 188 if (s.hasChildren()) { 189 Iterator<Status> ite = s.iterator(); 190 while (ite.hasNext()) { 191 Status child = ite.next(); 192 buildStr(sb, indentation + " ", child); 193 } 194 } 195 } 196}