log.c

Go to the documentation of this file.
00001 /*
00002 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00003 %                                                                             %
00004 %                                                                             %
00005 %                                                                             %
00006 %                             L       OOO    GGGG                             %
00007 %                             L      O   O  G                                 %
00008 %                             L      O   O  G GG                              %
00009 %                             L      O   O  G   G                             %
00010 %                             LLLLL   OOO    GGG                              %
00011 %                                                                             %
00012 %                                                                             %
00013 %                             MagickCore Log Events                           %
00014 %                                                                             %
00015 %                               Software Design                               %
00016 %                                 John Cristy                                 %
00017 %                                September 2002                               %
00018 %                                                                             %
00019 %                                                                             %
00020 %  Copyright 1999-2008 ImageMagick Studio LLC, a non-profit organization      %
00021 %  dedicated to making software imaging solutions freely available.           %
00022 %                                                                             %
00023 %  You may not use this file except in compliance with the License.  You may  %
00024 %  obtain a copy of the License at                                            %
00025 %                                                                             %
00026 %    http://www.imagemagick.org/script/license.php                            %
00027 %                                                                             %
00028 %  Unless required by applicable law or agreed to in writing, software        %
00029 %  distributed under the License is distributed on an "AS IS" BASIS,          %
00030 %  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
00031 %  See the License for the specific language governing permissions and        %
00032 %  limitations under the License.                                             %
00033 %                                                                             %
00034 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00035 %
00036 %
00037 */
00038 
00039 /*
00040   Include declarations.
00041 */
00042 #include "magick/studio.h"
00043 #include "magick/blob.h"
00044 #include "magick/client.h"
00045 #include "magick/configure.h"
00046 #include "magick/exception.h"
00047 #include "magick/exception-private.h"
00048 #include "magick/hashmap.h"
00049 #include "magick/log.h"
00050 #include "magick/memory_.h"
00051 #include "magick/option.h"
00052 #include "magick/semaphore.h"
00053 #include "magick/timer.h"
00054 #include "magick/string_.h"
00055 #include "magick/token.h"
00056 #include "magick/utility.h"
00057 #include "magick/version.h"
00058 #include "magick/xml-tree.h"
00059 #if defined(MAGICKCORE_HAVE_PTHREAD)
00060 #include <pthread.h>
00061 #endif
00062 #if defined(MAGICKCORE_HAVE_LINUX_UNISTD_H)
00063 #include <linux/unistd.h>
00064 #endif
00065 #if defined(__WINDOWS__)
00066 #include <windows.h>
00067 #endif
00068 
00069 /*
00070   Define declarations.
00071 */
00072 #define LogFilename  "log.xml"
00073 
00074 /*
00075   Typedef declarations.
00076 */
00077 typedef enum
00078 {
00079   UndefinedHandler = 0x0000,
00080   NoHandler = 0x0000,
00081   ConsoleHandler = 0x0001,
00082   StdoutHandler = 0x0002,
00083   StderrHandler = 0x0004,
00084   FileHandler = 0x0008,
00085   DebugHandler = 0x0010,
00086   EventHandler = 0x0020
00087 } LogHandlerType;
00088 
00089 typedef struct _EventInfo
00090 {
00091   char
00092     *name;
00093 
00094   LogEventType
00095     event;
00096 } EventInfo;
00097 
00098 typedef struct _HandlerInfo
00099 {
00100   const char
00101     *name;
00102 
00103   LogHandlerType
00104     handler;
00105 } HandlerInfo;
00106 
00107 struct _LogInfo
00108 {
00109   LogEventType
00110     event_mask;
00111 
00112   LogHandlerType
00113     handler_mask;
00114 
00115   char
00116     *path,
00117     *name,
00118     *filename,
00119     *format;
00120 
00121   unsigned long
00122     generations,
00123     limit;
00124 
00125   FILE
00126     *file;
00127 
00128   unsigned long
00129     generation;
00130 
00131   MagickBooleanType
00132     append,
00133     stealth;
00134 
00135   TimerInfo
00136     timer;
00137 
00138   unsigned long
00139     signature;
00140 };
00141 
00142 /*
00143   Declare log map.
00144 */
00145 static const HandlerInfo
00146   LogHandlers[] =
00147   {
00148     { "console", ConsoleHandler },
00149     { "debug", DebugHandler },
00150     { "event", EventHandler },
00151     { "file", FileHandler },
00152     { "none", NoHandler },
00153     { "stderr", StderrHandler },
00154     { "stdout", StdoutHandler },
00155     { (char *) NULL, UndefinedHandler }
00156   };
00157 
00158 static const char
00159   *LogMap = (const char *)
00160     "<?xml version=\"1.0\"?>"
00161     "<logmap>"
00162     "  <log events=\"None\" />"
00163     "  <log output=\"console\" />"
00164     "  <log filename=\"Magick-%d.log\" />"
00165     "  <log format=\"%t %r %u %v %d %c[%p]: %m/%f/%l/%d\n  %e\" />"
00166     "</logmap>";
00167 
00168 /*
00169   Static declarations.
00170 */
00171 static char
00172   log_name[MaxTextExtent] = "Magick";
00173 
00174 static LinkedListInfo
00175   *log_list = (LinkedListInfo *) NULL;
00176 
00177 static SemaphoreInfo
00178   *log_semaphore = (SemaphoreInfo *) NULL;
00179 
00180 static volatile MagickBooleanType
00181   instantiate_log = MagickFalse;
00182 
00183 /*
00184   Forward declarations.
00185 */
00186 static LogHandlerType
00187   ParseLogHandlers(const char *);
00188 
00189 static MagickBooleanType
00190   InitializeLogList(ExceptionInfo *),
00191   LoadLogLists(const char *,ExceptionInfo *);
00192 
00193 /*
00194 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00195 %                                                                             %
00196 %                                                                             %
00197 %                                                                             %
00198 %   C l o s e M a g i c k L o g                                               %
00199 %                                                                             %
00200 %                                                                             %
00201 %                                                                             %
00202 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00203 %
00204 %  CloseMagickLog() closes the Magick log.
00205 %
00206 %  The format of the CloseMagickLog method is:
00207 %
00208 %      CloseMagickLog(void)
00209 %
00210 */
00211 MagickExport void CloseMagickLog(void)
00212 {
00213   ExceptionInfo
00214     *exception;
00215 
00216   LogInfo
00217     *log_info;
00218 
00219   if (IsEventLogging() == MagickFalse)
00220     return;
00221   exception=AcquireExceptionInfo();
00222   log_info=(LogInfo *) GetLogInfo("*",exception);
00223   exception=DestroyExceptionInfo(exception);
00224   AcquireSemaphoreInfo(&log_semaphore);
00225   if (log_info->file != (FILE *) NULL)
00226     {
00227       if (log_info->append == MagickFalse)
00228         (void) fprintf(log_info->file,"</log>\n");
00229       (void) fclose(log_info->file);
00230       log_info->file=(FILE *) NULL;
00231     }
00232   RelinquishSemaphoreInfo(log_semaphore);
00233 }
00234 
00235 /*
00236 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00237 %                                                                             %
00238 %                                                                             %
00239 %                                                                             %
00240 +   D e s t r o y L o g L i s t                                               %
00241 %                                                                             %
00242 %                                                                             %
00243 %                                                                             %
00244 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00245 %
00246 %  DestroyLogList() deallocates memory associated with the log list.
00247 %
00248 %  The format of the DestroyLogList method is:
00249 %
00250 %      DestroyLogList(void)
00251 %
00252 */
00253 
00254 static void *DestroyLogElement(void *log_info)
00255 {
00256   register LogInfo
00257     *p;
00258 
00259   p=(LogInfo *) log_info;
00260   if (p->file != (FILE *) NULL)
00261     {
00262       if (p->append == MagickFalse)
00263         (void) fprintf(p->file,"</log>\n");
00264       (void) fclose(p->file);
00265       p->file=(FILE *) NULL;
00266     }
00267   if (p->filename != (char *) NULL)
00268     p->filename=DestroyString(p->filename);
00269   if (p->path != (char *) NULL)
00270     p->path=DestroyString(p->path);
00271   if (p->format != (char *) NULL)
00272     p->format=DestroyString(p->format);
00273   p=(LogInfo *) RelinquishMagickMemory(p);
00274   return((void *) NULL);
00275 }
00276 
00277 MagickExport void DestroyLogList(void)
00278 {
00279   AcquireSemaphoreInfo(&log_semaphore);
00280   if (log_list != (LinkedListInfo *) NULL)
00281     log_list=DestroyLinkedList(log_list,DestroyLogElement);
00282   instantiate_log=MagickFalse;
00283   RelinquishSemaphoreInfo(log_semaphore);
00284   DestroySemaphoreInfo(&log_semaphore);
00285 }
00286 
00287 /*
00288 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00289 %                                                                             %
00290 %                                                                             %
00291 %                                                                             %
00292 +   G e t L o g I n f o                                                       %
00293 %                                                                             %
00294 %                                                                             %
00295 %                                                                             %
00296 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00297 %
00298 %  GetLogInfo() searches the log list for the specified name and if found
00299 %  returns attributes for that log.
00300 %
00301 %  The format of the GetLogInfo method is:
00302 %
00303 %      const LogInfo *GetLogInfo(const char *name,ExceptionInfo *exception)
00304 %
00305 %  A description of each parameter follows:
00306 %
00307 %    o name: the log name.
00308 %
00309 %    o exception: return any errors or warnings in this structure.
00310 %
00311 */
00312 MagickExport const LogInfo *GetLogInfo(const char *name,
00313   ExceptionInfo *exception)
00314 {
00315   register const LogInfo
00316     *p;
00317 
00318   assert(exception != (ExceptionInfo *) NULL);
00319   if ((log_list == (LinkedListInfo *) NULL) || (instantiate_log == MagickFalse))
00320     if (InitializeLogList(exception) == MagickFalse)
00321       return((const LogInfo *) NULL);
00322   if ((log_list == (LinkedListInfo *) NULL) ||
00323       (IsLinkedListEmpty(log_list) != MagickFalse))
00324     return((const LogInfo *) NULL);
00325   if ((name == (const char *) NULL) || (LocaleCompare(name,"*") == 0))
00326     return((const LogInfo *) GetValueFromLinkedList(log_list,0));
00327   /*
00328     Search for log tag.
00329   */
00330   AcquireSemaphoreInfo(&log_semaphore);
00331   ResetLinkedListIterator(log_list);
00332   p=(const LogInfo *) GetNextValueInLinkedList(log_list);
00333   while (p != (const LogInfo *) NULL)
00334   {
00335     if (LocaleCompare(name,p->name) == 0)
00336       break;
00337     p=(const LogInfo *) GetNextValueInLinkedList(log_list);
00338   }
00339   if (p != (LogInfo *) NULL)
00340     (void) InsertValueInLinkedList(log_list,0,
00341       RemoveElementByValueFromLinkedList(log_list,p));
00342   RelinquishSemaphoreInfo(log_semaphore);
00343   return(p);
00344 }
00345 
00346 /*
00347 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00348 %                                                                             %
00349 %                                                                             %
00350 %                                                                             %
00351 %   G e t L o g I n f o L i s t                                               %
00352 %                                                                             %
00353 %                                                                             %
00354 %                                                                             %
00355 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00356 %
00357 %  GetLogInfoList() returns any logs that match the specified pattern.
00358 %
00359 %  The format of the GetLogInfoList function is:
00360 %
00361 %      const LogInfo **GetLogInfoList(const char *pattern,
00362 %        unsigned long *number_preferences,ExceptionInfo *exception)
00363 %
00364 %  A description of each parameter follows:
00365 %
00366 %    o pattern: Specifies a pointer to a text string containing a pattern.
00367 %
00368 %    o number_preferences:  This integer returns the number of logs in the list.
00369 %
00370 %    o exception: return any errors or warnings in this structure.
00371 %
00372 */
00373 #if defined(__cplusplus) || defined(c_plusplus)
00374 extern "C" {
00375 #endif
00376 
00377 static int LogInfoCompare(const void *x,const void *y)
00378 {
00379   const LogInfo
00380     **p,
00381     **q;
00382 
00383   p=(const LogInfo **) x,
00384   q=(const LogInfo **) y;
00385   if (LocaleCompare((*p)->path,(*q)->path) == 0)
00386     return(LocaleCompare((*p)->name,(*q)->name));
00387   return(LocaleCompare((*p)->path,(*q)->path));
00388 }
00389 
00390 #if defined(__cplusplus) || defined(c_plusplus)
00391 }
00392 #endif
00393 
00394 MagickExport const LogInfo **GetLogInfoList(const char *pattern,
00395   unsigned long *number_preferences,ExceptionInfo *exception)
00396 {
00397   const LogInfo
00398     **preferences;
00399 
00400   register const LogInfo
00401     *p;
00402 
00403   register long
00404     i;
00405 
00406   /*
00407     Allocate log list.
00408   */
00409   assert(pattern != (char *) NULL);
00410   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
00411   assert(number_preferences != (unsigned long *) NULL);
00412   *number_preferences=0;
00413   p=GetLogInfo("*",exception);
00414   if (p == (const LogInfo *) NULL)
00415     return((const LogInfo **) NULL);
00416   preferences=(const LogInfo **) AcquireQuantumMemory((size_t)
00417     GetNumberOfElementsInLinkedList(log_list)+1UL,sizeof(*preferences));
00418   if (preferences == (const LogInfo **) NULL)
00419     return((const LogInfo **) NULL);
00420   /*
00421     Generate log list.
00422   */
00423   AcquireSemaphoreInfo(&log_semaphore);
00424   ResetLinkedListIterator(log_list);
00425   p=(const LogInfo *) GetNextValueInLinkedList(log_list);
00426   for (i=0; p != (const LogInfo *) NULL; )
00427   {
00428     if ((p->stealth == MagickFalse) &&
00429         (GlobExpression(p->name,pattern,MagickFalse) != MagickFalse))
00430       preferences[i++]=p;
00431     p=(const LogInfo *) GetNextValueInLinkedList(log_list);
00432   }
00433   RelinquishSemaphoreInfo(log_semaphore);
00434   qsort((void *) preferences,(size_t) i,sizeof(*preferences),LogInfoCompare);
00435   preferences[i]=(LogInfo *) NULL;
00436   *number_preferences=(unsigned long) i;
00437   return(preferences);
00438 }
00439 
00440 /*
00441 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00442 %                                                                             %
00443 %                                                                             %
00444 %                                                                             %
00445 %   G e t L o g L i s t                                                       %
00446 %                                                                             %
00447 %                                                                             %
00448 %                                                                             %
00449 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00450 %
00451 %  GetLogList() returns any logs that match the specified pattern.
00452 %
00453 %  The format of the GetLogList function is:
00454 %
00455 %      char **GetLogList(const char *pattern,unsigned long *number_preferences,
00456 %        ExceptionInfo *exception)
00457 %
00458 %  A description of each parameter follows:
00459 %
00460 %    o pattern: Specifies a pointer to a text string containing a pattern.
00461 %
00462 %    o number_preferences:  This integer returns the number of logs in the list.
00463 %
00464 %    o exception: return any errors or warnings in this structure.
00465 %
00466 */
00467 
00468 #if defined(__cplusplus) || defined(c_plusplus)
00469 extern "C" {
00470 #endif
00471 
00472 static int LogCompare(const void *x,const void *y)
00473 {
00474   register const char
00475     **p,
00476     **q;
00477 
00478   p=(const char **) x;
00479   q=(const char **) y;
00480   return(LocaleCompare(*p,*q));
00481 }
00482 
00483 #if defined(__cplusplus) || defined(c_plusplus)
00484 }
00485 #endif
00486 
00487 MagickExport char **GetLogList(const char *pattern,
00488   unsigned long *number_preferences,ExceptionInfo *exception)
00489 {
00490   char
00491     **preferences;
00492 
00493   register const LogInfo
00494     *p;
00495 
00496   register long
00497     i;
00498 
00499   /*
00500     Allocate log list.
00501   */
00502   assert(pattern != (char *) NULL);
00503   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
00504   assert(number_preferences != (unsigned long *) NULL);
00505   *number_preferences=0;
00506   p=GetLogInfo("*",exception);
00507   if (p == (const LogInfo *) NULL)
00508     return((char **) NULL);
00509   preferences=(char **) AcquireQuantumMemory((size_t)
00510     GetNumberOfElementsInLinkedList(log_list)+1UL,sizeof(*preferences));
00511   if (preferences == (char **) NULL)
00512     return((char **) NULL);
00513   /*
00514     Generate log list.
00515   */
00516   AcquireSemaphoreInfo(&log_semaphore);
00517   ResetLinkedListIterator(log_list);
00518   p=(const LogInfo *) GetNextValueInLinkedList(log_list);
00519   for (i=0; p != (const LogInfo *) NULL; )
00520   {
00521     if ((p->stealth == MagickFalse) &&
00522         (GlobExpression(p->name,pattern,MagickFalse) != MagickFalse))
00523       preferences[i++]=ConstantString(p->name);
00524     p=(const LogInfo *) GetNextValueInLinkedList(log_list);
00525   }
00526   RelinquishSemaphoreInfo(log_semaphore);
00527   qsort((void *) preferences,(size_t) i,sizeof(*preferences),LogCompare);
00528   preferences[i]=(char *) NULL;
00529   *number_preferences=(unsigned long) i;
00530   return(preferences);
00531 }
00532 
00533 /*
00534 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00535 %                                                                             %
00536 %                                                                             %
00537 %                                                                             %
00538 %   G e t L o g N a m e                                                       %
00539 %                                                                             %
00540 %                                                                             %
00541 %                                                                             %
00542 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00543 %
00544 %  GetLogName() returns the current log name.
00545 %
00546 %  The format of the GetLogName method is:
00547 %
00548 %      const char *GetLogName(void)
00549 %
00550 */
00551 MagickExport const char *GetLogName(void)
00552 {
00553   return(log_name);
00554 }
00555 
00556 /*
00557 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00558 %                                                                             %
00559 %                                                                             %
00560 %                                                                             %
00561 +   I n i t i a l i z e L o g L i s t                                         %
00562 %                                                                             %
00563 %                                                                             %
00564 %                                                                             %
00565 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00566 %
00567 %  InitializeLogList() initialize the log list.
00568 %
00569 %  The format of the InitializeLogList method is:
00570 %
00571 %      MagickBooleanType InitializeLogList(ExceptionInfo *exception)
00572 %
00573 %  A description of each parameter follows.
00574 %
00575 %    o exception: return any errors or warnings in this structure.
00576 %
00577 */
00578 static MagickBooleanType InitializeLogList(ExceptionInfo *exception)
00579 {
00580   if ((log_list == (LinkedListInfo *) NULL) && (instantiate_log == MagickFalse))
00581     {
00582       AcquireSemaphoreInfo(&log_semaphore);
00583       if ((log_list == (LinkedListInfo *) NULL) &&
00584           (instantiate_log == MagickFalse))
00585         {
00586           (void) LoadLogLists(LogFilename,exception);
00587           instantiate_log=MagickTrue;
00588         }
00589       RelinquishSemaphoreInfo(log_semaphore);
00590     }
00591   return(log_list != (LinkedListInfo *) NULL ? MagickTrue : MagickFalse);
00592 }
00593 
00594 /*
00595 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00596 %                                                                             %
00597 %                                                                             %
00598 %                                                                             %
00599 %  I s E v e n t L o g g i n g                                                %
00600 %                                                                             %
00601 %                                                                             %
00602 %                                                                             %
00603 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00604 %
00605 %  IsEventLogging() returns MagickTrue if debug of events is enabled otherwise
00606 %  MagickFalse.
00607 %
00608 %  The format of the IsEventLogging method is:
00609 %
00610 %      MagickBooleanType IsEventLogging(void)
00611 %
00612 */
00613 MagickExport MagickBooleanType IsEventLogging(void)
00614 {
00615   const LogInfo
00616     *log_info;
00617 
00618   ExceptionInfo
00619     *exception;
00620 
00621   if ((log_list == (LinkedListInfo *) NULL) ||
00622       (IsLinkedListEmpty(log_list) != MagickFalse))
00623     return(MagickFalse);
00624   exception=AcquireExceptionInfo();
00625   log_info=GetLogInfo("*",exception);
00626   exception=DestroyExceptionInfo(exception);
00627   return(log_info->event_mask != NoEvents ? MagickTrue : MagickFalse);
00628 }
00629 /*
00630 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00631 %                                                                             %
00632 %                                                                             %
00633 %                                                                             %
00634 %  L i s t L o g I n f o                                                      %
00635 %                                                                             %
00636 %                                                                             %
00637 %                                                                             %
00638 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00639 %
00640 %  ListLogInfo() lists the log info to a file.
00641 %
00642 %  The format of the ListLogInfo method is:
00643 %
00644 %      MagickBooleanType ListLogInfo(FILE *file,ExceptionInfo *exception)
00645 %
00646 %  A description of each parameter follows.
00647 %
00648 %    o file:  An pointer to a FILE.
00649 %
00650 %    o exception: return any errors or warnings in this structure.
00651 %
00652 */
00653 MagickExport MagickBooleanType ListLogInfo(FILE *file,ExceptionInfo *exception)
00654 {
00655 #define MegabytesToBytes(value) ((MagickSizeType) (value)*1024*1024)
00656 
00657   char
00658     limit[MaxTextExtent];
00659 
00660   const char
00661     *path;
00662 
00663   const LogInfo
00664     **log_info;
00665 
00666   long
00667     j;
00668 
00669   register long
00670     i;
00671 
00672   unsigned long
00673     number_aliases;
00674 
00675   if (file == (const FILE *) NULL)
00676     file=stdout;
00677   log_info=GetLogInfoList("*",&number_aliases,exception);
00678   if (log_info == (const LogInfo **) NULL)
00679     return(MagickFalse);
00680   j=0;
00681   path=(const char *) NULL;
00682   for (i=0; i < (long) number_aliases; i++)
00683   {
00684     if (log_info[i]->stealth != MagickFalse)
00685       continue;
00686     if ((path == (const char *) NULL) ||
00687         (LocaleCompare(path,log_info[i]->path) != 0))
00688       {
00689         if (log_info[i]->path != (char *) NULL)
00690           (void) fprintf(file,"\nPath: %s\n\n",log_info[i]->path);
00691         (void) fprintf(file,"Filename       Generations     Limit  Format\n");
00692         (void) fprintf(file,"-------------------------------------------------"
00693           "------------------------------\n");
00694       }
00695     path=log_info[i]->path;
00696     if (log_info[i]->filename != (char *) NULL)
00697       {
00698         (void) fprintf(file,"%s",log_info[i]->filename);
00699         for (j=(long) strlen(log_info[i]->filename); j <= 16; j++)
00700           (void) fprintf(file," ");
00701       }
00702     (void) fprintf(file,"%9lu  ",log_info[i]->generations);
00703     (void) FormatMagickSize(MegabytesToBytes(log_info[i]->limit),limit);
00704     (void) fprintf(file,"%8s  ",limit);
00705     if (log_info[i]->format != (char *) NULL)
00706       (void) fprintf(file,"%s",log_info[i]->format);
00707     (void) fprintf(file,"\n");
00708   }
00709   (void) fflush(file);
00710   log_info=(const LogInfo **) RelinquishMagickMemory((void *) log_info);
00711   return(MagickTrue);
00712 }
00713 
00714 /*
00715 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00716 %                                                                             %
00717 %                                                                             %
00718 %                                                                             %
00719 %   L o g M a g i c k E v e n t                                               %
00720 %                                                                             %
00721 %                                                                             %
00722 %                                                                             %
00723 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00724 %
00725 %  LogMagickEvent() logs an event as determined by the log configuration file.
00726 %  If an error occurs, MagickFalse is returned otherwise MagickTrue.
00727 %
00728 %  The format of the LogMagickEvent method is:
00729 %
00730 %      MagickBooleanType LogMagickEvent(const LogEventType type,
00731 %        const char *module,const char *function,const unsigned long line,
00732 %        const char *format,...)
00733 %
00734 %  A description of each parameter follows:
00735 %
00736 %    o type: the event type.
00737 %
00738 %    o filename: the source module filename.
00739 %
00740 %    o function: the function name.
00741 %
00742 %    o line: the line number of the source module.
00743 %
00744 %    o format: the output format.
00745 %
00746 */
00747 
00748 static unsigned long GetLogThreadId(void)
00749 {
00750 #if defined(MAGICKCORE_HAVE_PTHREAD) && defined(MAGICKCORE_HAVE_LINUX_UNISTD_H)
00751   return((unsigned long) ((pid_t) syscall(__NR_gettid)));
00752 #endif
00753 #if defined(__WINDOWS__)
00754   return((unsigned long) GetCurrentThreadId());
00755 #endif
00756   return((unsigned long) getpid());
00757 }
00758 
00759 static char *TranslateEvent(const LogEventType magick_unused(type),
00760   const char *module,const char *function,const unsigned long line,
00761   const char *domain,const char *event)
00762 {
00763   char
00764     *text;
00765 
00766   double
00767     elapsed_time,
00768     user_time;
00769 
00770   ExceptionInfo
00771     *exception;
00772 
00773   LogInfo
00774     *log_info;
00775 
00776   register char
00777     *q;
00778 
00779   register const char
00780     *p;
00781 
00782   size_t
00783     extent;
00784 
00785   time_t
00786     seconds;
00787 
00788   exception=AcquireExceptionInfo();
00789   log_info=(LogInfo *) GetLogInfo("*",exception);
00790   exception=DestroyExceptionInfo(exception);
00791   seconds=time((time_t *) NULL);
00792   elapsed_time=GetElapsedTime(&log_info->timer);
00793   user_time=GetUserTime(&log_info->timer);
00794   text=AcquireString(event);
00795   if (log_info->format == (char *) NULL)
00796     return(text);
00797   extent=strlen(event)+MaxTextExtent;
00798   if (LocaleCompare(log_info->format,"xml") == 0)
00799     {
00800       char
00801         timestamp[MaxTextExtent];
00802 
00803       /*
00804         Translate event in "XML" format.
00805       */
00806       (void) FormatMagickTime(seconds,extent,timestamp);
00807       (void) FormatMagickString(text,extent,
00808         "<entry>\n"
00809         "  <timestamp>%s</timestamp>\n"
00810         "  <elapsed-time>%ld:%02ld</elapsed-time>\n"
00811         "  <user-time>%0.3f</user-time>\n"
00812         "  <process-id>%ld</process-id>\n"
00813         "  <thread-id>%lu</thread-id>\n"
00814         "  <module>%s</module>\n"
00815         "  <function>%s</function>\n"
00816         "  <line>%lu</line>\n"
00817         "  <domain>%s</domain>\n"
00818         "  <event>%s</event>\n"
00819         "</entry>",timestamp,(long) (elapsed_time/60.0),
00820         (long) ceil(fmod(elapsed_time,60.0)),user_time,(long) getpid(),
00821         GetLogThreadId(),module,function,line,domain,event);
00822       return(text);
00823     }
00824   /*
00825     Translate event in "human readable" format.
00826   */
00827   q=text;
00828   for (p=log_info->format; *p != '\0'; p++)
00829   {
00830     *q='\0';
00831     if ((size_t) (q-text+MaxTextExtent) >= extent)
00832       {
00833         extent+=MaxTextExtent;
00834         text=(char *) ResizeQuantumMemory(text,extent+MaxTextExtent,
00835           sizeof(*text));
00836         if (text == (char *) NULL)
00837           return((char *) NULL);
00838         q=text+strlen(text);
00839       }
00840     /*
00841       The format of the log is defined by embedding special format characters:
00842 
00843         %c   client name
00844         %d   domain
00845         %e   event
00846         %f   function
00847         %g   generation
00848         %l   line
00849         %m   module
00850         %n   log name
00851         %p   process id
00852         %r   real CPU time
00853         %t   wall clock time
00854         %u   user CPU time
00855         %v   version
00856         %%   percent sign
00857         \n   newline
00858         \r   carriage return
00859     */
00860     if ((*p == '\\') && (*(p+1) == 'r'))
00861       {
00862         *q++='\r';
00863         p++;
00864         continue;
00865       }
00866     if ((*p == '\\') && (*(p+1) == 'n'))
00867       {
00868         *q++='\n';
00869         p++;
00870         continue;
00871       }
00872     if (*p != '%')
00873       {
00874         *q++=(*p);
00875         continue;
00876       }
00877     p++;
00878     switch (*p)
00879     {
00880       case 'c':
00881       {
00882         q+=CopyMagickString(q,GetClientName(),extent);
00883         break;
00884       }
00885       case 'd':
00886       {
00887         q+=CopyMagickString(q,domain,extent);
00888         break;
00889       }
00890       case 'e':
00891       {
00892         q+=CopyMagickString(q,event,extent);
00893         break;
00894       }
00895       case 'f':
00896       {
00897         q+=CopyMagickString(q,function,extent);
00898         break;
00899       }
00900       case 'g':
00901       {
00902         if (log_info->generations == 0)
00903           {
00904             (void) CopyMagickString(q,"0",extent);
00905             q++;
00906             break;
00907           }
00908         q+=FormatMagickString(q,extent,"%lu",log_info->generation %
00909           log_info->generations);
00910         break;
00911       }
00912       case 'l':
00913       {
00914         q+=FormatMagickString(q,extent,"%lu",line);
00915         break;
00916       }
00917       case 'm':
00918       {
00919         register const char
00920           *p;
00921 
00922         for (p=module+strlen(module)-1; p > module; p--)
00923           if (*p == *DirectorySeparator)
00924             {
00925               p++;
00926               break;
00927             }
00928         q+=CopyMagickString(q,p,extent);
00929         break;
00930       }
00931       case 'n':
00932       {
00933         q+=CopyMagickString(q,GetLogName(),extent);
00934         break;
00935       }
00936       case 'p':
00937       {
00938         q+=FormatMagickString(q,extent,"%ld",(long) getpid());
00939         break;
00940       }
00941       case 'r':
00942       {
00943         q+=FormatMagickString(q,extent,"%ld:%02ld",(long)
00944           (elapsed_time/60.0),(long) ceil(fmod(elapsed_time,60.0)));
00945         break;
00946       }
00947       case 't':
00948       {
00949         q+=FormatMagickTime(seconds,extent,q);
00950         break;
00951       }
00952       case 'u':
00953       {
00954         q+=FormatMagickString(q,extent,"%0.3fu",user_time);
00955         break;
00956       }
00957       case 'v':
00958       {
00959         q+=CopyMagickString(q,MagickLibVersionText,extent);
00960         break;
00961       }
00962       case '%':
00963       {
00964         *q++=(*p);
00965         break;
00966       }
00967       default:
00968       {
00969         *q++='%';
00970         *q++=(*p);
00971         break;
00972       }
00973     }
00974   }
00975   *q='\0';
00976   return(text);
00977 }
00978 
00979 static char *TranslateFilename(const LogInfo *log_info)
00980 {
00981   char
00982     *filename;
00983 
00984   register char
00985     *q;
00986 
00987   register const char
00988     *p;
00989 
00990   size_t
00991     extent;
00992 
00993   /*
00994     Translate event in "human readable" format.
00995   */
00996   assert(log_info != (LogInfo *) NULL);
00997   assert(log_info->filename != (char *) NULL);
00998   filename=AcquireString((char *) NULL);
00999   extent=MaxTextExtent;
01000   q=filename;
01001   for (p=log_info->filename; *p != '\0'; p++)
01002   {
01003     *q='\0';
01004     if ((size_t) (q-filename+MaxTextExtent) >= extent)
01005       {
01006         extent+=MaxTextExtent;
01007         filename=(char *) ResizeQuantumMemory(filename,extent+MaxTextExtent,
01008           sizeof(*filename));
01009         if (filename == (char *) NULL)
01010           return((char *) NULL);
01011         q=filename+strlen(filename);
01012       }
01013     /*
01014       The format of the filename is defined by embedding special format
01015       characters:
01016 
01017         %c   client name
01018         %n   log name
01019         %p   process id
01020         %v   version
01021         %%   percent sign
01022     */
01023     if (*p != '%')
01024       {
01025         *q++=(*p);
01026         continue;
01027       }
01028     p++;
01029     switch (*p)
01030     {
01031       case 'c':
01032       {
01033         q+=CopyMagickString(q,GetClientName(),extent);
01034         break;
01035       }
01036       case 'g':
01037       {
01038         if (log_info->generations == 0)
01039           {
01040             (void) CopyMagickString(q,"0",extent);
01041             q++;
01042             break;
01043           }
01044         q+=FormatMagickString(q,extent,"%lu",log_info->generation %
01045           log_info->generations);
01046         break;
01047       }
01048       case 'n':
01049       {
01050         q+=CopyMagickString(q,GetLogName(),extent);
01051         break;
01052       }
01053       case 'p':
01054       {
01055         q+=FormatMagickString(q,extent,"%ld",(long) getpid());
01056         break;
01057       }
01058       case 'v':
01059       {
01060         q+=CopyMagickString(q,MagickLibVersionText,extent);
01061         break;
01062       }
01063       case '%':
01064       {
01065         *q++=(*p);
01066         break;
01067       }
01068       default:
01069       {
01070         *q++='%';
01071         *q++=(*p);
01072         break;
01073       }
01074     }
01075   }
01076   *q='\0';
01077   return(filename);
01078 }
01079 
01080 MagickBooleanType LogMagickEventList(const LogEventType type,const char *module,
01081   const char *function,const unsigned long line,const char *format,
01082   va_list operands)
01083 {
01084   char
01085     event[MaxTextExtent],
01086     *text;
01087 
01088   const char
01089     *domain;
01090 
01091   ExceptionInfo
01092     *exception;
01093 
01094   int
01095     n;
01096 
01097   LogInfo
01098     *log_info;
01099 
01100   if (IsEventLogging() == MagickFalse)
01101     return(MagickFalse);
01102   exception=AcquireExceptionInfo();
01103   log_info=(LogInfo *) GetLogInfo("*",exception);
01104   exception=DestroyExceptionInfo(exception);
01105   AcquireSemaphoreInfo(&log_semaphore);
01106   if ((log_info->event_mask & type) == 0)
01107     {
01108       RelinquishSemaphoreInfo(log_semaphore);
01109       return(MagickTrue);
01110     }
01111   domain=MagickOptionToMnemonic(MagickLogEventOptions,type);
01112 #if defined(MAGICKCORE_HAVE_VSNPRINTF)
01113   n=vsnprintf(event,MaxTextExtent,format,operands);
01114 #else
01115   n=vsprintf(event,format,operands);
01116 #endif
01117   if (n < 0)
01118     event[MaxTextExtent-1]='\0';
01119   text=TranslateEvent(type,module,function,line,domain,event);
01120   if (text == (char *) NULL)
01121     {
01122       (void) ContinueTimer((TimerInfo *) &log_info->timer);
01123       RelinquishSemaphoreInfo(log_semaphore);
01124       return(MagickFalse);
01125     }
01126   if ((log_info->handler_mask & ConsoleHandler) != 0)
01127     {
01128       (void) fprintf(stderr,"%s\n",text);
01129       (void) fflush(stderr);
01130     }
01131   if ((log_info->handler_mask & DebugHandler) != 0)
01132     {
01133 #if defined(__WINDOWS__)
01134       OutputDebugString(text);
01135 #endif
01136     }
01137   if ((log_info->handler_mask & EventHandler) != 0)
01138     {
01139 #if defined(__WINDOWS__)
01140       (void)