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