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