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.status;
015
016import static ch.qos.logback.core.CoreConstants.LINE_SEPARATOR;
017
018import java.io.IOException;
019import java.io.PrintWriter;
020import java.io.StringWriter;
021import java.util.List;
022
023import jakarta.servlet.ServletException;
024import jakarta.servlet.http.HttpServlet;
025import jakarta.servlet.http.HttpServletRequest;
026import jakarta.servlet.http.HttpServletResponse;
027
028import ch.qos.logback.core.CoreConstants;
029import ch.qos.logback.core.helpers.Transform;
030import ch.qos.logback.core.util.CachingDateFormatter;
031
032abstract public class ViewStatusMessagesServletBase extends HttpServlet {
033
034    private static final long serialVersionUID = -3551928133801157219L;
035    private static CachingDateFormatter SDF = new CachingDateFormatter("yyyy-MM-dd HH:mm:ss");
036
037    static String SUBMIT = "submit";
038    static String CLEAR = "Clear";
039
040    protected abstract StatusManager getStatusManager(HttpServletRequest req, HttpServletResponse resp);
041
042    protected abstract String getPageTitle(HttpServletRequest req, HttpServletResponse resp);
043
044    int count;
045
046    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
047
048        count = 0;
049        StatusManager sm = getStatusManager(req, resp);
050
051        resp.setContentType("text/html");
052        PrintWriter output = resp.getWriter();
053
054        output.append("<html>\r\n");
055        output.append("<head>\r\n");
056        printCSS(req.getContextPath(), output);
057        output.append("</head>\r\n");
058        output.append("<body>\r\n");
059        output.append(getPageTitle(req, resp));
060
061        output.append("<form method=\"POST\">\r\n");
062        output.append("<input type=\"submit\" name=\"" + SUBMIT + "\" value=\"" + CLEAR + "\">");
063        output.append("</form>\r\n");
064
065        if (CLEAR.equalsIgnoreCase(req.getParameter(SUBMIT))) {
066            sm.clear();
067            sm.add(new InfoStatus("Cleared all status messages", this));
068        }
069
070        output.append("<table>");
071        StringBuilder buf = new StringBuilder();
072        if (sm != null) {
073            printList(buf, sm);
074        } else {
075            output.append("Could not find status manager");
076        }
077        output.append(buf);
078        output.append("</table>");
079        output.append("</body>\r\n");
080        output.append("</html>\r\n");
081        output.flush();
082        output.close();
083    }
084
085    public void printCSS(String localRef, PrintWriter output) {
086        output.append("  <STYLE TYPE=\"text/css\">\r\n");
087        output.append("    .warn  { font-weight: bold; color: #FF6600;} \r\n"); // orange
088        output.append("    .error { font-weight: bold; color: #CC0000;} \r\n");
089        output.append("    table { margin-left: 2em; margin-right: 2em; border-left: 2px solid #AAA; }\r\n");
090        output.append("    tr.even { background: #FFFFFF; }\r\n");
091        output.append("    tr.odd  { background: #EAEAEA; }\r\n");
092        output.append("    td { padding-right: 1ex; padding-left: 1ex; border-right: 2px solid #AAA; }\r\n");
093        output.append("    td.date { text-align: right; font-family: courier, monospace; font-size: smaller; }");
094        output.append(LINE_SEPARATOR);
095
096        output.append("  td.level { text-align: right; }");
097        output.append(LINE_SEPARATOR);
098        output.append("    tr.header { background: #596ED5; color: #FFF; font-weight: bold; font-size: larger; }");
099        output.append(CoreConstants.LINE_SEPARATOR);
100
101        output.append("  td.exception { background: #A2AEE8; white-space: pre; font-family: courier, monospace;}");
102        output.append(LINE_SEPARATOR);
103
104        output.append("  </STYLE>\r\n");
105
106    }
107
108    public void printList(StringBuilder buf, StatusManager sm) {
109        buf.append("<table>\r\n");
110        printHeader(buf);
111        List<Status> statusList = sm.getCopyOfStatusList();
112        for (Status s : statusList) {
113            count++;
114            printStatus(buf, s);
115        }
116        buf.append("</table>\r\n");
117    }
118
119    public void printHeader(StringBuilder buf) {
120        buf.append("  <tr class=\"header\">\r\n");
121        buf.append("    <th>Date </th>\r\n");
122        buf.append("    <th>Level</th>\r\n");
123        buf.append("    <th>Origin</th>\r\n");
124        buf.append("    <th>Message</th>\r\n");
125        buf.append("  </tr>\r\n");
126
127    }
128
129    String statusLevelAsString(Status s) {
130        switch (s.getEffectiveLevel()) {
131        case Status.INFO:
132            return "INFO";
133        case Status.WARN:
134            return "<span class=\"warn\">WARN</span>";
135        case Status.ERROR:
136            return "<span class=\"error\">ERROR</span>";
137        }
138        return null;
139    }
140
141    String abbreviatedOrigin(Status s) {
142        Object o = s.getOrigin();
143        if (o == null) {
144            return null;
145        }
146        String fqClassName = o.getClass().getName();
147        int lastIndex = fqClassName.lastIndexOf(CoreConstants.DOT);
148        if (lastIndex != -1) {
149            return fqClassName.substring(lastIndex + 1, fqClassName.length());
150        } else {
151            return fqClassName;
152        }
153    }
154
155    private void printStatus(StringBuilder buf, Status s) {
156        String trClass;
157        if (count % 2 == 0) {
158            trClass = "even";
159        } else {
160            trClass = "odd";
161        }
162        buf.append("  <tr class=\"").append(trClass).append("\">\r\n");
163        String dateStr = SDF.format(s.getTimestamp());
164        buf.append("    <td class=\"date\">").append(dateStr).append("</td>\r\n");
165        buf.append("    <td class=\"level\">").append(statusLevelAsString(s)).append("</td>\r\n");
166        buf.append("    <td>").append(abbreviatedOrigin(s)).append("</td>\r\n");
167        buf.append("    <td>").append(s.getMessage()).append("</td>\r\n");
168        buf.append("  </tr>\r\n");
169        if (s.getThrowable() != null) {
170            printThrowable(buf, s.getThrowable());
171        }
172    }
173
174    private void printThrowable(StringBuilder buf, Throwable t) {
175        buf.append("  <tr>\r\n");
176        buf.append("    <td colspan=\"4\" class=\"exception\"><pre>");
177        StringWriter sw = new StringWriter();
178        PrintWriter pw = new PrintWriter(sw);
179        t.printStackTrace(pw);
180        buf.append(Transform.escapeTags(sw.getBuffer()));
181        buf.append("    </pre></td>\r\n");
182        buf.append("  </tr>\r\n");
183
184    }
185}