1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.logging.log4j.core.appender;
18
19 import java.io.IOException;
20 import java.io.OutputStream;
21 import java.io.PrintStream;
22 import java.io.Serializable;
23 import java.io.UnsupportedEncodingException;
24 import java.lang.reflect.Constructor;
25 import java.nio.charset.Charset;
26
27 import org.apache.logging.log4j.core.Filter;
28 import org.apache.logging.log4j.core.Layout;
29 import org.apache.logging.log4j.core.config.plugins.Plugin;
30 import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
31 import org.apache.logging.log4j.core.config.plugins.PluginElement;
32 import org.apache.logging.log4j.core.config.plugins.PluginFactory;
33 import org.apache.logging.log4j.core.helpers.Booleans;
34 import org.apache.logging.log4j.core.helpers.Loader;
35 import org.apache.logging.log4j.core.layout.PatternLayout;
36 import org.apache.logging.log4j.util.PropertiesUtil;
37
38
39
40
41
42
43
44
45
46
47
48 @Plugin(name = "Console", category = "Core", elementType = "appender", printObject = true)
49 public final class ConsoleAppender extends AbstractOutputStreamAppender {
50
51 private static final String JANSI_CLASS = "org.fusesource.jansi.WindowsAnsiOutputStream";
52 private static ConsoleManagerFactory factory = new ConsoleManagerFactory();
53
54
55
56
57 public enum Target {
58
59 SYSTEM_OUT,
60
61 SYSTEM_ERR
62 }
63
64 private ConsoleAppender(final String name, final Layout<? extends Serializable> layout, final Filter filter,
65 final OutputStreamManager manager,
66 final boolean ignoreExceptions) {
67 super(name, layout, filter, ignoreExceptions, true, manager);
68 }
69
70
71
72
73
74
75
76
77
78
79
80
81 @PluginFactory
82 public static ConsoleAppender createAppender(
83 @PluginElement("Layout") Layout<? extends Serializable> layout,
84 @PluginElement("Filters") final Filter filter,
85 @PluginAttribute("target") final String t,
86 @PluginAttribute("name") final String name,
87 @PluginAttribute("follow") final String follow,
88 @PluginAttribute("ignoreExceptions") final String ignore) {
89 if (name == null) {
90 LOGGER.error("No name provided for ConsoleAppender");
91 return null;
92 }
93 if (layout == null) {
94 layout = PatternLayout.createLayout(null, null, null, null, null);
95 }
96 final boolean isFollow = Boolean.parseBoolean(follow);
97 final boolean ignoreExceptions = Booleans.parseBoolean(ignore, true);
98 final Target target = t == null ? Target.SYSTEM_OUT : Target.valueOf(t);
99 return new ConsoleAppender(name, layout, filter, getManager(isFollow, target, layout), ignoreExceptions);
100 }
101
102 private static OutputStreamManager getManager(final boolean follow, final Target target, final Layout<? extends Serializable> layout) {
103 final String type = target.name();
104 final OutputStream os = getOutputStream(follow, target);
105 return OutputStreamManager.getManager(target.name() + "." + follow, new FactoryData(os, type, layout), factory);
106 }
107
108 private static OutputStream getOutputStream(final boolean follow, final Target target) {
109 final String enc = Charset.defaultCharset().name();
110 PrintStream printStream = null;
111 try {
112 printStream = target == Target.SYSTEM_OUT ?
113 follow ? new PrintStream(new SystemOutStream(), true, enc) : System.out :
114 follow ? new PrintStream(new SystemErrStream(), true, enc) : System.err;
115 } catch (final UnsupportedEncodingException ex) {
116 throw new IllegalStateException("Unsupported default encoding " + enc, ex);
117 }
118 final PropertiesUtil propsUtil = PropertiesUtil.getProperties();
119 if (!propsUtil.getStringProperty("os.name").startsWith("Windows") ||
120 propsUtil.getBooleanProperty("log4j.skipJansi")) {
121 return printStream;
122 }
123 try {
124 final ClassLoader loader = Loader.getClassLoader();
125
126 final Class<?> clazz = loader.loadClass(JANSI_CLASS);
127 final Constructor<?> constructor = clazz.getConstructor(OutputStream.class);
128 return (OutputStream) constructor.newInstance(printStream);
129 } catch (final ClassNotFoundException cnfe) {
130 LOGGER.debug("Jansi is not installed, cannot find {}", JANSI_CLASS);
131 } catch (final NoSuchMethodException nsme) {
132 LOGGER.warn("{} is missing the proper constructor", JANSI_CLASS);
133 } catch (final Exception ex) {
134 LOGGER.warn("Unable to instantiate {}", JANSI_CLASS);
135 }
136 return printStream;
137 }
138
139
140
141
142 private static class SystemErrStream extends OutputStream {
143 public SystemErrStream() {
144 }
145
146 @Override
147 public void close() {
148
149 }
150
151 @Override
152 public void flush() {
153 System.err.flush();
154 }
155
156 @Override
157 public void write(final byte[] b) throws IOException {
158 System.err.write(b);
159 }
160
161 @Override
162 public void write(final byte[] b, final int off, final int len)
163 throws IOException {
164 System.err.write(b, off, len);
165 }
166
167 @Override
168 public void write(final int b) {
169 System.err.write(b);
170 }
171 }
172
173
174
175
176 private static class SystemOutStream extends OutputStream {
177 public SystemOutStream() {
178 }
179
180 @Override
181 public void close() {
182
183 }
184
185 @Override
186 public void flush() {
187 System.out.flush();
188 }
189
190 @Override
191 public void write(final byte[] b) throws IOException {
192 System.out.write(b);
193 }
194
195 @Override
196 public void write(final byte[] b, final int off, final int len)
197 throws IOException {
198 System.out.write(b, off, len);
199 }
200
201 @Override
202 public void write(final int b) throws IOException {
203 System.out.write(b);
204 }
205 }
206
207
208
209
210 private static class FactoryData {
211 private final OutputStream os;
212 private final String type;
213 private final Layout<? extends Serializable> layout;
214
215
216
217
218
219
220
221 public FactoryData(final OutputStream os, final String type, final Layout<? extends Serializable> layout) {
222 this.os = os;
223 this.type = type;
224 this.layout = layout;
225 }
226 }
227
228
229
230
231 private static class ConsoleManagerFactory implements ManagerFactory<OutputStreamManager, FactoryData> {
232
233
234
235
236
237
238
239 @Override
240 public OutputStreamManager createManager(final String name, final FactoryData data) {
241 return new OutputStreamManager(data.os, data.type, data.layout);
242 }
243 }
244
245 }