• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one
3  * or more contributor license agreements. See the NOTICE file
4  * distributed with this work for additional information
5  * regarding copyright ownership. The ASF licenses this file
6  * to you under the Apache License, Version 2.0 (the  "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18 /*
19  * $Id$
20  */
21 
22 /*
23  *
24  * ConsoleLogger.java
25  *
26  */
27 package org.apache.qetest;
28 
29 import java.io.PrintStream;
30 import java.io.PrintWriter;
31 import java.io.StringWriter;
32 import java.util.Enumeration;
33 import java.util.Hashtable;
34 import java.util.Properties;
35 
36 /**
37  * Logger that prints human-readable output to System.out.
38  * As an experiment, the ConsoleLogger supports an independent
39  * loggingLevel that can be more restrictive than a loggingLevel
40  * set in any enclosing Reporter.
41  * Note this isn't quite as well architected as I would like,
42  * but it does address what seems to be the
43  * most common usage case: where you're running tests automatically,
44  * and likely will be using some file-based output for results
45  * analysis.  This allows you to set loggingLevel for your Reporter
46  * high, so that most/all output is sent to the file, but set this
47  * ConsoleLogger's loggingLevel low, so only critical problems
48  * are displayed on the screen (since most of the time users will
49  * never be watching the console in this situation).
50  * @author Shane_Curcuru@lotus.com
51  * @version $Id$
52  */
53 public class ConsoleLogger implements Logger
54 {
55 
56     //-----------------------------------------------------
57     //-------- Class members --------
58     //-----------------------------------------------------
59 
60     /** Our output stream - currently hard-coded to System.out. */
61     protected PrintStream outStream = System.out;
62 
63     /** If we're ready to start outputting yet. */
64     protected boolean ready = false;
65 
66     /** If we should indent sub-results or not. */
67     protected boolean indent = true;
68 
69     /** Level (number of spaces?) to indent sub-results. */
70     protected StringBuffer sIndent = new StringBuffer();
71 
72     /** Generic properties for this Logger; sort-of replaces instance variables. */
73     protected Properties loggerProps = null;
74 
75     /**
76     * Special LoggingLevel for just this instance.
77     * May be set from "ConsoleLogger.loggingLevel" property;
78     * defaults to 100 which should be larger than any other
79     * loggingLevels in use currently.
80     * Note that different levels here will even restrict output
81     * from control messages like testCaseInit; see individual
82     * javadocs for what controls what.  This may affect the level
83     * of indenting you see as well; I traded off a little speed
84     * (don't calc indent if not using that message) for prettiness.
85     */
86     protected int consoleLoggingLevel = 100;
87 
88     //-----------------------------------------------------
89     //-------- Control and utility routines --------
90     //-----------------------------------------------------
91 
92     /** Simple constructor, does not perform initialization. */
ConsoleLogger()93     public ConsoleLogger()
94     { /* no-op */
95     }
96 
97     /**
98      * Constructor calls initialize(p).
99      * @param p Properties block to initialize us with.
100      */
ConsoleLogger(Properties p)101     public ConsoleLogger(Properties p)
102     {
103         ready = initialize(p);
104     }
105 
106     /**
107      * Return a description of what this Logger does.
108      * @return "reports results to System.out".
109      */
getDescription()110     public String getDescription()
111     {
112         return ("org.apache.qetest.ConsoleLogger - reports results to System.out.");
113     }
114 
115     /**
116      * Returns information about the Property name=value pairs that
117      * are understood by this Logger/Reporter.
118      * @return same as {@link java.applet.Applet.getParameterInfo}.
119      */
getParameterInfo()120     public String[][] getParameterInfo()
121     {
122 
123         String pinfo[][] =
124         {
125             { OPT_INDENT, "boolean", "If reporter should indent sub-results" },
126             { "ConsoleLogger.loggingLevel", "String", "loggingLevel for just ConsoleLogger; only if more restrictive than other loggingLevels" }
127         };
128 
129         return pinfo;
130     }
131 
132     /**
133      * Accessor methods for our properties block.
134      *
135      * NEEDSDOC ($objectName$) @return
136      */
getProperties()137     public Properties getProperties()
138     {
139         return loggerProps;
140     }
141 
142     /**
143      * Accessor methods for our properties block.
144      * @param p Properties to set (is cloned).
145      */
setProperties(Properties p)146     public void setProperties(Properties p)
147     {
148 
149         if (p != null)
150         {
151             loggerProps = (Properties) p.clone();
152         }
153     }
154 
155     /**
156      * Call once to initialize this Logger/Reporter from Properties.
157      * @param Properties block to initialize from.
158      * @param status, true if OK, false if an error occoured.
159      *
160      * @param p Properties block to initialize from
161      * @return true if OK; currently always returns true
162      */
initialize(Properties p)163     public boolean initialize(Properties p)
164     {
165 
166         setProperties(p);
167 
168         String i = loggerProps.getProperty(OPT_INDENT);
169 
170         if (i != null)
171         {
172             if (i.toLowerCase().equals("no")
173                     || i.toLowerCase().equals("false"))
174                 indent = false;
175             else if (i.toLowerCase().equals("yes")
176                      || i.toLowerCase().equals("true"))
177                 indent = true;
178         }
179 
180         // Grab our specific loggingLevel and set if needed
181         String logLvl = loggerProps.getProperty("ConsoleLogger.loggingLevel");
182         if (logLvl != null)
183         {
184             // Note: if present, we'll attempt to set it
185             // It doesn't really make much sense to set it if
186             //  this value is larger than an enclosing Reporter's
187             //  loggingLevel, but it won't hurt either
188             try
189             {
190                 consoleLoggingLevel = Integer.parseInt(logLvl);
191             }
192             catch (NumberFormatException numEx)
193             { /* no-op */
194             }
195         }
196 
197         ready = true;
198 
199         return true;
200     }
201 
202     /**
203      * Is this Logger/Reporter ready to log results?
204      * @return status - true if it's ready to report, false otherwise
205      */
isReady()206     public boolean isReady()
207     {
208         return ready;
209     }
210 
211     /**
212      * Flush this Logger/Reporter - no-op for ConsoleLogger.
213      */
flush()214     public void flush()
215     { /* no-op */
216     }
217 
218     /**
219      * Close this Logger/Reporter - essentially no-op for ConsoleLogger.
220      */
close()221     public void close()
222     {
223 
224         flush();
225 
226         ready = false;
227     }
228 
229     /** Simplistic indenting - two spaces. */
indent()230     protected void indent()
231     {
232         if (indent)
233             sIndent.append("  ");
234     }
235 
236     /** Simplistic outdenting - two spaces. */
outdent()237     protected void outdent()
238     {
239         if ((indent) && (sIndent.length() >= 2))
240             sIndent.setLength(sIndent.length() - 2);
241     }
242 
243     //-----------------------------------------------------
244     //-------- Testfile / Testcase start and stop routines --------
245     //-----------------------------------------------------
246 
247     /**
248      * Report that a testfile has started.
249      * Output only when ConsoleLogger.loggingLevel >= ERRORMSG
250      *
251      * @param name file name or tag specifying the test.
252      * @param comment comment about the test.
253      */
testFileInit(String name, String comment)254     public void testFileInit(String name, String comment)
255     {
256         if (consoleLoggingLevel < ERRORMSG)
257             return;
258 
259         outStream.println(sIndent + "TestFileInit " + name + ":" + comment);
260         indent();
261     }
262 
263     /**
264      * Report that a testfile has finished, and report it's result.
265      * Output only when ConsoleLogger.loggingLevel >= ERRORMSG
266      *
267      * @param msg message or name of test to log out
268      * @param result result of testfile
269      */
testFileClose(String msg, String result)270     public void testFileClose(String msg, String result)
271     {
272         if (consoleLoggingLevel < ERRORMSG)
273             return;
274 
275         outdent();
276         outStream.println(sIndent + "TestFileClose(" + result + ") " + msg);
277     }
278 
279     /**
280      * Report that a testcase has started.
281      * Output only when ConsoleLogger.loggingLevel >= WARNINGMSG
282      *
283      * @param comment short description of this test case's objective.
284      */
testCaseInit(String comment)285     public void testCaseInit(String comment)
286     {
287         if (consoleLoggingLevel < WARNINGMSG)
288             return;
289 
290         outStream.println(sIndent + "TestCaseInit " + comment);
291         indent();
292     }
293 
294     /**
295      * Report that a testcase has finished, and report it's result.
296      * Output only when ConsoleLogger.loggingLevel >= WARNINGMSG
297      *
298      * @param msg message of name of test case to log out
299      * @param result result of testfile
300      */
testCaseClose(String msg, String result)301     public void testCaseClose(String msg, String result)
302     {
303         if (consoleLoggingLevel < WARNINGMSG)
304             return;
305 
306         outdent();
307         outStream.println(sIndent + "TestCaseClose(" + result + ") " + msg);
308     }
309 
310     //-----------------------------------------------------
311     //-------- Test results logging routines --------
312     //-----------------------------------------------------
313 
314     /**
315      * Report a comment to result file with specified severity.
316      * Output only when ConsoleLogger.loggingLevel >= level
317      *
318      * @param level severity or class of message.
319      * @param msg comment to log out.
320      */
logMsg(int level, String msg)321     public void logMsg(int level, String msg)
322     {
323         if (consoleLoggingLevel < level)
324             return;
325 
326         outStream.println(sIndent + msg);
327     }
328 
329     /**
330      * Report an arbitrary String to result file with specified severity.
331      * Log out the String provided exactly as-is.
332      * Output only when ConsoleLogger.loggingLevel >= level
333      *
334      * @param level severity or class of message.
335      * @param msg arbitrary String to log out.
336      */
logArbitrary(int level, String msg)337     public void logArbitrary(int level, String msg)
338     {
339         if (consoleLoggingLevel < level)
340             return;
341 
342         outStream.println(msg);
343     }
344 
345     /**
346      * Logs out statistics to result file with specified severity.
347      * Output only when ConsoleLogger.loggingLevel >= level
348      *
349      * @param level severity of message.
350      * @param lVal statistic in long format.
351      * @param dVal statistic in double format.
352      * @param msg comment to log out.
353      */
logStatistic(int level, long lVal, double dVal, String msg)354     public void logStatistic(int level, long lVal, double dVal, String msg)
355     {
356         if (consoleLoggingLevel < level)
357             return;
358 
359         outStream.println(sIndent + msg + " l: " + lVal + " d: " + dVal);
360     }
361 
362     /**
363      * Logs out Throwable.toString() and a stack trace of the
364      * Throwable with the specified severity.
365      * @author Shane_Curcuru@lotus.com
366      * @param level severity of message.
367      * @param throwable throwable/exception to log out.
368      * @param msg description of the throwable.
369      */
logThrowable(int level, Throwable throwable, String msg)370     public void logThrowable(int level, Throwable throwable, String msg)
371     {
372         if (consoleLoggingLevel < level)
373             return;
374 
375         StringWriter sWriter = new StringWriter();
376 
377         sWriter.write(msg + "\n");
378         sWriter.write(throwable.toString() + "\n");
379 
380         PrintWriter pWriter = new PrintWriter(sWriter);
381         throwable.printStackTrace(pWriter);
382 
383         outStream.println(sWriter.toString());
384     }
385 
386     /**
387      * Logs out a element to results with specified severity.
388      * Simply indents and dumps output as string like so:
389      * <pre>
390      *    element
391      *    attr1=value1
392      *    ...
393      *    msg.toString()
394      * </pre>
395      * Output only when ConsoleLogger.loggingLevel >= level
396      *
397      * @param level severity of message.
398      * @param element name of enclosing element
399      * @param attrs hash of name=value attributes
400      * @param msg Object to log out; up to reporters to handle
401      * processing of this; usually logs just .toString().
402      */
logElement(int level, String element, Hashtable attrs, Object msg)403     public void logElement(int level, String element, Hashtable attrs,
404                            Object msg)
405     {
406         if (consoleLoggingLevel < level)
407             return;
408 
409         if ((element == null)
410            || (attrs == null))
411         {
412             // Bail if either element name or attr list is null
413             // Note: we should really handle this case more elegantly
414             return;
415         }
416 
417         indent();
418         outStream.println(sIndent + element);
419         indent();
420 
421         for (Enumeration keys = attrs.keys();
422                 keys.hasMoreElements(); /* no increment portion */ )
423         {
424             Object key = keys.nextElement();
425 
426             outStream.println(sIndent + key.toString() + "="
427                               + attrs.get(key).toString());
428         }
429 
430         outdent();
431         if (msg != null)
432             outStream.println(sIndent + msg.toString());
433         outdent();
434     }
435 
436     /**
437      * Logs out contents of a Hashtable with specified severity.
438      * Output only when ConsoleLogger.loggingLevel >= level
439      *
440      * @param level severity or class of message.
441      * @param hash Hashtable to log the contents of.
442      * @param msg decription of the Hashtable.
443      */
logHashtable(int level, Hashtable hash, String msg)444     public void logHashtable(int level, Hashtable hash, String msg)
445     {
446         if (consoleLoggingLevel < level)
447             return;
448 
449         indent();
450         outStream.println(sIndent + "HASHTABLE: " + msg);
451         indent();
452 
453         if (hash == null)
454         {
455             outStream.println(sIndent + "hash == null, no data");
456         }
457         else
458         {
459             try
460             {
461 
462                 // Fake the Properties-like output
463                 for (Enumeration keys = hash.keys();
464                         keys.hasMoreElements(); /* no increment portion */ )
465                 {
466                     Object key = keys.nextElement();
467 
468                     outStream.println(sIndent + key.toString() + "="
469                                       + hash.get(key).toString());
470                 }
471             }
472             catch (Exception e)
473             {
474 
475                 // No-op: should ensure we have clean output
476             }
477         }
478 
479         outdent();
480         outdent();
481     }
482 
483     //-----------------------------------------------------
484     //-------- Test results reporting check* routines --------
485     //-----------------------------------------------------
486 
487     /**
488      * Writes out a Pass record with comment.
489      * Output only when ConsoleLogger.loggingLevel > FAILSONLY
490      *
491      * @param comment comment to log with the pass record.
492      */
checkPass(String comment)493     public void checkPass(String comment)
494     {
495         // Note <=, since FAILSONLY is a special level
496         if (consoleLoggingLevel <= FAILSONLY)
497             return;
498 
499         outStream.println(sIndent + "PASS!  " + comment);
500     }
501 
502     /**
503      * Writes out an ambiguous record with comment.
504      * Output only when ConsoleLogger.loggingLevel > FAILSONLY
505      *
506      * @param comment comment to log with the ambg record.
507      */
checkAmbiguous(String comment)508     public void checkAmbiguous(String comment)
509     {
510         // Note <=, since FAILSONLY is a special level
511         if (consoleLoggingLevel <= FAILSONLY)
512             return;
513 
514         outStream.println(sIndent + "AMBG   " + comment);
515     }
516 
517     /**
518      * Writes out a Fail record with comment.
519      * Output only when ConsoleLogger.loggingLevel >= FAILSONLY
520      *
521      * @param comment comment to log with the fail record.
522      */
checkFail(String comment)523     public void checkFail(String comment)
524     {
525         if (consoleLoggingLevel < FAILSONLY)
526             return;
527 
528         outStream.println(sIndent + "FAIL   " + comment);
529     }
530 
531     /**
532      * Writes out a Error record with comment.
533      * Output only when ConsoleLogger.loggingLevel >= ERRORMSG
534      *
535      * @param comment comment to log with the error record.
536      */
checkErr(String comment)537     public void checkErr(String comment)
538     {
539         if (consoleLoggingLevel < ERRORMSG)
540             return;
541 
542         outStream.println(sIndent + "ERROR  " + comment);
543     }
544 
545     /* EXPERIMENTAL: have duplicate set of check*() methods
546        that all output some form of ID as well as comment.
547        Leave the non-ID taking forms for both simplicity to the
548        end user who doesn't care about IDs as well as for
549        backwards compatibility.
550     */
551 
552     /**
553      * Writes out a Pass record with comment and ID.
554      * Output only when ConsoleLogger.loggingLevel > FAILSONLY
555      *
556      * @param comment comment to log with the pass record.
557      * @param ID token to log with the pass record.
558      */
checkPass(String comment, String id)559     public void checkPass(String comment, String id)
560     {
561         // Note <=, since FAILSONLY is a special level
562         if (consoleLoggingLevel <= FAILSONLY)
563             return;
564 
565         if (id != null)
566             outStream.println(sIndent + "PASS!  (" + id + ") " + comment);
567         else
568             outStream.println(sIndent + "PASS!  " + comment);
569     }
570 
571     /**
572      * Writes out an ambiguous record with comment and ID.
573      * Output only when ConsoleLogger.loggingLevel > FAILSONLY
574      *
575      * @param comment to log with the ambg record.
576      * @param ID token to log with the pass record.
577      */
checkAmbiguous(String comment, String id)578     public void checkAmbiguous(String comment, String id)
579     {
580         // Note <=, since FAILSONLY is a special level
581         if (consoleLoggingLevel <= FAILSONLY)
582             return;
583 
584         if (id != null)
585             outStream.println(sIndent + "AMBG   (" + id + ") " + comment);
586         else
587             outStream.println(sIndent + "AMBG   " + comment);
588     }
589 
590     /**
591      * Writes out a Fail record with comment and ID.
592      * Output only when ConsoleLogger.loggingLevel >= FAILSONLY
593      *
594      * @param comment comment to log with the fail record.
595      * @param ID token to log with the pass record.
596      */
checkFail(String comment, String id)597     public void checkFail(String comment, String id)
598     {
599         if (consoleLoggingLevel < FAILSONLY)
600             return;
601 
602         if (id != null)
603             outStream.println(sIndent + "FAIL!  (" + id + ") " + comment);
604         else
605             outStream.println(sIndent + "FAIL!  " + comment);
606     }
607 
608     /**
609      * Writes out an Error record with comment and ID.
610      * Output only when ConsoleLogger.loggingLevel >= ERRORMSG
611      *
612      * @param comment comment to log with the error record.
613      * @param ID token to log with the pass record.
614      */
checkErr(String comment, String id)615     public void checkErr(String comment, String id)
616     {
617         if (consoleLoggingLevel < ERRORMSG)
618             return;
619 
620         if (id != null)
621             outStream.println(sIndent + "ERROR  (" + id + ") " + comment);
622         else
623             outStream.println(sIndent + "ERROR  " + comment);
624     }
625 }  // end of class ConsoleLogger
626 
627