root/trunk/src/java/org/jcoderz/phoenix/checkstyle/LoggingLevel.java

Revision 1011, 10.6 kB (checked in by amandel, 4 years ago)

Aligned svn keyword settings.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
Line 
1/*
2 * $Id$
3 *
4 * Copyright 2006, The jCoderZ.org Project. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
8 * met:
9 *
10 *    * Redistributions of source code must retain the above copyright
11 *      notice, this list of conditions and the following disclaimer.
12 *    * Redistributions in binary form must reproduce the above
13 *      copyright notice, this list of conditions and the following
14 *      disclaimer in the documentation and/or other materials
15 *      provided with the distribution.
16 *    * Neither the name of the jCoderZ.org Project nor the names of
17 *      its contributors may be used to endorse or promote products
18 *      derived from this software without specific prior written
19 *      permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS" AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS
25 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
28 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
29 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
30 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
31 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 */
33package org.jcoderz.phoenix.checkstyle;
34
35import java.util.HashSet;
36import java.util.Set;
37import java.util.StringTokenizer;
38import java.util.logging.Level;
39
40import com.puppycrawl.tools.checkstyle.api.Check;
41import com.puppycrawl.tools.checkstyle.api.DetailAST;
42import com.puppycrawl.tools.checkstyle.api.TokenTypes;
43
44/**
45 * This check makes sure that a class' source code does not
46 * contain illegal logging levels in calls to the Java Logging
47 * API. Such a check is interesting when you have a logging
48 * message framework that uses generated classes for messages up to
49 * a certain level in order to guarantee certain information
50 * in these messages when written to the log file.
51 * One example scenario is when log file entries should be sent
52 * to a management console where an operator is looking at the
53 * messages and needs to take actions depending on the severity
54 * of the information he receives. In such cases it is important
55 * that these logging messages need a special format to contain
56 * all the necessary information. In our special case an XML
57 * was used from which exception or warning message classes
58 * had been created. Those classes had to be used for all log
59 * levels INFO and above as these logging records were
60 * automatically forwarded to the operators sitting in from of
61 * a management console, monitoring the application behaviour.
62 * For debugging purposes the developer was allowed to use
63 * only the logging levels below INFO so that no debugging
64 * message accidentally was sent to the management console.
65 *
66 * The default configuration of this check is:
67 * <ul>
68 *    <li>LoggerName = logger</li>
69 *    <li>AllowedLoggerMethods
70 *        = fine,finer,entering,exiting,throwing,finest</li>
71 *    <li>LogCallMaxLevel = FINE</li>
72 * </ul>
73 * The class' logger instance variable must have the name 'logger'.
74 * Only calls to the methods 'fine', 'finer', 'entering', 'exiting',
75 * 'throwing', and 'finest' are allowed. For the methods 'log',
76 * 'logp', and 'logrb' only the logging level FINE and below is
77 * allowed. You can override these settings by specifying
78 * the properties in the checkstyle configuration file.
79 *
80 */
81public class LoggingLevel
82      extends Check
83{
84   private static final int [] TOKEN_LIST = new int[] {TokenTypes.METHOD_CALL};
85
86   /** The required name of the logger. Default is 'logger'. */
87   private static final String DEFAULT_LOGGER_NAME = "logger";
88
89   /** This is the maximum allowed level for logXYZ() calls */
90   private static final Level LOG_CALL_MAX_ALLOWED_LEVEL = Level.FINE;
91   /** This prefix covers the methods: log, logp, logrb */
92   private static final String LOG_CALL_PREFIX = "log";
93
94   /** A set of all logger method names besides logXYZ(). */
95   private static final Set LOGGER_METHODS = new HashSet();
96
97   /** A set of allowed logger method names besides logXYZ(). */
98   private static final Set ALLOWED_LOGGER_METHODS = new HashSet();
99
100   private String mLoggerName = DEFAULT_LOGGER_NAME;
101   private Level mLogCallMaxLevel = LOG_CALL_MAX_ALLOWED_LEVEL;
102
103   static
104   {
105      // All logger methods
106      LOGGER_METHODS.add("severe");
107      LOGGER_METHODS.add("warning");
108      LOGGER_METHODS.add("info");
109      LOGGER_METHODS.add("config");
110      LOGGER_METHODS.add("fine");
111      LOGGER_METHODS.add("finer");
112      LOGGER_METHODS.add("entering");
113      LOGGER_METHODS.add("exiting");
114      LOGGER_METHODS.add("throwing");
115      LOGGER_METHODS.add("finest");
116
117      // The allowed logger methods
118      ALLOWED_LOGGER_METHODS.add("fine");
119      ALLOWED_LOGGER_METHODS.add("finer");
120      ALLOWED_LOGGER_METHODS.add("entering");
121      ALLOWED_LOGGER_METHODS.add("exiting");
122      ALLOWED_LOGGER_METHODS.add("throwing");
123      ALLOWED_LOGGER_METHODS.add("finest");
124   }
125
126   /**
127    * Sets the name of the logger instance.
128    * The default name is 'logger'.
129    *
130    * @param loggerName The name of the logger.
131    */
132   public void setLoggerName (final String loggerName)
133   {
134      mLoggerName = loggerName;
135   }
136
137   /**
138    * Sets the names of allowed logger methods.
139    * The default names are: 'entering', 'exiting', 'throwing', 'fine',
140    * 'finer', and 'finest'.
141    *
142    * @param allowedLoggerMethods The names of allowed logger methods,
143    *       separated by colons.
144    */
145   public void setAllowedLoggerMethods (final String allowedLoggerMethods)
146   {
147      final StringTokenizer st = new StringTokenizer(
148            allowedLoggerMethods, ",");
149
150      ALLOWED_LOGGER_METHODS.clear();
151      while (st.hasMoreTokens())
152      {
153         final String tok = st.nextToken();
154         if (tok != null)
155         {
156            ALLOWED_LOGGER_METHODS.add(tok.trim());
157         }
158      }
159   }
160
161   /**
162    * Sets the maximum allowed level for logger methods
163    * starting with 'log' (log, logp, logrb).
164    * The default level is 'FINE'.
165    *
166    * @param logCallMaxLevel The maximum allowed logger level for
167    * the methods log, logp, and logrb.
168    */
169   public void setLogCallMaxLevel (final String logCallMaxLevel)
170   {
171      mLogCallMaxLevel = Level.parse(logCallMaxLevel);
172   }
173
174   /** {@inheritDoc} */
175   public int[] getDefaultTokens ()
176   {
177      final int [] rc = new int[TOKEN_LIST.length];
178      System.arraycopy(TOKEN_LIST, 0, rc, 0, rc.length);
179      return rc;
180   }
181
182   /** {@inheritDoc} */
183   public void visitToken (final DetailAST ast)
184   {
185      switch (ast.getType())
186      {
187         case TokenTypes.METHOD_CALL:
188            visitMethodCall(ast);
189
190         default:
191            break;
192      }
193   }
194
195   /**
196    * Visits a method call token. Since we are interested in logger.method calls
197    * only, the first child must be a DOT type, otherwise no interest.
198    *
199    * @param methCall The visited token
200    */
201   private void visitMethodCall (final DetailAST methCall)
202   {
203      final DetailAST dot = methCall.findFirstToken(TokenTypes.DOT);
204
205      if (dot != null)
206      {
207         // the first child of the dot-Token is the variable name, which is
208         // 'logger' in our case, otherwise not interested.
209         final DetailAST varName = dot.findFirstToken(TokenTypes.IDENT);
210         if (varName.getText().equals(mLoggerName))
211         {
212            visitLoggerCall(methCall, varName);
213         }
214      }
215   }
216
217   /**
218    * Visits a logger call. The supplied node is the logger variable, the next
219    * sibling the called logger method.
220    *
221    * @param methCall The method call node.
222    * @param logger The Logger variable used in the logger call.
223    */
224   private void visitLoggerCall (
225         final DetailAST methCall,
226         final DetailAST logger)
227   {
228      final DetailAST method = (DetailAST) logger.getNextSibling();
229      if (method != null)
230      {
231         final String methodName = method.getText();
232   
233         if (methodName.startsWith(LOG_CALL_PREFIX))
234         {
235            visitExpressionList(methCall, method);
236         }
237         else
238         {
239            // ignore all other methods than those defined above
240            if (LOGGER_METHODS.contains(methodName)
241                  && !ALLOWED_LOGGER_METHODS.contains(methodName))
242            {
243               logDisallowedLoggerMethod(method);
244            }
245         }
246      }
247   }
248
249   /**
250    * Checks the first parameter given to the supplied method call
251    *
252    * @param methCall The method call node.
253    * @param method The called logger method.
254    */
255   private void visitExpressionList (
256         final DetailAST methCall,
257         final DetailAST method)
258   {
259      final DetailAST expressionList = methCall.
260            findFirstToken(TokenTypes.ELIST);
261      if (expressionList != null)
262      {
263         final DetailAST level = expressionList.findFirstToken(TokenTypes.EXPR);
264         if (level != null)
265         {
266            final DetailAST dot = level.findFirstToken(TokenTypes.DOT);
267            visitLoggerLevel(methCall, dot);
268         }
269      }
270   }
271
272   private void visitLoggerLevel (
273         final DetailAST methCall,
274         final DetailAST dot)
275   {
276      /* in this case we are interested in the last child, which gives the
277         log level. */
278      final DetailAST logLevel = dot.findFirstToken(TokenTypes.IDENT);
279      if (logLevel != null)
280      {
281         final DetailAST levelName = (DetailAST) logLevel.getNextSibling();
282         if (levelName != null)
283         {
284            final Level level = Level.parse(levelName.getText());
285            if (level.intValue() > mLogCallMaxLevel.intValue())
286            {
287               logDisallowedLogLevel(levelName);
288            }
289         }
290      }
291   }
292
293   /**
294    * Logs the disallowed logger level.
295    *
296    * @param level The disallowed log level.
297    */
298   private void logDisallowedLogLevel (final DetailAST level)
299   {
300      // trace.loglevel=Maximum allowed log level for trace log is
301      //     ''{0}'' but was ''{1}''.
302      log(level.getLineNo(), "trace.loglevel",
303            new Object[] {mLogCallMaxLevel, level.getText()});
304   }
305
306   /**
307    * Logs the disallowed logger method call.
308    *
309    * @param method The disallowed logger method.
310    */
311   private void logDisallowedLoggerMethod (final DetailAST method)
312   {
313      // trace.logmethod=Logger method ''{0}'' is not allowed.
314      log(method.getLineNo(), "trace.logmethod",
315            new Object[] {method.getText()});
316   }
317}
Note: See TracBrowser for help on using the browser.