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 import org.opends.messages.Message;
029
030 import org.opends.server.api.*;
031 import org.opends.server.loggers.*;
032 import org.opends.server.types.*;
033 import org.opends.server.util.ServerConstants;
034 import org.opends.server.util.StaticUtils;
035 import org.opends.server.util.TimeThread;
036 import static org.opends.server.util.StaticUtils.stackTraceToSingleLineString;
037 import static org.opends.server.util.StaticUtils.getFileForPath;
038 import static org.opends.server.util.ServerConstants.PROPERTY_DEBUG_TARGET;
039 import org.opends.server.admin.std.server.DebugTargetCfg;
040 import org.opends.server.admin.std.server.FileBasedDebugLogPublisherCfg;
041 import org.opends.server.admin.std.server.DebugLogPublisherCfg;
042 import org.opends.server.admin.std.meta.DebugLogPublisherCfgDefn;
043 import org.opends.server.admin.server.ConfigurationChangeListener;
044 import org.opends.server.admin.server.ConfigurationDeleteListener;
045 import org.opends.server.admin.server.ConfigurationAddListener;
046 import org.opends.server.config.ConfigException;
047 import org.opends.server.core.DirectoryServer;
048 import static org.opends.messages.ConfigMessages.
049 ERR_CONFIG_LOGGING_CANNOT_CREATE_WRITER;
050 import static org.opends.messages.ConfigMessages.
051 ERR_CONFIG_LOGGING_CANNOT_OPEN_FILE;
052 import static org.opends.messages.ConfigMessages.
053 ERR_CONFIG_LOGGING_INSANE_MODE;
054 import static org.opends.messages.ConfigMessages.
055 ERR_CONFIG_LOGGING_MODE_INVALID;
056
057
058 import java.util.*;
059 import java.io.File;
060 import java.io.IOException;
061
062 import com.sleepycat.je.*;
063
064 /**
065 * The debug log publisher implementation that writes debug messages to files
066 * on disk. It also maintains the rotation and retention polices of the log
067 * files.
068 */
069 public class TextDebugLogPublisher
070 extends DebugLogPublisher<FileBasedDebugLogPublisherCfg>
071 implements ConfigurationChangeListener<FileBasedDebugLogPublisherCfg>,
072 ConfigurationAddListener<DebugTargetCfg>,
073 ConfigurationDeleteListener<DebugTargetCfg>
074 {
075 private static long globalSequenceNumber;
076
077 private TextWriter writer;
078
079 private FileBasedDebugLogPublisherCfg currentConfig;
080
081 /**
082 * Returns an instance of the text debug log publisher that will print
083 * all messages to the provided writer. This is used to print the messages
084 * to the console when the server starts up. By default, only error level
085 * messages are printed. Special debug targets are also parsed from
086 * system properties if any are specified.
087 *
088 * @param writer The text writer where the message will be written to.
089 * @return The instance of the text error log publisher that will print
090 * all messages to standard out.
091 */
092 public static TextDebugLogPublisher
093 getStartupTextDebugPublisher(TextWriter writer)
094 {
095 TextDebugLogPublisher startupPublisher = new TextDebugLogPublisher();
096 startupPublisher.writer = writer;
097
098 Set<Map.Entry<Object, Object>> propertyEntries =
099 System.getProperties().entrySet();
100 for(Map.Entry<Object, Object> entry : propertyEntries)
101 {
102 if(((String)entry.getKey()).startsWith(PROPERTY_DEBUG_TARGET))
103 {
104 String value = (String)entry.getValue();
105 int settingsStart= value.indexOf(":");
106
107 //See if the scope and settings exists
108 if(settingsStart > 0)
109 {
110 String scope = value.substring(0, settingsStart);
111 TraceSettings settings =
112 TraceSettings.parseTraceSettings(
113 value.substring(settingsStart+1));
114 if(settings != null)
115 {
116 startupPublisher.addTraceSettings(scope, settings);
117 }
118 }
119 }
120 }
121
122 return startupPublisher;
123 }
124
125 /**
126 * {@inheritDoc}
127 */
128 public boolean isConfigurationAcceptable(DebugLogPublisherCfg configuration,
129 List<Message> unacceptableReasons)
130 {
131 FileBasedDebugLogPublisherCfg config =
132 (FileBasedDebugLogPublisherCfg) configuration;
133 return isConfigurationChangeAcceptable(config, unacceptableReasons);
134 }
135
136 /**
137 * {@inheritDoc}
138 */
139 public void initializeDebugLogPublisher(FileBasedDebugLogPublisherCfg config)
140 throws ConfigException, InitializationException
141 {
142 File logFile = getFileForPath(config.getLogFile());
143 FileNamingPolicy fnPolicy = new TimeStampNaming(logFile);
144
145 try
146 {
147 FilePermission perm =
148 FilePermission.decodeUNIXMode(config.getLogFilePermissions());
149
150 LogPublisherErrorHandler errorHandler =
151 new LogPublisherErrorHandler(config.dn());
152
153 boolean writerAutoFlush =
154 config.isAutoFlush() && !config.isAsynchronous();
155
156 MultifileTextWriter writer =
157 new MultifileTextWriter("Multifile Text Writer for " +
158 config.dn().toNormalizedString(),
159 config.getTimeInterval(),
160 fnPolicy,
161 perm,
162 errorHandler,
163 "UTF-8",
164 writerAutoFlush,
165 config.isAppend(),
166 (int)config.getBufferSize());
167
168 // Validate retention and rotation policies.
169 for(DN dn : config.getRotationPolicyDNs())
170 {
171 writer.addRotationPolicy(DirectoryServer.getRotationPolicy(dn));
172 }
173
174 for(DN dn: config.getRetentionPolicyDNs())
175 {
176 writer.addRetentionPolicy(DirectoryServer.getRetentionPolicy(dn));
177 }
178
179 if(config.isAsynchronous())
180 {
181 this.writer = new AsyncronousTextWriter("Asyncronous Text Writer for " +
182 config.dn().toNormalizedString(), config.getQueueSize(),
183 config.isAutoFlush(), writer);
184 }
185 else
186 {
187 this.writer = writer;
188 }
189 }
190 catch(DirectoryException e)
191 {
192 Message message = ERR_CONFIG_LOGGING_CANNOT_CREATE_WRITER.get(
193 config.dn().toString(), String.valueOf(e));
194 throw new InitializationException(message, e);
195
196 }
197 catch(IOException e)
198 {
199 Message message = ERR_CONFIG_LOGGING_CANNOT_OPEN_FILE.get(
200 logFile.toString(), config.dn().toString(), String.valueOf(e));
201 throw new InitializationException(message, e);
202
203 }
204
205
206 config.addDebugTargetAddListener(this);
207 config.addDebugTargetDeleteListener(this);
208
209 //Get the default/global settings
210 LogLevel logLevel =
211 DebugLogLevel.parse(config.getDefaultDebugLevel().toString());
212 Set<LogCategory> logCategories = null;
213 if(!config.getDefaultDebugCategory().isEmpty())
214 {
215 logCategories =
216 new HashSet<LogCategory>(config.getDefaultDebugCategory().size());
217 for(DebugLogPublisherCfgDefn.DefaultDebugCategory category :
218 config.getDefaultDebugCategory())
219 {
220 logCategories.add(DebugLogCategory.parse(category.toString()));
221 }
222 }
223
224 TraceSettings defaultSettings =
225 new TraceSettings(logLevel, logCategories,
226 config.isDefaultOmitMethodEntryArguments(),
227 config.isDefaultOmitMethodReturnValue(),
228 config.getDefaultThrowableStackFrames(),
229 config.isDefaultIncludeThrowableCause());
230
231 addTraceSettings(null, defaultSettings);
232
233 for(String name : config.listDebugTargets())
234 {
235 DebugTargetCfg targetCfg = config.getDebugTarget(name);
236
237 addTraceSettings(targetCfg.getDebugScope(), new TraceSettings(targetCfg));
238 }
239
240 currentConfig = config;
241
242 config.addFileBasedDebugChangeListener(this);
243 }
244
245
246
247 /**
248 * {@inheritDoc}
249 */
250 public boolean isConfigurationChangeAcceptable(
251 FileBasedDebugLogPublisherCfg config, List<Message> unacceptableReasons)
252 {
253 // Make sure the permission is valid.
254 try
255 {
256 FilePermission filePerm =
257 FilePermission.decodeUNIXMode(config.getLogFilePermissions());
258 if(!filePerm.isOwnerWritable())
259 {
260 Message message = ERR_CONFIG_LOGGING_INSANE_MODE.get(
261 config.getLogFilePermissions());
262 unacceptableReasons.add(message);
263 return false;
264 }
265 }
266 catch(DirectoryException e)
267 {
268 Message message = ERR_CONFIG_LOGGING_MODE_INVALID.get(
269 config.getLogFilePermissions(), String.valueOf(e));
270 unacceptableReasons.add(message);
271 return false;
272 }
273
274 return true;
275 }
276
277 /**
278 * {@inheritDoc}
279 */
280 public ConfigChangeResult applyConfigurationChange(
281 FileBasedDebugLogPublisherCfg config)
282 {
283 // Default result code.
284 ResultCode resultCode = ResultCode.SUCCESS;
285 boolean adminActionRequired = false;
286 ArrayList<Message> messages = new ArrayList<Message>();
287
288 //Get the default/global settings
289 LogLevel logLevel =
290 DebugLogLevel.parse(config.getDefaultDebugLevel().toString());
291 Set<LogCategory> logCategories = null;
292 if(!config.getDefaultDebugCategory().isEmpty())
293 {
294 logCategories =
295 new HashSet<LogCategory>(config.getDefaultDebugCategory().size());
296 for(DebugLogPublisherCfgDefn.DefaultDebugCategory category :
297 config.getDefaultDebugCategory())
298 {
299 logCategories.add(DebugLogCategory.parse(category.toString()));
300 }
301 }
302
303 TraceSettings defaultSettings =
304 new TraceSettings(logLevel, logCategories,
305 config.isDefaultOmitMethodEntryArguments(),
306 config.isDefaultOmitMethodReturnValue(),
307 config.getDefaultThrowableStackFrames(),
308 config.isDefaultIncludeThrowableCause());
309
310 addTraceSettings(null, defaultSettings);
311
312 DebugLogger.updateTracerSettings();
313
314 File logFile = getFileForPath(config.getLogFile());
315 FileNamingPolicy fnPolicy = new TimeStampNaming(logFile);
316
317 try
318 {
319 FilePermission perm =
320 FilePermission.decodeUNIXMode(config.getLogFilePermissions());
321
322 boolean writerAutoFlush =
323 config.isAutoFlush() && !config.isAsynchronous();
324
325 TextWriter currentWriter;
326 // Determine the writer we are using. If we were writing asyncronously,
327 // we need to modify the underlaying writer.
328 if(writer instanceof AsyncronousTextWriter)
329 {
330 currentWriter = ((AsyncronousTextWriter)writer).getWrappedWriter();
331 }
332 else
333 {
334 currentWriter = writer;
335 }
336
337 if(currentWriter instanceof MultifileTextWriter)
338 {
339 MultifileTextWriter mfWriter = (MultifileTextWriter)writer;
340
341 mfWriter.setNamingPolicy(fnPolicy);
342 mfWriter.setFilePermissions(perm);
343 mfWriter.setAppend(config.isAppend());
344 mfWriter.setAutoFlush(writerAutoFlush);
345 mfWriter.setBufferSize((int)config.getBufferSize());
346 mfWriter.setInterval(config.getTimeInterval());
347
348 mfWriter.removeAllRetentionPolicies();
349 mfWriter.removeAllRotationPolicies();
350
351 for(DN dn : config.getRotationPolicyDNs())
352 {
353 mfWriter.addRotationPolicy(DirectoryServer.getRotationPolicy(dn));
354 }
355
356 for(DN dn: config.getRetentionPolicyDNs())
357 {
358 mfWriter.addRetentionPolicy(DirectoryServer.getRetentionPolicy(dn));
359 }
360
361 if(writer instanceof AsyncronousTextWriter && !config.isAsynchronous())
362 {
363 // The asynronous setting is being turned off.
364 AsyncronousTextWriter asyncWriter = ((AsyncronousTextWriter)writer);
365 writer = mfWriter;
366 asyncWriter.shutdown(false);
367 }
368
369 if(!(writer instanceof AsyncronousTextWriter) &&
370 config.isAsynchronous())
371 {
372 // The asynronous setting is being turned on.
373 AsyncronousTextWriter asyncWriter =
374 new AsyncronousTextWriter("Asyncronous Text Writer for " +
375 config.dn().toNormalizedString(), config.getQueueSize(),
376 config.isAutoFlush(),
377 mfWriter);
378 writer = asyncWriter;
379 }
380
381 if((currentConfig.isAsynchronous() && config.isAsynchronous()) &&
382 (currentConfig.getQueueSize() != config.getQueueSize()))
383 {
384 adminActionRequired = true;
385 }
386
387 currentConfig = config;
388 }
389 }
390 catch(Exception e)
391 {
392 Message message = ERR_CONFIG_LOGGING_CANNOT_CREATE_WRITER.get(
393 config.dn().toString(),
394 stackTraceToSingleLineString(e));
395 resultCode = DirectoryServer.getServerErrorResultCode();
396 messages.add(message);
397
398 }
399
400 return new ConfigChangeResult(resultCode, adminActionRequired, messages);
401 }
402
403 /**
404 * {@inheritDoc}
405 */
406 public boolean isConfigurationAddAcceptable(DebugTargetCfg config,
407 List<Message> unacceptableReasons)
408 {
409 return getTraceSettings(config.getDebugScope()) == null;
410 }
411
412 /**
413 * {@inheritDoc}
414 */
415 public boolean isConfigurationDeleteAcceptable(DebugTargetCfg config,
416 List<Message> unacceptableReasons)
417 {
418 // A delete should always be acceptable.
419 return true;
420 }
421
422 /**
423 * {@inheritDoc}
424 */
425 public ConfigChangeResult applyConfigurationAdd(DebugTargetCfg config)
426 {
427 // Default result code.
428 ResultCode resultCode = ResultCode.SUCCESS;
429 boolean adminActionRequired = false;
430 ArrayList<Message> messages = new ArrayList<Message>();
431
432 addTraceSettings(config.getDebugScope(), new TraceSettings(config));
433
434 DebugLogger.updateTracerSettings();
435
436 return new ConfigChangeResult(resultCode, adminActionRequired, messages);
437 }
438
439 /**
440 * {@inheritDoc}
441 */
442 public ConfigChangeResult applyConfigurationDelete(DebugTargetCfg config)
443 {
444 // Default result code.
445 ResultCode resultCode = ResultCode.SUCCESS;
446 boolean adminActionRequired = false;
447 ArrayList<Message> messages = new ArrayList<Message>();
448
449 removeTraceSettings(config.getDebugScope());
450
451 DebugLogger.updateTracerSettings();
452
453 return new ConfigChangeResult(resultCode, adminActionRequired, messages);
454 }
455
456 /**
457 * {@inheritDoc}
458 */
459 public void traceConstructor(LogLevel level,
460 TraceSettings settings,
461 String signature,
462 String sourceLocation,
463 Object[] args,
464 StackTraceElement[] stackTrace)
465 {
466 LogCategory category = DebugLogCategory.CONSTRUCTOR;
467
468 String msg = "";
469 if(args != null)
470 {
471 msg = buildDefaultEntryMessage(args);
472 }
473
474 String stack = null;
475 if(stackTrace != null)
476 {
477 stack = DebugStackTraceFormatter.formatStackTrace(stackTrace,
478 settings.stackDepth);
479 }
480 publish(category, level, signature, sourceLocation, msg, stack);
481 }
482
483 /**
484 * {@inheritDoc}
485 */
486 public void traceMethodEntry(LogLevel level,
487 TraceSettings settings,
488 String signature,
489 String sourceLocation,
490 Object obj,
491 Object[] args,
492 StackTraceElement[] stackTrace)
493 {
494 LogCategory category = DebugLogCategory.ENTER;
495 String msg = "";
496 if(args != null)
497 {
498 msg = buildDefaultEntryMessage(args);
499 }
500
501 String stack = null;
502 if(stackTrace != null)
503 {
504 stack = DebugStackTraceFormatter.formatStackTrace(stackTrace,
505 settings.stackDepth);
506 }
507 publish(category, level, signature, sourceLocation, msg, stack);
508 }
509
510 /**
511 * {@inheritDoc}
512 */
513 public void traceStaticMethodEntry(LogLevel level,
514 TraceSettings settings,
515 String signature,
516 String sourceLocation,
517 Object[] args,
518 StackTraceElement[] stackTrace)
519 {
520 LogCategory category = DebugLogCategory.ENTER;
521 String msg = "";
522 if(args != null)
523 {
524 msg = buildDefaultEntryMessage(args);
525 }
526
527 String stack = null;
528 if(stackTrace != null)
529 {
530 stack = DebugStackTraceFormatter.formatStackTrace(stackTrace,
531 settings.stackDepth);
532 }
533 publish(category, level, signature, sourceLocation, msg, stack);
534 }
535
536 /**
537 * {@inheritDoc}
538 */
539 public void traceReturn(LogLevel level,
540 TraceSettings settings,
541 String signature,
542 String sourceLocation,
543 Object ret,
544 StackTraceElement[] stackTrace)
545 {
546 LogCategory category = DebugLogCategory.EXIT;
547 String msg = "";
548 if(ret != null)
549 {
550 msg = DebugMessageFormatter.format("returned={%s}",
551 new Object[] {ret});
552 }
553
554 String stack = null;
555 if(stackTrace != null)
556 {
557 stack = DebugStackTraceFormatter.formatStackTrace(stackTrace,
558 settings.stackDepth);
559 }
560 publish(category, level, signature, sourceLocation, msg, stack);
561 }
562
563 /**
564 * {@inheritDoc}
565 */
566 public void traceThrown(LogLevel level,
567 TraceSettings settings,
568 String signature,
569 String sourceLocation,
570 Throwable ex,
571 StackTraceElement[] stackTrace)
572 {
573 LogCategory category = DebugLogCategory.THROWN;
574
575 String msg = DebugMessageFormatter.format("thrown={%s}",
576 new Object[] {ex});
577
578 String stack = null;
579 if(stackTrace != null)
580 {
581 stack = DebugStackTraceFormatter.formatStackTrace(ex,
582 settings.stackDepth,
583 settings.includeCause);
584 }
585 publish(category, level, signature, sourceLocation, msg, stack);
586 }
587
588 /**
589 * {@inheritDoc}
590 */
591 public void traceMessage(LogLevel level,
592 TraceSettings settings,
593 String signature,
594 String sourceLocation,
595 String msg,
596 StackTraceElement[] stackTrace)
597 {
598 LogCategory category = DebugLogCategory.MESSAGE;
599
600 String stack = null;
601 if(stackTrace != null)
602 {
603 stack = DebugStackTraceFormatter.formatStackTrace(stackTrace,
604 settings.stackDepth);
605 }
606 publish(category, level, signature, sourceLocation, msg, stack);
607 }
608
609 /**
610 * {@inheritDoc}
611 */
612 public void traceCaught(LogLevel level,
613 TraceSettings settings,
614 String signature,
615 String sourceLocation,
616 Throwable ex,
617 StackTraceElement[] stackTrace)
618 {
619 LogCategory category = DebugLogCategory.CAUGHT;
620 String msg = DebugMessageFormatter.format("caught={%s}",
621 new Object[] {ex});
622
623 String stack = null;
624 if(stackTrace != null)
625 {
626 stack = DebugStackTraceFormatter.formatStackTrace(ex,
627 settings.stackDepth,
628 settings.includeCause);
629 }
630 publish(category, level, signature, sourceLocation, msg, stack);
631 }
632
633 /**
634 * {@inheritDoc}
635 */
636 public void traceJEAccess(LogLevel level,
637 TraceSettings settings,
638 String signature,
639 String sourceLocation,
640 OperationStatus status,
641 Database database, Transaction txn,
642 DatabaseEntry key, DatabaseEntry data,
643 StackTraceElement[] stackTrace)
644 {
645 LogCategory category = DebugLogCategory.DATABASE_ACCESS;
646
647 // Build the string that is common to category DATABASE_ACCESS.
648 StringBuilder builder = new StringBuilder();
649 builder.append(" (");
650 builder.append(status.toString());
651 builder.append(")");
652 builder.append(" db=");
653 try
654 {
655 builder.append(database.getDatabaseName());
656 }
657 catch(DatabaseException de)
658 {
659 builder.append(de.toString());
660 }
661 if (txn != null)
662 {
663 builder.append(" txnid=");
664 try
665 {
666 builder.append(txn.getId());
667 }
668 catch(DatabaseException de)
669 {
670 builder.append(de.toString());
671 }
672 }
673 else
674 {
675 builder.append(" txnid=none");
676 }
677
678 builder.append(ServerConstants.EOL);
679 if(key != null)
680 {
681 builder.append("key:");
682 builder.append(ServerConstants.EOL);
683 StaticUtils.byteArrayToHexPlusAscii(builder, key.getData(), 4);
684 }
685
686 // If the operation was successful we log the same common information
687 // plus the data
688 if (status == OperationStatus.SUCCESS && data != null)
689 {
690
691 builder.append("data(len=");
692 builder.append(data.getSize());
693 builder.append("):");
694 builder.append(ServerConstants.EOL);
695 StaticUtils.byteArrayToHexPlusAscii(builder, data.getData(), 4);
696
697 }
698
699 String stack = null;
700 if(stackTrace != null)
701 {
702 stack = DebugStackTraceFormatter.formatStackTrace(stackTrace,
703 settings.stackDepth);
704 }
705 publish(category, level, signature, sourceLocation,
706 builder.toString(), stack);
707 }
708
709 /**
710 * {@inheritDoc}
711 */
712 public void traceData(LogLevel level,
713 TraceSettings settings,
714 String signature,
715 String sourceLocation,
716 byte[] data,
717 StackTraceElement[] stackTrace)
718 {
719 LogCategory category = DebugLogCategory.DATA;
720 if(data != null)
721 {
722 StringBuilder builder = new StringBuilder();
723 builder.append(ServerConstants.EOL);
724 builder.append("data(len=");
725 builder.append(data.length);
726 builder.append("):");
727 builder.append(ServerConstants.EOL);
728 StaticUtils.byteArrayToHexPlusAscii(builder, data, 4);
729
730 String stack = null;
731 if(stackTrace != null)
732 {
733 stack = DebugStackTraceFormatter.formatStackTrace(stackTrace,
734 settings.stackDepth);
735 }
736 publish(category, level, signature, sourceLocation,
737 builder.toString(), stack);
738 }
739 }
740
741 /**
742 * {@inheritDoc}
743 */
744 public void traceProtocolElement(LogLevel level,
745 TraceSettings settings,
746 String signature,
747 String sourceLocation,
748 ProtocolElement element,
749 StackTraceElement[] stackTrace)
750 {
751 LogCategory category = DebugLogCategory.PROTOCOL;
752
753 StringBuilder builder = new StringBuilder();
754 builder.append(ServerConstants.EOL);
755 element.toString(builder, 4);
756
757 String stack = null;
758 if(stackTrace != null)
759 {
760 stack = DebugStackTraceFormatter.formatStackTrace(stackTrace,
761 settings.stackDepth);
762 }
763 publish(category, level, signature, sourceLocation,
764 builder.toString(), stack);
765 }
766
767 /**
768 * {@inheritDoc}
769 */
770 public void close()
771 {
772 writer.shutdown();
773
774 if(currentConfig != null)
775 {
776 currentConfig.removeFileBasedDebugChangeListener(this);
777 }
778 }
779
780
781 // Publishes a record, optionally performing some "special" work:
782 // - injecting a stack trace into the message
783 // - format the message with argument values
784 private void publish(LogCategory category, LogLevel level, String signature,
785 String sourceLocation, String msg, String stack)
786 {
787 Thread thread = Thread.currentThread();
788
789 StringBuilder buf = new StringBuilder();
790 // Emit the timestamp.
791 buf.append("[");
792 buf.append(TimeThread.getLocalTime());
793 buf.append("] ");
794
795 // Emit the seq num
796 buf.append(globalSequenceNumber++);
797 buf.append(" ");
798
799 // Emit debug category.
800 buf.append(category);
801 buf.append(" ");
802
803 // Emit the debug level.
804 buf.append(level);
805 buf.append(" ");
806
807 // Emit thread info.
808 buf.append("thread={");
809 buf.append(thread.getName());
810 buf.append("(");
811 buf.append(thread.getId());
812 buf.append(")} ");
813
814 if(thread instanceof DirectoryThread)
815 {
816 buf.append("threadDetail={");
817 for (Map.Entry<String, String> entry :
818 ((DirectoryThread) thread).getDebugProperties().entrySet())
819 {
820 buf.append(entry.getKey());
821 buf.append("=");
822 buf.append(entry.getValue());
823 buf.append(" ");
824 }
825 buf.append("} ");
826 }
827
828 // Emit method info.
829 buf.append("method={");
830 buf.append(signature);
831 buf.append("(");
832 buf.append(sourceLocation);
833 buf.append(")} ");
834
835 // Emit message.
836 buf.append(msg);
837
838 // Emit Stack Trace.
839 if(stack != null)
840 {
841 buf.append("\nStack Trace:\n");
842 buf.append(stack);
843 }
844
845 writer.writeRecord(buf.toString());
846 }
847
848 private String buildDefaultEntryMessage(Object[] args)
849 {
850 StringBuilder format = new StringBuilder();
851 for (int i = 0; i < args.length; i++)
852 {
853 if (i != 0) format.append(", ");
854 format.append("arg");
855 format.append(i + 1);
856 format.append("={%s}");
857 }
858
859 return DebugMessageFormatter.format(format.toString(), args);
860 }
861
862 /**
863 * {@inheritDoc}
864 */
865 public DN getDN()
866 {
867 if(currentConfig != null)
868 {
869 return currentConfig.dn();
870 }
871 else
872 {
873 return null;
874 }
875 }
876 }