1 /*
2 * Copyright (c) 2002-2026 Gargoyle Software Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 * https://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15 package org.htmlunit;
16
17 import java.io.IOException;
18 import java.io.ObjectInputStream;
19 import java.io.Serializable;
20
21 import org.apache.commons.logging.Log;
22 import org.apache.commons.logging.LogFactory;
23 import org.htmlunit.corejs.javascript.Context;
24 import org.htmlunit.corejs.javascript.NativeConsole;
25 import org.htmlunit.corejs.javascript.NativeConsole.ConsolePrinter;
26 import org.htmlunit.corejs.javascript.NativeConsole.Level;
27 import org.htmlunit.corejs.javascript.ScriptStackElement;
28 import org.htmlunit.corejs.javascript.VarScope;
29
30 /**
31 * This class can be used to print messages to the logger. The first parameter
32 * can be a message-object containing format specifiers such as ("%o", "%s",
33 * "%d", "%i", "%f"). The logging methods are null-safe, so if the number of
34 * format specifiers and the numbers of parameters don't match, no exception is thrown.
35 * <p>
36 * The default logger uses Apache Commons Logging.
37 * </p>
38 *
39 * @author Andrea Martino
40 * @author Ronald Brill
41 */
42 public class WebConsole implements ConsolePrinter, Serializable {
43
44 private static final Log LOG = LogFactory.getLog(WebConsole.class);
45
46 private transient Logger logger_ = new DefaultLogger(LOG);
47
48 /**
49 * A simple logging interface abstracting logging APIs.
50 */
51 public interface Logger {
52
53 /**
54 * Is trace logging currently enabled?.
55 * <p>
56 * Call this method to prevent having to perform expensive operations
57 * (for example, <code>String</code> concatenation)
58 * when the log level is more than trace.
59 * </p>
60 *
61 * @return true if trace is enabled in the underlying logger.
62 */
63 boolean isTraceEnabled();
64
65 /**
66 * Logs a message with trace log level.
67 *
68 * @param message log this message
69 */
70 void trace(Object message);
71
72 /**
73 * Is debug logging currently enabled?.
74 * <p>
75 * Call this method to prevent having to perform expensive operations
76 * (for example, <code>String</code> concatenation)
77 * when the log level is more than debug.
78 * </p>
79 *
80 * @return true if debug is enabled in the underlying logger.
81 */
82 boolean isDebugEnabled();
83
84 /**
85 * Logs a message with debug log level.
86 *
87 * @param message log this message
88 */
89 void debug(Object message);
90
91 /**
92 * Is info logging currently enabled?.
93 * <p>
94 * Call this method to prevent having to perform expensive operations
95 * (for example, <code>String</code> concatenation)
96 * when the log level is more than info.
97 * </p>
98 *
99 * @return true if info is enabled in the underlying logger.
100 */
101 boolean isInfoEnabled();
102
103 /**
104 * Logs a message with info log level.
105 *
106 * @param message log this message
107 */
108 void info(Object message);
109
110 /**
111 * Is warn logging currently enabled?.
112 * <p>
113 * Call this method to prevent having to perform expensive operations
114 * (for example, <code>String</code> concatenation)
115 * when the log level is more than warn.
116 * </p>
117 *
118 * @return true if warn is enabled in the underlying logger.
119 */
120 boolean isWarnEnabled();
121
122 /**
123 * Logs a message with warn log level.
124 *
125 * @param message log this message
126 */
127 void warn(Object message);
128
129 /**
130 * Is error logging currently enabled?.
131 * <p>
132 * Call this method to prevent having to perform expensive operations
133 * (for example, <code>String</code> concatenation)
134 * when the log level is more than error.
135 * </p>
136 *
137 * @return true if error is enabled in the underlying logger.
138 */
139 boolean isErrorEnabled();
140
141 /**
142 * Logs a message with error log level.
143 *
144 * @param message log this message
145 */
146 void error(Object message);
147 }
148
149 /**
150 * Sets the Logger_.
151 * @param logger the logger
152 */
153 public void setLogger(final Logger logger) {
154 logger_ = logger;
155 }
156
157 /**
158 * Returns the current Logger.
159 * @return the logger
160 */
161 public Logger getLogger() {
162 return logger_;
163 }
164
165 @Override
166 public void print(final Context cx, final VarScope scope, final Level level,
167 final Object[] args, final ScriptStackElement[] stack) {
168 switch (level) {
169 case TRACE:
170 if (logger_.isInfoEnabled()) {
171 String msg = format(cx, scope, args);
172 if (stack != null) {
173 final StringBuilder scriptStack = new StringBuilder();
174 scriptStack.append(msg);
175
176 for (final ScriptStackElement scriptStackElement : stack) {
177 if (scriptStack.length() > 0) {
178 scriptStack.append('\n');
179 }
180 scriptStack.append(scriptStackElement);
181 }
182
183 msg = scriptStack.toString();
184 }
185 logger_.info(msg);
186 }
187 break;
188 case DEBUG:
189 if (logger_.isDebugEnabled()) {
190 logger_.debug(format(cx, scope, args));
191 }
192 break;
193 case INFO:
194 if (logger_.isInfoEnabled()) {
195 logger_.info(format(cx, scope, args));
196 }
197 break;
198 case WARN:
199 if (logger_.isWarnEnabled()) {
200 logger_.warn(format(cx, scope, args));
201 }
202 break;
203 case ERROR:
204 if (logger_.isErrorEnabled()) {
205 logger_.error(format(cx, scope, args));
206 }
207 break;
208
209 default:
210 break;
211 }
212 }
213
214 private static String format(final Context cx, final VarScope scope, final Object[] args) {
215 String msg = NativeConsole.format(cx, scope, args);
216 msg = msg.replaceAll("\\r?\\n", "\n");
217 return msg;
218 }
219
220 private void readObject(final ObjectInputStream ois) throws ClassNotFoundException, IOException {
221 ois.defaultReadObject();
222 setLogger(new DefaultLogger(LOG));
223 }
224
225 /**
226 * This class is the default logger used by WebConsole.
227 */
228 private static class DefaultLogger implements Logger {
229
230 private final Log webConsoleLogger_;
231
232 /**
233 * Ctor.
234 */
235 DefaultLogger(final Log logger) {
236 super();
237 webConsoleLogger_ = logger;
238 }
239
240 @Override
241 public boolean isTraceEnabled() {
242 return webConsoleLogger_.isTraceEnabled();
243 }
244
245 @Override
246 public void trace(final Object message) {
247 webConsoleLogger_.trace(message);
248 }
249
250 @Override
251 public boolean isDebugEnabled() {
252 return webConsoleLogger_.isDebugEnabled();
253 }
254
255 @Override
256 public void debug(final Object message) {
257 webConsoleLogger_.debug(message);
258 }
259
260 @Override
261 public boolean isInfoEnabled() {
262 return webConsoleLogger_.isInfoEnabled();
263 }
264
265 @Override
266 public void info(final Object message) {
267 webConsoleLogger_.info(message);
268 }
269
270 @Override
271 public boolean isWarnEnabled() {
272 return webConsoleLogger_.isWarnEnabled();
273 }
274
275 @Override
276 public void warn(final Object message) {
277 webConsoleLogger_.warn(message);
278 }
279
280 @Override
281 public boolean isErrorEnabled() {
282 return webConsoleLogger_.isErrorEnabled();
283 }
284
285 @Override
286 public void error(final Object message) {
287 webConsoleLogger_.error(message);
288 }
289 }
290 }