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