001//////////////////////////////////////////////////////////////////////////////// 002// checkstyle: Checks Java source code for adherence to a set of rules. 003// Copyright (C) 2001-2016 the original author or authors. 004// 005// This library is free software; you can redistribute it and/or 006// modify it under the terms of the GNU Lesser General Public 007// License as published by the Free Software Foundation; either 008// version 2.1 of the License, or (at your option) any later version. 009// 010// This library 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 GNU 013// Lesser General Public License for more details. 014// 015// You should have received a copy of the GNU Lesser General Public 016// License along with this library; if not, write to the Free Software 017// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 018//////////////////////////////////////////////////////////////////////////////// 019 020package com.puppycrawl.tools.checkstyle; 021 022import java.io.OutputStream; 023import java.io.OutputStreamWriter; 024import java.io.PrintWriter; 025import java.io.Writer; 026import java.nio.charset.StandardCharsets; 027 028import com.puppycrawl.tools.checkstyle.api.AuditEvent; 029import com.puppycrawl.tools.checkstyle.api.AuditListener; 030import com.puppycrawl.tools.checkstyle.api.AutomaticBean; 031import com.puppycrawl.tools.checkstyle.api.SeverityLevel; 032 033/** 034 * Simple plain logger for text output. 035 * This is maybe not very suitable for a text output into a file since it 036 * does not need all 'audit finished' and so on stuff, but it looks good on 037 * stdout anyway. If there is really a problem this is what XMLLogger is for. 038 * It gives structure. 039 * 040 * @author <a href="mailto:stephane.bailliez@wanadoo.fr">Stephane Bailliez</a> 041 * @see XMLLogger 042 */ 043public class DefaultLogger extends AutomaticBean implements AuditListener { 044 045 /** Where to write info messages. **/ 046 private final PrintWriter infoWriter; 047 /** Close info stream after use. */ 048 private final boolean closeInfo; 049 050 /** Where to write error messages. **/ 051 private final PrintWriter errorWriter; 052 /** Close error stream after use. */ 053 private final boolean closeError; 054 055 /** Formatter for the log message. */ 056 private final AuditEventFormatter formatter; 057 058 /** 059 * Creates a new {@code DefaultLogger} instance. 060 * @param outputStream where to log infos and errors 061 * @param closeStreamsAfterUse if oS should be closed in auditFinished() 062 */ 063 public DefaultLogger(OutputStream outputStream, boolean closeStreamsAfterUse) { 064 // no need to close oS twice 065 this(outputStream, closeStreamsAfterUse, outputStream, false); 066 } 067 068 /** 069 * Creates a new <code>DefaultLogger</code> instance. 070 * @param infoStream the {@code OutputStream} for info messages. 071 * @param closeInfoAfterUse auditFinished should close infoStream. 072 * @param errorStream the {@code OutputStream} for error messages. 073 * @param closeErrorAfterUse auditFinished should close errorStream 074 */ 075 public DefaultLogger(OutputStream infoStream, 076 boolean closeInfoAfterUse, 077 OutputStream errorStream, 078 boolean closeErrorAfterUse) { 079 this(infoStream, closeInfoAfterUse, errorStream, closeErrorAfterUse, 080 new AuditEventDefaultFormatter()); 081 } 082 083 /** 084 * Creates a new {@code DefaultLogger} instance. 085 * 086 * @param infoStream the {@code OutputStream} for info messages 087 * @param closeInfoAfterUse auditFinished should close infoStream 088 * @param errorStream the {@code OutputStream} for error messages 089 * @param closeErrorAfterUse auditFinished should close errorStream 090 * @param messageFormatter formatter for the log message. 091 */ 092 public DefaultLogger(OutputStream infoStream, 093 boolean closeInfoAfterUse, 094 OutputStream errorStream, 095 boolean closeErrorAfterUse, 096 AuditEventFormatter messageFormatter) { 097 closeInfo = closeInfoAfterUse; 098 closeError = closeErrorAfterUse; 099 final Writer infoStreamWriter = new OutputStreamWriter(infoStream, StandardCharsets.UTF_8); 100 infoWriter = new PrintWriter(infoStreamWriter); 101 102 if (infoStream == errorStream) { 103 errorWriter = infoWriter; 104 } 105 else { 106 final Writer errorStreamWriter = new OutputStreamWriter(errorStream, 107 StandardCharsets.UTF_8); 108 errorWriter = new PrintWriter(errorStreamWriter); 109 } 110 formatter = messageFormatter; 111 } 112 113 /** 114 * Print an Emacs compliant line on the error stream. 115 * If the column number is non zero, then also display it. 116 * @see AuditListener 117 **/ 118 @Override 119 public void addError(AuditEvent event) { 120 final SeverityLevel severityLevel = event.getSeverityLevel(); 121 if (severityLevel != SeverityLevel.IGNORE) { 122 final String errorMessage = formatter.format(event); 123 errorWriter.println(errorMessage); 124 } 125 } 126 127 @Override 128 public void addException(AuditEvent event, Throwable throwable) { 129 synchronized (errorWriter) { 130 errorWriter.println("Error auditing " + event.getFileName()); 131 throwable.printStackTrace(errorWriter); 132 } 133 } 134 135 @Override 136 public void auditStarted(AuditEvent event) { 137 infoWriter.println("Starting audit..."); 138 infoWriter.flush(); 139 } 140 141 @Override 142 public void auditFinished(AuditEvent event) { 143 infoWriter.println("Audit done."); 144 closeStreams(); 145 } 146 147 @Override 148 public void fileStarted(AuditEvent event) { 149 // No need to implement this method in this class 150 } 151 152 @Override 153 public void fileFinished(AuditEvent event) { 154 infoWriter.flush(); 155 } 156 157 /** 158 * Flushes the output streams and closes them if needed. 159 */ 160 private void closeStreams() { 161 infoWriter.flush(); 162 if (closeInfo) { 163 infoWriter.close(); 164 } 165 166 errorWriter.flush(); 167 if (closeError) { 168 errorWriter.close(); 169 } 170 } 171}