MagickCore  7.0.9
log.c
Go to the documentation of this file.
1 /*
2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3 % %
4 % %
5 % %
6 % L OOO GGGG %
7 % L O O G %
8 % L O O G GG %
9 % L O O G G %
10 % LLLLL OOO GGG %
11 % %
12 % %
13 % MagickCore Log Events %
14 % %
15 % Software Design %
16 % Cristy %
17 % September 2002 %
18 % %
19 % %
20 % Copyright 1999-2019 ImageMagick Studio LLC, a non-profit organization %
21 % dedicated to making software imaging solutions freely available. %
22 % %
23 % You may not use this file except in compliance with the License. You may %
24 % obtain a copy of the License at %
25 % %
26 % https://imagemagick.org/script/license.php %
27 % %
28 % Unless required by applicable law or agreed to in writing, software %
29 % distributed under the License is distributed on an "AS IS" BASIS, %
30 % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
31 % See the License for the specific language governing permissions and %
32 % limitations under the License. %
33 % %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35 %
36 %
37 */
38 
39 /*
40  Include declarations.
41 */
42 #include "MagickCore/studio.h"
43 #include "MagickCore/blob.h"
44 #include "MagickCore/client.h"
45 #include "MagickCore/configure.h"
47 #include "MagickCore/exception.h"
49 #include "MagickCore/linked-list.h"
50 #include "MagickCore/log.h"
51 #include "MagickCore/log-private.h"
52 #include "MagickCore/memory_.h"
55 #include "MagickCore/option.h"
56 #include "MagickCore/semaphore.h"
57 #include "MagickCore/timer.h"
58 #include "MagickCore/string_.h"
60 #include "MagickCore/thread_.h"
63 #include "MagickCore/token.h"
64 #include "MagickCore/utility.h"
66 #include "MagickCore/version.h"
67 #include "MagickCore/xml-tree.h"
69 
70 /*
71  Define declarations.
72 */
73 #define LogFilename "log.xml"
74 
75 /*
76  Typedef declarations.
77 */
78 typedef enum
79 {
80  UndefinedHandler = 0x0000,
81  NoHandler = 0x0000,
82  ConsoleHandler = 0x0001,
83  StdoutHandler = 0x0002,
84  StderrHandler = 0x0004,
85  FileHandler = 0x0008,
86  DebugHandler = 0x0010,
87  EventHandler = 0x0020,
88  MethodHandler = 0x0040
90 
91 typedef struct _EventInfo
92 {
93  char
94  *name;
95 
98 } EventInfo;
99 
100 typedef struct _HandlerInfo
101 {
102  const char
103  name[10];
104 
107 } HandlerInfo;
108 
109 struct _LogInfo
110 {
113 
116 
117  char
119  *name,
120  *filename,
121  *format;
122 
123  size_t
125  limit;
126 
127  FILE
129 
130  size_t
132 
135  stealth;
136 
137  TimerInfo
139 
142 
145 
146  size_t
148 };
149 
150 typedef struct _LogMapInfo
151 {
152  const LogEventType
154 
155  const LogHandlerType
157 
158  const char
160  *format;
161 } LogMapInfo;
162 
163 /*
164  Static declarations.
165 */
166 static const HandlerInfo
168  {
169  { "Console", ConsoleHandler },
170  { "Debug", DebugHandler },
171  { "Event", EventHandler },
172  { "File", FileHandler },
173  { "None", NoHandler },
174  { "Stderr", StderrHandler },
175  { "Stdout", StdoutHandler },
176  { "", UndefinedHandler },
177  { "", UndefinedHandler },
178  { "", UndefinedHandler },
179  { "", UndefinedHandler },
180  { "", UndefinedHandler },
181  { "", UndefinedHandler },
182  { "", UndefinedHandler },
183  { "", UndefinedHandler },
184  { "", UndefinedHandler },
185  { "", UndefinedHandler },
186  { "", UndefinedHandler },
187  { "", UndefinedHandler },
188  { "", UndefinedHandler },
189  { "", UndefinedHandler },
190  { "", UndefinedHandler },
191  { "", UndefinedHandler },
192  { "", UndefinedHandler },
193  { "", UndefinedHandler },
194  { "", UndefinedHandler },
195  { "", UndefinedHandler },
196  { "", UndefinedHandler },
197  { "", UndefinedHandler },
198  { "", UndefinedHandler },
199  { "", UndefinedHandler },
200  { "", UndefinedHandler }
201  };
202 
203 static const LogMapInfo
204  LogMap[] =
205  {
206  { NoEvents, ConsoleHandler, "Magick-%g.log",
207  "%t %r %u %v %d %c[%p]: %m/%f/%l/%d\\n %e" }
208  };
209 
210 static char
212 
213 static LinkedListInfo
215 
216 static MagickBooleanType
218 
219 static SemaphoreInfo
221 
222 /*
223  Forward declarations.
224 */
225 static LogHandlerType
226  ParseLogHandlers(const char *) magick_attribute((__pure__));
227 
228 static LogInfo
229  *GetLogInfo(const char *,ExceptionInfo *);
230 
231 static MagickBooleanType
232  IsLogCacheInstantiated(ExceptionInfo *) magick_attribute((__pure__)),
233  LoadLogCache(LinkedListInfo *,const char *,const char *,const size_t,
234  ExceptionInfo *);
235 
236 /*
237 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
238 % %
239 % %
240 % %
241 % A c q u i r e L o g C a c h e %
242 % %
243 % %
244 % %
245 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
246 %
247 % AcquireLogCache() caches one or more log configurations which provides a
248 % mapping between log attributes and log name.
249 %
250 % The format of the AcquireLogCache method is:
251 %
252 % LinkedListInfo *AcquireLogCache(const char *filename,
253 % ExceptionInfo *exception)
254 %
255 % A description of each parameter follows:
256 %
257 % o filename: the log configuration filename.
258 %
259 % o exception: return any errors or warnings in this structure.
260 %
261 */
262 static LinkedListInfo *AcquireLogCache(const char *filename,
263  ExceptionInfo *exception)
264 {
265  LinkedListInfo
266  *cache;
267 
269  status;
270 
271  register ssize_t
272  i;
273 
274  /*
275  Load external log map.
276  */
277  cache=NewLinkedList(0);
278  status=MagickTrue;
279 #if !defined(MAGICKCORE_ZERO_CONFIGURATION_SUPPORT)
280  {
281  const StringInfo
282  *option;
283 
284  LinkedListInfo
285  *options;
286 
287  options=GetConfigureOptions(filename,exception);
288  option=(const StringInfo *) GetNextValueInLinkedList(options);
289  while (option != (const StringInfo *) NULL)
290  {
291  status&=LoadLogCache(cache,(const char *) GetStringInfoDatum(option),
292  GetStringInfoPath(option),0,exception);
293  option=(const StringInfo *) GetNextValueInLinkedList(options);
294  }
295  options=DestroyConfigureOptions(options);
296  }
297 #endif
298  /*
299  Load built-in log map.
300  */
301  for (i=0; i < (ssize_t) (sizeof(LogMap)/sizeof(*LogMap)); i++)
302  {
303  LogInfo
304  *log_info;
305 
306  register const LogMapInfo
307  *p;
308 
309  p=LogMap+i;
310  log_info=(LogInfo *) AcquireMagickMemory(sizeof(*log_info));
311  if (log_info == (LogInfo *) NULL)
312  {
313  (void) ThrowMagickException(exception,GetMagickModule(),
314  ResourceLimitError,"MemoryAllocationFailed","`%s'",p->filename);
315  continue;
316  }
317  (void) memset(log_info,0,sizeof(*log_info));
318  log_info->path=ConstantString("[built-in]");
319  GetTimerInfo((TimerInfo *) &log_info->timer);
320  log_info->event_mask=p->event_mask;
321  log_info->handler_mask=p->handler_mask;
322  log_info->filename=ConstantString(p->filename);
323  log_info->format=ConstantString(p->format);
324  log_info->signature=MagickCoreSignature;
325  status&=AppendValueToLinkedList(cache,log_info);
326  if (status == MagickFalse)
327  (void) ThrowMagickException(exception,GetMagickModule(),
328  ResourceLimitError,"MemoryAllocationFailed","`%s'",log_info->name);
329  }
330  return(cache);
331 }
332 
333 /*
334 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
335 % %
336 % %
337 % %
338 % C l o s e M a g i c k L o g %
339 % %
340 % %
341 % %
342 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
343 %
344 % CloseMagickLog() closes the Magick log.
345 %
346 % The format of the CloseMagickLog method is:
347 %
348 % CloseMagickLog(void)
349 %
350 */
352 {
354  *exception;
355 
356  LogInfo
357  *log_info;
358 
359  if (IsEventLogging() == MagickFalse)
360  return;
361  exception=AcquireExceptionInfo();
362  log_info=GetLogInfo("*",exception);
363  exception=DestroyExceptionInfo(exception);
365  if (log_info->file != (FILE *) NULL)
366  {
367  (void) FormatLocaleFile(log_info->file,"</log>\n");
368  (void) fclose(log_info->file);
369  log_info->file=(FILE *) NULL;
370  }
372 }
373 
374 /*
375 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
376 % %
377 % %
378 % %
379 + G e t L o g I n f o %
380 % %
381 % %
382 % %
383 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
384 %
385 % GetLogInfo() searches the log list for the specified name and if found
386 % returns attributes for that log.
387 %
388 % The format of the GetLogInfo method is:
389 %
390 % LogInfo *GetLogInfo(const char *name,ExceptionInfo *exception)
391 %
392 % A description of each parameter follows:
393 %
394 % o name: the log name.
395 %
396 % o exception: return any errors or warnings in this structure.
397 %
398 */
399 static LogInfo *GetLogInfo(const char *name,ExceptionInfo *exception)
400 {
401  register LogInfo
402  *p;
403 
404  assert(exception != (ExceptionInfo *) NULL);
405  if (IsLogCacheInstantiated(exception) == MagickFalse)
406  return((LogInfo *) NULL);
407  /*
408  Search for log tag.
409  */
413  if ((name == (const char *) NULL) || (LocaleCompare(name,"*") == 0))
414  {
416  return(p);
417  }
418  while (p != (LogInfo *) NULL)
419  {
420  if (LocaleCompare(name,p->name) == 0)
421  break;
423  }
424  if (p != (LogInfo *) NULL)
428  return(p);
429 }
430 
431 /*
432 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
433 % %
434 % %
435 % %
436 % G e t L o g I n f o L i s t %
437 % %
438 % %
439 % %
440 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
441 %
442 % GetLogInfoList() returns any logs that match the specified pattern.
443 %
444 % The format of the GetLogInfoList function is:
445 %
446 % const LogInfo **GetLogInfoList(const char *pattern,
447 % size_t *number_preferences,ExceptionInfo *exception)
448 %
449 % A description of each parameter follows:
450 %
451 % o pattern: Specifies a pointer to a text string containing a pattern.
452 %
453 % o number_preferences: This integer returns the number of logs in the list.
454 %
455 % o exception: return any errors or warnings in this structure.
456 %
457 */
458 #if defined(__cplusplus) || defined(c_plusplus)
459 extern "C" {
460 #endif
461 
462 static int LogInfoCompare(const void *x,const void *y)
463 {
464  const LogInfo
465  **p,
466  **q;
467 
468  p=(const LogInfo **) x,
469  q=(const LogInfo **) y;
470  if (LocaleCompare((*p)->path,(*q)->path) == 0)
471  return(LocaleCompare((*p)->name,(*q)->name));
472  return(LocaleCompare((*p)->path,(*q)->path));
473 }
474 
475 #if defined(__cplusplus) || defined(c_plusplus)
476 }
477 #endif
478 
479 MagickExport const LogInfo **GetLogInfoList(const char *pattern,
480  size_t *number_preferences,ExceptionInfo *exception)
481 {
482  const LogInfo
483  **preferences;
484 
485  register const LogInfo
486  *p;
487 
488  register ssize_t
489  i;
490 
491  /*
492  Allocate log list.
493  */
494  assert(pattern != (char *) NULL);
495  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
496  assert(number_preferences != (size_t *) NULL);
497  *number_preferences=0;
498  p=GetLogInfo("*",exception);
499  if (p == (const LogInfo *) NULL)
500  return((const LogInfo **) NULL);
501  preferences=(const LogInfo **) AcquireQuantumMemory((size_t)
502  GetNumberOfElementsInLinkedList(log_cache)+1UL,sizeof(*preferences));
503  if (preferences == (const LogInfo **) NULL)
504  return((const LogInfo **) NULL);
505  /*
506  Generate log list.
507  */
511  for (i=0; p != (const LogInfo *) NULL; )
512  {
513  if ((p->stealth == MagickFalse) &&
514  (GlobExpression(p->name,pattern,MagickFalse) != MagickFalse))
515  preferences[i++]=p;
517  }
519  qsort((void *) preferences,(size_t) i,sizeof(*preferences),LogInfoCompare);
520  preferences[i]=(LogInfo *) NULL;
521  *number_preferences=(size_t) i;
522  return(preferences);
523 }
524 
525 /*
526 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
527 % %
528 % %
529 % %
530 % G e t L o g L i s t %
531 % %
532 % %
533 % %
534 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
535 %
536 % GetLogList() returns any logs that match the specified pattern.
537 %
538 % The format of the GetLogList function is:
539 %
540 % char **GetLogList(const char *pattern,size_t *number_preferences,
541 % ExceptionInfo *exception)
542 %
543 % A description of each parameter follows:
544 %
545 % o pattern: Specifies a pointer to a text string containing a pattern.
546 %
547 % o number_preferences: This integer returns the number of logs in the list.
548 %
549 % o exception: return any errors or warnings in this structure.
550 %
551 */
552 
553 #if defined(__cplusplus) || defined(c_plusplus)
554 extern "C" {
555 #endif
556 
557 static int LogCompare(const void *x,const void *y)
558 {
559  register const char
560  **p,
561  **q;
562 
563  p=(const char **) x;
564  q=(const char **) y;
565  return(LocaleCompare(*p,*q));
566 }
567 
568 #if defined(__cplusplus) || defined(c_plusplus)
569 }
570 #endif
571 
572 MagickExport char **GetLogList(const char *pattern,size_t *number_preferences,
573  ExceptionInfo *exception)
574 {
575  char
576  **preferences;
577 
578  register const LogInfo
579  *p;
580 
581  register ssize_t
582  i;
583 
584  /*
585  Allocate log list.
586  */
587  assert(pattern != (char *) NULL);
588  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
589  assert(number_preferences != (size_t *) NULL);
590  *number_preferences=0;
591  p=GetLogInfo("*",exception);
592  if (p == (const LogInfo *) NULL)
593  return((char **) NULL);
594  preferences=(char **) AcquireQuantumMemory((size_t)
595  GetNumberOfElementsInLinkedList(log_cache)+1UL,sizeof(*preferences));
596  if (preferences == (char **) NULL)
597  return((char **) NULL);
598  /*
599  Generate log list.
600  */
604  for (i=0; p != (const LogInfo *) NULL; )
605  {
606  if ((p->stealth == MagickFalse) &&
607  (GlobExpression(p->name,pattern,MagickFalse) != MagickFalse))
608  preferences[i++]=ConstantString(p->name);
610  }
612  qsort((void *) preferences,(size_t) i,sizeof(*preferences),LogCompare);
613  preferences[i]=(char *) NULL;
614  *number_preferences=(size_t) i;
615  return(preferences);
616 }
617 
618 /*
619 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
620 % %
621 % %
622 % %
623 % G e t L o g N a m e %
624 % %
625 % %
626 % %
627 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
628 %
629 % GetLogName() returns the current log name.
630 %
631 % The format of the GetLogName method is:
632 %
633 % const char *GetLogName(void)
634 %
635 */
636 MagickExport const char *GetLogName(void)
637 {
638  return(log_name);
639 }
640 
641 /*
642 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
643 % %
644 % %
645 % %
646 + I s L o g C a c h e I n s t a n t i a t e d %
647 % %
648 % %
649 % %
650 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
651 %
652 % IsLogCacheInstantiated() determines if the log list is instantiated. If
653 % not, it instantiates the list and returns it.
654 %
655 % The format of the IsLogInstantiated method is:
656 %
657 % MagickBooleanType IsLogCacheInstantiated(ExceptionInfo *exception)
658 %
659 % A description of each parameter follows.
660 %
661 % o exception: return any errors or warnings in this structure.
662 %
663 */
664 
665 static inline void CheckEventLogging()
666 {
667  /*
668  Are we logging events?
669  */
672  else
673  {
674  LogInfo
675  *p;
676 
679  event_logging=(p != (LogInfo *) NULL) && (p->event_mask != NoEvents) ?
681  }
682 }
683 
685 {
686  if (log_cache == (LinkedListInfo *) NULL)
687  {
688  if (log_semaphore == (SemaphoreInfo *) NULL)
691  if (log_cache == (LinkedListInfo *) NULL)
692  {
693  log_cache=AcquireLogCache(LogFilename,exception);
695  }
697  }
698  return(log_cache != (LinkedListInfo *) NULL ? MagickTrue : MagickFalse);
699 }
700 
701 /*
702 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
703 % %
704 % %
705 % %
706 % I s E v e n t L o g g i n g %
707 % %
708 % %
709 % %
710 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
711 %
712 % IsEventLogging() returns MagickTrue if debug of events is enabled otherwise
713 % MagickFalse.
714 %
715 % The format of the IsEventLogging method is:
716 %
717 % MagickBooleanType IsEventLogging(void)
718 %
719 */
721 {
722  return(event_logging);
723 }
724 
725 /*
726 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
727 % %
728 % %
729 % %
730 % L i s t L o g I n f o %
731 % %
732 % %
733 % %
734 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
735 %
736 % ListLogInfo() lists the log info to a file.
737 %
738 % The format of the ListLogInfo method is:
739 %
740 % MagickBooleanType ListLogInfo(FILE *file,ExceptionInfo *exception)
741 %
742 % A description of each parameter follows.
743 %
744 % o file: An pointer to a FILE.
745 %
746 % o exception: return any errors or warnings in this structure.
747 %
748 */
750 {
751 #define MegabytesToBytes(value) ((MagickSizeType) (value)*1024*1024)
752 
753  const char
754  *path;
755 
756  const LogInfo
757  **log_info;
758 
759  register ssize_t
760  i;
761 
762  size_t
763  number_aliases;
764 
765  ssize_t
766  j;
767 
768  if (file == (const FILE *) NULL)
769  file=stdout;
770  log_info=GetLogInfoList("*",&number_aliases,exception);
771  if (log_info == (const LogInfo **) NULL)
772  return(MagickFalse);
773  j=0;
774  path=(const char *) NULL;
775  for (i=0; i < (ssize_t) number_aliases; i++)
776  {
777  if (log_info[i]->stealth != MagickFalse)
778  continue;
779  if ((path == (const char *) NULL) ||
780  (LocaleCompare(path,log_info[i]->path) != 0))
781  {
782  size_t
783  length;
784 
785  if (log_info[i]->path != (char *) NULL)
786  (void) FormatLocaleFile(file,"\nPath: %s\n\n",log_info[i]->path);
787  length=0;
788  for (j=0; j < (ssize_t) (8*sizeof(LogHandlerType)); j++)
789  {
790  size_t
791  mask;
792 
793  if (*LogHandlers[j].name == '\0')
794  break;
795  mask=1;
796  mask<<=j;
797  if ((log_info[i]->handler_mask & mask) != 0)
798  {
799  (void) FormatLocaleFile(file,"%s ",LogHandlers[j].name);
800  length+=strlen(LogHandlers[j].name);
801  }
802  }
803  for (j=(ssize_t) length; j <= 12; j++)
804  (void) FormatLocaleFile(file," ");
805  (void) FormatLocaleFile(file," Generations Limit Format\n");
806  (void) FormatLocaleFile(file,"-----------------------------------------"
807  "--------------------------------------\n");
808  }
809  path=log_info[i]->path;
810  if (log_info[i]->filename != (char *) NULL)
811  {
812  (void) FormatLocaleFile(file,"%s",log_info[i]->filename);
813  for (j=(ssize_t) strlen(log_info[i]->filename); j <= 16; j++)
814  (void) FormatLocaleFile(file," ");
815  }
816  (void) FormatLocaleFile(file,"%9g ",(double) log_info[i]->generations);
817  (void) FormatLocaleFile(file,"%8g ",(double) log_info[i]->limit);
818  if (log_info[i]->format != (char *) NULL)
819  (void) FormatLocaleFile(file,"%s",log_info[i]->format);
820  (void) FormatLocaleFile(file,"\n");
821  }
822  (void) fflush(file);
823  log_info=(const LogInfo **) RelinquishMagickMemory((void *) log_info);
824  return(MagickTrue);
825 }
826 
827 /*
828 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
829 % %
830 % %
831 % %
832 + L o g C o m p o n e n t G e n e s i s %
833 % %
834 % %
835 % %
836 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
837 %
838 % LogComponentGenesis() instantiates the log component.
839 %
840 % The format of the LogComponentGenesis method is:
841 %
842 % MagickBooleanType LogComponentGenesis(void)
843 %
844 */
846 {
848  *exception;
849 
850  if (log_semaphore == (SemaphoreInfo *) NULL)
852  exception=AcquireExceptionInfo();
853  (void) GetLogInfo("*",exception);
854  exception=DestroyExceptionInfo(exception);
855  return(MagickTrue);
856 }
857 
858 /*
859 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
860 % %
861 % %
862 % %
863 + L o g C o m p o n e n t T e r m i n u s %
864 % %
865 % %
866 % %
867 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
868 %
869 % LogComponentTerminus() destroys the logging component.
870 %
871 % The format of the LogComponentTerminus method is:
872 %
873 % LogComponentTerminus(void)
874 %
875 */
876 
877 static void *DestroyLogElement(void *log_info)
878 {
879  register LogInfo
880  *p;
881 
882  p=(LogInfo *) log_info;
883  if (p->file != (FILE *) NULL)
884  {
885  (void) FormatLocaleFile(p->file,"</log>\n");
886  (void) fclose(p->file);
887  p->file=(FILE *) NULL;
888  }
889  if (p->format != (char *) NULL)
890  p->format=DestroyString(p->format);
891  if (p->path != (char *) NULL)
892  p->path=DestroyString(p->path);
893  if (p->filename != (char *) NULL)
895  if (p->event_semaphore != (SemaphoreInfo *) NULL)
898  return((void *) NULL);
899 }
900 
902 {
903  if (log_semaphore == (SemaphoreInfo *) NULL)
906  if (log_cache != (LinkedListInfo *) NULL)
911 }
912 
913 /*
914 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
915 % %
916 % %
917 % %
918 % L o g M a g i c k E v e n t %
919 % %
920 % %
921 % %
922 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
923 %
924 % LogMagickEvent() logs an event as determined by the log configuration file.
925 % If an error occurs, MagickFalse is returned otherwise MagickTrue.
926 %
927 % The format of the LogMagickEvent method is:
928 %
929 % MagickBooleanType LogMagickEvent(const LogEventType type,
930 % const char *module,const char *function,const size_t line,
931 % const char *format,...)
932 %
933 % A description of each parameter follows:
934 %
935 % o type: the event type.
936 %
937 % o filename: the source module filename.
938 %
939 % o function: the function name.
940 %
941 % o line: the line number of the source module.
942 %
943 % o format: the output format.
944 %
945 */
946 static char *TranslateEvent(const char *module,const char *function,
947  const size_t line,const char *domain,const char *event)
948 {
949  char
950  *text;
951 
952  double
953  elapsed_time,
954  user_time;
955 
957  *exception;
958 
959  LogInfo
960  *log_info;
961 
962  register char
963  *q;
964 
965  register const char
966  *p;
967 
968  size_t
969  extent;
970 
971  time_t
972  seconds;
973 
974  exception=AcquireExceptionInfo();
975  log_info=(LogInfo *) GetLogInfo("*",exception);
976  exception=DestroyExceptionInfo(exception);
977  seconds=GetMagickTime();
978  elapsed_time=GetElapsedTime(&log_info->timer);
979  user_time=GetUserTime(&log_info->timer);
980  text=AcquireString(event);
981  if (log_info->format == (char *) NULL)
982  return(text);
983  extent=strlen(event)+MagickPathExtent;
984  if (LocaleCompare(log_info->format,"xml") == 0)
985  {
986  char
987  timestamp[MagickPathExtent];
988 
989  /*
990  Translate event in "XML" format.
991  */
992  (void) FormatMagickTime(seconds,extent,timestamp);
993  (void) FormatLocaleString(text,extent,
994  "<entry>\n"
995  " <timestamp>%s</timestamp>\n"
996  " <elapsed-time>%lu:%02lu.%06lu</elapsed-time>\n"
997  " <user-time>%0.3f</user-time>\n"
998  " <process-id>%.20g</process-id>\n"
999  " <thread-id>%.20g</thread-id>\n"
1000  " <module>%s</module>\n"
1001  " <function>%s</function>\n"
1002  " <line>%.20g</line>\n"
1003  " <domain>%s</domain>\n"
1004  " <event>%s</event>\n"
1005  "</entry>",timestamp,(unsigned long) (elapsed_time/60.0),
1006  (unsigned long) floor(fmod(elapsed_time,60.0)),(unsigned long)
1007  (1000000.0*(elapsed_time-floor(elapsed_time))+0.5),user_time,
1008  (double) getpid(),(double) GetMagickThreadSignature(),module,function,
1009  (double) line,domain,event);
1010  return(text);
1011  }
1012  /*
1013  Translate event in "human readable" format.
1014  */
1015  q=text;
1016  for (p=log_info->format; *p != '\0'; p++)
1017  {
1018  *q='\0';
1019  if ((size_t) (q-text+MagickPathExtent) >= extent)
1020  {
1021  extent+=MagickPathExtent;
1022  text=(char *) ResizeQuantumMemory(text,extent+MagickPathExtent,
1023  sizeof(*text));
1024  if (text == (char *) NULL)
1025  return((char *) NULL);
1026  q=text+strlen(text);
1027  }
1028  /*
1029  The format of the log is defined by embedding special format characters:
1030 
1031  %c client name
1032  %d domain
1033  %e event
1034  %f function
1035  %g generation
1036  %i thread id
1037  %l line
1038  %m module
1039  %n log name
1040  %p process id
1041  %r real CPU time
1042  %t wall clock time
1043  %u user CPU time
1044  %v version
1045  %% percent sign
1046  \n newline
1047  \r carriage return
1048  */
1049  if ((*p == '\\') && (*(p+1) == 'r'))
1050  {
1051  *q++='\r';
1052  p++;
1053  continue;
1054  }
1055  if ((*p == '\\') && (*(p+1) == 'n'))
1056  {
1057  *q++='\n';
1058  p++;
1059  continue;
1060  }
1061  if (*p != '%')
1062  {
1063  *q++=(*p);
1064  continue;
1065  }
1066  p++;
1067  if (*p == '\0')
1068  break;
1069  switch (*p)
1070  {
1071  case 'c':
1072  {
1073  q+=CopyMagickString(q,GetClientName(),extent);
1074  break;
1075  }
1076  case 'd':
1077  {
1078  q+=CopyMagickString(q,domain,extent);
1079  break;
1080  }
1081  case 'e':
1082  {
1083  q+=CopyMagickString(q,event,extent);
1084  break;
1085  }
1086  case 'f':
1087  {
1088  q+=CopyMagickString(q,function,extent);
1089  break;
1090  }
1091  case 'g':
1092  {
1093  if (log_info->generations == 0)
1094  {
1095  (void) CopyMagickString(q,"0",extent);
1096  q++;
1097  break;
1098  }
1099  q+=FormatLocaleString(q,extent,"%.20g",(double) (log_info->generation %
1100  log_info->generations));
1101  break;
1102  }
1103  case 'i':
1104  {
1105  q+=FormatLocaleString(q,extent,"%.20g",(double)
1107  break;
1108  }
1109  case 'l':
1110  {
1111  q+=FormatLocaleString(q,extent,"%.20g",(double) line);
1112  break;
1113  }
1114  case 'm':
1115  {
1116  register const char
1117  *r;
1118 
1119  for (r=module+strlen(module)-1; r > module; r--)
1120  if (*r == *DirectorySeparator)
1121  {
1122  r++;
1123  break;
1124  }
1125  q+=CopyMagickString(q,r,extent);
1126  break;
1127  }
1128  case 'n':
1129  {
1130  q+=CopyMagickString(q,GetLogName(),extent);
1131  break;
1132  }
1133  case 'p':
1134  {
1135  q+=FormatLocaleString(q,extent,"%.20g",(double) getpid());
1136  break;
1137  }
1138  case 'r':
1139  {
1140  q+=FormatLocaleString(q,extent,"%lu:%02lu.%03lu",(unsigned long)
1141  (elapsed_time/60.0),(unsigned long) floor(fmod(elapsed_time,60.0)),
1142  (unsigned long) (1000.0*(elapsed_time-floor(elapsed_time))+0.5));
1143  break;
1144  }
1145  case 't':
1146  {
1147  q+=FormatMagickTime(seconds,extent,q);
1148  break;
1149  }
1150  case 'u':
1151  {
1152  q+=FormatLocaleString(q,extent,"%0.3fu",user_time);
1153  break;
1154  }
1155  case 'v':
1156  {
1158  break;
1159  }
1160  case '%':
1161  {
1162  *q++=(*p);
1163  break;
1164  }
1165  default:
1166  {
1167  *q++='%';
1168  *q++=(*p);
1169  break;
1170  }
1171  }
1172  }
1173  *q='\0';
1174  return(text);
1175 }
1176 
1177 static char *TranslateFilename(const LogInfo *log_info)
1178 {
1179  char
1180  *filename;
1181 
1182  register char
1183  *q;
1184 
1185  register const char
1186  *p;
1187 
1188  size_t
1189  extent;
1190 
1191  /*
1192  Translate event in "human readable" format.
1193  */
1194  assert(log_info != (LogInfo *) NULL);
1195  assert(log_info->filename != (char *) NULL);
1196  filename=AcquireString((char *) NULL);
1197  extent=MagickPathExtent;
1198  q=filename;
1199  for (p=log_info->filename; *p != '\0'; p++)
1200  {
1201  *q='\0';
1202  if ((size_t) (q-filename+MagickPathExtent) >= extent)
1203  {
1204  extent+=MagickPathExtent;
1205  filename=(char *) ResizeQuantumMemory(filename,extent+MagickPathExtent,
1206  sizeof(*filename));
1207  if (filename == (char *) NULL)
1208  return((char *) NULL);
1209  q=filename+strlen(filename);
1210  }
1211  /*
1212  The format of the filename is defined by embedding special format
1213  characters:
1214 
1215  %c client name
1216  %n log name
1217  %p process id
1218  %v version
1219  %% percent sign
1220  */
1221  if (*p != '%')
1222  {
1223  *q++=(*p);
1224  continue;
1225  }
1226  p++;
1227  if (*p == '\0')
1228  break;
1229  switch (*p)
1230  {
1231  case '\0':
1232  {
1233  p--;
1234  break;
1235  }
1236  case 'c':
1237  {
1238  q+=CopyMagickString(q,GetClientName(),extent);
1239  break;
1240  }
1241  case 'g':
1242  {
1243  if (log_info->generations == 0)
1244  {
1245  (void) CopyMagickString(q,"0",extent);
1246  q++;
1247  break;
1248  }
1249  q+=FormatLocaleString(q,extent,"%.20g",(double) (log_info->generation %
1250  log_info->generations));
1251  break;
1252  }
1253  case 'n':
1254  {
1255  q+=CopyMagickString(q,GetLogName(),extent);
1256  break;
1257  }
1258  case 'p':
1259  {
1260  q+=FormatLocaleString(q,extent,"%.20g",(double) getpid());
1261  break;
1262  }
1263  case 'v':
1264  {
1266  break;
1267  }
1268  case '%':
1269  {
1270  *q++=(*p);
1271  break;
1272  }
1273  default:
1274  {
1275  *q++='%';
1276  *q++=(*p);
1277  break;
1278  }
1279  }
1280  }
1281  *q='\0';
1282  return(filename);
1283 }
1284 
1286  const char *module,const char *function,const size_t line,const char *format,
1287  va_list operands)
1288 {
1289  char
1290  event[MagickPathExtent],
1291  *text;
1292 
1293  const char
1294  *domain;
1295 
1297  *exception;
1298 
1299  int
1300  n;
1301 
1302  LogInfo
1303  *log_info;
1304 
1305  exception=AcquireExceptionInfo();
1306  log_info=(LogInfo *) GetLogInfo("*",exception);
1307  exception=DestroyExceptionInfo(exception);
1308  if (log_info->event_semaphore == (SemaphoreInfo *) NULL)
1311  if ((log_info->event_mask & type) == 0)
1312  {
1314  return(MagickTrue);
1315  }
1317 #if defined(MAGICKCORE_HAVE_VSNPRINTF)
1318  n=vsnprintf(event,MagickPathExtent,format,operands);
1319 #else
1320  n=vsprintf(event,format,operands);
1321 #endif
1322  if (n < 0)
1323  event[MagickPathExtent-1]='\0';
1324  text=TranslateEvent(module,function,line,domain,event);
1325  if (text == (char *) NULL)
1326  {
1327  (void) ContinueTimer((TimerInfo *) &log_info->timer);
1329  return(MagickFalse);
1330  }
1331  if ((log_info->handler_mask & ConsoleHandler) != 0)
1332  {
1333  (void) FormatLocaleFile(stderr,"%s\n",text);
1334  (void) fflush(stderr);
1335  }
1336  if ((log_info->handler_mask & DebugHandler) != 0)
1337  {
1338 #if defined(MAGICKCORE_WINDOWS_SUPPORT)
1339  OutputDebugString(text);
1340  OutputDebugString("\n");
1341 #endif
1342  }
1343  if ((log_info->handler_mask & EventHandler) != 0)
1344  {
1345 #if defined(MAGICKCORE_WINDOWS_SUPPORT)
1346  (void) NTReportEvent(text,MagickFalse);
1347 #endif
1348  }
1349  if ((log_info->handler_mask & FileHandler) != 0)
1350  {
1351  struct stat
1352  file_info;
1353 
1354  file_info.st_size=0;
1355  if (log_info->file != (FILE *) NULL)
1356  (void) fstat(fileno(log_info->file),&file_info);
1357  if (file_info.st_size > (MagickOffsetType) (1024*1024*log_info->limit))
1358  {
1359  (void) FormatLocaleFile(log_info->file,"</log>\n");
1360  (void) fclose(log_info->file);
1361  log_info->file=(FILE *) NULL;
1362  }
1363  if (log_info->file == (FILE *) NULL)
1364  {
1365  char
1366  *filename;
1367 
1368  filename=TranslateFilename(log_info);
1369  if (filename == (char *) NULL)
1370  {
1371  (void) ContinueTimer((TimerInfo *) &log_info->timer);
1373  return(MagickFalse);
1374  }
1375  log_info->append=IsPathAccessible(filename);
1376  log_info->file=fopen_utf8(filename,"ab");
1377  filename=(char *) RelinquishMagickMemory(filename);
1378  if (log_info->file == (FILE *) NULL)
1379  {
1381  return(MagickFalse);
1382  }
1383  log_info->generation++;
1384  if (log_info->append == MagickFalse)
1385  (void) FormatLocaleFile(log_info->file,"<?xml version=\"1.0\" "
1386  "encoding=\"UTF-8\" standalone=\"yes\"?>\n");
1387  (void) FormatLocaleFile(log_info->file,"<log>\n");
1388  }
1389  (void) FormatLocaleFile(log_info->file," <event>%s</event>\n",text);
1390  (void) fflush(log_info->file);
1391  }
1392  if ((log_info->handler_mask & MethodHandler) != 0)
1393  {
1394  if (log_info->method != (MagickLogMethod) NULL)
1395  log_info->method(type,text);
1396  }
1397  if ((log_info->handler_mask & StdoutHandler) != 0)
1398  {
1399  (void) FormatLocaleFile(stdout,"%s\n",text);
1400  (void) fflush(stdout);
1401  }
1402  if ((log_info->handler_mask & StderrHandler) != 0)
1403  {
1404  (void) FormatLocaleFile(stderr,"%s\n",text);
1405  (void) fflush(stderr);
1406  }
1407  text=(char *) RelinquishMagickMemory(text);
1408  (void) ContinueTimer((TimerInfo *) &log_info->timer);
1410  return(MagickTrue);
1411 }
1412 
1414  const char *module,const char *function,const size_t line,
1415  const char *format,...)
1416 {
1417  va_list
1418  operands;
1419 
1421  status;
1422 
1423  if (IsEventLogging() == MagickFalse)
1424  return(MagickFalse);
1425  va_start(operands,format);
1426  status=LogMagickEventList(type,module,function,line,format,operands);
1427  va_end(operands);
1428  return(status);
1429 }
1430 
1431 /*
1432 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1433 % %
1434 % %
1435 % %
1436 + L o a d L o g C a c h e %
1437 % %
1438 % %
1439 % %
1440 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1441 %
1442 % LoadLogCache() loads the log configurations which provides a
1443 % mapping between log attributes and log name.
1444 %
1445 % The format of the LoadLogCache method is:
1446 %
1447 % MagickBooleanType LoadLogCache(LinkedListInfo *cache,const char *xml,
1448 % const char *filename,const size_t depth,ExceptionInfo *exception)
1449 %
1450 % A description of each parameter follows:
1451 %
1452 % o xml: The log list in XML format.
1453 %
1454 % o filename: The log list filename.
1455 %
1456 % o depth: depth of <include /> statements.
1457 %
1458 % o exception: return any errors or warnings in this structure.
1459 %
1460 */
1461 static MagickBooleanType LoadLogCache(LinkedListInfo *cache,const char *xml,
1462  const char *filename,const size_t depth,ExceptionInfo *exception)
1463 {
1464  char
1465  keyword[MagickPathExtent],
1466  *token;
1467 
1468  const char
1469  *q;
1470 
1471  LogInfo
1472  *log_info = (LogInfo *) NULL;
1473 
1475  status;
1476 
1477  size_t
1478  extent;
1479 
1480  /*
1481  Load the log map file.
1482  */
1483  if (xml == (const char *) NULL)
1484  return(MagickFalse);
1485  status=MagickTrue;
1486  token=AcquireString(xml);
1487  extent=strlen(token)+MagickPathExtent;
1488  for (q=(const char *) xml; *q != '\0'; )
1489  {
1490  /*
1491  Interpret XML.
1492  */
1493  (void) GetNextToken(q,&q,extent,token);
1494  if (*token == '\0')
1495  break;
1496  (void) CopyMagickString(keyword,token,MagickPathExtent);
1497  if (LocaleNCompare(keyword,"<!DOCTYPE",9) == 0)
1498  {
1499  /*
1500  Doctype element.
1501  */
1502  while ((LocaleNCompare(q,"]>",2) != 0) && (*q != '\0'))
1503  (void) GetNextToken(q,&q,extent,token);
1504  continue;
1505  }
1506  if (LocaleNCompare(keyword,"<!--",4) == 0)
1507  {
1508  /*
1509  Comment element.
1510  */
1511  while ((LocaleNCompare(q,"->",2) != 0) && (*q != '\0'))
1512  (void) GetNextToken(q,&q,extent,token);
1513  continue;
1514  }
1515  if (LocaleCompare(keyword,"<include") == 0)
1516  {
1517  /*
1518  Include element.
1519  */
1520  while (((*token != '/') && (*(token+1) != '>')) && (*q != '\0'))
1521  {
1522  (void) CopyMagickString(keyword,token,MagickPathExtent);
1523  (void) GetNextToken(q,&q,extent,token);
1524  if (*token != '=')
1525  continue;
1526  (void) GetNextToken(q,&q,extent,token);
1527  if (LocaleCompare(keyword,"file") == 0)
1528  {
1529  if (depth > MagickMaxRecursionDepth)
1530  (void) ThrowMagickException(exception,GetMagickModule(),
1531  ConfigureError,"IncludeElementNestedTooDeeply","`%s'",token);
1532  else
1533  {
1534  char
1535  path[MagickPathExtent],
1536  *file_xml;
1537 
1538  GetPathComponent(filename,HeadPath,path);
1539  if (*path != '\0')
1542  if (*token == *DirectorySeparator)
1543  (void) CopyMagickString(path,token,MagickPathExtent);
1544  else
1545  (void) ConcatenateMagickString(path,token,MagickPathExtent);
1546  file_xml=FileToXML(path,~0UL);
1547  if (file_xml != (char *) NULL)
1548  {
1549  status&=LoadLogCache(cache,file_xml,path,depth+1,
1550  exception);
1551  file_xml=DestroyString(file_xml);
1552  }
1553  }
1554  }
1555  }
1556  continue;
1557  }
1558  if (LocaleCompare(keyword,"<logmap>") == 0)
1559  {
1560  /*
1561  Allocate memory for the log list.
1562  */
1563  log_info=(LogInfo *) AcquireCriticalMemory(sizeof(*log_info));
1564  (void) memset(log_info,0,sizeof(*log_info));
1565  log_info->path=ConstantString(filename);
1566  GetTimerInfo((TimerInfo *) &log_info->timer);
1567  log_info->signature=MagickCoreSignature;
1568  continue;
1569  }
1570  if (log_info == (LogInfo *) NULL)
1571  continue;
1572  if (LocaleCompare(keyword,"</logmap>") == 0)
1573  {
1574  status=AppendValueToLinkedList(cache,log_info);
1575  if (status == MagickFalse)
1576  (void) ThrowMagickException(exception,GetMagickModule(),
1577  ResourceLimitError,"MemoryAllocationFailed","`%s'",filename);
1578  log_info=(LogInfo *) NULL;
1579  continue;
1580  }
1581  (void) GetNextToken(q,(const char **) NULL,extent,token);
1582  if (*token != '=')
1583  continue;
1584  (void) GetNextToken(q,&q,extent,token);
1585  (void) GetNextToken(q,&q,extent,token);
1586  switch (*keyword)
1587  {
1588  case 'E':
1589  case 'e':
1590  {
1591  if (LocaleCompare((char *) keyword,"events") == 0)
1592  {
1593  log_info->event_mask=(LogEventType) (log_info->event_mask |
1595  break;
1596  }
1597  break;
1598  }
1599  case 'F':
1600  case 'f':
1601  {
1602  if (LocaleCompare((char *) keyword,"filename") == 0)
1603  {
1604  if (log_info->filename != (char *) NULL)
1605  log_info->filename=(char *)
1606  RelinquishMagickMemory(log_info->filename);
1607  log_info->filename=ConstantString(token);
1608  break;
1609  }
1610  if (LocaleCompare((char *) keyword,"format") == 0)
1611  {
1612  if (log_info->format != (char *) NULL)
1613  log_info->format=(char *)
1614  RelinquishMagickMemory(log_info->format);
1615  log_info->format=ConstantString(token);
1616  break;
1617  }
1618  break;
1619  }
1620  case 'G':
1621  case 'g':
1622  {
1623  if (LocaleCompare((char *) keyword,"generations") == 0)
1624  {
1625  if (LocaleCompare(token,"unlimited") == 0)
1626  {
1627  log_info->generations=(~0UL);
1628  break;
1629  }
1630  log_info->generations=StringToUnsignedLong(token);
1631  break;
1632  }
1633  break;
1634  }
1635  case 'L':
1636  case 'l':
1637  {
1638  if (LocaleCompare((char *) keyword,"limit") == 0)
1639  {
1640  if (LocaleCompare(token,"unlimited") == 0)
1641  {
1642  log_info->limit=(~0UL);
1643  break;
1644  }
1645  log_info->limit=StringToUnsignedLong(token);
1646  break;
1647  }
1648  break;
1649  }
1650  case 'O':
1651  case 'o':
1652  {
1653  if (LocaleCompare((char *) keyword,"output") == 0)
1654  {
1655  log_info->handler_mask=(LogHandlerType)
1656  (log_info->handler_mask | ParseLogHandlers(token));
1657  break;
1658  }
1659  break;
1660  }
1661  default:
1662  break;
1663  }
1664  }
1665  token=DestroyString(token);
1666  if (cache == (LinkedListInfo *) NULL)
1667  return(MagickFalse);
1668  return(status != 0 ? MagickTrue : MagickFalse);
1669 }
1670 
1671 /*
1672 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1673 % %
1674 % %
1675 % %
1676 + P a r s e L o g H a n d l e r s %
1677 % %
1678 % %
1679 % %
1680 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1681 %
1682 % ParseLogHandlers() parses a string defining which handlers takes a log
1683 % message and exports them.
1684 %
1685 % The format of the ParseLogHandlers method is:
1686 %
1687 % LogHandlerType ParseLogHandlers(const char *handlers)
1688 %
1689 % A description of each parameter follows:
1690 %
1691 % o handlers: one or more handlers separated by commas.
1692 %
1693 */
1694 static LogHandlerType ParseLogHandlers(const char *handlers)
1695 {
1697  handler_mask;
1698 
1699  register const char
1700  *p;
1701 
1702  register ssize_t
1703  i;
1704 
1705  size_t
1706  length;
1707 
1708  handler_mask=NoHandler;
1709  for (p=handlers; p != (char *) NULL; p=strchr(p,','))
1710  {
1711  while ((*p != '\0') && ((isspace((int) ((unsigned char) *p)) != 0) ||
1712  (*p == ',')))
1713  p++;
1714  for (i=0; *LogHandlers[i].name != '\0'; i++)
1715  {
1716  length=strlen(LogHandlers[i].name);
1717  if (LocaleNCompare(p,LogHandlers[i].name,length) == 0)
1718  {
1719  handler_mask=(LogHandlerType) (handler_mask | LogHandlers[i].handler);
1720  break;
1721  }
1722  }
1723  if (*LogHandlers[i].name == '\0')
1724  return(UndefinedHandler);
1725  }
1726  return(handler_mask);
1727 }
1728 
1729 /*
1730 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1731 % %
1732 % %
1733 % %
1734 % S e t L o g E v e n t M a s k %
1735 % %
1736 % %
1737 % %
1738 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1739 %
1740 % SetLogEventMask() accepts a list that determines which events to log. All
1741 % other events are ignored. By default, no debug is enabled. This method
1742 % returns the previous log event mask.
1743 %
1744 % The format of the SetLogEventMask method is:
1745 %
1746 % LogEventType SetLogEventMask(const char *events)
1747 %
1748 % A description of each parameter follows:
1749 %
1750 % o events: log these events.
1751 %
1752 */
1754 {
1756  *exception;
1757 
1758  LogInfo
1759  *log_info;
1760 
1761  ssize_t
1762  option;
1763 
1764  exception=AcquireExceptionInfo();
1765  log_info=(LogInfo *) GetLogInfo("*",exception);
1766  exception=DestroyExceptionInfo(exception);
1769  log_info=(LogInfo *) GetValueFromLinkedList(log_cache,0);
1770  log_info->event_mask=(LogEventType) option;
1771  if (option == -1)
1772  log_info->event_mask=UndefinedEvents;
1775  return(log_info->event_mask);
1776 }
1777 
1778 /*
1779 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1780 % %
1781 % %
1782 % %
1783 % S e t L o g F o r m a t %
1784 % %
1785 % %
1786 % %
1787 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1788 %
1789 % SetLogFormat() sets the format for the "human readable" log record.
1790 %
1791 % The format of the LogMagickFormat method is:
1792 %
1793 % SetLogFormat(const char *format)
1794 %
1795 % A description of each parameter follows:
1796 %
1797 % o format: the log record format.
1798 %
1799 */
1800 MagickExport void SetLogFormat(const char *format)
1801 {
1802  LogInfo
1803  *log_info;
1804 
1806  *exception;
1807 
1808  exception=AcquireExceptionInfo();
1809  log_info=(LogInfo *) GetLogInfo("*",exception);
1810  exception=DestroyExceptionInfo(exception);
1812  if (log_info->format != (char *) NULL)
1813  log_info->format=DestroyString(log_info->format);
1814  log_info->format=ConstantString(format);
1816 }
1817 
1818 /*
1819 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1820 % %
1821 % %
1822 % %
1823 % S e t L o g M e t h o d %
1824 % %
1825 % %
1826 % %
1827 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1828 %
1829 % SetLogMethod() sets the method that will be called when an event is logged.
1830 %
1831 % The format of the SetLogMethod method is:
1832 %
1833 % void SetLogMethod(MagickLogMethod method)
1834 %
1835 % A description of each parameter follows:
1836 %
1837 % o method: pointer to a method that will be called when LogMagickEvent is
1838 % being called.
1839 %
1840 */
1842 {
1844  *exception;
1845 
1846  LogInfo
1847  *log_info;
1848 
1849  exception=AcquireExceptionInfo();
1850  log_info=(LogInfo *) GetLogInfo("*",exception);
1851  exception=DestroyExceptionInfo(exception);
1853  log_info=(LogInfo *) GetValueFromLinkedList(log_cache,0);
1854  log_info->handler_mask=(LogHandlerType) (log_info->handler_mask |
1855  MethodHandler);
1856  log_info->method=method;
1858 }
1859 
1860 /*
1861 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1862 % %
1863 % %
1864 % %
1865 % S e t L o g N a m e %
1866 % %
1867 % %
1868 % %
1869 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1870 %
1871 % SetLogName() sets the log name and returns it.
1872 %
1873 % The format of the SetLogName method is:
1874 %
1875 % const char *SetLogName(const char *name)
1876 %
1877 % A description of each parameter follows:
1878 %
1879 % o log_name: SetLogName() returns the current client name.
1880 %
1881 % o name: Specifies the new client name.
1882 %
1883 */
1884 MagickExport const char *SetLogName(const char *name)
1885 {
1886  if ((name != (char *) NULL) && (*name != '\0'))
1888  return(log_name);
1889 }
static const HandlerInfo LogHandlers[32]
Definition: log.c:167
MagickExport void * GetValueFromLinkedList(LinkedListInfo *list_info, const size_t index)
Definition: linked-list.c:382
size_t signature
Definition: log.c:147
#define MagickMaxRecursionDepth
Definition: studio.h:344
const char * format
Definition: log.c:159
MagickExport double GetUserTime(TimerInfo *time_info)
Definition: timer.c:401
size_t generations
Definition: log.c:124
MagickExport MagickBooleanType LogMagickEventList(const LogEventType type, const char *module, const char *function, const size_t line, const char *format, va_list operands)
Definition: log.c:1285
MagickExport void UnlockSemaphoreInfo(SemaphoreInfo *semaphore_info)
Definition: semaphore.c:450
static unsigned long StringToUnsignedLong(const char *magick_restrict value)
MagickExport void ResetLinkedListIterator(LinkedListInfo *list_info)
Definition: linked-list.c:959
static LogInfo * GetLogInfo(const char *name, ExceptionInfo *exception)
Definition: log.c:399
MagickExport ssize_t ParseCommandOption(const CommandOption option, const MagickBooleanType list, const char *options)
Definition: option.c:2972
void(* MagickLogMethod)(const LogEventType, const char *)
Definition: log.h:65
Definition: log.c:81
LogHandlerType handler
Definition: log.c:106
MagickPrivate MagickBooleanType LogComponentGenesis(void)
Definition: log.c:845
char * name
Definition: log.c:94
MagickExport LinkedListInfo * DestroyLinkedList(LinkedListInfo *list_info, void *(*relinquish_value)(void *))
Definition: linked-list.c:219
MagickExport size_t ConcatenateMagickString(char *destination, const char *source, const size_t length)
Definition: string.c:426
SemaphoreInfo * event_semaphore
Definition: log.c:144
MagickExport SemaphoreInfo * AcquireSemaphoreInfo(void)
Definition: semaphore.c:192
MagickPrivate void LogComponentTerminus(void)
Definition: log.c:901
MagickExport MagickBooleanType InsertValueInLinkedList(LinkedListInfo *list_info, const size_t index, const void *value)
Definition: linked-list.c:447
static int LogInfoCompare(const void *x, const void *y)
Definition: log.c:462
LogEventType
Definition: log.h:33
MagickExport ExceptionInfo * AcquireExceptionInfo(void)
Definition: exception.c:115
MagickExport MagickBooleanType IsLinkedListEmpty(const LinkedListInfo *list_info)
Definition: linked-list.c:633
MagickExport MagickBooleanType AppendValueToLinkedList(LinkedListInfo *list_info, const void *value)
Definition: linked-list.c:111
MagickExport ssize_t FormatLocaleString(char *magick_restrict string, const size_t length, const char *magick_restrict format,...)
Definition: locale.c:499
static void * AcquireCriticalMemory(const size_t size)
MagickExport void * RemoveElementByValueFromLinkedList(LinkedListInfo *list_info, const void *value)
Definition: linked-list.c:756
MagickLogMethod method
Definition: log.c:141
char * path
Definition: log.c:118
LogHandlerType handler_mask
Definition: log.c:115
MagickExport void * ResizeQuantumMemory(void *memory, const size_t count, const size_t quantum)
Definition: memory.c:1369
MagickExport size_t GetNextToken(const char *start, const char **end, const size_t extent, char *token)
Definition: token.c:173
MagickExport MagickBooleanType ListLogInfo(FILE *file, ExceptionInfo *exception)
Definition: log.c:749
static LogHandlerType ParseLogHandlers(static MagickBooleanTypeIsLogCacheInstantiated(ExceptionInfo *) magick_attribute((__pure__)) const char *)
Definition: log.c:226
MagickExport LogEventType SetLogEventMask(const char *events)
Definition: log.c:1753
Definition: log.h:52
ssize_t MagickOffsetType
Definition: magick-type.h:129
struct _EventInfo EventInfo
MagickExport void * GetNextValueInLinkedList(LinkedListInfo *list_info)
Definition: linked-list.c:305
#define magick_attribute(x)
MagickBooleanType append
Definition: log.c:134
#define MagickCoreSignature
MagickExport void LockSemaphoreInfo(SemaphoreInfo *semaphore_info)
Definition: semaphore.c:293
MagickExport unsigned char * GetStringInfoDatum(const StringInfo *string_info)
Definition: string.c:1215
MagickExport LinkedListInfo * GetConfigureOptions(const char *filename, ExceptionInfo *exception)
Definition: configure.c:639
static void * DestroyLogElement(void *log_info)
Definition: log.c:877
TimerInfo timer
Definition: log.c:138
MagickExport void GetPathComponent(const char *path, PathType type, char *component)
Definition: utility.c:1213
MagickExport ssize_t FormatLocaleFile(FILE *file, const char *magick_restrict format,...)
Definition: locale.c:404
MagickBooleanType
Definition: magick-type.h:158
MagickExport const LogInfo ** GetLogInfoList(const char *pattern, size_t *number_preferences, ExceptionInfo *exception)
Definition: log.c:479
#define DirectorySeparator
Definition: studio.h:259
unsigned int MagickStatusType
Definition: magick-type.h:121
MagickExport char * AcquireString(const char *source)
Definition: string.c:129
MagickExport char ** GetLogList(const char *pattern, size_t *number_preferences, ExceptionInfo *exception)
Definition: log.c:572
MagickExport const char * CommandOptionToMnemonic(const CommandOption option, const ssize_t type)
Definition: option.c:2681
MagickExport void SetLogFormat(const char *format)
Definition: log.c:1800
#define MagickLibVersionText
Definition: version.h:31
Definition: log.c:109
LogEventType event
Definition: log.c:97
MagickBooleanType stealth
Definition: log.c:134
MagickExport void * AcquireQuantumMemory(const size_t count, const size_t quantum)
Definition: memory.c:553
static FILE * fopen_utf8(const char *path, const char *mode)
MagickExport int LocaleNCompare(const char *p, const char *q, const size_t length)
Definition: locale.c:1570
MagickExport time_t GetMagickTime(void)
Definition: timer.c:326
char * format
Definition: log.c:118
MagickExport MagickBooleanType GlobExpression(const char *expression, const char *pattern, const MagickBooleanType case_insensitive)
Definition: token.c:352
#define MagickPathExtent
MagickExport const char * GetLogName(void)
Definition: log.c:636
const char * filename
Definition: log.c:159
MagickExport MagickBooleanType IsEventLogging(void)
Definition: log.c:720
const LogHandlerType handler_mask
Definition: log.c:156
MagickExport void CloseMagickLog(void)
Definition: log.c:351
MagickExport MagickBooleanType ThrowMagickException(ExceptionInfo *exception, const char *module, const char *function, const size_t line, const ExceptionType severity, const char *tag, const char *format,...)
Definition: exception.c:1145
const char * module
Definition: static.c:77
size_t limit
Definition: log.c:124
MagickExport MagickBooleanType LogMagickEvent(const LogEventType type, const char *module, const char *function, const size_t line, const char *format,...)
Definition: log.c:1413
MagickExport MagickBooleanType IsPathAccessible(const char *path)
Definition: utility.c:1467
char * filename
Definition: log.c:118
static void CheckEventLogging()
Definition: log.c:665
MagickExport LinkedListInfo * NewLinkedList(const size_t capacity)
Definition: linked-list.c:713
MagickExport size_t CopyMagickString(char *destination, const char *source, const size_t length)
Definition: string.c:755
MagickExport const char * GetClientName(void)
Definition: client.c:65
static MagickBooleanType event_logging
Definition: log.c:217
struct _HandlerInfo HandlerInfo
static char * TranslateFilename(const LogInfo *log_info)
Definition: log.c:1177
MagickExport int LocaleCompare(const char *p, const char *q)
Definition: locale.c:1435
Definition: log.c:91
#define GetMagickModule()
Definition: log.h:28
MagickExport const char * GetStringInfoPath(const StringInfo *string_info)
Definition: string.c:1302
MagickExport void GetTimerInfo(TimerInfo *time_info)
Definition: timer.c:365
const LogEventType event_mask
Definition: log.c:153
MagickExport void SetLogMethod(MagickLogMethod method)
Definition: log.c:1841
static MagickBooleanType IsLogCacheInstantiated(ExceptionInfo *exception)
Definition: log.c:684
static MagickBooleanType LoadLogCache(LinkedListInfo *cache, const char *xml, const char *filename, const size_t depth, ExceptionInfo *exception)
Definition: log.c:1461
MagickExport char * DestroyString(char *string)
Definition: string.c:823
MagickExport void * AcquireMagickMemory(const size_t size)
Definition: memory.c:482
LogEventType event_mask
Definition: log.c:112
MagickExport void ActivateSemaphoreInfo(SemaphoreInfo **semaphore_info)
Definition: semaphore.c:97
static LinkedListInfo * log_cache
Definition: log.c:214
MagickExport size_t GetNumberOfElementsInLinkedList(const LinkedListInfo *list_info)
Definition: linked-list.c:348
static char log_name[MagickPathExtent]
Definition: log.c:211
MagickExport double GetElapsedTime(TimerInfo *time_info)
Definition: timer.c:297
const char name[10]
Definition: log.c:103
FILE * file
Definition: log.c:128
static const LogMapInfo LogMap[]
Definition: log.c:204
char * name
Definition: log.c:118
MagickExport void * RelinquishMagickMemory(void *memory)
Definition: memory.c:1084
size_t generation
Definition: log.c:131
static size_t GetMagickThreadSignature(void)
MagickExport const char * SetLogName(const char *name)
Definition: log.c:1884
#define MagickPrivate
MagickPrivate char * FileToXML(const char *, const size_t)
Definition: xml-tree.c:599
Definition: log.h:36
#define MagickExport
static SemaphoreInfo * log_semaphore
Definition: log.c:220
static char * TranslateEvent(const char *module, const char *function, const size_t line, const char *domain, const char *event)
Definition: log.c:946
MagickExport ssize_t FormatMagickTime(const time_t time, const size_t length, char *timestamp)
Definition: timer.c:255
struct _LogMapInfo LogMapInfo
static int LogCompare(const void *x, const void *y)
Definition: log.c:557
MagickExport void RelinquishSemaphoreInfo(SemaphoreInfo **semaphore_info)
Definition: semaphore.c:351
MagickExport LinkedListInfo * DestroyConfigureOptions(LinkedListInfo *options)
Definition: configure.c:311
MagickExport char * ConstantString(const char *source)
Definition: string.c:700
MagickExport ExceptionInfo * DestroyExceptionInfo(ExceptionInfo *exception)
Definition: exception.c:418
#define LogFilename
Definition: log.c:73
MagickExport MagickBooleanType ContinueTimer(TimerInfo *time_info)
Definition: timer.c:125
LogHandlerType
Definition: log.c:78