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