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