View Javadoc
1   /*
2    * This file is part of Waarp Project (named also Waarp or GG).
3    *
4    *  Copyright (c) 2019, Waarp SAS, and individual contributors by the @author
5    *  tags. See the COPYRIGHT.txt in the distribution for a full listing of
6    * individual contributors.
7    *
8    *  All Waarp Project is free software: you can redistribute it and/or
9    * modify it under the terms of the GNU General Public License as published by
10   * the Free Software Foundation, either version 3 of the License, or (at your
11   * option) any later version.
12   *
13   * Waarp is distributed in the hope that it will be useful, but WITHOUT ANY
14   * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
15   * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
16   *
17   *  You should have received a copy of the GNU General Public License along with
18   * Waarp . If not, see <http://www.gnu.org/licenses/>.
19   */
20  
21  /*
22   * Copyright 2012 The Netty Project
23   * The Netty Project licenses this file to you under the Apache License,
24   * version 2.0 (the "License"); you may not use this file except in compliance
25   * with the License. You may obtain a copy of the License at:
26   * http://www.apache.org/licenses/LICENSE-2.0
27   * Unless required by applicable law or agreed to in writing, software
28   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
29   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
30   * License for the specific language governing permissions and limitations
31   * under the License.
32   */
33  /**
34   * Copyright (c) 2004-2011 QOS.ch
35   * All rights reserved.
36   * <p>
37   * Permission is hereby granted, free of charge, to any person obtaining
38   * a copy of this software and associated documentation files (the
39   * "Software"), to deal in the Software without restriction, including
40   * without limitation the rights to use, copy, modify, merge, publish,
41   * distribute, sublicense, and/or sell copies of the Software, and to
42   * permit persons to whom the Software is furnished to do so, subject to
43   * the following conditions:
44   * <p>
45   * The above copyright notice and this permission notice shall be
46   * included in all copies or substantial portions of the Software.
47   * <p>
48   * THE SOFTWARE IS PROVIDED "AS  IS", WITHOUT WARRANTY OF ANY KIND,
49   * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
50   * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
51   * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
52   * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
53   * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
54   * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
55   */
56  package org.waarp.common.logging;
57  
58  import java.util.logging.Level;
59  import java.util.logging.LogRecord;
60  import java.util.logging.Logger;
61  
62  /**
63   * <a href="http://java.sun.com/javase/6/docs/technotes/guides/logging/index.html">java.util.logging</a>
64   * logger.
65   */
66  public class WaarpJdkLogger extends AbstractWaarpLogger {
67  
68    private static final long serialVersionUID = -1767272577989225979L;
69  
70    final transient Logger logger;
71  
72    WaarpJdkLogger(final Logger logger) {
73      super(logger.getName());
74      this.logger = logger;
75    }
76  
77    @Override
78    public final void setLevel(final WaarpLogLevel level) {
79      switch (level) {
80        case TRACE:
81          logger.setLevel(Level.FINEST);
82          break;
83        case DEBUG:
84          logger.setLevel(Level.FINE);
85          break;
86        case INFO:
87          logger.setLevel(Level.INFO);
88          break;
89        case WARN:
90          logger.setLevel(Level.WARNING);
91          break;
92        case ERROR:
93          logger.setLevel(Level.SEVERE);
94          break;
95        case NONE:
96          logger.setLevel(Level.OFF);
97          break;
98      }
99    }
100 
101   /**
102    * Is this logger instance enabled for the FINEST level?
103    *
104    * @return True if this Logger is enabled for level FINEST, false otherwise.
105    */
106   @Override
107   public final boolean isTraceEnabled() {
108     return logger.isLoggable(Level.FINEST);
109   }
110 
111   @Override
112   public final void junit(final int callee, final String msg) {
113     logger.warning(msg);
114   }
115 
116   /**
117    * Log a message object at level FINEST.
118    *
119    * @param msg - the message object to be logged
120    */
121   @Override
122   public final void trace(final String msg) {
123     if (logger.isLoggable(Level.FINEST)) {
124       log(SELF, Level.FINEST, msg, null);
125     }
126   }
127 
128   /**
129    * Log a message at level FINEST according to the specified format and
130    * argument.
131    *
132    * <p>
133    * This form avoids superfluous object creation when the logger is disabled
134    * for level FINEST.
135    * </p>
136    *
137    * @param format the format string
138    * @param arg the argument
139    */
140   @Override
141   public final void trace(final String format, final Object arg) {
142     if (logger.isLoggable(Level.FINEST)) {
143       final FormattingTuple ft = MessageFormatter.format(format, arg);
144       log(SELF, Level.FINEST, ft.getMessage(), ft.getThrowable());
145     }
146   }
147 
148   /**
149    * Log a message at level FINEST according to the specified format and
150    * arguments.
151    *
152    * <p>
153    * This form avoids superfluous object creation when the logger is disabled
154    * for the FINEST level.
155    * </p>
156    *
157    * @param format the format string
158    * @param argA the first argument
159    * @param argB the second argument
160    */
161   @Override
162   public final void trace(final String format, final Object argA,
163                           final Object argB) {
164     if (logger.isLoggable(Level.FINEST)) {
165       final FormattingTuple ft = MessageFormatter.format(format, argA, argB);
166       log(SELF, Level.FINEST, ft.getMessage(), ft.getThrowable());
167     }
168   }
169 
170   /**
171    * Log a message at level FINEST according to the specified format and
172    * arguments.
173    *
174    * <p>
175    * This form avoids superfluous object creation when the logger is disabled
176    * for the FINEST level.
177    * </p>
178    *
179    * @param format the format string
180    * @param argArray an array of arguments
181    */
182   @Override
183   public final void trace(final String format, final Object... argArray) {
184     if (logger.isLoggable(Level.FINEST)) {
185       final FormattingTuple ft = MessageFormatter.arrayFormat(format, argArray);
186       log(SELF, Level.FINEST, ft.getMessage(), ft.getThrowable());
187     }
188   }
189 
190   /**
191    * Log an exception (throwable) at level FINEST with an accompanying
192    * message.
193    *
194    * @param msg the message accompanying the exception
195    * @param t the exception (throwable) to log
196    */
197   @Override
198   public final void trace(final String msg, final Throwable t) {
199     if (logger.isLoggable(Level.FINEST)) {
200       log(SELF, Level.FINEST, msg, t);
201     }
202   }
203 
204   /**
205    * Is this logger instance enabled for the FINE level?
206    *
207    * @return True if this Logger is enabled for level FINE, false otherwise.
208    */
209   @Override
210   public final boolean isDebugEnabled() {
211     return logger.isLoggable(Level.FINE);
212   }
213 
214   /**
215    * Log a message object at level FINE.
216    *
217    * @param msg - the message object to be logged
218    */
219   @Override
220   public final void debug(final String msg) {
221     if (logger.isLoggable(Level.FINE)) {
222       log(SELF, Level.FINE, msg, null);
223     }
224   }
225 
226   /**
227    * Log a message at level FINE according to the specified format and
228    * argument.
229    *
230    * <p>
231    * This form avoids superfluous object creation when the logger is disabled
232    * for level FINE.
233    * </p>
234    *
235    * @param format the format string
236    * @param arg the argument
237    */
238   @Override
239   public final void debug(final String format, final Object arg) {
240     if (logger.isLoggable(Level.FINE)) {
241       final FormattingTuple ft = MessageFormatter.format(format, arg);
242       log(SELF, Level.FINE, ft.getMessage(), ft.getThrowable());
243     }
244   }
245 
246   /**
247    * Log a message at level FINE according to the specified format and
248    * arguments.
249    *
250    * <p>
251    * This form avoids superfluous object creation when the logger is disabled
252    * for the FINE level.
253    * </p>
254    *
255    * @param format the format string
256    * @param argA the first argument
257    * @param argB the second argument
258    */
259   @Override
260   public final void debug(final String format, final Object argA,
261                           final Object argB) {
262     if (logger.isLoggable(Level.FINE)) {
263       final FormattingTuple ft = MessageFormatter.format(format, argA, argB);
264       log(SELF, Level.FINE, ft.getMessage(), ft.getThrowable());
265     }
266   }
267 
268   /**
269    * Log a message at level FINE according to the specified format and
270    * arguments.
271    *
272    * <p>
273    * This form avoids superfluous object creation when the logger is disabled
274    * for the FINE level.
275    * </p>
276    *
277    * @param format the format string
278    * @param argArray an array of arguments
279    */
280   @Override
281   public final void debug(final String format, final Object... argArray) {
282     if (logger.isLoggable(Level.FINE)) {
283       final FormattingTuple ft = MessageFormatter.arrayFormat(format, argArray);
284       log(SELF, Level.FINE, ft.getMessage(), ft.getThrowable());
285     }
286   }
287 
288   /**
289    * Log an exception (throwable) at level FINE with an accompanying message.
290    *
291    * @param msg the message accompanying the exception
292    * @param t the exception (throwable) to log
293    */
294   @Override
295   public final void debug(final String msg, final Throwable t) {
296     if (logger.isLoggable(Level.FINE)) {
297       log(SELF, Level.FINE, msg, t);
298     }
299   }
300 
301   /**
302    * Is this logger instance enabled for the INFO level?
303    *
304    * @return True if this Logger is enabled for the INFO level, false
305    *     otherwise.
306    */
307   @Override
308   public final boolean isInfoEnabled() {
309     return logger.isLoggable(Level.INFO);
310   }
311 
312   /**
313    * Log a message object at the INFO level.
314    *
315    * @param msg - the message object to be logged
316    */
317   @Override
318   public final void info(final String msg) {
319     if (logger.isLoggable(Level.INFO)) {
320       log(SELF, Level.INFO, msg, null);
321     }
322   }
323 
324   /**
325    * Log a message at level INFO according to the specified format and
326    * argument.
327    *
328    * <p>
329    * This form avoids superfluous object creation when the logger is disabled
330    * for the INFO level.
331    * </p>
332    *
333    * @param format the format string
334    * @param arg the argument
335    */
336   @Override
337   public final void info(final String format, final Object arg) {
338     if (logger.isLoggable(Level.INFO)) {
339       final FormattingTuple ft = MessageFormatter.format(format, arg);
340       log(SELF, Level.INFO, ft.getMessage(), ft.getThrowable());
341     }
342   }
343 
344   /**
345    * Log a message at the INFO level according to the specified format and
346    * arguments.
347    *
348    * <p>
349    * This form avoids superfluous object creation when the logger is disabled
350    * for the INFO level.
351    * </p>
352    *
353    * @param format the format string
354    * @param argA the first argument
355    * @param argB the second argument
356    */
357   @Override
358   public final void info(final String format, final Object argA,
359                          final Object argB) {
360     if (logger.isLoggable(Level.INFO)) {
361       final FormattingTuple ft = MessageFormatter.format(format, argA, argB);
362       log(SELF, Level.INFO, ft.getMessage(), ft.getThrowable());
363     }
364   }
365 
366   /**
367    * Log a message at level INFO according to the specified format and
368    * arguments.
369    *
370    * <p>
371    * This form avoids superfluous object creation when the logger is disabled
372    * for the INFO level.
373    * </p>
374    *
375    * @param format the format string
376    * @param argArray an array of arguments
377    */
378   @Override
379   public final void info(final String format, final Object... argArray) {
380     if (logger.isLoggable(Level.INFO)) {
381       final FormattingTuple ft = MessageFormatter.arrayFormat(format, argArray);
382       log(SELF, Level.INFO, ft.getMessage(), ft.getThrowable());
383     }
384   }
385 
386   /**
387    * Log an exception (throwable) at the INFO level with an accompanying
388    * message.
389    *
390    * @param msg the message accompanying the exception
391    * @param t the exception (throwable) to log
392    */
393   @Override
394   public final void info(final String msg, final Throwable t) {
395     if (logger.isLoggable(Level.INFO)) {
396       log(SELF, Level.INFO, msg, t);
397     }
398   }
399 
400   /**
401    * Is this logger instance enabled for the WARNING level?
402    *
403    * @return True if this Logger is enabled for the WARNING level, false
404    *     otherwise.
405    */
406   @Override
407   public final boolean isWarnEnabled() {
408     return logger.isLoggable(Level.WARNING);
409   }
410 
411   /**
412    * Log a message object at the WARNING level.
413    *
414    * @param msg - the message object to be logged
415    */
416   @Override
417   public final void warn(final String msg) {
418     if (logger.isLoggable(Level.WARNING)) {
419       log(SELF, Level.WARNING, msg, null);
420     }
421   }
422 
423   /**
424    * Log a message at the WARNING level according to the specified format and
425    * argument.
426    *
427    * <p>
428    * This form avoids superfluous object creation when the logger is disabled
429    * for the WARNING level.
430    * </p>
431    *
432    * @param format the format string
433    * @param arg the argument
434    */
435   @Override
436   public final void warn(final String format, final Object arg) {
437     if (logger.isLoggable(Level.WARNING)) {
438       final FormattingTuple ft = MessageFormatter.format(format, arg);
439       log(SELF, Level.WARNING, ft.getMessage(), ft.getThrowable());
440     }
441   }
442 
443   /**
444    * Log a message at the WARNING level according to the specified format and
445    * arguments.
446    *
447    * <p>
448    * This form avoids superfluous object creation when the logger is disabled
449    * for the WARNING level.
450    * </p>
451    *
452    * @param format the format string
453    * @param argA the first argument
454    * @param argB the second argument
455    */
456   @Override
457   public final void warn(final String format, final Object argA,
458                          final Object argB) {
459     if (logger.isLoggable(Level.WARNING)) {
460       final FormattingTuple ft = MessageFormatter.format(format, argA, argB);
461       log(SELF, Level.WARNING, ft.getMessage(), ft.getThrowable());
462     }
463   }
464 
465   /**
466    * Log a message at level WARNING according to the specified format and
467    * arguments.
468    *
469    * <p>
470    * This form avoids superfluous object creation when the logger is disabled
471    * for the WARNING level.
472    * </p>
473    *
474    * @param format the format string
475    * @param argArray an array of arguments
476    */
477   @Override
478   public final void warn(final String format, final Object... argArray) {
479     if (logger.isLoggable(Level.WARNING)) {
480       final FormattingTuple ft = MessageFormatter.arrayFormat(format, argArray);
481       log(SELF, Level.WARNING, ft.getMessage(), ft.getThrowable());
482     }
483   }
484 
485   /**
486    * Log an exception (throwable) at the WARNING level with an accompanying
487    * message.
488    *
489    * @param msg the message accompanying the exception
490    * @param t the exception (throwable) to log
491    */
492   @Override
493   public final void warn(final String msg, final Throwable t) {
494     if (logger.isLoggable(Level.WARNING)) {
495       log(SELF, Level.WARNING, msg, t);
496     }
497   }
498 
499   /**
500    * Is this logger instance enabled for level SEVERE?
501    *
502    * @return True if this Logger is enabled for level SEVERE, false otherwise.
503    */
504   @Override
505   public final boolean isErrorEnabled() {
506     return logger.isLoggable(Level.SEVERE);
507   }
508 
509   /**
510    * Log a message object at the SEVERE level.
511    *
512    * @param msg - the message object to be logged
513    */
514   @Override
515   public final void error(final String msg) {
516     if (logger.isLoggable(Level.SEVERE)) {
517       log(SELF, Level.SEVERE, msg, null);
518     }
519   }
520 
521   /**
522    * Log a message at the SEVERE level according to the specified format and
523    * argument.
524    *
525    * <p>
526    * This form avoids superfluous object creation when the logger is disabled
527    * for the SEVERE level.
528    * </p>
529    *
530    * @param format the format string
531    * @param arg the argument
532    */
533   @Override
534   public final void error(final String format, final Object arg) {
535     if (logger.isLoggable(Level.SEVERE)) {
536       final FormattingTuple ft = MessageFormatter.format(format, arg);
537       log(SELF, Level.SEVERE, ft.getMessage(), ft.getThrowable());
538     }
539   }
540 
541   /**
542    * Log a message at the SEVERE level according to the specified format and
543    * arguments.
544    *
545    * <p>
546    * This form avoids superfluous object creation when the logger is disabled
547    * for the SEVERE level.
548    * </p>
549    *
550    * @param format the format string
551    * @param argA the first argument
552    * @param argB the second argument
553    */
554   @Override
555   public final void error(final String format, final Object argA,
556                           final Object argB) {
557     if (logger.isLoggable(Level.SEVERE)) {
558       final FormattingTuple ft = MessageFormatter.format(format, argA, argB);
559       log(SELF, Level.SEVERE, ft.getMessage(), ft.getThrowable());
560     }
561   }
562 
563   /**
564    * Log a message at level SEVERE according to the specified format and
565    * arguments.
566    *
567    * <p>
568    * This form avoids superfluous object creation when the logger is disabled
569    * for the SEVERE level.
570    * </p>
571    *
572    * @param format the format string
573    * @param arguments an array of arguments
574    */
575   @Override
576   public final void error(final String format, final Object... arguments) {
577     if (logger.isLoggable(Level.SEVERE)) {
578       final FormattingTuple ft =
579           MessageFormatter.arrayFormat(format, arguments);
580       log(SELF, Level.SEVERE, ft.getMessage(), ft.getThrowable());
581     }
582   }
583 
584   /**
585    * Log an exception (throwable) at the SEVERE level with an accompanying
586    * message.
587    *
588    * @param msg the message accompanying the exception
589    * @param t the exception (throwable) to log
590    */
591   @Override
592   public final void error(final String msg, final Throwable t) {
593     if (logger.isLoggable(Level.SEVERE)) {
594       log(SELF, Level.SEVERE, msg, t);
595     }
596   }
597 
598   /**
599    * Log the message at the specified level with the specified throwable if
600    * any.
601    * This method creates a LogRecord
602    * and fills in caller date before calling this instance's JDK14 logger.
603    * <p>
604    * See bug report #13 for more details.
605    */
606   private void log(final String callerFQCN, final Level level, final String msg,
607                    final Throwable t) {
608     // millis and thread are filled by the constructor
609     final LogRecord record = new LogRecord(level, msg);
610     record.setLoggerName(name());
611     record.setThrown(t);
612     fillCallerData(callerFQCN, record);
613     logger.log(record);
614   }
615 
616   static final String SELF = WaarpJdkLogger.class.getName();
617   static final String SUPER = AbstractWaarpLogger.class.getName();
618 
619   /**
620    * Fill in caller data if possible.
621    *
622    * @param record The record to update
623    */
624   private static void fillCallerData(final String callerFQCN,
625                                      final LogRecord record) {
626     final StackTraceElement[] steArray = new Throwable().getStackTrace();
627 
628     int selfIndex = -1;
629     for (int i = 0; i < steArray.length; i++) {
630       final String className = steArray[i].getClassName();
631       if (className.equals(callerFQCN) || className.equals(SUPER)) {
632         selfIndex = i;
633         break;
634       }
635     }
636 
637     int found = -1;
638     for (int i = selfIndex + 1; i < steArray.length; i++) {
639       final String className = steArray[i].getClassName();
640       if (!(className.equals(callerFQCN) || className.equals(SUPER))) {
641         found = i;
642         break;
643       }
644     }
645 
646     if (found != -1) {
647       final StackTraceElement ste = steArray[found];
648       // setting the class name has the side effect of setting
649       // the needToInferCaller variable to false.
650       record.setSourceClassName(ste.getClassName());
651       record.setSourceMethodName(ste.getMethodName());
652     }
653   }
654 }