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