001// ***************************************************************************************************************************
002// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
003// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
004// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance            *
005// * with the License.  You may obtain a copy of the License at                                                              *
006// *                                                                                                                         *
007// *  http://www.apache.org/licenses/LICENSE-2.0                                                                             *
008// *                                                                                                                         *
009// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an  *
010// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
011// * specific language governing permissions and limitations under the License.                                              *
012// ***************************************************************************************************************************
013package org.apache.juneau.rest;
014
015import static org.apache.juneau.internal.StringUtils.*;
016
017import java.text.*;
018import java.util.logging.*;
019
020import javax.servlet.http.*;
021
022import org.apache.juneau.internal.*;
023import org.apache.juneau.json.*;
024
025/**
026 * Logging utility class.
027 *
028 * <div class='warn'>
029 *    <b>Deprecated</b> - Use {@link BasicRestCallLogger}
030 * </div>
031 *
032 * <p>
033 * Subclasses can override these methods to tailor logging of HTTP requests.
034 * <br>Subclasses MUST implement a no-arg public constructor.
035 *
036 * <ul class='seealso'>
037 *    <li class='link'>{@doc RestLoggingAndDebugging}
038 * </ul>
039 */
040@Deprecated
041public class BasicRestLogger implements RestLogger {
042
043   private final JuneauLogger logger;
044   private final RestContext context;
045
046
047   /**
048    * Constructor.
049    *
050    * @param context The context of the resource object.
051    */
052   public BasicRestLogger(RestContext context) {
053      this.context = context;
054      this.logger = JuneauLogger.getLogger(getLoggerName());
055   }
056
057   /**
058    * Returns the logger name.
059    *
060    * <p>
061    * By default returns the class name of the servlet class passed in to the context.
062    *
063    * <p>
064    * Subclasses can override this to provide their own customized logger names.
065    *
066    * @return The logger name.
067    */
068   protected String getLoggerName() {
069      return context == null ? getClass().getName() : context.getResource().getClass().getName();
070   }
071
072   /**
073    * Returns the Java logger used for logging.
074    *
075    * <p>
076    * Subclasses can provide their own logger.
077    * The default implementation returns the logger created using <c>Logger.getLogger(getClass())</c>.
078    *
079    * @return The logger used for logging.
080    */
081   protected Logger getLogger() {
082      return logger;
083   }
084
085   @Override /* RestLogger */
086   public void setLevel(Level level) {
087      getLogger().setLevel(level);
088   }
089
090   /**
091    * Log a message to the logger.
092    *
093    * <p>
094    * Subclasses can override this method if they wish to log messages using a library other than Java Logging
095    * (e.g. Apache Commons Logging).
096    *
097    * @param level The log level.
098    * @param cause The cause.
099    * @param msg The message to log.
100    * @param args Optional {@link MessageFormat}-style arguments.
101    */
102   @Override /* RestLogger */
103   public void log(Level level, Throwable cause, String msg, Object...args) {
104      msg = format(msg, args);
105      getLogger().log(level, msg, cause);
106   }
107
108   /**
109    * Log a message.
110    *
111    * <p>
112    * Equivalent to calling <code>log(level, <jk>null</jk>, msg, args);</code>
113    *
114    * @param level The log level.
115    * @param msg The message to log.
116    * @param args Optional {@link MessageFormat}-style arguments.
117    */
118   @Override /* RestLogger */
119   public void log(Level level, String msg, Object...args) {
120      log(level, null, msg, args);
121   }
122
123   /**
124    * Same as {@link #log(Level, String, Object...)} excepts runs the arguments through {@link JsonSerializer#DEFAULT_READABLE}.
125    *
126    * <p>
127    * Serialization of arguments do not occur if message is not logged, so it's safe to use this method from within
128    * debug log statements.
129    *
130    * <h5 class='section'>Example:</h5>
131    * <p class='bcode w800'>
132    *    logObjects(<jsf>DEBUG</jsf>, <js>"Pojo contents:\n{0}"</js>, myPojo);
133    * </p>
134    *
135    * @param level The log level.
136    * @param msg The message to log.
137    * @param args Optional {@link MessageFormat}-style arguments.
138    */
139   @Override /* RestLogger */
140   public void logObjects(Level level, String msg, Object...args) {
141      for (int i = 0; i < args.length; i++)
142         args[i] = SimpleJsonSerializer.DEFAULT_READABLE.toStringObject(args[i]);
143      log(level, null, msg, args);
144   }
145
146   /**
147    * Callback method for logging errors during HTTP requests.
148    *
149    * <p>
150    * Typically, subclasses will override this method and log errors themselves.
151    *
152    * <p>
153    * The default implementation simply logs errors to the <c>RestServlet</c> logger.
154    *
155    * <p>
156    * Here's a typical implementation showing how stack trace hashing can be used to reduce log file sizes...
157    * <p class='bcode w800'>
158    *    <jk>protected void</jk> onError(HttpServletRequest req, HttpServletResponse res, RestException e, <jk>boolean</jk> noTrace) {
159    *       String qs = req.getQueryString();
160    *       String msg = <js>"HTTP "</js> + req.getMethod() + <js>" "</js> + e.getStatus() + <js>" "</js> + req.getRequestURI() + (qs == <jk>null</jk> ? <js>""</js> : <js>"?"</js> + qs);
161    *       <jk>int</jk> c = e.getOccurrence();
162    *
163    *       <jc>// REST_useStackTraceHashes is disabled, so we have to log the exception every time.</jc>
164    *       <jk>if</jk> (c == 0)
165    *          myLogger.log(Level.<jsf>WARNING</jsf>, <jsm>format</jsm>(<js>"[%s] %s"</js>, e.getStatus(), msg), e);
166    *
167    *       <jc>// This is the first time we've countered this error, so log a stack trace
168    *       // unless ?noTrace was passed in as a URL parameter.</jc>
169    *       <jk>else if</jk> (c == 1 &amp;&amp; ! noTrace)
170    *          myLogger.log(Level.<jsf>WARNING</jsf>, <jsm>format</jsm>(<js>"[%h.%s.%s] %s"</js>, e.hashCode(), e.getStatus(), c, msg), e);
171    *
172    *       <jc>// This error occurred before.
173    *       // Only log the message, not the stack trace.</jc>
174    *       <jk>else</jk>
175    *          myLogger.log(Level.<jsf>WARNING</jsf>, <jsm>format</jsm>(<js>"[%h.%s.%s] %s, %s"</js>, e.hashCode(), e.getStatus(), c, msg, e.getLocalizedMessage()));
176    *    }
177    * </p>
178    *
179    * @param req The servlet request object.
180    * @param res The servlet response object.
181    * @param e Exception indicating what error occurred.
182    */
183   @Override /* RestLogger */
184   public void onError(HttpServletRequest req, HttpServletResponse res, RestException e) {
185      // No-op
186   }
187
188   /**
189    * Returns <jk>true</jk> if the specified exception should be logged.
190    *
191    * <p>
192    * Subclasses can override this method to provide their own logic for determining when exceptions are logged.
193    *
194    * <p>
195    * The default implementation will return <jk>false</jk> if <js>"noTrace=true"</js> is passed in the query string
196    * or <c>No-Trace: true</c> is specified in the header.
197    *
198    * @param req The HTTP request.
199    * @param res The HTTP response.
200    * @param e The exception.
201    * @return <jk>true</jk> if exception should be logged.
202    */
203   protected boolean shouldLog(HttpServletRequest req, HttpServletResponse res, RestException e) {
204      return false;
205   }
206
207   /**
208    * Returns <jk>true</jk> if a stack trace should be logged for this exception.
209    *
210    * <p>
211    * Subclasses can override this method to provide their own logic for determining when stack traces are logged.
212    *
213    * <p>
214    * The default implementation will only log a stack trace if {@link RestException#getOccurrence()} returns
215    * <c>1</c> and the exception is not one of the following:
216    * <ul>
217    *    <li>{@link HttpServletResponse#SC_UNAUTHORIZED}
218    *    <li>{@link HttpServletResponse#SC_FORBIDDEN}
219    *    <li>{@link HttpServletResponse#SC_NOT_FOUND}
220    * </ul>
221    *
222    * @param req The HTTP request.
223    * @param res The HTTP response.
224    * @param e The exception.
225    * @return <jk>true</jk> if stack trace should be logged.
226    */
227   protected boolean shouldLogStackTrace(HttpServletRequest req, HttpServletResponse res, RestException e) {
228      return false;
229   }
230}