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