001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache license, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the license for the specific language governing permissions and 015 * limitations under the license. 016 */ 017package org.apache.logging.log4j.spi; 018 019import org.apache.logging.log4j.Level; 020import org.apache.logging.log4j.Marker; 021import org.apache.logging.log4j.message.Message; 022 023import java.io.ByteArrayOutputStream; 024import java.io.IOException; 025import java.io.PrintStream; 026import java.util.Locale; 027 028/** 029 * Output stream that logs each line written to a pre-defined level. Can also 030 * be configured with a Marker. This class provides an interface that follows 031 * the {@link java.io.PrintStream} methods in spirit, but doesn't output to 032 * any external stream. This class should <em>not</em> be used as a stream for an 033 * underlying logger unless it's being used as a bridge. Otherwise, infinite 034 * loops may occur! 035 */ 036public class LoggerStream extends PrintStream { 037 038 final PrintStream stream; 039 040 public LoggerStream(final AbstractLogger logger, final Level level) { 041 super(System.out); 042 stream = new PrintStream(new HelperStream(logger, null, level), true); 043 } 044 045 public LoggerStream(final AbstractLogger logger, final Marker marker, final Level level) { 046 super(System.out); 047 stream = new PrintStream(new HelperStream(logger, marker, level), true); 048 } 049 050 @Override 051 public void write(int b) { 052 stream.write(b); 053 } 054 055 @Override 056 public void write(byte[] b) throws IOException { 057 stream.write(b); 058 } 059 060 @Override 061 public void write(byte[] b, int off, int len) { 062 stream.write(b, off, len); 063 } 064 065 @Override 066 public void flush() { 067 stream.flush(); 068 } 069 070 @Override 071 public void close() { 072 stream.close(); 073 } 074 075 @Override 076 public void print(boolean b) { 077 stream.print(b); 078 } 079 080 @Override 081 public void print(char c) { 082 stream.print(c); 083 } 084 085 @Override 086 public void print(int i) { 087 stream.print(i); 088 } 089 090 @Override 091 public void print(long l) { 092 stream.print(l); 093 } 094 095 @Override 096 public void print(float f) { 097 stream.print(f); 098 } 099 100 @Override 101 public void print(double d) { 102 stream.print(d); 103 } 104 105 @Override 106 public void print(char[] s) { 107 stream.print(s); 108 } 109 110 @Override 111 public void print(String s) { 112 stream.print(s); 113 } 114 115 @Override 116 public void print(Object obj) { 117 stream.print(obj); 118 } 119 120 @Override 121 public void println() { 122 stream.println(); 123 } 124 125 @Override 126 public void println(boolean x) { 127 stream.println(x); 128 } 129 130 @Override 131 public void println(char x) { 132 stream.println(x); 133 } 134 135 @Override 136 public void println(int x) { 137 stream.println(x); 138 } 139 140 @Override 141 public void println(long x) { 142 stream.println(x); 143 } 144 145 @Override 146 public void println(float x) { 147 stream.println(x); 148 } 149 150 @Override 151 public void println(double x) { 152 stream.println(x); 153 } 154 155 @Override 156 public void println(char[] x) { 157 stream.println(x); 158 } 159 160 @Override 161 public void println(String x) { 162 stream.println(x); 163 } 164 165 @Override 166 public void println(Object x) { 167 stream.println(x); 168 } 169 170 @Override 171 public LoggerStream printf(String format, Object... args) { 172 stream.printf(format, args); 173 return this; 174 } 175 176 @Override 177 public LoggerStream printf(Locale l, String format, Object... args) { 178 stream.printf(l, format, args); 179 return this; 180 } 181 182 @Override 183 public LoggerStream append(char c) { 184 stream.append(c); 185 return this; 186 } 187 188 @Override 189 public LoggerStream append(CharSequence csq) { 190 stream.append(csq); 191 return this; 192 } 193 194 @Override 195 public LoggerStream append(CharSequence csq, int start, int end) { 196 stream.append(csq, start, end); 197 return this; 198 } 199 200 @Override 201 public LoggerStream format(String format, Object... args) { 202 stream.format(format, args); 203 return this; 204 } 205 206 @Override 207 public LoggerStream format(Locale l, String format, Object... args) { 208 stream.format(l, format, args); 209 return this; 210 } 211 212 @Override 213 public boolean checkError() { 214 return stream.checkError(); 215 } 216 217 @Override 218 public String toString() { 219 return "LoggerStream{" + 220 "stream=" + stream + 221 '}'; 222 } 223 224 @Override 225 public boolean equals(Object other) { 226 return this == other 227 || !(other == null || getClass() != other.getClass()) 228 && stream.equals(((LoggerStream) other).stream); 229 } 230 231 @Override 232 public int hashCode() { 233 return stream.hashCode(); 234 } 235 236 private static class HelperStream extends ByteArrayOutputStream { 237 private static final String FQCN = LoggerStream.class.getName(); 238 private final AbstractLogger logger; 239 private final Level level; 240 private final Marker marker; 241 242 private HelperStream(AbstractLogger logger, Marker marker, Level level) { 243 this.logger = logger; 244 this.marker = marker; 245 this.level = level; 246 } 247 248 private void log(int upTo) { 249 if (upTo < 0 || upTo >= count) { 250 throw new IndexOutOfBoundsException(); 251 } 252 final Message message = logger.getMessageFactory().newMessage(extractLine(upTo)); 253 logger.log(marker, FQCN, level, message, null); 254 } 255 256 private String extractLine(int upTo) { 257 final String line = new String(buf, 0, upTo); 258 leftShiftBuffer(upTo + 1); 259 return line; 260 } 261 262 private void leftShiftBuffer(int numBytes) { 263 int remaining = count - numBytes; 264 if (remaining > 0) { 265 System.arraycopy(buf, numBytes, buf, 0, remaining); 266 count = remaining + 1; 267 } else { 268 reset(); 269 } 270 } 271 272 @Override 273 public synchronized void write(int b) { 274 if (b == '\r') { 275 return; 276 } 277 super.write(b); 278 if (b == '\n') { 279 log(count - 1); 280 } 281 } 282 283 @Override 284 public synchronized void write(byte[] b, int off, int len) { 285 for (int i = 0; i < len; ++i) { 286 write(b[off + i]); 287 } 288 } 289 } 290}