1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.logging.log4j.core.config.status;
19
20 import java.io.File;
21 import java.io.FileNotFoundException;
22 import java.io.FileOutputStream;
23 import java.io.PrintStream;
24 import java.net.URI;
25 import java.net.URISyntaxException;
26 import java.util.Collection;
27 import java.util.Collections;
28 import java.util.LinkedList;
29
30 import org.apache.logging.log4j.Level;
31 import org.apache.logging.log4j.core.util.FileUtils;
32 import org.apache.logging.log4j.status.StatusConsoleListener;
33 import org.apache.logging.log4j.status.StatusListener;
34 import org.apache.logging.log4j.status.StatusLogger;
35
36
37
38
39 public class StatusConfiguration {
40
41 @SuppressWarnings("UseOfSystemOutOrSystemErr")
42 private static final PrintStream DEFAULT_STREAM = System.out;
43 private static final Level DEFAULT_STATUS = Level.ERROR;
44 private static final Verbosity DEFAULT_VERBOSITY = Verbosity.QUIET;
45
46 private final Collection<String> errorMessages = Collections.synchronizedCollection(new LinkedList<String>());
47 private final StatusLogger logger = StatusLogger.getLogger();
48
49 private volatile boolean initialized = false;
50
51 private PrintStream destination = DEFAULT_STREAM;
52 private Level status = DEFAULT_STATUS;
53 private Verbosity verbosity = DEFAULT_VERBOSITY;
54 private String[] verboseClasses;
55
56
57
58
59 public static enum Verbosity {
60 QUIET, VERBOSE;
61
62
63
64
65
66
67
68 public static Verbosity toVerbosity(final String value) {
69 return Boolean.parseBoolean(value) ? VERBOSE : QUIET;
70 }
71 }
72
73
74
75
76
77
78
79 public void error(final String message) {
80 if (!this.initialized) {
81 this.errorMessages.add(message);
82 } else {
83 this.logger.error(message);
84 }
85 }
86
87
88
89
90
91
92
93
94
95
96 public StatusConfiguration withDestination(final String destination) {
97 try {
98 this.destination = parseStreamName(destination);
99 } catch (final URISyntaxException e) {
100 this.error("Could not parse URI [" + destination + "]. Falling back to default of stdout.");
101 this.destination = DEFAULT_STREAM;
102 } catch (final FileNotFoundException e) {
103 this.error("File could not be found at [" + destination + "]. Falling back to default of stdout.");
104 this.destination = DEFAULT_STREAM;
105 }
106 return this;
107 }
108
109 private PrintStream parseStreamName(final String name) throws URISyntaxException, FileNotFoundException {
110 if (name == null || name.equalsIgnoreCase("out")) {
111 return DEFAULT_STREAM;
112 }
113 if (name.equalsIgnoreCase("err")) {
114 return System.err;
115 }
116 final URI destination = FileUtils.getCorrectedFilePathUri(name);
117 final File output = FileUtils.fileFromUri(destination);
118 if (output == null) {
119
120 return DEFAULT_STREAM;
121 }
122 final FileOutputStream fos = new FileOutputStream(output);
123 return new PrintStream(fos, true);
124 }
125
126
127
128
129
130
131
132
133 public StatusConfiguration withStatus(final String status) {
134 this.status = Level.toLevel(status, null);
135 if (this.status == null) {
136 this.error("Invalid status level specified: " + status + ". Defaulting to ERROR.");
137 this.status = Level.ERROR;
138 }
139 return this;
140 }
141
142
143
144
145
146
147
148 public StatusConfiguration withStatus(final Level status) {
149 this.status = status;
150 return this;
151 }
152
153
154
155
156
157
158
159
160 public StatusConfiguration withVerbosity(final String verbosity) {
161 this.verbosity = Verbosity.toVerbosity(verbosity);
162 return this;
163 }
164
165
166
167
168
169
170
171 public StatusConfiguration withVerboseClasses(final String... verboseClasses) {
172 this.verboseClasses = verboseClasses;
173 return this;
174 }
175
176
177
178
179 public void initialize() {
180 if (!this.initialized) {
181 if (this.status == Level.OFF) {
182 this.initialized = true;
183 } else {
184 final boolean configured = configureExistingStatusConsoleListener();
185 if (!configured) {
186 registerNewStatusConsoleListener();
187 }
188 migrateSavedLogMessages();
189 }
190 }
191 }
192
193 private boolean configureExistingStatusConsoleListener() {
194 boolean configured = false;
195 for (final StatusListener statusListener : this.logger.getListeners()) {
196 if (statusListener instanceof StatusConsoleListener) {
197 final StatusConsoleListener listener = (StatusConsoleListener) statusListener;
198 listener.setLevel(this.status);
199 if (this.verbosity == Verbosity.QUIET) {
200 listener.setFilters(this.verboseClasses);
201 }
202 configured = true;
203 }
204 }
205 return configured;
206 }
207
208
209 private void registerNewStatusConsoleListener() {
210 final StatusConsoleListener listener = new StatusConsoleListener(this.status, this.destination);
211 if (this.verbosity == Verbosity.QUIET) {
212 listener.setFilters(this.verboseClasses);
213 }
214 this.logger.registerListener(listener);
215 }
216
217 private void migrateSavedLogMessages() {
218 for (final String message : this.errorMessages) {
219 this.logger.error(message);
220 }
221 this.initialized = true;
222 this.errorMessages.clear();
223 }
224 }