View Javadoc
1   /*
2    * Licensed under the GPL License. You may not use this file except in compliance with the License.
3    * You may obtain a copy of the License at
4    *
5    *   https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
6    *
7    * THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
8    * WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
9    * PURPOSE.
10   */
11  package psiprobe.tools;
12  
13  import java.io.IOException;
14  import java.io.OutputStream;
15  import java.io.PrintStream;
16  import java.nio.charset.StandardCharsets;
17  
18  import org.slf4j.Logger;
19  import org.slf4j.LoggerFactory;
20  
21  /**
22   * An {@code OutputStream} which writes to a commons-logging {@code Log} at a particular level.
23   */
24  public final class LogOutputStream extends OutputStream {
25  
26    /** The Constant INTERNAL_LOGGER. */
27    private static final Logger INTERNAL_LOGGER = LoggerFactory.getLogger(LogOutputStream.class);
28  
29    /** The Constant LEVEL_OFF. */
30    public static final int LEVEL_OFF = 0;
31  
32    /** The Constant LEVEL_TRACE. */
33    public static final int LEVEL_TRACE = 1;
34  
35    /** The Constant LEVEL_DEBUG. */
36    public static final int LEVEL_DEBUG = 2;
37  
38    /** The Constant LEVEL_INFO. */
39    public static final int LEVEL_INFO = 3;
40  
41    /** The Constant LEVEL_WARN. */
42    public static final int LEVEL_WARN = 4;
43  
44    /** The Constant LEVEL_ERROR. */
45    public static final int LEVEL_ERROR = 5;
46  
47    /** The Constant LEVEL_FATAL. */
48    public static final int LEVEL_FATAL = 6;
49  
50    /** The logger. */
51    private final Logger logger;
52  
53    /** The level. */
54    private final int level;
55  
56    /** The buf. */
57    private final StringBuilder buf = new StringBuilder();
58  
59    /**
60     * Creates a new instance of {@code LogOutputStream} which will write to a given {@code Log} at
61     * the given level.
62     *
63     * @param log the {@code Log} to which to write
64     * @param level the level at which to write
65     */
66    private LogOutputStream(Logger log, int level) {
67      if (log == null) {
68        throw new IllegalArgumentException("Log cannot be null");
69      }
70      this.logger = log;
71      this.level = level;
72    }
73  
74    /**
75     * Creates a {@code PrintStream} with autoFlush enabled which will write to the given {@code Log}
76     * at the given level.
77     *
78     * @param log the {@code Log} to which to write
79     * @param level the level at which to write
80     *
81     * @return a {@code PrintStream} that writes to the given log
82     */
83    public static PrintStream createPrintStream(Logger log, int level) {
84      try (LogOutputStream logStream = new LogOutputStream(log, level)) {
85        return new PrintStream(logStream, true, StandardCharsets.UTF_8.name());
86      } catch (IOException e) {
87        INTERNAL_LOGGER.error("", e);
88      }
89      return null;
90    }
91  
92    /**
93     * Flushes the contents of this stream to its {@code Log}.
94     */
95    @Override
96    public void flush() {
97      if (shouldWrite()) {
98        String message = buf.toString();
99        log(message);
100     }
101     buf.setLength(0);
102   }
103 
104   /**
105    * Writes the specified {@code byte} to this stream.
106    *
107    * @param out the {@code byte} to write
108    */
109   @Override
110   public void write(int out) {
111     if (shouldWrite()) {
112       char chr = (char) out;
113       buf.append(chr);
114     }
115   }
116 
117   /**
118    * Returns the {@code Log} to which this stream writes.
119    *
120    * @return the {@code Log} to which this stream writes
121    */
122   public Logger getLog() {
123     return logger;
124   }
125 
126   /**
127    * Returns the level at which this stream writes to the {@code Log}.
128    *
129    * @return the level at which this stream writes to the {@code Log}
130    */
131   public int getLevel() {
132     return level;
133   }
134 
135   /**
136    * Determines if the {@code Log} is configured to accept messages at this stream's level.
137    *
138    * @return {@code true} if the level of the underlying {@code Log} is equal to or greater than the
139    *         level assigned to this stream
140    */
141   private boolean shouldWrite() {
142     switch (level) {
143       case LEVEL_TRACE:
144         return logger.isTraceEnabled();
145       case LEVEL_DEBUG:
146         return logger.isDebugEnabled();
147       case LEVEL_INFO:
148         return logger.isInfoEnabled();
149       case LEVEL_WARN:
150         return logger.isWarnEnabled();
151       case LEVEL_ERROR:
152         return logger.isErrorEnabled();
153       default:
154         return false;
155     }
156   }
157 
158   /**
159    * Writes the given message to this stream's {@code Log} at this stream's level.
160    *
161    * @param message the message to be written
162    */
163   private void log(String message) {
164     if (message == null || message.isEmpty()) {
165       return;
166     }
167     switch (level) {
168       case LEVEL_TRACE:
169         logger.trace(message);
170         break;
171       case LEVEL_DEBUG:
172         logger.debug(message);
173         break;
174       case LEVEL_INFO:
175         logger.info(message);
176         break;
177       case LEVEL_WARN:
178         logger.warn(message);
179         break;
180       case LEVEL_ERROR:
181         logger.error(message);
182         break;
183       default:
184         // Don't log anything
185         break;
186     }
187   }
188 
189 }