1 /*******************************************************************************
2 
3         copyright:      Copyright (c) 2004 Kris Bell. All rights reserved
4 
5         license:        BSD style: $(LICENSE)
6 
7         version:        May 2004 : Initial release
8         version:        Oct 2004: Hierarchy moved due to circular dependencies
9         version:        Apr 2008: Lazy delegates removed due to awkward usage
10         author:         Kris
11 
12 
13         Simplified, pedestrian usage:
14         ---
15         import tango.util.log.Config;
16 
17         Log ("hello world");
18         Log ("temperature is {} degrees", 75);
19         ---
20 
21         Generic usage:
22 
23         Loggers are named entities, sometimes shared, sometimes specific to
24         a particular portion of code. The names are generally hierarchical in
25         nature, using dot notation (with '.') to separate each named section.
26         For example, a typical name might be something like "mail.send.writer"
27         ---
28         import tango.util.log.Log;
29 
30         auto log = Log.lookup ("mail.send.writer");
31 
32         log.info  ("an informational message");
33         log.error ("an exception message: {}", exception);
34 
35         etc ...
36         ---
37 
38         It is considered good form to pass a logger instance as a function or
39         class-ctor argument, or to assign a new logger instance during static
40         class construction. For example: if it were considered appropriate to
41         have one logger instance per class, each might be constructed like so:
42         ---
43         private Logger log;
44 
45         static this()
46         {
47             log = Log.lookup (nameOfThisClassOrStructOrModule);
48         }
49         ---
50 
51         Messages passed to a Logger are assumed to be either self-contained
52         or configured with "{}" notation a la Layout & Stdout:
53         ---
54         log.warn ("temperature is {} degrees!", 101);
55         ---
56 
57         Note that an internal workspace is used to format the message, which
58         is limited to 2000 bytes. Use "{.256}" truncation notation to limit
59         the size of individual message components, or use explicit formatting:
60         ---
61         char[4096] buf = void;
62 
63         log.warn (log.format (buf, "a very long message: {}", someLongMessage));
64         ---
65 
66         To avoid overhead when constructing arguments passed to formatted
67         messages, you should check to see whether a logger is active or not:
68         ---
69         if (log.warn)
70             log.warn ("temperature is {} degrees!", complexFunction());
71         ---
72 
73         tango.log closely follows both the API and the behaviour as documented
74         at the official Log4J site, where you'll find a good tutorial. Those
75         pages are hosted over
76         <A HREF="http://logging.apache.org/log4j/docs/documentation.html">here</A>.
77 
78 *******************************************************************************/
79 
80 module tango.util.log.Log;
81 
82 private import  tango.sys.Common;
83 
84 private import  tango.time.Clock;
85 
86 private import  tango.core.Exception;
87 
88 private import  tango.io.model.IConduit;
89 
90 private import  tango.text.convert.Format;
91 
92 private import  tango.util.log.model.ILogger;
93 
94 /*******************************************************************************
95 
96         Platform issues ...
97 
98 *******************************************************************************/
99 
100 version (GNU)
101         {
102         private import tango.core.Vararg;
103         alias void* Arg;
104         alias va_list ArgList;
105         }
106 else version (DigitalMars)
107         {
108         private import tango.core.Vararg;
109         alias void* Arg;
110         alias va_list ArgList;
111 
112     version(X86_64)  version = DigitalMarsX64;
113 
114         }
115      else
116         {
117         alias void* Arg;
118         alias void* ArgList;
119         }
120 
121 /*******************************************************************************
122 
123         Pull in additional functions from the C library
124 
125 *******************************************************************************/
126 
127 extern (C)
128 {
129         private int memcmp (const(void) *, const(void) *, size_t);
130 }
131 
132 version (Win32)
133 {
134         private extern(Windows) int QueryPerformanceCounter(ulong *count);
135         private extern(Windows) int QueryPerformanceFrequency(ulong *frequency);
136 }
137 
138 /*******************************************************************************
139 
140         These represent the standard LOG4J event levels. Note that
141         Debug is called Trace here, because debug is a reserved word
142         in D
143 
144 *******************************************************************************/
145 
146 alias ILogger.Level Level;
147 
148 
149 /*******************************************************************************
150 
151         Manager for routing Logger calls to the default hierarchy. Note
152         that you may have multiple hierarchies per application, but must
153         access the hierarchy directly for root() and lookup() methods within
154         each additional instance.
155 
156 *******************************************************************************/
157 
158 public struct Log
159 {
160         // support for old API
161         public alias lookup getLogger;
162 
163         // trivial usage via opCall
164         public alias formatln opCall;
165 
166         // internal use only
167         private static __gshared Hierarchy base;
168         private static __gshared Time beginTime;
169 
170         version (Win32)
171         {
172                 private static __gshared double multiplier;
173                 private static __gshared ulong  timerStart;
174         }
175 
176         private struct  Pair {const(char)[] name; Level value;}
177 
178         private static  __gshared Level [immutable(char)[]] map;
179 
180         private static  __gshared Pair[] Pairs =
181                         [
182                         {"TRACE",  Level.Trace},
183                         {"Trace",  Level.Trace},
184                         {"trace",  Level.Trace},
185                         {"INFO",   Level.Info},
186                         {"Info",   Level.Info},
187                         {"info",   Level.Info},
188                         {"WARN",   Level.Warn},
189                         {"Warn",   Level.Warn},
190                         {"warn",   Level.Warn},
191                         {"ERROR",  Level.Error},
192                         {"Error",  Level.Error},
193                         {"error",  Level.Error},
194                         {"Fatal",  Level.Fatal},
195                         {"FATAL",  Level.Fatal},
196                         {"fatal",  Level.Fatal},
197                         {"NONE",   Level.None},
198                         {"None",   Level.None},
199                         {"none",   Level.None},
200                         ];
201 
202         // logging-level names
203         private __gshared immutable char[][] LevelNames =
204         [
205                 "Trace", "Info", "Warn", "Error", "Fatal", "None"
206         ];
207 
208         /***********************************************************************
209 
210                 Initialize the base hierarchy
211 
212         ***********************************************************************/
213 
214         shared static this ()
215         {
216                 base = new Hierarchy ("tango");
217 
218                 foreach (p; Pairs)
219                          map[p.name] = p.value;
220 
221                 version (Posix)
222                 {
223                         beginTime = Clock.now;
224                 }
225 
226                 version (Win32)
227                 {
228                         ulong freq;
229 
230                         if (! QueryPerformanceFrequency (&freq))
231                               throw new PlatformException ("high-resolution timer is not available");
232 
233                         QueryPerformanceCounter (&timerStart);
234                         multiplier = cast(double) TimeSpan.TicksPerSecond / freq;
235                         beginTime = Clock.now;
236                 }
237         }
238 
239         /***********************************************************************
240 
241                 Return the level of a given name
242 
243         ***********************************************************************/
244 
245         static Level convert (const(char[]) name, Level def=Level.Trace)
246         {
247                 auto p = name in map;
248                 if (p)
249                     return *p;
250                 return def;
251         }
252 
253         /***********************************************************************
254 
255                 Return the current time
256 
257         ***********************************************************************/
258 
259         @property static Time time ()
260         {
261                 version (Posix)
262                 {
263                         return Clock.now;
264                 }
265 
266                 version (Win32)
267                 {
268                         ulong now;
269 
270                         QueryPerformanceCounter (&now);
271                         return beginTime + TimeSpan(cast(long)((now - timerStart) * multiplier));
272                 }
273         }
274 
275         /***********************************************************************
276 
277                 Return the root Logger instance. This is the ancestor of
278                 all loggers and, as such, can be used to manipulate the
279                 entire hierarchy. For instance, setting the root 'level'
280                 attribute will affect all other loggers in the tree.
281 
282         ***********************************************************************/
283 
284         @property static Logger root ()
285         {
286                 return base.root;
287         }
288 
289         /***********************************************************************
290 
291                 Return an instance of the named logger. Names should be
292                 hierarchical in nature, using dot notation (with '.') to
293                 separate each name section. For example, a typical name
294                 might be something like "tango.io.Stdout".
295 
296                 If the logger does not currently exist, it is created and
297                 inserted into the hierarchy. A parent will be attached to
298                 it, which will be either the root logger or the closest
299                 ancestor in terms of the hierarchical name space.
300 
301         ***********************************************************************/
302 
303         static Logger lookup (const(char[]) name)
304         {
305                 return base.lookup (name);
306         }
307 
308         /***********************************************************************
309 
310                 Return text name for a log level
311 
312         ***********************************************************************/
313 
314         static const(char)[] convert (int level)
315         {
316                 assert (level >= Level.Trace && level <= Level.None);
317                 return LevelNames[level];
318         }
319 
320         /***********************************************************************
321 
322                 Return the singleton hierarchy.
323 
324         ***********************************************************************/
325 
326         static Hierarchy hierarchy ()
327         {
328                 return base;
329         }
330 
331         /***********************************************************************
332 
333                 Pedestrian usage support, as an alias for Log.root.info()
334 
335         ***********************************************************************/
336 
337         static void formatln (const(char[]) fmt, ...)
338         {
339             version (DigitalMarsX64)
340             {
341                 va_list ap;
342 
343                 version(GNU) {} else va_start(ap, __va_argsave);
344 
345                 scope(exit) va_end(ap);
346 
347                 root.format (Level.Info, fmt, _arguments, ap);
348             }
349             else            
350                 root.format (Level.Info, fmt, _arguments, _argptr);
351         }
352 
353         /***********************************************************************
354 
355                 Initialize the behaviour of a basic logging hierarchy.
356 
357                 Adds a StreamAppender to the root node, and sets
358                 the activity level to be everything enabled.
359 
360         ***********************************************************************/
361 
362         static void config (OutputStream stream, bool flush = true)
363         {
364                 root.add (new AppendStream (stream, flush));
365         }
366 }
367 
368 
369 /*******************************************************************************
370 
371         Loggers are named entities, sometimes shared, sometimes specific to
372         a particular portion of code. The names are generally hierarchical in
373         nature, using dot notation (with '.') to separate each named section.
374         For example, a typical name might be something like "mail.send.writer"
375         ---
376         import tango.util.log.Log;format
377 
378         auto log = Log.lookup ("mail.send.writer");
379 
380         log.info  ("an informational message");
381         log.error ("an exception message: {}", exception.toString);
382 
383         etc ...
384         ---
385 
386         It is considered good form to pass a logger instance as a function or
387         class-ctor argument, or to assign a new logger instance during static
388         class construction. For example: if it were considered appropriate to
389         have one logger instance per class, each might be constructed like so:
390         ---
391         private Logger log;
392 
393         static this()
394         {
395             log = Log.lookup (nameOfThisClassOrStructOrModule);
396         }
397         ---
398 
399         Messages passed to a Logger are assumed to be either self-contained
400         or configured with "{}" notation a la Layout & Stdout:
401         ---
402         log.warn ("temperature is {} degrees!", 101);
403         ---
404 
405         Note that an internal workspace is used to format the message, which
406         is limited to 2048 bytes. Use "{.256}" truncation notation to limit
407         the size of individual message components. You can also use your own
408         formatting buffer:
409         ---
410         log.buffer (new char[](4096));
411 
412         log.warn ("a very long warning: {}", someLongWarning);
413         ---
414 
415         Or you can use explicit formatting:
416         ---
417         char[4096] buf = void;
418 
419         log.warn (log.format (buf, "a very long warning: {}", someLongWarning));
420         ---
421 
422         To avoid overhead when constructing argument passed to formatted
423         messages, you should check to see whether a logger is active or not:
424         ---
425         if (log.enabled (log.Warn))
426             log.warn ("temperature is {} degrees!", complexFunction());
427         ---
428 
429         The above will be handled implicitly by the logging system when
430         macros are added to the language (used to be handled implicitly
431         via lazy delegates, but usage of those turned out to be awkward).
432 
433         tango.log closely follows both the API and the behaviour as documented
434         at the official Log4J site, where you'll find a good tutorial. Those
435         pages are hosted over
436         <A HREF="http://logging.apache.org/log4j/docs/documentation.html">here</A>.
437 
438 *******************************************************************************/
439 
440 public class Logger : ILogger
441 {
442 
443         alias Level.Trace Trace;        // shortcut to Level values
444         alias Level.Info  Info;         // ...
445         alias Level.Warn  Warn;         // ...
446         alias Level.Error Error;        // ...
447         alias Level.Fatal Fatal;        // ...
448 
449         alias append      opCall;       // shortcut to append
450 
451         /***********************************************************************
452 
453                 Context for a hierarchy, used for customizing behaviour
454                 of log hierarchies. You can use this to implement dynamic
455                 log-levels, based upon filtering or some other mechanism
456 
457         ***********************************************************************/
458 
459         interface Context
460         {
461                 /// return a label for this context
462                 @property const const(char)[] label ();
463 
464                 /// first arg is the setting of the logger itself, and
465                 /// the second arg is what kind of message we're being
466                 /// asked to produce
467                 const bool enabled (Level setting, Level target);
468         }
469 
470         /***********************************************************************
471 
472         ***********************************************************************/
473 
474         private Logger          next,
475                                 parent;
476 
477         private Hierarchy       host_;
478         private const(char)[]          name_;
479         private Level           level_;
480         private bool            additive_;
481         private Appender        appender_;
482         private char[]          buffer_;
483         private size_t          buffer_size_;
484 
485         /***********************************************************************
486 
487                 Construct a LoggerInstance with the specified name for the
488                 given hierarchy. By default, logger instances are additive
489                 and are set to emit all events.
490 
491         ***********************************************************************/
492 
493         private this (Hierarchy host, const(char[]) name)
494         {
495                 host_ = host;
496                 level_ = Level.Trace;
497                 additive_ = true;
498                 name_ = name;
499         }
500 
501         /***********************************************************************
502 
503                 Is this logger enabed for the specified Level?
504 
505         ***********************************************************************/
506 
507         final bool enabled (Level level = Level.Fatal)
508         {
509                 return host_.context.enabled (level_, level);
510         }
511 
512         /***********************************************************************
513 
514                 Is trace enabled?
515 
516         ***********************************************************************/
517 
518         final bool trace ()
519         {
520                 return enabled (Level.Trace);
521         }
522 
523         /***********************************************************************
524 
525                 Append a trace message
526 
527         ***********************************************************************/
528 
529         final void trace (const(char[]) fmt, ...)
530         {
531             version (DigitalMarsX64)
532             {
533                 va_list ap;
534 
535                 va_start(ap, __va_argsave);
536 
537                 scope(exit) va_end(ap);
538 
539                 format (Level.Trace, fmt, _arguments, ap);
540             }
541             else            
542                 format (Level.Trace, fmt, _arguments, _argptr);
543         }
544 
545         /***********************************************************************
546 
547                 Is info enabled?
548 
549         ***********************************************************************/
550 
551         final bool info ()
552         {
553                 return enabled (Level.Info);
554         }
555 
556         /***********************************************************************
557 
558                 Append an info message
559 
560         ***********************************************************************/
561 
562         final void info (const(char[]) fmt, ...)
563         {
564             version (DigitalMarsX64)
565             {
566                 va_list ap;
567 
568                 va_start(ap, __va_argsave);
569 
570                 scope(exit) va_end(ap);
571 
572                 format (Level.Info, fmt, _arguments, ap);
573             }
574             else            
575                 format (Level.Info, fmt, _arguments, _argptr);
576         }
577 
578         /***********************************************************************
579 
580                 Is warn enabled?
581 
582         ***********************************************************************/
583 
584         final bool warn ()
585         {
586                 return enabled (Level.Warn);
587         }
588 
589         /***********************************************************************
590 
591                 Append a warning message
592 
593         ***********************************************************************/
594 
595         final void warn (const(char[]) fmt, ...)
596         {
597             version (DigitalMarsX64)
598             {
599                 va_list ap;
600 
601                 va_start(ap, __va_argsave);
602 
603                 scope(exit) va_end(ap);
604 
605                 format (Level.Warn, fmt, _arguments, ap);
606             }
607             else            
608                 format (Level.Warn, fmt, _arguments, _argptr);
609         }
610 
611         /***********************************************************************
612 
613                 Is error enabled?
614 
615         ***********************************************************************/
616 
617         final bool error ()
618         {
619                 return enabled (Level.Error);
620         }
621 
622         /***********************************************************************
623 
624                 Append an error message
625 
626         ***********************************************************************/
627 
628         final void error (const(char[]) fmt, ...)
629         {
630             version (DigitalMarsX64)
631             {
632                 va_list ap;
633 
634                 va_start(ap, __va_argsave);
635 
636                 scope(exit) va_end(ap);
637 
638                 format (Level.Error, fmt, _arguments, ap);
639             }
640             else            
641                 format (Level.Error, fmt, _arguments, _argptr);
642         }
643 
644         /***********************************************************************
645 
646                 Is fatal enabled?
647 
648         ***********************************************************************/
649 
650         final bool fatal ()
651         {
652                 return enabled (Level.Fatal);
653         }
654 
655         /***********************************************************************
656 
657                 Append a fatal message
658 
659         ***********************************************************************/
660 
661         final void fatal (const(char[]) fmt, ...)
662         {
663             version (DigitalMarsX64)
664             {
665                 va_list ap;
666 
667                 va_start(ap, __va_argsave);
668 
669                 scope(exit) va_end(ap);
670 
671                 format (Level.Fatal, fmt, _arguments, ap);
672             }
673             else            
674                 format (Level.Fatal, fmt, _arguments, _argptr);
675         }
676 
677         /***********************************************************************
678 
679                 Return the name of this Logger (sans the appended dot).
680 
681         ***********************************************************************/
682 
683         @property final const(char)[] name ()
684         {
685                 size_t i = name_.length;
686                 if (i > 0)
687                     --i;
688                 return name_[0 .. i];
689         }
690 
691         /***********************************************************************
692 
693                 Return the Level this logger is set to
694 
695         ***********************************************************************/
696 
697         final Level level ()
698         {
699                 return level_;
700         }
701 
702         /***********************************************************************
703 
704                 Set the current level for this logger (and only this logger).
705 
706         ***********************************************************************/
707 
708         final Logger level (Level l)
709         {
710                 return level (l, false);
711         }
712 
713         /***********************************************************************
714 
715                 Set the current level for this logger, and (optionally) all
716                 of its descendents.
717 
718         ***********************************************************************/
719 
720         final Logger level (Level level, bool propagate)
721         {
722                 level_ = level;
723                 if (propagate)
724                     foreach (log; host_)
725                              if (log.isChildOf (name_))
726                                  log.level_ = level;
727                 return this;
728         }
729 
730         /***********************************************************************
731 
732                 Is this logger additive? That is, should we walk ancestors
733                 looking for more appenders?
734 
735         ***********************************************************************/
736 
737         @property final const bool additive ()
738         {
739                 return additive_;
740         }
741 
742         /***********************************************************************
743 
744                 Set the additive status of this logger. See bool additive().
745 
746         ***********************************************************************/
747 
748         @property final Logger additive (bool enabled)
749         {
750                 additive_ = enabled;
751                 return this;
752         }
753 
754         /***********************************************************************
755 
756                 Add (another) appender to this logger. Appenders are each
757                 invoked for log events as they are produced. At most, one
758                 instance of each appender will be invoked.
759 
760         ***********************************************************************/
761 
762         final Logger add (Appender another)
763         {
764                 assert (another);
765                 another.next = appender_;
766                 appender_ = another;
767                 return this;
768         }
769 
770         /***********************************************************************
771 
772                 Remove all appenders from this Logger
773 
774         ***********************************************************************/
775 
776         final Logger clear ()
777         {
778                 appender_ = null;
779                 return this;
780         }
781 
782         /***********************************************************************
783 
784                 Get the current formatting buffer (null if none).
785 
786         ***********************************************************************/
787 
788         @property final char[] buffer ()
789         {
790                 return buffer_;
791         }
792 
793         /***********************************************************************
794 
795                 Set the current formatting buffer.
796 
797                 Set to null to use the default internal buffer.
798 
799         ***********************************************************************/
800 
801         @property final Logger buffer (char[] buf)
802         {
803                 buffer_ = buf;
804                 buffer_size_ = buf.length;
805                 return this;
806         }
807 
808         /***********************************************************************
809 
810                 Get time since this application started
811 
812         ***********************************************************************/
813 
814         @property final const TimeSpan runtime ()
815         {
816                 return Clock.now - Log.beginTime;
817         }
818 
819         /***********************************************************************
820 
821                 Send a message to this logger via its appender list.
822 
823         ***********************************************************************/
824 
825         final Logger append (Level level, lazy const(char[]) exp)
826         {
827                 if (host_.context.enabled (level_, level))
828                    {
829                    LogEvent event;
830 
831                    // set the event attributes and append it
832                    event.set (host_, level, exp, name.length ? name_[0..$-1] : "root");
833                    append (event);
834                    }
835                 return this;
836         }
837 
838         /***********************************************************************
839 
840                 Send a message to this logger via its appender list.
841 
842         ***********************************************************************/
843 
844         private void append (LogEvent event)
845         {
846                 // combine appenders from all ancestors
847                 auto links = this;
848                 Appender.Mask masks = 0;
849                 do {
850                    auto appender = links.appender_;
851 
852                    // this level have an appender?
853                    while (appender)
854                          {
855                          auto mask = appender.mask;
856 
857                          // have we visited this appender already?
858                          if ((masks & mask) is 0)
859                               // is appender enabled for this level?
860                               if (appender.level <= event.level)
861                                  {
862                                  // append message and update mask
863                                  appender.append (event);
864                                  masks |= mask;
865                                  }
866                          // process all appenders for this node
867                          appender = appender.next;
868                          }
869                      // process all ancestors
870                    } while (links.additive_ && ((links = links.parent) !is null));
871         }
872 
873         /***********************************************************************
874 
875                 Return a formatted string from the given arguments
876 
877         ***********************************************************************/
878 
879         final char[] format (char[] buffer, const(char[]) formatStr, ...)
880         {
881             version (DigitalMarsX64)
882             {
883                 va_list ap;
884 
885                 va_start(ap, __va_argsave);
886 
887                 scope(exit) va_end(ap);
888 
889                 return Format.vprint (buffer, formatStr, _arguments, ap);
890             }
891             else
892                 return Format.vprint (buffer, formatStr, _arguments, _argptr);
893 
894         }
895 
896         /***********************************************************************
897 
898                 Format and emit text from the given arguments
899 
900         ***********************************************************************/
901 
902         final Logger format (Level level, const(char[]) fmt, TypeInfo[] types, ArgList args)
903         {
904                 if (types.length)
905                 {
906                     if (buffer_ is null)
907                         formatWithDefaultBuffer(level, fmt, types, args);
908                     else
909                         formatWithProvidedBuffer(level, fmt, types, args);
910                 }
911                 else
912                    append (level, fmt);
913                 return this;
914         }
915 
916         private void formatWithDefaultBuffer(Level level, const(char)[] fmt, TypeInfo[] types, ArgList args)
917         {
918             char[2048] tmp = void;
919             formatWithBuffer(level, fmt, types, args, tmp);
920         }
921 
922         private void formatWithProvidedBuffer(Level level, const(char)[] fmt, TypeInfo[] types, ArgList args)
923         {
924             formatWithBuffer(level, fmt, types, args, buffer_);
925             buffer_.length = buffer_size_;
926         }
927 
928         private void formatWithBuffer(Level level, const(char)[] fmt, TypeInfo[] types, ArgList args, char[] buf)
929         {
930             append (level, Format.vprint (buf, fmt, types, args));
931         }
932 
933         /***********************************************************************
934 
935                 See if the provided Logger name is a parent of this one. Note
936                 that each Logger name has a '.' appended to the end, such that
937                 name segments will not partially match.
938 
939         ***********************************************************************/
940 
941         private final bool isChildOf (const(char[]) candidate)
942         {
943                 auto len = candidate.length;
944 
945                 // possible parent if length is shorter
946                 if (len < name_.length)
947                     // does the prefix match? Note we append a "." to each
948                     // (the root is a parent of everything)
949                     return (len is 0 ||
950                             memcmp (&candidate[0], &name_[0], len) is 0);
951                 return false;
952         }
953 
954         /***********************************************************************
955 
956                 See if the provided Logger is a better match as a parent of
957                 this one. This is used to restructure the hierarchy when a
958                 new logger instance is introduced
959 
960         ***********************************************************************/
961 
962         private final bool isCloserAncestor (Logger other)
963         {
964                 auto name = other.name_;
965                 if (isChildOf (name))
966                     // is this a better (longer) match than prior parent?
967                     if ((parent is null) || (name.length >= parent.name_.length))
968                          return true;
969                 return false;
970         }
971 }
972 
973 /*******************************************************************************
974 
975         The Logger hierarchy implementation. We keep a reference to each
976         logger in a hash-table for convenient lookup purposes, plus keep
977         each logger linked to the others in an ordered group. Ordering
978         places shortest names at the head and longest ones at the tail,
979         making the job of identifying ancestors easier in an orderly
980         fashion. For example, when propagating levels across descendents
981         it would be a mistake to propagate to a child before all of its
982         ancestors were taken care of.
983 
984 *******************************************************************************/
985 
986 private class Hierarchy : Logger.Context
987 {
988         private Logger                  root_;
989         private const(char)[]           name_,
990                                         address_;
991         private Logger.Context          context_;
992         private Logger[char[]]          loggers;
993 
994 
995         /***********************************************************************
996 
997                 Construct a hierarchy with the given name.
998 
999         ***********************************************************************/
1000 
1001         this (const(char[]) name)
1002         {
1003                 name_ = name;
1004                 address_ = "network";
1005 
1006                 // insert a root node; the root has an empty name
1007                 root_ = new Logger (this, "");
1008                 context_ = this;
1009         }
1010 
1011         /**********************************************************************
1012 
1013         **********************************************************************/
1014 
1015         final const const(char)[] label ()
1016         {
1017                 return "";
1018         }
1019 
1020         /**********************************************************************
1021 
1022 
1023         **********************************************************************/
1024 
1025         final const bool enabled (Level level, Level test)
1026         {
1027                 return test >= level;
1028         }
1029 
1030         /**********************************************************************
1031 
1032                 Return the name of this Hierarchy
1033 
1034         **********************************************************************/
1035 
1036         @property final const const(char)[] name ()
1037         {
1038                 return name_;
1039         }
1040 
1041         /**********************************************************************
1042 
1043                 Set the name of this Hierarchy
1044 
1045         **********************************************************************/
1046 
1047         @property final void name (const(char[]) name)
1048         {
1049                 name_ = name;
1050         }
1051 
1052         /**********************************************************************
1053 
1054                 Return the address of this Hierarchy. This is typically
1055                 attached when sending events to remote monitors.
1056 
1057         **********************************************************************/
1058 
1059         @property final const const(char)[] address ()
1060         {
1061                 return address_;
1062         }
1063 
1064         /**********************************************************************
1065 
1066                 Set the address of this Hierarchy. The address is attached
1067                 used when sending events to remote monitors.
1068 
1069         **********************************************************************/
1070 
1071         @property final void address (const(char[]) address)
1072         {
1073                 address_ = address;
1074         }
1075 
1076         /**********************************************************************
1077 
1078                 Return the diagnostic context.  Useful for setting an
1079                 override logging level.
1080 
1081         **********************************************************************/
1082 
1083         @property final Logger.Context context ()
1084         {
1085         	return context_;
1086         }
1087 
1088         /**********************************************************************
1089 
1090                 Set the diagnostic context.  Not usually necessary, as a
1091                 default was created.  Useful when you need to provide a
1092                 different implementation, such as a ThreadLocal variant.
1093 
1094         **********************************************************************/
1095 
1096         @property final void context (Logger.Context context)
1097         {
1098         	context_ = context;
1099         }
1100 
1101         /***********************************************************************
1102 
1103                 Return the root node.
1104 
1105         ***********************************************************************/
1106 
1107         @property final Logger root ()
1108         {
1109                 return root_;
1110         }
1111 
1112         /***********************************************************************
1113 
1114                 Return the instance of a Logger with the provided label. If
1115                 the instance does not exist, it is created at this time.
1116 
1117                 Note that an empty label is considered illegal, and will be
1118                 ignored.
1119 
1120         ***********************************************************************/
1121 
1122         final Logger lookup (const(char[]) label)
1123         {
1124                 if (label.length)
1125                     return inject (label, (const(char[]) name)
1126                                           {return new Logger (this, name);});
1127                 return null;
1128         }
1129 
1130         /***********************************************************************
1131 
1132                 traverse the set of configured loggers
1133 
1134         ***********************************************************************/
1135 
1136         final int opApply (scope int delegate(ref Logger) dg)
1137         {
1138                 int ret;
1139 
1140                 for (auto log=root; log; log = log.next)
1141                      if ((ret = dg(log)) != 0)
1142                           break;
1143                 return ret;
1144         }
1145 
1146         /***********************************************************************
1147 
1148                 Return the instance of a Logger with the provided label. If
1149                 the instance does not exist, it is created at this time.
1150 
1151         ***********************************************************************/
1152 
1153         private Logger inject (const(char[]) label, scope Logger delegate(const(char[]) name) dg)
1154         {
1155                 synchronized(this)
1156                 {
1157                     // try not to allocate unless you really need to
1158                     char[255] stack_buffer;
1159                     char[] buffer = stack_buffer;
1160 
1161                     if (buffer.length < label.length + 1)
1162                         buffer.length = label.length + 1;
1163 
1164                     buffer[0 .. label.length] = label[];
1165                     buffer[label.length] = '.';
1166 
1167                     auto name = buffer[0 .. label.length + 1]; 
1168                     auto l = name in loggers;
1169 
1170                     if (l is null)
1171                        {
1172                        // don't use the stack allocated buffer
1173                        if (name.ptr is stack_buffer.ptr)
1174                            name = name.dup;
1175                        // create a new logger
1176                        auto li = dg(name);
1177                        l = &li;
1178 
1179                        // insert into linked list
1180                        insert (li);
1181 
1182                        // look for and adjust children. Don't force 
1183                        // property inheritance on existing loggers
1184                        update (li);
1185 
1186                        // insert into map
1187                        loggers [name.idup] = li;
1188                        }
1189 
1190                     return *l;
1191                 }
1192         }
1193 
1194         /***********************************************************************
1195 
1196                 Loggers are maintained in a sorted linked-list. The order
1197                 is maintained such that the shortest name is at the root,
1198                 and the longest at the tail.
1199 
1200                 This is done so that updateLoggers() will always have a
1201                 known environment to manipulate, making it much faster.
1202 
1203         ***********************************************************************/
1204 
1205         private void insert (Logger l)
1206         {
1207                 Logger prev,
1208                        curr = root;
1209 
1210                 while (curr)
1211                       {
1212                       // insert here if the new name is shorter
1213                       if (l.name.length < curr.name.length)
1214                           if (prev is null)
1215                               throw new IllegalElementException ("invalid hierarchy");
1216                           else
1217                              {
1218                              l.next = prev.next;
1219                              prev.next = l;
1220                              return;
1221                              }
1222                       else
1223                          // find best match for parent of new entry
1224                          // and inherit relevant properties (level, etc)
1225                          propagate (l, curr, true);
1226 
1227                       // remember where insertion point should be
1228                       prev = curr;
1229                       curr = curr.next;
1230                       }
1231 
1232                 // add to tail
1233                 prev.next = l;
1234         }
1235 
1236         /***********************************************************************
1237 
1238                 Propagate hierarchical changes across known loggers.
1239                 This includes changes in the hierarchy itself, and to
1240                 the various settings of child loggers with respect to
1241                 their parent(s).
1242 
1243         ***********************************************************************/
1244 
1245         private void update (Logger changed, bool force=false)
1246         {
1247                 foreach (logger; this)
1248                          propagate (logger, changed, force);
1249         }
1250 
1251         /***********************************************************************
1252 
1253                 Propagate changes in the hierarchy downward to child Loggers.
1254                 Note that while 'parent' is always changed, the adjustment of
1255                 'level' is selectable.
1256 
1257         ***********************************************************************/
1258 
1259         private void propagate (Logger logger, Logger changed, bool force=false)
1260         {
1261                 // is the changed instance a better match for our parent?
1262                 if (logger.isCloserAncestor (changed))
1263                    {
1264                    // update parent (might actually be current parent)
1265                    logger.parent = changed;
1266 
1267                    // if we don't have an explicit level set, inherit it
1268                    // Be careful to avoid recursion, or other overhead
1269                    if (force)
1270                        logger.level_ = changed.level();
1271                    }
1272         }
1273 }
1274 
1275 
1276 
1277 /*******************************************************************************
1278 
1279         Contains all information about a logging event, and is passed around
1280         between methods once it has been determined that the invoking logger
1281         is enabled for output.
1282 
1283         Note that Event instances are maintained in a freelist rather than
1284         being allocated each time, and they include a scratchpad area for
1285         EventLayout formatters to use.
1286 
1287 *******************************************************************************/
1288 
1289 package struct LogEvent
1290 {
1291         private const(char)[]   msg_,
1292                                 name_;
1293         private Time            time_;
1294         private Level           level_;
1295         private Hierarchy       host_;
1296 
1297         /***********************************************************************
1298 
1299                 Set the various attributes of this event.
1300 
1301         ***********************************************************************/
1302 
1303         void set (Hierarchy host, Level level, const(char[]) msg, const(char[]) name)
1304         {
1305                 time_ = Log.time;
1306                 level_ = level;
1307                 host_ = host;
1308                 name_ = name;
1309                 msg_ = msg;
1310         }
1311 
1312         /***********************************************************************
1313 
1314                 Return the message attached to this event.
1315 
1316         ***********************************************************************/
1317 
1318         const const(char)[] toString ()
1319         {
1320                 return msg_;
1321         }
1322 
1323         /***********************************************************************
1324 
1325                 Return the name of the logger which produced this event
1326 
1327         ***********************************************************************/
1328 
1329         @property const const(char)[] name ()
1330         {
1331                 return name_;
1332         }
1333 
1334         /***********************************************************************
1335 
1336                 Return the logger level of this event.
1337 
1338         ***********************************************************************/
1339 
1340         @property const Level level ()
1341         {
1342                 return level_;
1343         }
1344 
1345         /***********************************************************************
1346 
1347                 Return the hierarchy where the event was produced from
1348 
1349         ***********************************************************************/
1350 
1351         @property Hierarchy host ()
1352         {
1353                 return host_;
1354         }
1355 
1356         /***********************************************************************
1357 
1358                 Return the time this event was produced, relative to the
1359                 start of this executable
1360 
1361         ***********************************************************************/
1362 
1363         @property const TimeSpan span ()
1364         {
1365                 return time_ - Log.beginTime;
1366         }
1367 
1368         /***********************************************************************
1369 
1370                 Return the time this event was produced relative to Epoch
1371 
1372         ***********************************************************************/
1373 
1374         @property const const(Time) time ()
1375         {
1376                 return time_;
1377         }
1378 
1379         /***********************************************************************
1380 
1381                 Return time when the executable started
1382 
1383         ***********************************************************************/
1384 
1385         @property const(Time) started ()
1386         {
1387                 return Log.beginTime;
1388         }
1389 
1390         /***********************************************************************
1391 
1392                 Return the logger level name of this event.
1393 
1394         ***********************************************************************/
1395 
1396         @property const(char)[] levelName ()
1397         {
1398                 return Log.LevelNames[level_];
1399         }
1400 
1401         /***********************************************************************
1402 
1403                 Convert a time value (in milliseconds) to ascii
1404 
1405         ***********************************************************************/
1406 
1407         static char[] toMilli (char[] s, TimeSpan time)
1408         {
1409                 assert (s.length > 0);
1410                 long ms = time.millis;
1411 
1412                 size_t len = s.length;
1413                 do {
1414                    s[--len] = cast(char)(ms % 10 + '0');
1415                    ms /= 10;
1416                    } while (ms && len);
1417                 return s[len..s.length];
1418         }
1419 }
1420 
1421 
1422 /*******************************************************************************
1423 
1424         Base class for all Appenders. These objects are responsible for
1425         emitting messages sent to a particular logger. There may be more
1426         than one appender attached to any logger. The actual message is
1427         constructed by another class known as an EventLayout.
1428 
1429 *******************************************************************************/
1430 
1431 public class Appender
1432 {
1433         alias int Mask;
1434 
1435         private Appender        next_;
1436         private Level           level_;
1437         private Layout          layout_;
1438         private static __gshared Layout   generic;
1439 
1440         /***********************************************************************
1441 
1442                 Interface for all logging layout instances
1443 
1444                 Implement this method to perform the formatting of
1445                 message content.
1446 
1447         ***********************************************************************/
1448 
1449         interface Layout
1450         {
1451                 void format (LogEvent event, scope size_t delegate(const(void)[]) dg);
1452         }
1453 
1454         /***********************************************************************
1455 
1456                 Return the mask used to identify this Appender. The mask
1457                 is used to figure out whether an appender has already been
1458                 invoked for a particular logger.
1459 
1460         ***********************************************************************/
1461 
1462         @property abstract const Mask mask ();
1463 
1464         /***********************************************************************
1465 
1466                 Return the name of this Appender.
1467 
1468         ***********************************************************************/
1469 
1470         @property abstract const const(char)[] name ();
1471 
1472         /***********************************************************************
1473 
1474                 Append a message to the output.
1475 
1476         ***********************************************************************/
1477 
1478         abstract void append (LogEvent event);
1479 
1480         /***********************************************************************
1481 
1482               Create an Appender and default its layout to LayoutSimple.
1483 
1484         ***********************************************************************/
1485 
1486         this ()
1487         {
1488                 layout_ = generic;
1489         }
1490 
1491         /***********************************************************************
1492 
1493               Create an Appender and default its layout to LayoutSimple.
1494 
1495         ***********************************************************************/
1496 
1497         shared static this ()
1498         {
1499                 generic = new LayoutTimer;
1500         }
1501 
1502         /***********************************************************************
1503 
1504                 Return the current Level setting
1505 
1506         ***********************************************************************/
1507 
1508         @property final Level level ()
1509         {
1510                 return level_;
1511         }
1512 
1513         /***********************************************************************
1514 
1515                 Return the current Level setting
1516 
1517         ***********************************************************************/
1518 
1519         @property final Appender level (Level l)
1520         {
1521                 level_ = l;
1522                 return this;
1523         }
1524 
1525         /***********************************************************************
1526 
1527                 Static method to return a mask for identifying the Appender.
1528                 Each Appender class should have a unique fingerprint so that
1529                 we can figure out which ones have been invoked for a given
1530                 event. A bitmask is a simple an efficient way to do that.
1531 
1532         ***********************************************************************/
1533 
1534         protected Mask register (const(char)[] tag)
1535         {
1536                 static Mask mask = 1;
1537                 static Mask[immutable(char)[]] registry;
1538 
1539                 Mask* p = tag in registry;
1540                 if (p)
1541                     return *p;
1542                 else
1543                    {
1544                    auto ret = mask;
1545                    registry [tag] = mask;
1546 
1547                    if (mask < 0)
1548                        throw new IllegalArgumentException ("too many unique registrations");
1549 
1550                    mask <<= 1;
1551                    return ret;
1552                    }
1553         }
1554 
1555         /***********************************************************************
1556 
1557                 Set the current layout to be that of the argument, or the
1558                 generic layout where the argument is null
1559 
1560         ***********************************************************************/
1561 
1562         @property void layout (Layout how)
1563         {
1564                 layout_ = how ? how : generic;
1565         }
1566 
1567         /***********************************************************************
1568 
1569                 Return the current Layout
1570 
1571         ***********************************************************************/
1572 
1573         @property Layout layout ()
1574         {
1575                 return layout_;
1576         }
1577 
1578         /***********************************************************************
1579 
1580                 Attach another appender to this one
1581 
1582         ***********************************************************************/
1583 
1584         @property void next (Appender appender)
1585         {
1586                 next_ = appender;
1587         }
1588 
1589         /***********************************************************************
1590 
1591                 Return the next appender in the list
1592 
1593         ***********************************************************************/
1594 
1595         @property Appender next ()
1596         {
1597                 return next_;
1598         }
1599 
1600         /***********************************************************************
1601 
1602                 Close this appender. This would be used for file, sockets,
1603                 and such like.
1604 
1605         ***********************************************************************/
1606 
1607         void close ()
1608         {
1609         }
1610 }
1611 
1612 
1613 /*******************************************************************************
1614 
1615         An appender that does nothing. This is useful for cutting and
1616         pasting, and for benchmarking the tango.log environment.
1617 
1618 *******************************************************************************/
1619 
1620 public class AppendNull : Appender
1621 {
1622         private Mask mask_;
1623 
1624         /***********************************************************************
1625 
1626                 Create with the given Layout
1627 
1628         ***********************************************************************/
1629 
1630         this (Layout how = null)
1631         {
1632                 mask_ = register (name);
1633                 layout (how);
1634         }
1635 
1636         /***********************************************************************
1637 
1638                 Return the fingerprint for this class
1639 
1640         ***********************************************************************/
1641 
1642         @property override final const Mask mask ()
1643         {
1644                 return mask_;
1645         }
1646 
1647         /***********************************************************************
1648 
1649                 Return the name of this class
1650 
1651         ***********************************************************************/
1652 
1653         @property override final const const(char)[] name ()
1654         {
1655                 return this.classinfo.name;
1656         }
1657 
1658         /***********************************************************************
1659 
1660                 Append an event to the output.
1661 
1662         ***********************************************************************/
1663 
1664         override final void append (LogEvent event)
1665         {
1666                 layout.format (event, (const(void)[]){return cast(size_t) 0;});
1667         }
1668 }
1669 
1670 
1671 /*******************************************************************************
1672 
1673         Append to a configured OutputStream
1674 
1675 *******************************************************************************/
1676 
1677 public class AppendStream : Appender
1678 {
1679         private Mask            mask_;
1680         private bool            flush_;
1681         private OutputStream    stream_;
1682 
1683         /***********************************************************************
1684 
1685                 Create with the given stream and layout
1686 
1687         ***********************************************************************/
1688 
1689         this (OutputStream stream, bool flush = false, Appender.Layout how = null)
1690         {
1691                 assert (stream);
1692 
1693                 mask_ = register (name);
1694                 stream_ = stream;
1695                 flush_ = flush;
1696                 layout (how);
1697         }
1698 
1699         /***********************************************************************
1700 
1701                 Return the fingerprint for this class
1702 
1703         ***********************************************************************/
1704 
1705         @property override final const Mask mask ()
1706         {
1707                 return mask_;
1708         }
1709 
1710         /***********************************************************************
1711 
1712                 Return the name of this class
1713 
1714         ***********************************************************************/
1715 
1716         @property override const const(char)[] name ()
1717         {
1718                 return this.classinfo.name;
1719         }
1720 
1721         /***********************************************************************
1722 
1723                 Append an event to the output.
1724 
1725         ***********************************************************************/
1726 
1727         override final void append (LogEvent event)
1728         {
1729                 version(Win32)
1730                         immutable char[] Eol = "\r\n";
1731                    else
1732                        immutable char[] Eol = "\n";
1733 
1734                 synchronized (stream_)
1735                              {
1736                              layout.format (event, (const(void)[] content){return stream_.write(content);});
1737                              stream_.write (Eol);
1738                              if (flush_)
1739                                  stream_.flush();
1740                              }
1741         }
1742 }
1743 
1744 /*******************************************************************************
1745 
1746         A simple layout comprised only of time(ms), level, name, and message
1747 
1748 *******************************************************************************/
1749 
1750 public class LayoutTimer : Appender.Layout
1751 {
1752         /***********************************************************************
1753 
1754                 Subclasses should implement this method to perform the
1755                 formatting of the actual message content.
1756 
1757         ***********************************************************************/
1758 
1759         void format (LogEvent event, scope size_t delegate(const(void)[]) dg)
1760         {
1761                 char[20] tmp = void;
1762 
1763                 dg (event.toMilli (tmp, event.span));
1764                 dg (" ");
1765                 dg (event.levelName);
1766                 dg (" [");
1767                 dg (event.name);
1768                 dg ("] ");
1769                 dg (event.host.context.label);
1770                 dg ("- ");
1771                 dg (event.toString());
1772         }
1773 }
1774 
1775 
1776 /*******************************************************************************
1777 
1778 *******************************************************************************/
1779 
1780 debug (Log)
1781 {
1782         import tango.io.Console;
1783 
1784         void main()
1785         {
1786                 Log.config (Cerr.stream);
1787                 auto log = Log.lookup ("fu.bar");
1788                 log.level = log.Trace;
1789                 // traditional usage
1790                 log.trace ("hello {}", "world");
1791 
1792                 char[100] buf;
1793                 log (log.Trace, log.format(buf, "hello {}", "world"));
1794 
1795                 // formatted output
1796 /*                /
1797                 auto format = Log.format;
1798                 log.info (format ("blah{}", 1));
1799 
1800                 // snapshot
1801                 auto snap = Log.snapshot (log, Level.Error);
1802                 snap.format ("arg{}; ", 1);
1803                 snap.format ("arg{}; ", 2);
1804                 //log.trace (snap.format ("error! arg{}", 3));
1805                 snap.flush;
1806 */
1807         }
1808 }