1 /*
2 * Copyright (c) 2002-2025 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.Scriptable;
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 *
38 * @author Andrea Martino
39 * @author Ronald Brill
40 */
41 public class WebConsole implements ConsolePrinter, Serializable {
42
43 private static final Log LOG = LogFactory.getLog(WebConsole.class);
44
45 private transient Logger logger_ = new DefaultLogger(LOG);
46
47 /**
48 * A simple logging interface abstracting logging APIs.
49 */
50 public interface Logger {
51
52 /**
53 * Is trace logging currently enabled?
54 * <p>
55 * Call this method to prevent having to perform expensive operations
56 * (for example, <code>String</code> concatenation)
57 * when the log level is more than trace.
58 *
59 * @return true if trace is enabled in the underlying logger.
60 */
61 boolean isTraceEnabled();
62
63 /**
64 * Logs a message with trace log level.
65 *
66 * @param message log this message
67 */
68 void trace(Object message);
69
70 /**
71 * Is debug logging currently enabled?
72 * <p>
73 * Call this method to prevent having to perform expensive operations
74 * (for example, <code>String</code> concatenation)
75 * when the log level is more than debug.
76 *
77 * @return true if debug is enabled in the underlying logger.
78 */
79 boolean isDebugEnabled();
80
81 /**
82 * Logs a message with debug log level.
83 *
84 * @param message log this message
85 */
86 void debug(Object message);
87
88 /**
89 * Is info logging currently enabled?
90 * <p>
91 * Call this method to prevent having to perform expensive operations
92 * (for example, <code>String</code> concatenation)
93 * when the log level is more than info.
94 *
95 * @return true if info is enabled in the underlying logger.
96 */
97 boolean isInfoEnabled();
98
99 /**
100 * Logs a message with info log level.
101 *
102 * @param message log this message
103 */
104 void info(Object message);
105
106 /**
107 * Is warn logging currently enabled?
108 * <p>
109 * Call this method to prevent having to perform expensive operations
110 * (for example, <code>String</code> concatenation)
111 * when the log level is more than warn.
112 *
113 * @return true if warn is enabled in the underlying logger.
114 */
115 boolean isWarnEnabled();
116
117 /**
118 * Logs a message with warn log level.
119 *
120 * @param message log this message
121 */
122 void warn(Object message);
123
124 /**
125 * Is error logging currently enabled?
126 * <p>
127 * Call this method to prevent having to perform expensive operations
128 * (for example, <code>String</code> concatenation)
129 * when the log level is more than error.
130 *
131 * @return true if error is enabled in the underlying logger.
132 */
133 boolean isErrorEnabled();
134
135 /**
136 * Logs a message with error log level.
137 *
138 * @param message log this message
139 */
140 void error(Object message);
141 }
142
143 /**
144 * Sets the Logger_.
145 * @param logger the logger
146 */
147 public void setLogger(final Logger logger) {
148 logger_ = logger;
149 }
150
151 /**
152 * Returns the current Logger.
153 * @return the logger
154 */
155 public Logger getLogger() {
156 return logger_;
157 }
158
159 @Override
160 public void print(final Context cx, final Scriptable scope, final Level level,
161 final Object[] args, final ScriptStackElement[] stack) {
162 switch (level) {
163 case TRACE:
164 if (logger_.isInfoEnabled()) {
165 String msg = format(cx, scope, args);
166 if (stack != null) {
167 final StringBuilder scriptStack = new StringBuilder();
168 scriptStack.append(msg);
169
170 for (final ScriptStackElement scriptStackElement : stack) {
171 if (scriptStack.length() > 0) {
172 scriptStack.append('\n');
173 }
174 scriptStack.append(scriptStackElement);
175 }
176
177 msg = scriptStack.toString();
178 }
179 logger_.info(msg);
180 }
181 break;
182 case DEBUG:
183 if (logger_.isDebugEnabled()) {
184 logger_.debug(format(cx, scope, args));
185 }
186 break;
187 case INFO:
188 if (logger_.isInfoEnabled()) {
189 logger_.info(format(cx, scope, args));
190 }
191 break;
192 case WARN:
193 if (logger_.isWarnEnabled()) {
194 logger_.warn(format(cx, scope, args));
195 }
196 break;
197 case ERROR:
198 if (logger_.isErrorEnabled()) {
199 logger_.error(format(cx, scope, args));
200 }
201 break;
202
203 default:
204 break;
205 }
206 }
207
208 private static String format(final Context cx, final Scriptable scope, final Object[] args) {
209 String msg = NativeConsole.format(cx, scope, args);
210 msg = msg.replaceAll("\\r?\\n", "\n");
211 return msg;
212 }
213
214 private void readObject(final ObjectInputStream ois) throws ClassNotFoundException, IOException {
215 ois.defaultReadObject();
216 setLogger(new DefaultLogger(LOG));
217 }
218
219 /**
220 * This class is the default logger used by WebConsole.
221 */
222 private static class DefaultLogger implements Logger {
223
224 private final Log webConsoleLogger_;
225
226 /**
227 * Ctor.
228 */
229 DefaultLogger(final Log logger) {
230 super();
231 webConsoleLogger_ = logger;
232 }
233
234 @Override
235 public boolean isTraceEnabled() {
236 return webConsoleLogger_.isTraceEnabled();
237 }
238
239 @Override
240 public void trace(final Object message) {
241 webConsoleLogger_.trace(message);
242 }
243
244 @Override
245 public boolean isDebugEnabled() {
246 return webConsoleLogger_.isDebugEnabled();
247 }
248
249 @Override
250 public void debug(final Object message) {
251 webConsoleLogger_.debug(message);
252 }
253
254 @Override
255 public boolean isInfoEnabled() {
256 return webConsoleLogger_.isInfoEnabled();
257 }
258
259 @Override
260 public void info(final Object message) {
261 webConsoleLogger_.info(message);
262 }
263
264 @Override
265 public boolean isWarnEnabled() {
266 return webConsoleLogger_.isWarnEnabled();
267 }
268
269 @Override
270 public void warn(final Object message) {
271 webConsoleLogger_.warn(message);
272 }
273
274 @Override
275 public boolean isErrorEnabled() {
276 return webConsoleLogger_.isErrorEnabled();
277 }
278
279 @Override
280 public void error(final Object message) {
281 webConsoleLogger_.error(message);
282 }
283 }
284 }