root/branches/branch-5-0/mapserver/mapdebug.c

Revision 6770, 10.0 kB (checked in by tamas, 10 months ago)

Use spaces instead of tabs with the recent fix

Line 
1 /******************************************************************************
2  *
3  * Project:  MapServer
4  * Purpose:  Implementation of debug/logging, msDebug() and related functions.
5  * Author:   Daniel Morissette
6  *
7  ******************************************************************************
8  * Copyright (c) 1996-2007 Regents of the University of Minnesota.
9  *
10  * Permission is hereby granted, free of charge, to any person obtaining a
11  * copy of this software and associated documentation files (the "Software"),
12  * to deal in the Software without restriction, including without limitation
13  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
14  * and/or sell copies of the Software, and to permit persons to whom the
15  * Software is furnished to do so, subject to the following conditions:
16  *
17  * The above copyright notice and this permission notice shall be included in
18  * all copies of this Software or works derived from this Software.
19  *
20  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26  * DEALINGS IN THE SOFTWARE.
27  ****************************************************************************/
28
29
30 #include "mapserver.h"
31 #include "maperror.h"
32 #include "mapthread.h"
33 #include "maptime.h"
34
35 #include <time.h>
36 #ifndef _WIN32
37 #include <sys/time.h>
38 #include <unistd.h>
39 #endif
40 #include <stdarg.h>
41
42 #ifdef NEED_NONBLOCKING_STDERR
43 #include <fcntl.h>
44 #endif
45
46 #ifdef _WIN32
47 #include <windows.h> /* OutputDebugStringA() */
48 #endif
49
50 #if defined(_WIN32) && !defined(__CYGWIN__)
51 /* Need to use _vsnprintf() with VS2003 */
52 #define vsnprintf _vsnprintf
53 #endif
54
55 MS_CVSID("$Id: $")
56
57
58 #ifndef USE_THREAD
59
60 debugInfoObj *msGetDebugInfoObj()
61 {
62     static debugInfoObj debuginfo = {MS_DEBUGLEVEL_ERRORSONLY,
63                                      MS_DEBUGMODE_OFF, NULL, NULL };
64     return &debuginfo;
65 }
66
67 #else
68
69 static debugInfoObj *debuginfo_list = NULL;
70
71 debugInfoObj *msGetDebugInfoObj()
72 {
73     debugInfoObj *link;
74     int          thread_id;
75     debugInfoObj *ret_obj;
76    
77     msAcquireLock( TLOCK_DEBUGOBJ );
78    
79     thread_id = msGetThreadId();
80
81     /* find link for this thread */
82    
83     for( link = debuginfo_list;
84          link != NULL && link->thread_id != thread_id
85              && link->next != NULL && link->next->thread_id != thread_id;
86          link = link->next ) {}
87
88     /* If the target thread link is already at the head of the list were ok */
89     if( debuginfo_list != NULL && debuginfo_list->thread_id == thread_id )
90     {
91     }
92
93     /* We don't have one ... initialize one. */
94     else if( link == NULL || link->next == NULL )
95     {
96         debugInfoObj *new_link;
97
98         new_link = (debugInfoObj *) malloc(sizeof(debugInfoObj));
99         new_link->next = debuginfo_list;
100         new_link->thread_id = thread_id;
101         new_link->global_debug_level = MS_DEBUGLEVEL_ERRORSONLY;
102         new_link->debug_mode = MS_DEBUGMODE_OFF;
103         new_link->errorfile = NULL;
104         new_link->fp = NULL;
105
106         debuginfo_list = new_link;
107     }
108
109     /* If the link is not already at the head of the list, promote it */
110     else if( link != NULL && link->next != NULL )
111     {
112         debugInfoObj *target = link->next;
113
114         link->next = link->next->next;
115         target->next = debuginfo_list;
116         debuginfo_list = target;
117     }
118
119     ret_obj = debuginfo_list;
120
121     msReleaseLock( TLOCK_DEBUGOBJ );
122
123     return ret_obj;
124 }
125 #endif
126
127
128 /* msSetErrorFile()
129 **
130 ** Set output target, ready to write to it, open file if necessary
131 **
132 ** Returns MS_SUCCESS/MS_FAILURE
133 */
134 int msSetErrorFile(const char *pszErrorFile)
135 {
136     debugInfoObj *debuginfo = msGetDebugInfoObj();
137
138     if (debuginfo->errorfile && pszErrorFile &&
139         strcmp(debuginfo->errorfile, pszErrorFile) == 0)
140     {
141         /* Nothing to do, already writing to the right place */
142         return MS_SUCCESS;
143     }
144
145     /* Close current output file if any */
146     msCloseErrorFile();
147
148     /* NULL or empty target will just close current output and return */
149     if (pszErrorFile == NULL || *pszErrorFile == '\0')
150         return MS_SUCCESS; 
151
152     if (strcmp(pszErrorFile, "stderr") == 0)
153     {
154         debuginfo->fp = stderr;
155         debuginfo->errorfile = strdup(pszErrorFile);
156         debuginfo->debug_mode = MS_DEBUGMODE_STDERR;
157 #if defined(NEED_NONBLOCKING_STDERR) && !defined(USE_MAPIO) && !defined(_WIN32)
158         fcntl(fileno(stderr), F_SETFL, O_NONBLOCK);
159         nonblocking_set = 1;
160 #endif
161     }
162     else if (strcmp(pszErrorFile, "stdout") == 0)
163     {
164         debuginfo->fp = stdout;
165         debuginfo->errorfile = strdup(pszErrorFile);
166         debuginfo->debug_mode = MS_DEBUGMODE_STDOUT;
167     }
168     else if (strcmp(pszErrorFile, "windowsdebug") == 0)
169     {
170 #ifdef _WIN32
171         debuginfo->errorfile = strdup(pszErrorFile);
172         debuginfo->fp = NULL;
173         debuginfo->debug_mode = MS_DEBUGMODE_WINDOWSDEBUG;
174 #else
175         msSetError(MS_MISCERR, "'MS_ERRORFILE windowsdebug' is available only on Windows platforms.", "msSetErrorFile()");
176         return MS_FAILURE;
177 #endif
178     }
179     else
180     {
181         debuginfo->fp = fopen(pszErrorFile, "a");
182         if (debuginfo->fp == NULL)
183         {
184             msSetError(MS_MISCERR, "Failed to open MS_ERRORFILE %s", "msSetErrorFile()", pszErrorFile);
185             return MS_FAILURE;
186         }
187         debuginfo->errorfile = strdup(pszErrorFile);
188         debuginfo->debug_mode = MS_DEBUGMODE_FILE;
189     }
190
191     return MS_SUCCESS;
192 }
193
194 /* msCloseErrorFile()
195 **
196 ** Close current output file (if one is open) and reset related members
197 */
198 void msCloseErrorFile()
199 {
200     debugInfoObj *debuginfo = msGetDebugInfoObj();
201
202     if (debuginfo && debuginfo->debug_mode != MS_DEBUGMODE_OFF)
203     {
204         if (debuginfo->fp && debuginfo->debug_mode == MS_DEBUGMODE_FILE)
205             fclose(debuginfo->fp);
206
207         if (debuginfo->fp && (debuginfo->debug_mode == MS_DEBUGMODE_STDERR ||
208                               debuginfo->debug_mode == MS_DEBUGMODE_STDOUT))
209             fflush(debuginfo->fp); /* just flush stderr or stdout */
210
211         debuginfo->fp = NULL;
212
213         msFree(debuginfo->errorfile);
214         debuginfo->errorfile = NULL;
215
216         debuginfo->debug_mode = MS_DEBUGMODE_OFF;
217     }
218 }
219
220
221
222 /* msGetErrorFile()
223 **
224 ** Returns name of current error file
225 **
226 ** Returns NULL if not set.
227 */
228 const char *msGetErrorFile()
229 {
230     debugInfoObj *debuginfo = msGetDebugInfoObj();
231
232     if (debuginfo)
233         return debuginfo->errorfile;
234    
235     return NULL;
236 }
237
238 /* Set/Get the current global debug level value, used as default value for
239 ** new map and layer objects and to control msDebug() calls outside of
240 ** the context of mapObj or layerObj.
241 **
242 */
243 void msSetGlobalDebugLevel(int level)
244 {
245     debugInfoObj *debuginfo = msGetDebugInfoObj();
246
247     if (debuginfo)
248         debuginfo->global_debug_level = (debugLevel)level;
249 }
250
251 debugLevel msGetGlobalDebugLevel()
252 {
253     debugInfoObj *debuginfo = msGetDebugInfoObj();
254
255     if (debuginfo)
256         return debuginfo->global_debug_level;
257
258     return MS_DEBUGLEVEL_ERRORSONLY;
259 }
260
261
262 /* msDebugInitFromEnv()
263 **
264 ** Init debug state from MS_ERRORFILE and MS_DEBUGLEVEL env vars if set
265 **
266 ** Returns MS_SUCCESS/MS_FAILURE
267 */
268 int msDebugInitFromEnv()
269 {
270     const char *val;
271
272     if( (val=getenv( "MS_ERRORFILE" )) != NULL )
273     {
274         if ( msSetErrorFile(val) != MS_SUCCESS )
275             return MS_FAILURE;
276     }
277    
278     if( (val=getenv( "MS_DEBUGLEVEL" )) != NULL )
279         msSetGlobalDebugLevel(atoi(val));
280
281     return MS_SUCCESS;
282 }
283
284
285 /* msDebugCleanup()
286 **
287 ** Called by msCleanup to remove info related to this thread.
288 */
289 void msDebugCleanup()
290 {
291     /* make sure file is closed */
292     msCloseErrorFile();
293
294 #ifdef USE_THREAD
295   {
296       int  thread_id = msGetThreadId();
297       debugInfoObj *link;
298
299       msAcquireLock( TLOCK_DEBUGOBJ );
300      
301       /* find link for this thread */
302    
303       for( link = debuginfo_list;
304            link != NULL && link->thread_id != thread_id
305                && link->next != NULL && link->next->thread_id != thread_id;
306            link = link->next ) {}
307      
308       if( link->thread_id == thread_id )
309       {
310           /* presumably link is at head of list.  */
311           if( debuginfo_list == link )
312               debuginfo_list = link->next;
313
314           free( link );
315       }
316       else if( link->next != NULL && link->next->thread_id == thread_id )
317       {
318           debugInfoObj *next_link = link->next;
319           link->next = link->next->next;
320           free( next_link );
321       }
322       msReleaseLock( TLOCK_DEBUGOBJ );
323   }
324 #endif
325
326 }
327
328 /* msDebug()
329 **
330 ** Outputs/logs messages to the MS_ERRORFILE if one is set
331 ** (see msSetErrorFile())
332 **
333 */
334 void msDebug( const char * pszFormat, ... )
335 {
336     va_list args;
337     debugInfoObj *debuginfo = msGetDebugInfoObj();
338
339     if (debuginfo == NULL || debuginfo->debug_mode == MS_DEBUGMODE_OFF)
340         return/* Don't waste time here! */
341
342     if (debuginfo->fp)
343     {
344         /* Writing to a stdio file handle */
345
346 #if defined(USE_FASTCGI)
347         /* It seems the FastCGI stuff inserts a timestamp anyways, so  */
348         /* we might as well skip this one if writing to stderr w/ FastCGI. */
349         if (debuginfo->debug_mode != MS_DEBUGMODE_STDERR)
350 #endif
351         {
352             struct mstimeval tv;
353             time_t t;
354             msGettimeofday(&tv, NULL);
355             t = tv.tv_sec;
356             msIO_fprintf(debuginfo->fp, "[%s].%ld ",
357                          msStringChop(ctime(&t)), (long)tv.tv_usec);
358         }
359
360         va_start(args, pszFormat);
361         msIO_vfprintf(debuginfo->fp, pszFormat, args);
362         va_end(args);
363     }
364 #ifdef _WIN32
365     else if (debuginfo->debug_mode == MS_DEBUGMODE_WINDOWSDEBUG)
366     {
367         /* Writing to Windows Debug Console */
368
369         char szMessage[MESSAGELENGTH];
370
371         va_start(args, pszFormat);
372         vsnprintf( szMessage, MESSAGELENGTH, pszFormat, args );
373         va_end(args);
374
375         szMessage[MESSAGELENGTH-1] = '\0';
376         OutputDebugStringA(szMessage);
377     }
378 #endif
379
380 }
381
Note: See TracBrowser for help on using the browser.