001    /*
002     * CDDL HEADER START
003     *
004     * The contents of this file are subject to the terms of the
005     * Common Development and Distribution License, Version 1.0 only
006     * (the "License").  You may not use this file except in compliance
007     * with the License.
008     *
009     * You can obtain a copy of the license at
010     * trunk/opends/resource/legal-notices/OpenDS.LICENSE
011     * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
012     * See the License for the specific language governing permissions
013     * and limitations under the License.
014     *
015     * When distributing Covered Code, include this CDDL HEADER in each
016     * file and include the License file at
017     * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
018     * add the following below this CDDL HEADER, with the fields enclosed
019     * by brackets "[]" replaced with your own identifying information:
020     *      Portions Copyright [yyyy] [name of copyright owner]
021     *
022     * CDDL HEADER END
023     *
024     *
025     *      Copyright 2006-2008 Sun Microsystems, Inc.
026     */
027    package org.opends.server.loggers.debug;
028    
029    import org.opends.server.api.DebugLogPublisher;
030    import org.opends.server.api.ProtocolElement;
031    import org.opends.server.types.DebugLogCategory;
032    import org.opends.server.types.DebugLogLevel;
033    import org.opends.server.loggers.LogLevel;
034    import org.opends.server.loggers.LogCategory;
035    
036    import java.util.Map;
037    import java.nio.ByteBuffer;
038    
039    import com.sleepycat.je.OperationStatus;
040    import com.sleepycat.je.Transaction;
041    import com.sleepycat.je.DatabaseEntry;
042    import com.sleepycat.je.Database;
043    
044    /**
045     * Class for source-code tracing at the method level.
046     *
047     * One DebugTracer instance exists for each Java class using tracing.
048     * Tracer must be registered with the DebugLogger.
049     *
050     * Logging is always done at a level basis, with debug log messages
051     * exceeding the trace threshold being traced, others being discarded.
052     */
053    
054    public class DebugTracer
055    {
056      // The class this aspect traces.
057      private String className;
058    
059      /**
060       * A class that represents a settings cache entry.
061       */
062      private class PublisherSettings
063      {
064        DebugLogPublisher debugPublisher;
065        TraceSettings classSettings;
066        Map<String, TraceSettings> methodSettings;
067      }
068    
069      PublisherSettings[] publisherSettings;
070    
071      /**
072       * Construct a new DebugTracer object with cached settings obtained from
073       * the provided array of publishers.
074       *
075       * @param publishers The array of publishers to obtain the settings from.
076       */
077      @SuppressWarnings("unchecked")
078      DebugTracer(DebugLogPublisher[] publishers)
079      {
080        // Trim off the debug logging and non OpenDS frames.
081        StackTraceElement callerFrame =
082            getCallerFrame(Thread.currentThread().getStackTrace());
083    
084        // TODO: What if this is null or 0 length?
085        if(callerFrame != null)
086        {
087          // The caller should be the first item on the stack.
088          className = callerFrame.getClassName();
089        }
090    
091        publisherSettings = new PublisherSettings[publishers.length];
092    
093        // Get the settings from all publishers.
094        for(int i = 0; i < publishers.length; i++)
095        {
096          DebugLogPublisher publisher = publishers[i];
097          PublisherSettings settings = new PublisherSettings();
098    
099          settings.debugPublisher = publisher;
100          settings.classSettings = publisher.getClassSettings(className);
101    
102          // For some reason, the compiler doesn't see that
103          // debugLogPublihser.getMethodSettings returns a parameterized Map.
104          // This problem goes away if a parameterized verson of DebugLogPublisher
105          // is used. However, we can't not use reflection to instantiate a generic
106          // DebugLogPublisher<? extends DebugLogPublisherCfg> type. The only thing
107          // we can do is to just supress the compiler warnings.
108          settings.methodSettings = publisher.getMethodSettings(className);
109    
110          publisherSettings[i] = settings;
111        }
112      }
113    
114      /**
115       * Log an constructor execution event.
116       *
117       * @param level The level of the message being logged.
118       * @param args The arguments passed to the constructor.
119       */
120      public void debugConstructor(LogLevel level, Object... args)
121      {
122        if(DebugLogger.debugEnabled())
123        {
124          StackTraceElement[] stackTrace = null;
125          StackTraceElement[] filteredStackTrace = null;
126          StackTraceElement callerFrame = null;
127          for (PublisherSettings settings : publisherSettings)
128          {
129            TraceSettings activeSettings = settings.classSettings;
130            Map<String, TraceSettings> methodSettings = settings.methodSettings;
131    
132            if (shouldLog(level, DebugLogCategory.CONSTRUCTOR,
133                          activeSettings) || methodSettings != null)
134            {
135              if(stackTrace == null)
136              {
137                stackTrace = Thread.currentThread().getStackTrace();
138              }
139              if (callerFrame == null)
140              {
141                callerFrame = getCallerFrame(stackTrace);
142              }
143    
144              String signature = callerFrame.getMethodName();
145    
146              // Specific method settings still could exist. Try getting
147              // the settings for this method.
148              if(methodSettings != null)
149              {
150                TraceSettings mSettings = methodSettings.get(signature);
151    
152                if (mSettings == null)
153                {
154                  // Try looking for an undecorated method name
155                  int idx = signature.indexOf('(');
156                  if (idx != -1)
157                  {
158                    mSettings =
159                        methodSettings.get(signature.substring(0, idx));
160                  }
161                }
162    
163                // If this method does have a specific setting and it is not
164                // suppose to be logged, continue.
165                if (mSettings != null)
166                {
167                  if(!shouldLog(level, DebugLogCategory.CONSTRUCTOR,
168                                mSettings))
169                  {
170                    continue;
171                  }
172                  else
173                  {
174                    activeSettings = mSettings;
175                  }
176                }
177              }
178    
179              String sl = callerFrame.getFileName() + ":" +
180                  callerFrame.getLineNumber();
181    
182              if (activeSettings.noArgs)
183              {
184                args = null;
185              }
186    
187              if (filteredStackTrace == null && activeSettings.stackDepth > 0)
188              {
189                filteredStackTrace =
190                    DebugStackTraceFormatter.SMART_FRAME_FILTER.
191                        getFilteredStackTrace(stackTrace);
192              }
193    
194              settings.debugPublisher.traceConstructor(level,
195                                                       activeSettings, signature,
196                                                       sl, args,
197                                                       filteredStackTrace);
198            }
199          }
200        }
201      }
202    
203      /**
204       * Log an non static method entry event.
205       *
206       * @param level The level of the message being logged.
207       * @param obj The object type instance the method is a member of.
208       * @param args The arguments passed to the method.
209       */
210      public void debugMethodEntry(LogLevel level, Object obj, Object... args)
211      {
212        if(DebugLogger.debugEnabled())
213        {
214          StackTraceElement[] stackTrace = null;
215          StackTraceElement[] filteredStackTrace = null;
216          StackTraceElement callerFrame = null;
217          for (PublisherSettings settings : publisherSettings)
218          {
219            TraceSettings activeSettings = settings.classSettings;
220            Map<String, TraceSettings> methodSettings = settings.methodSettings;
221    
222            if (shouldLog(level, DebugLogCategory.ENTER,
223                          activeSettings) || methodSettings != null)
224            {
225              if(stackTrace == null)
226              {
227                stackTrace = Thread.currentThread().getStackTrace();
228              }
229              if (callerFrame == null)
230              {
231                callerFrame = getCallerFrame(stackTrace);
232              }
233    
234              String signature = callerFrame.getMethodName();
235    
236              // Specific method settings still could exist. Try getting
237              // the settings for this method.
238              if(methodSettings != null)
239              {
240                TraceSettings mSettings = methodSettings.get(signature);
241    
242                if (mSettings == null)
243                {
244                  // Try looking for an undecorated method name
245                  int idx = signature.indexOf('(');
246                  if (idx != -1)
247                  {
248                    mSettings =
249                        methodSettings.get(signature.substring(0, idx));
250                  }
251                }
252    
253                // If this method does have a specific setting and it is not
254                // suppose to be logged, continue.
255                if (mSettings != null)
256                {
257                  if(!shouldLog(level, DebugLogCategory.ENTER,
258                                mSettings))
259                  {
260                    continue;
261                  }
262                  else
263                  {
264                    activeSettings = mSettings;
265                  }
266                }
267              }
268    
269              String sl = callerFrame.getFileName() + ":" +
270                  callerFrame.getLineNumber();
271    
272              if (activeSettings.noArgs)
273              {
274                args = null;
275              }
276    
277              if (filteredStackTrace == null && activeSettings.stackDepth > 0)
278              {
279                filteredStackTrace =
280                    DebugStackTraceFormatter.SMART_FRAME_FILTER.
281                        getFilteredStackTrace(stackTrace);
282              }
283    
284              settings.debugPublisher.traceMethodEntry(level,
285                                                       activeSettings, signature,
286                                                       sl, obj, args,
287                                                       filteredStackTrace);
288            }
289          }
290        }
291      }
292    
293      /**
294       * Log an static method entry event.
295       *
296       * @param level The level of the message being logged.
297       * @param args The arguments passed to the method.
298       */
299      public void debugStaticMethodEntry(LogLevel level, Object... args)
300      {
301        if(DebugLogger.debugEnabled())
302        {
303          StackTraceElement[] stackTrace = null;
304          StackTraceElement[] filteredStackTrace = null;
305          StackTraceElement callerFrame = null;
306          for (PublisherSettings settings : publisherSettings)
307          {
308            TraceSettings activeSettings = settings.classSettings;
309            Map<String, TraceSettings> methodSettings = settings.methodSettings;
310    
311            if (shouldLog(level, DebugLogCategory.ENTER,
312                          activeSettings) || methodSettings != null)
313            {
314              if(stackTrace == null)
315              {
316                stackTrace = Thread.currentThread().getStackTrace();
317              }
318              if (callerFrame == null)
319              {
320                callerFrame = getCallerFrame(stackTrace);
321              }
322    
323              String signature = callerFrame.getMethodName();
324    
325              // Specific method settings still could exist. Try getting
326              // the settings for this method.
327              if(methodSettings != null)
328              {
329                TraceSettings mSettings = methodSettings.get(signature);
330    
331                if (mSettings == null)
332                {
333                  // Try looking for an undecorated method name
334                  int idx = signature.indexOf('(');
335                  if (idx != -1)
336                  {
337                    mSettings =
338                        methodSettings.get(signature.substring(0, idx));
339                  }
340                }
341    
342                // If this method does have a specific setting and it is not
343                // suppose to be logged, continue.
344                if (mSettings != null)
345                {
346                  if(!shouldLog(level, DebugLogCategory.ENTER,
347                                mSettings))
348                  {
349                    continue;
350                  }
351                  else
352                  {
353                    activeSettings = mSettings;
354                  }
355                }
356              }
357    
358              String sl = callerFrame.getFileName() + ":" +
359                  callerFrame.getLineNumber();
360    
361              if (activeSettings.noArgs)
362              {
363                args = null;
364              }
365    
366              if (filteredStackTrace == null && activeSettings.stackDepth > 0)
367              {
368                filteredStackTrace =
369                    DebugStackTraceFormatter.SMART_FRAME_FILTER.
370                        getFilteredStackTrace(stackTrace);
371              }
372    
373              settings.debugPublisher.traceStaticMethodEntry(level,
374                                                             activeSettings,
375                                                             signature, sl, args,
376                                                             filteredStackTrace);
377            }
378          }
379        }
380      }
381    
382      /**
383       * Log a return from a method call event.
384       *
385       * @param level The level of the message being logged.
386       * @param ret The value being returned from the method.
387       */
388      public void debugReturn(LogLevel level, Object ret)
389      {
390        if(DebugLogger.debugEnabled())
391        {
392          StackTraceElement[] stackTrace = null;
393          StackTraceElement[] filteredStackTrace = null;
394          StackTraceElement callerFrame = null;
395          for (PublisherSettings settings : publisherSettings)
396          {
397            TraceSettings activeSettings = settings.classSettings;
398            Map<String, TraceSettings> methodSettings = settings.methodSettings;
399    
400            if (shouldLog(level, DebugLogCategory.ENTER,
401                          activeSettings) || methodSettings != null)
402            {
403              if(stackTrace == null)
404              {
405                stackTrace = Thread.currentThread().getStackTrace();
406              }
407              if (callerFrame == null)
408              {
409                callerFrame = getCallerFrame(stackTrace);
410              }
411    
412              String signature = callerFrame.getMethodName();
413    
414              // Specific method settings still could exist. Try getting
415              // the settings for this method.
416              if(methodSettings != null)
417              {
418                TraceSettings mSettings = methodSettings.get(signature);
419    
420                if (mSettings == null)
421                {
422                  // Try looking for an undecorated method name
423                  int idx = signature.indexOf('(');
424                  if (idx != -1)
425                  {
426                    mSettings =
427                        methodSettings.get(signature.substring(0, idx));
428                  }
429                }
430    
431                // If this method does have a specific setting and it is not
432                // suppose to be logged, continue.
433                if (mSettings != null)
434                {
435                  if(!shouldLog(level, DebugLogCategory.ENTER,
436                                mSettings))
437                  {
438                    continue;
439                  }
440                  else
441                  {
442                    activeSettings = mSettings;
443                  }
444                }
445              }
446    
447              String sl = callerFrame.getFileName() + ":" +
448                  callerFrame.getLineNumber();
449    
450              if (activeSettings.noRetVal)
451              {
452                ret = null;
453              }
454    
455              if (filteredStackTrace == null && activeSettings.stackDepth > 0)
456              {
457                filteredStackTrace =
458                    DebugStackTraceFormatter.SMART_FRAME_FILTER.
459                        getFilteredStackTrace(stackTrace);
460              }
461    
462              settings.debugPublisher.traceReturn(level,
463                                                  activeSettings, signature,
464                                                  sl, ret,
465                                                  filteredStackTrace);
466            }
467          }
468        }
469      }
470    
471      /**
472       * Log an exception thrown from a method.
473       *
474       * @param level The level of the message being logged.
475       * @param ex The exception being thrown.
476       */
477      public void debugThrown(LogLevel level, Throwable ex)
478      {
479        if(DebugLogger.debugEnabled())
480        {
481          StackTraceElement[] stackTrace = null;
482          StackTraceElement[] filteredStackTrace = null;
483          StackTraceElement callerFrame = null;
484          for (PublisherSettings settings : publisherSettings)
485          {
486            TraceSettings activeSettings = settings.classSettings;
487            Map<String, TraceSettings> methodSettings = settings.methodSettings;
488    
489            if (shouldLog(level, DebugLogCategory.THROWN,
490                          activeSettings) || methodSettings != null)
491            {
492              if(stackTrace == null)
493              {
494                stackTrace = Thread.currentThread().getStackTrace();
495              }
496              if (callerFrame == null)
497              {
498                callerFrame = getCallerFrame(stackTrace);
499              }
500    
501              String signature = callerFrame.getMethodName();
502    
503              // Specific method settings still could exist. Try getting
504              // the settings for this method.
505              if(methodSettings != null)
506              {
507                TraceSettings mSettings = methodSettings.get(signature);
508    
509                if (mSettings == null)
510                {
511                  // Try looking for an undecorated method name
512                  int idx = signature.indexOf('(');
513                  if (idx != -1)
514                  {
515                    mSettings =
516                        methodSettings.get(signature.substring(0, idx));
517                  }
518                }
519    
520                // If this method does have a specific setting and it is not
521                // suppose to be logged, continue.
522                if (mSettings != null)
523                {
524                  if(!shouldLog(level, DebugLogCategory.THROWN,
525                                mSettings))
526                  {
527                    continue;
528                  }
529                  else
530                  {
531                    activeSettings = mSettings;
532                  }
533                }
534              }
535    
536              String sl = callerFrame.getFileName() + ":" +
537                  callerFrame.getLineNumber();
538    
539              if (filteredStackTrace == null && activeSettings.stackDepth > 0)
540              {
541                filteredStackTrace =
542                    DebugStackTraceFormatter.SMART_FRAME_FILTER.
543                        getFilteredStackTrace(ex.getStackTrace());
544              }
545    
546              settings.debugPublisher.traceThrown(level, activeSettings, signature,
547                                                  sl, ex, filteredStackTrace);
548            }
549          }
550        }
551      }
552    
553      /**
554       * Log an arbitrary event at the verbose level.
555       * Same as debugMessage(DebugLogLevel.ERROR, msg)
556       *
557       * @param msg message to format and log.
558       */
559      public void debugVerbose(String msg)
560      {
561        debugMessage(DebugLogLevel.VERBOSE, msg, new Object[]{});
562      }
563    
564      /**
565       * Log an arbitrary event at the verbose level.
566       * Same as debugMessage(DebugLogLevel.ERROR, msg, msgArgs...)
567       *
568       * @param msg message to format and log.
569       * @param msgArgs arguments to place into the format string.
570       */
571      public void debugVerbose(String msg, Object... msgArgs)
572      {
573        debugMessage(DebugLogLevel.VERBOSE, msg, msgArgs);
574      }
575    
576      /**
577       * Log an arbitrary event at the info level.
578       * Same as debugMessage(DebugLogLevel.ERROR, msg)
579       *
580       * @param msg message to format and log.
581       */
582      public void debugInfo(String msg)
583      {
584        debugMessage(DebugLogLevel.INFO, msg, new Object[]{});
585      }
586    
587      /**
588       * Log an arbitrary event at the info level.
589       * Same as debugMessage(DebugLogLevel.ERROR, msg, msgArgs...)
590       *
591       * @param msg message to format and log.
592       * @param msgArgs arguments to place into the format string.
593       */
594      public void debugInfo(String msg, Object... msgArgs)
595      {
596        debugMessage(DebugLogLevel.INFO, msg, msgArgs);
597      }
598    
599      /**
600       * Log an arbitrary event at the warning level.
601       * Same as debugMessage(DebugLogLevel.ERROR, msg)
602       *
603       * @param msg message to format and log.
604       */
605      public void debugWarning(String msg)
606    
607      {
608        debugMessage(DebugLogLevel.WARNING, msg, new Object[]{});
609      }
610    
611      /**
612       * Log an arbitrary event at the warning level.
613       * Same as debugMessage(DebugLogLevel.ERROR, msg, msgArgs...)
614       *
615       * @param msg message to format and log.
616       * @param msgArgs arguments to place into the format string.
617       */
618      public void debugWarning(String msg, Object... msgArgs)
619      {
620        debugMessage(DebugLogLevel.WARNING, msg, msgArgs);
621      }
622    
623      /**
624       * Log an arbitrary event at the error level.
625       * Same as debugMessage(DebugLogLevel.ERROR, msg)
626       *
627       * @param msg message to format and log.
628       */
629      public void debugError(String msg)
630    
631      {
632        debugMessage(DebugLogLevel.ERROR, msg, new Object[]{});
633      }
634    
635      /**
636       * Log an arbitrary event at the error level.
637       * Same as debugMessage(DebugLogLevel.ERROR, msg, msgArgs...)
638       *
639       * @param msg message to format and log.
640       * @param msgArgs arguments to place into the format string.
641       */
642      public void debugError(String msg, Object... msgArgs)
643      {
644        debugMessage(DebugLogLevel.ERROR, msg, msgArgs);
645      }
646    
647      /**
648       * Log an arbitrary event.
649       *
650       * @param level the level of the log message.
651       * @param msg message to format and log.
652       */
653      public void debugMessage(LogLevel level, String msg)
654      {
655        debugMessage(level, msg, new Object[]{});
656      }
657    
658      /**
659       * Log an arbitrary event.
660       *
661       * @param level the level of the log message.
662       * @param msg message to format and log.
663       * @param msgArgs arguments to place into the format string.
664       */
665      public void debugMessage(LogLevel level, String msg, Object... msgArgs)
666      {
667        if(DebugLogger.debugEnabled())
668        {
669          StackTraceElement[] stackTrace = null;
670          StackTraceElement[] filteredStackTrace = null;
671          StackTraceElement callerFrame = null;
672          for (PublisherSettings settings : publisherSettings)
673          {
674            TraceSettings activeSettings = settings.classSettings;
675            Map<String, TraceSettings> methodSettings = settings.methodSettings;
676    
677            if (shouldLog(level, DebugLogCategory.MESSAGE,
678                          activeSettings) || methodSettings != null)
679            {
680              if(stackTrace == null)
681              {
682                stackTrace = Thread.currentThread().getStackTrace();
683              }
684              if (callerFrame == null)
685              {
686                callerFrame = getCallerFrame(stackTrace);
687              }
688    
689              String signature = callerFrame.getMethodName();
690    
691              // Specific method settings still could exist. Try getting
692              // the settings for this method.
693              if(methodSettings != null)
694              {
695                TraceSettings mSettings = methodSettings.get(signature);
696    
697                if (mSettings == null)
698                {
699                  // Try looking for an undecorated method name
700                  int idx = signature.indexOf('(');
701                  if (idx != -1)
702                  {
703                    mSettings =
704                        methodSettings.get(signature.substring(0, idx));
705                  }
706                }
707    
708                // If this method does have a specific setting and it is not
709                // suppose to be logged, continue.
710                if (mSettings != null)
711                {
712                  if(!shouldLog(level, DebugLogCategory.MESSAGE,
713                                mSettings))
714                  {
715                    continue;
716                  }
717                  else
718                  {
719                    activeSettings = mSettings;
720                  }
721                }
722              }
723    
724              String sl = callerFrame.getFileName() + ":" +
725                  callerFrame.getLineNumber();
726    
727              if(msgArgs != null && msgArgs.length > 0)
728              {
729                msg = String.format(msg, msgArgs);
730              }
731    
732              if (filteredStackTrace == null && activeSettings.stackDepth > 0)
733              {
734                filteredStackTrace =
735                    DebugStackTraceFormatter.SMART_FRAME_FILTER.
736                        getFilteredStackTrace(stackTrace);
737              }
738    
739              settings.debugPublisher.traceMessage(level, activeSettings, signature,
740                                                   sl, msg, filteredStackTrace);
741            }
742          }
743        }
744      }
745    
746      /**
747       * Log an cought exception.
748       *
749       * @param level the level of the log message.
750       * @param ex the exception caught.
751       */
752      public void debugCaught(LogLevel level, Throwable ex)
753      {
754        if(DebugLogger.debugEnabled())
755        {
756          StackTraceElement[] stackTrace = null;
757          StackTraceElement[] filteredStackTrace = null;
758          StackTraceElement callerFrame = null;
759          for (PublisherSettings settings : publisherSettings)
760          {
761            TraceSettings activeSettings = settings.classSettings;
762            Map<String, TraceSettings> methodSettings = settings.methodSettings;
763    
764            if (shouldLog(level, DebugLogCategory.CAUGHT,
765                          activeSettings) || methodSettings != null)
766            {
767              if(stackTrace == null)
768              {
769                stackTrace = Thread.currentThread().getStackTrace();
770              }
771              if (callerFrame == null)
772              {
773                callerFrame = getCallerFrame(stackTrace);
774              }
775    
776              String signature = callerFrame.getMethodName();
777    
778              // Specific method settings still could exist. Try getting
779              // the settings for this method.
780              if(methodSettings != null)
781              {
782                TraceSettings mSettings = methodSettings.get(signature);
783    
784                if (mSettings == null)
785                {
786                  // Try looking for an undecorated method name
787                  int idx = signature.indexOf('(');
788                  if (idx != -1)
789                  {
790                    mSettings =
791                        methodSettings.get(signature.substring(0, idx));
792                  }
793                }
794    
795                // If this method does have a specific setting and it is not
796                // suppose to be logged, continue.
797                if (mSettings != null)
798                {
799                  if(!shouldLog(level, DebugLogCategory.CAUGHT,
800                                mSettings))
801                  {
802                    continue;
803                  }
804                  else
805                  {
806                    activeSettings = mSettings;
807                  }
808                }
809              }
810    
811              String sl = callerFrame.getFileName() + ":" +
812                  callerFrame.getLineNumber();
813    
814              if (filteredStackTrace == null && activeSettings.stackDepth > 0)
815              {
816                filteredStackTrace =
817                    DebugStackTraceFormatter.SMART_FRAME_FILTER.
818                        getFilteredStackTrace(ex.getStackTrace());
819              }
820    
821              settings.debugPublisher.traceCaught(level, activeSettings, signature,
822                                                  sl, ex, filteredStackTrace);
823            }
824          }
825        }
826      }
827    
828      /**
829       * Log a JE database access event.
830       *
831       * @param level the level of the log message.
832       * @param status status of the JE operation.
833       * @param database the database handle.
834       * @param txn  transaction handle (may be null).
835       * @param key  the key to dump.
836       * @param data the data to dump.
837       */
838      public void debugJEAccess(LogLevel level, OperationStatus status,
839                                Database database, Transaction txn,
840                                DatabaseEntry key, DatabaseEntry data)
841      {
842        if(DebugLogger.debugEnabled())
843        {
844          StackTraceElement[] stackTrace = null;
845          StackTraceElement[] filteredStackTrace = null;
846          StackTraceElement callerFrame = null;
847          for (PublisherSettings settings : publisherSettings)
848          {
849            TraceSettings activeSettings = settings.classSettings;
850            Map<String, TraceSettings> methodSettings = settings.methodSettings;
851    
852            if (shouldLog(level, DebugLogCategory.DATABASE_ACCESS,
853                          activeSettings) || methodSettings != null)
854            {
855              if(stackTrace == null)
856              {
857                stackTrace = Thread.currentThread().getStackTrace();
858              }
859              if (callerFrame == null)
860              {
861                callerFrame = getCallerFrame(stackTrace);
862              }
863    
864              String signature = callerFrame.getMethodName();
865    
866              // Specific method settings still could exist. Try getting
867              // the settings for this method.
868              if(methodSettings != null)
869              {
870                TraceSettings mSettings = methodSettings.get(signature);
871    
872                if (mSettings == null)
873                {
874                  // Try looking for an undecorated method name
875                  int idx = signature.indexOf('(');
876                  if (idx != -1)
877                  {
878                    mSettings =
879                        methodSettings.get(signature.substring(0, idx));
880                  }
881                }
882    
883                // If this method does have a specific setting and it is not
884                // suppose to be logged, continue.
885                if (mSettings != null)
886                {
887                  if(!shouldLog(level, DebugLogCategory.DATABASE_ACCESS,
888                                mSettings))
889                  {
890                    continue;
891                  }
892                  else
893                  {
894                    activeSettings = mSettings;
895                  }
896                }
897              }
898    
899              String sl = callerFrame.getFileName() + ":" +
900                  callerFrame.getLineNumber();
901    
902              if (filteredStackTrace == null && activeSettings.stackDepth > 0)
903              {
904                filteredStackTrace =
905                    DebugStackTraceFormatter.SMART_FRAME_FILTER.
906                        getFilteredStackTrace(stackTrace);
907              }
908    
909              settings.debugPublisher.traceJEAccess(level, activeSettings,
910                                                    signature, sl, status, database,
911                                                    txn, key, data,
912                                                    filteredStackTrace);
913            }
914          }
915        }
916      }
917    
918      /**
919       * Log raw data in the form of a byte array.
920       *
921       * @param level the level of the log message.
922       * @param data the data to dump.
923       */
924      public void debugData(LogLevel level, byte[] data)
925      {
926        if(DebugLogger.debugEnabled() && data != null)
927        {
928          StackTraceElement[] stackTrace = null;
929          StackTraceElement[] filteredStackTrace = null;
930          StackTraceElement callerFrame = null;
931          for (PublisherSettings settings : publisherSettings)
932          {
933            TraceSettings activeSettings = settings.classSettings;
934            Map<String, TraceSettings> methodSettings = settings.methodSettings;
935    
936            if (shouldLog(level, DebugLogCategory.DATA,
937                          activeSettings) || methodSettings != null)
938            {
939              if(stackTrace == null)
940              {
941                stackTrace = Thread.currentThread().getStackTrace();
942              }
943              if (callerFrame == null)
944              {
945                callerFrame = getCallerFrame(stackTrace);
946              }
947    
948              String signature = callerFrame.getMethodName();
949    
950              // Specific method settings still could exist. Try getting
951              // the settings for this method.
952              if(methodSettings != null)
953              {
954                TraceSettings mSettings = methodSettings.get(signature);
955    
956                if (mSettings == null)
957                {
958                  // Try looking for an undecorated method name
959                  int idx = signature.indexOf('(');
960                  if (idx != -1)
961                  {
962                    mSettings =
963                        methodSettings.get(signature.substring(0, idx));
964                  }
965                }
966    
967                // If this method does have a specific setting and it is not
968                // suppose to be logged, continue.
969                if (mSettings != null)
970                {
971                  if(!shouldLog(level, DebugLogCategory.DATA,
972                                mSettings))
973                  {
974                    continue;
975                  }
976                  else
977                  {
978                    activeSettings = mSettings;
979                  }
980                }
981              }
982    
983              String sl = callerFrame.getFileName() + ":" +
984                  callerFrame.getLineNumber();
985    
986              if (filteredStackTrace == null && activeSettings.stackDepth > 0)
987              {
988                filteredStackTrace =
989                    DebugStackTraceFormatter.SMART_FRAME_FILTER.
990                        getFilteredStackTrace(stackTrace);
991              }
992    
993              settings.debugPublisher.traceData(level, activeSettings, signature,
994                                                sl, data, filteredStackTrace);
995            }
996          }
997        }
998      }
999    
1000      /**
1001       * Log a protocol element.
1002       *
1003       * @param level the level of the log message.
1004       * @param element the protocol element to dump.
1005       */
1006      public void debugProtocolElement(LogLevel level, ProtocolElement element)
1007      {
1008        if(DebugLogger.debugEnabled() && element != null)
1009        {
1010          StackTraceElement[] stackTrace = null;
1011          StackTraceElement[] filteredStackTrace = null;
1012          StackTraceElement callerFrame = null;
1013          for (PublisherSettings settings : publisherSettings)
1014          {
1015            TraceSettings activeSettings = settings.classSettings;
1016            Map<String, TraceSettings> methodSettings = settings.methodSettings;
1017    
1018            if (shouldLog(level, DebugLogCategory.PROTOCOL,
1019                          activeSettings) || methodSettings != null)
1020            {
1021              if(stackTrace == null)
1022              {
1023                stackTrace = Thread.currentThread().getStackTrace();
1024              }
1025              if (callerFrame == null)
1026              {
1027                callerFrame = getCallerFrame(stackTrace);
1028              }
1029    
1030              String signature = callerFrame.getMethodName();
1031    
1032              // Specific method settings still could exist. Try getting
1033              // the settings for this method.
1034              if(methodSettings != null)
1035              {
1036                TraceSettings mSettings = methodSettings.get(signature);
1037    
1038                if (mSettings == null)
1039                {
1040                  // Try looking for an undecorated method name
1041                  int idx = signature.indexOf('(');
1042                  if (idx != -1)
1043                  {
1044                    mSettings =
1045                        methodSettings.get(signature.substring(0, idx));
1046                  }
1047                }
1048    
1049                // If this method does have a specific setting and it is not
1050                // suppose to be logged, continue.
1051                if (mSettings != null)
1052                {
1053                  if(!shouldLog(level, DebugLogCategory.PROTOCOL,
1054                                mSettings))
1055                  {
1056                    continue;
1057                  }
1058                  else
1059                  {
1060                    activeSettings = mSettings;
1061                  }
1062                }
1063              }
1064    
1065              String sl = callerFrame.getFileName() + ":" +
1066                  callerFrame.getLineNumber();
1067    
1068              if (filteredStackTrace == null && activeSettings.stackDepth > 0)
1069              {
1070                filteredStackTrace =
1071                    DebugStackTraceFormatter.SMART_FRAME_FILTER.
1072                        getFilteredStackTrace(stackTrace);
1073              }
1074    
1075              settings.debugPublisher.traceProtocolElement(level, activeSettings,
1076                                                           signature, sl, element,
1077                                                           filteredStackTrace);
1078            }
1079          }
1080        }
1081      }
1082    
1083      /**
1084       * Log raw data in the form of a ByteBuffer.
1085       *
1086       * @param level the level of the log message.
1087       * @param buffer the data to dump.
1088       */
1089      public void debugData(LogLevel level, ByteBuffer buffer)
1090      {
1091        debugData(level, buffer.array());
1092      }
1093    
1094      /**
1095       * Gets the name of the class this tracer traces.
1096       *
1097       * @return The name of the class this tracer traces.
1098       */
1099      public String getTracedClassName()
1100      {
1101        return className;
1102      }
1103    
1104      /**
1105       * Update the cached settings of the tracer with the settings from the
1106       * provided publishers.
1107       *
1108       * @param publishers The array of publishers to obtain the settings from.
1109       */
1110      @SuppressWarnings("unchecked")
1111      void updateSettings(DebugLogPublisher[] publishers)
1112      {
1113        PublisherSettings[] newSettings =
1114            new PublisherSettings[publishers.length];
1115    
1116        // Get the settings from all publishers.
1117        for(int i = 0; i < publishers.length; i++)
1118        {
1119          DebugLogPublisher publisher = publishers[i];
1120          PublisherSettings settings = new PublisherSettings();
1121    
1122          settings.debugPublisher = publisher;
1123          settings.classSettings = publisher.getClassSettings(className);
1124    
1125          // For some reason, the compiler doesn't see that
1126          // debugLogPublihser.getMethodSettings returns a parameterized Map.
1127          // This problem goes away if a parameterized verson of DebugLogPublisher
1128          // is used. However, we can't not use reflection to instantiate a generic
1129          // DebugLogPublisher<? extends DebugLogPublisherCfg> type. The only thing
1130          // we can do is to just supress the compiler warnings.
1131          settings.methodSettings = publisher.getMethodSettings(className);
1132    
1133          newSettings[i] = settings;
1134        }
1135    
1136        publisherSettings = newSettings;
1137      }
1138    
1139      /**
1140       * Return the caller stack frame.
1141       *
1142       * @param stackTrace The entrie stack trace frames.
1143       * @return the caller stack frame or null if none is found on the
1144       * stack trace.
1145       */
1146      private StackTraceElement getCallerFrame(StackTraceElement[] stackTrace)
1147      {
1148        if (stackTrace != null && stackTrace.length > 0)
1149        {
1150          // Skip leading frames debug logging classes and getStackTrace
1151          // method call frame if any.
1152          for (int i = 0; i < stackTrace.length; i++)
1153          {
1154            StackTraceElement aStackTrace = stackTrace[i];
1155            if(aStackTrace.getClassName().startsWith("java.lang.Thread"))
1156            {
1157              continue;
1158            }
1159    
1160            if (!aStackTrace.getClassName().startsWith(
1161                "org.opends.server.loggers.debug"))
1162            {
1163              return aStackTrace;
1164            }
1165          }
1166        }
1167    
1168        return null;
1169      }
1170    
1171      private boolean shouldLog(LogLevel messageLevel, LogCategory messageCategory,
1172                                TraceSettings activeSettings)
1173      {
1174        return !(activeSettings.includeCategories != null &&
1175            !activeSettings.includeCategories.contains(messageCategory)) &&
1176            messageLevel.intValue() >= activeSettings.level.intValue();
1177    
1178      }
1179    }