Debugging MapServer¶
- Author:
Jeff McKenna
- Contact:
jmckenna at gatewaygeomatics.com
- Last Updated:
2024-06-27
Introduction¶
When developing an application for the Internet, you will inevitably across problems many problems in your environment. The goal of this guide is to assist you with locating the problem with your MapServer application.
Steps to Enable MapServer Debugging¶
Starting with MapServer 5.0, you are able to control the levels of debugging/logging information returned to you by MapServer, and also control the location of the output log file.
In technical terms, there are msDebug() calls in various areas of the MapServer code that generate information that may be useful in tuning and troubleshooting applications.
Step 1: Set the MS_ERRORFILE Variable¶
The MS_ERRORFILE variable is used to specify the output of debug messages from MapServer. You can pass the following values to MS_ERRORFILE:
- [filename]
Full path and filename of a log file, to contain MapServer’s debug messages. Any file extension can be used, but .log or .txt is recommended. The file will be created, if it does not already exist.
Starting with MapServer 6.0, a filename with relative path can be passed via the CONFIG MS_ERRORFILE directive, in which case the filename is relative to the mapfile location. Note that setting MS_ERRORFILE via an environment variable always requires an absolute path since there would be no mapfile to make the path relative to.
Note that on Linux, if your are using a path from the /tmp directory like /tmp/ms_error.txt, the log will actually output in (private directory provided by systemd) generated for the web server used (like Apache).
- stderr
Use this to send MapServer’s debug messages to the Web server’s log file (i.e. “standard error”). If you are using Apache, your debug messages will be placed in the Apache error_log file. If you are using Microsoft IIS, your debug messages will be sent to stdout (i.e. the browser), so its use is discouraged. With IIS it is recommended to direct output to a file instead.
- stdout
Use this to send MapServer’s debug messages to the standard output (i.e. the browser), combined with the rest of MapServer’s output.
- windowsdebug
Use this to send MapServer’s debug messages to the Windows OutputDebugString API, allowing the use of external programs like SysInternals debugview to display the debug output.
Through the Mapfile¶
The recommended way to set the MS_ERRORFILE variable is in your mapfile, within the MAP object, such as:
MAP
...
CONFIG "MS_ERRORFILE" "/ms4w/tmp/ms_error.txt"
...
LAYER
...
END
END
Through an Environment Variable¶
You can also set the MS_ERRORFILE variable as an environment variable on your system. Apache users can set the environment variable in Apache’s httpd.conf file, such as:
SetEnv MS_ERRORFILE "/ms4w/tmp/ms_error.txt"
Windows users can alternatively set the environment variable through the Windows System Properties; but make sure to set a SYSTEM environment variable.
Note
If both the MS_ERRORFILE environment variable is set and a CONFIG MS_ERRORFILE is also set, then the CONFIG directive takes precedence.
Step 2: Set the DEBUG Level¶
You can retrieve varying types of debug messages by setting the DEBUG parameter in the Mapfile. You can place the DEBUG parameter in any LAYER in the mapfile for layer-specific debug information, or instead, set it once in the MAP object to get general debug information. Use the value of the DEBUG parameter to set the type of information returned, as follows:
DEBUG Levels¶
- Level 0
Errors only (DEBUG OFF, or DEBUG 0)
In level 0, only msSetError() calls are logged to MS_ERORFILE. No msDebug() output at all. This is the default and corresponds to the original behavior of MS_ERRORFILE in MapServer 4.x
- Level 1
Errors and Notices (DEBUG ON, or DEBUG 1)
Level 1 includes all output from Level 0 plus msDebug() warnings about common pitfalls, failed assertions or non-fatal error situations (e.g. missing or invalid values for some parameters, missing shapefiles in tileindex, timeout error from remote WMS/WFS servers, etc.)
- Level 2
Map Tuning (DEBUG 2)
Level 2 includes all output from Level 1 plus notices and timing information useful for tuning mapfiles and applications. this is the recommended minimal debugging level
- Level 3
Verbose Debug (DEBUG 3)
All of Level 2 plus some debug output useful in troubleshooting problems such as WMS connection URLs being called, database connection calls, etc.
- Level 4
Very Verbose Debug (DEBUG 4)
Level 3 plus even more details…
- Level 5
Very Very Verbose Debug (DEBUG 5)
Level 4 plus any msDebug() output that might be more useful to developers than to users.
Mapfile Example: Map-Level Debug¶
The following example is the recommended method to set the DEBUG parameter for the map-level:
MAP
...
CONFIG "MS_ERRORFILE" "/ms4w/tmp/ms_error.txt"
DEBUG 5
...
LAYER
...
END
END
Mapfile Example: Layer-Level Debug¶
The following example is the recommended method to set the DEBUG parameter for a layer:
MAP
...
CONFIG "MS_ERRORFILE" "/ms4w/tmp/ms_error.txt"
...
LAYER
DEBUG 5
...
END
END
The MS_DEBUGLEVEL Environment Variable¶
Instead of setting the DEBUG Debug level in each of your mapfiles, you can also be set the level globally by using the MS_DEBUGLEVEL environment variable.
Tip
Although setting the MS_DEBUGLEVEL environment variable is possible, it is strongly encouraged to set DEBUG inside your mapfile for the map, layer, or class objects instead.
When set, this value is used as the default debug level value for all map and layer objects as they are loaded by the mapfile parser. This option also sets the debug level for any msDebug() call located outside of the context of a map or layer object, for instance for debug statements relating to initialization before a map is loaded. If a DEBUG value is also specified in the mapfile in some map or layer objects then the local value (in the mapfile) takes precedence over the value of the environment variable; debug info coming from outside of the context of a map or layer object cannot be turned off by having DEBUG OFF in the mapfile.
Setting this option (MS_DEBUGLEVEL) is mostly useful when tuning applications by enabling timing/debug output before the map is loaded, to capture the full process initialization and map loading time, for instance.
Apache users can set the environment variable in Apache’s httpd.conf file, such as:
SetEnv MS_DEBUGLEVEL 5
Windows users can alternatively set the environment variable through the Windows System Properties; but make sure to set a SYSTEM environment variable.
Step 3: Turn on CPL_DEBUG (optional)¶
MapServer relies on the GDAL library to access most data layers, so you may wish to turn on GDAL debugging, to hopefully get more information on how GDAL is accessing your data file. This could be very helpful for problems with accessing raster files and PostGIS tables. You can trigger this GDAL output by setting the CPL_DEBUG variable in your mapfile, within the MAP object, such as:
MAP
...
CONFIG "CPL_DEBUG" "ON"
...
LAYER
...
END
END
You can also add a timestamp (a date/time on each line) to that report with the CPL_TIMESTAMP variable, such as:
MAP
...
CONFIG "CPL_DEBUG" "ON"
CONFIG "CPL_TIMESTAMP" "ON"
...
LAYER
...
END
END
You can also add verbose output from the cURL library, which could be very useful for debugging network-hosted layer connections through GDAL such as /vsicurl with the CPL_CURL_VERBOSE variable, such as:
MAP
...
CONFIG "CPL_DEBUG" "ON"
CONFIG "CPL_CURL_VERBOSE" "ON"
...
LAYER
...
END
END
Step 4: Turn on PROJ_DEBUG (optional)¶
MapServer relies on the PROJ library to handle data projections, so you may wish to turn on PROJ debugging, to hopefully get more information back from the PROJ library. You can trigger this PROJ output by setting the PROJ_DEBUG variable in your mapfile, within the MAP object, such as:
MAP
...
CONFIG "CPL_DEBUG" "ON"
CONFIG "PROJ_DEBUG" "ON"
...
LAYER
...
END
END
Note
You can set “CPL_DEBUG” “PROJ” to restrict the information returned to PROJ (and not GDAL in general)
Note
For the full list of possible PROJ variables to use see the official list.
Step 5: Test your Mapfile¶
Once you have set the MS_ERRORFILE and DEBUG level in your mapfile, you should now test your mapfile and read your generated log file.
Using map2img¶
The recommended way to test your mapfile is to use the MapServer commandline utility map2img, to verify that your mapfile creates a valid map image. map2img should be included in your MapServer installation (MS4W users need to execute setenv.bat before using the utility).
You can set the DEBUG level by passing the map2img following parameters to your commandline call:
Note
If you have already set MS_ERRORFILE in your mapfile, you must comment this out in order to use these map2img options
Note
When using map2img to debug, your layer’s STATUS should be set to ON or DEFAULT. If the layer’s STATUS is set to OFF, you must additionally pass the layer name to map2img by using the “-l layername” syntax
-all_debug¶
Use this setting to set the debug level for the MAP object and all layers. this is the recommended switch to use
map2img -m spain.map -o test.png -all_debug 5
msLoadMap(): 0.002s
msDrawMap(): Layer 0 (spain provinces), 0.012s
msDrawRasterLayerLow(orthophoto): entering.
msDrawGDAL(): src=0,0,3540,2430, dst=188,48,1,1
source raster PL (-793.394,-1712.627) for dst PL (188,48).
msDrawGDAL(): red,green,blue,alpha bands = 1,2,3,0
msDrawMap(): Layer 1 (orthophoto), 0.150s
msDrawMap(): Layer 2 (urban areas), 0.004s
msDrawMap(): Layer 3 (species at risk), 0.008s
msDrawMap(): Layer 4 (populated places), 1.319s
msDrawMap(): Drawing Label Cache, 0.014s
msDrawMap() total time: 1.513s
msSaveImage() total time: 0.039s
msFreeMap(): freeing map at 0218C1A8.
freeLayer(): freeing layer at 0218F5E0.
freeLayer(): freeing layer at 030C33A0.
freeLayer(): freeing layer at 030C3BC8.
freeLayer(): freeing layer at 030C4948.
freeLayer(): freeing layer at 030C7678.
map2img total time: 1.567s
-map_debug¶
Use this setting to set the debug level for the MAP object only.
map2img -m spain.map -o test.png -map_debug 5
msDrawMap(): Layer 0 (spain provinces), 0.012s
msDrawRasterLayerLow(orthophoto): entering.
msDrawMap(): Layer 1 (orthophoto), 0.144s
msDrawMap(): Layer 2 (urban areas), 0.004s
msDrawMap(): Layer 3 (species at risk), 0.008s
msDrawMap(): Layer 4 (populated places), 1.323s
msDrawMap(): Drawing Label Cache, 0.013s
msDrawMap() total time: 1.511s
msSaveImage() total time: 0.039s
msFreeMap(): freeing map at 0205C1A8.
-layer_debug¶
Use this setting to set the debug level for one layer object only.
map2img -m spain.map -o test.png -layer_debug orthophoto 5
msDrawRasterLayerLow(orthophoto): entering.
msDrawGDAL(): src=0,0,3540,2430, dst=188,48,1,1
source raster PL (-793.394,-1712.627) for dst PL (188,48).
msDrawGDAL(): red,green,blue,alpha bands = 1,2,3,0
msDrawMap(): Layer 1 (orthophoto), 0.151s
freeLayer(): freeing layer at 02F23390.
Set CPL_DEBUG¶
At the commandline execute the following:
set CPL_DEBUG=ON
map2img -m spain.map -o test.png -layer_debug orthophoto 5
msDrawRasterLayerLow(orthophoto): entering.
GDAL: GDALOpen(D:\ms4w\apps\spain\map/.\../data/ov172068_200904_c100u50x75c24n.jpg, this=0
4059840) succeeds as JPEG.
msDrawGDAL(): src=0,0,3540,2430, dst=188,48,1,1
source raster PL (-793.394,-1712.627) for dst PL (188,48).
msDrawGDAL(): red,green,blue,alpha bands = 1,2,3,0
GDAL: GDALDefaultOverviews::OverviewScan()
msDrawMap(): Layer 1 (orthophoto), 0.155s
freeLayer(): freeing layer at 03113390.
GDAL: GDALDeregister_GTiff() called.
Reading Errors Returned by map2img¶
If there is a problem with your mapfile, map2img should output the line number in your mapfile that is causing the trouble. The following tells us that there is a problem on line 85 of my mapfile:
getSymbol(): Symbol definition error. Parsing error near (truetype2):(line 85)
If you are using mapfile INCLUDEs, it may be tricky to track down this line number, but most of the time the line number is useful.
Using mapserv CGI¶
Another handy way to test your mapfile is to call the mapserv CGI executable at the commandline, such as the following:
mapserv -nh "QUERY_STRING=map=/ms4w/apps/spain/map/spain.map&mode=map"
ON_MISSING_DATA¶
If you are using tile indexes to access your data, you should also be aware of the configuration settings added in MapServer 5.4 that allow you to tell MapServer how to handle missing data in tile indexes. Please see the CONFIG parameter’s ON_MISSING_DATA setting in the MAP object for more information.
Hint
You can check the attributes in the tileindex by executing “ogrinfo -al” on your data file
Step 6: Check your Web Server Logs¶
Once you have verified that there are no problems with you mapfile, next you should check your Web server log files, for any related information that may help you narrow down your problem.
Apache¶
Unix users will usually find Apache’s error_log file in a path similar to:
/var/log/apache2/
Windows users will usually find Apache’s log files in a path similar to:
C:\Program Files\Apache Group\Apache2\logs
MapServer for Windows (MS4W) users will find Apache’s log files at:
\ms4w\Apache\logs
Microsoft IIS¶
IIS log files can be located by:
Go to Start -> Control Panel -> Administrative Tools
Open the Internet Information Services (IIS) Manager.
Find your Web site under the tree on the left.
Right-click on it and choose Properties.
On the Web site tab, you will see an option near the bottom that says “Active Log Format.” Click on the Properties button.
At the bottom of the General Properties tab, you will see a box that contains the log file directory and the log file name. The full log path is comprised of the log file directory plus the first part of the log file name, for example:
C:\WINDOWS\system32\LogFiles\W3SVC1\ex100507.log
You may also want to check the Windows Event Viewer logs, which is located at:
Go to Start -> Control Panel -> Administrative Tools
Computer Management
Event Viewer
Warning
As mentioned previously, in IIS the MapServer stderr debug output is returned to the client instead of routed to the Web Server logs, so be sure to log the output to a file, by setting the following in your mapfile:
CONFIG "MS_ERRORFILE" "/ms4w/tmp/ms_error.txt"
CGI Error - The specified CGI application misbehaved by not returning a complete set of HTTP headers¶
This error is often caused by missing DLL files. You should try to execute “mapserv -v at the commandline, to make sure that MapServer loads properly.
Step 7: Verify your Application Settings¶
If you have verified that MapServer creates a valid map image through map2img, you’ve checked your MapServer log files, and there are no problems noted in your Web server logs, then you should focus your attention on possible application configuration problems. “Application” here means how you are displaying your map images on the Web page, such as with OpenLayers.
Step 8: Use QGIS to test your OGC services¶
When configuring MapServer for OGC services (WMS, WFS, etc.) it sometimes happens that users of your services report map issues in a desktop GIS or online application, even though no errors, logs, or local map2img tests give any hints; this is where the QGIS Network Logger can really help to get the exact problem request. For steps on how to implement the network logger see here.
Tip
To get the exact problem request, add your MapServer service as a QGIS layer, then right-click on the request in the Network Logger and select “Open URL” to see the full request and resulting map image in your browser.
PHP MapScript¶
If you are using PHP MapScript in your application, here are some important notes for debugging:
1. Make sure your php.ini file is configured to show all errors, by setting:
display_errors = On
To enable debugging in PHP MapScript, if you are using MapServer 5.6.0 or more recent, make sure to define ZEND_DEBUG in the PHP source.
If you are using MapServer < 5.6.0, then:
open the file /mapscript/php3/php_mapscript.c
change the following:
#define ZEND_DEBUG 0 to #define ZEND_DEBUG 1
Debugging MapServer using Compiler Debugging Tools¶
Running MapServer in GDB (Linux/Unix)¶
Section author: Frank Warmerdam
Building with Symbolic Debug Info¶
It is not strictly necessary to build MapServer with debugging enabled in order to use GDB on linux, but it does ensure that more meaningful information is reported within GDB. To enable full symbolic information use the –enable-debug configure switch. Note that use of this switch disables optimization and so it should not normally be used for production builds where performance is important.
./configure --enable-debug <other switches>
make clean
make
Running in the Debugger¶
To run either mapserv or map2img, give the name of the executable as an argument to the “gdb” command. If it is not in the path, you will need to provide the full path to the executable.
gdb map2img
GNU gdb (GDB) 7.0-ubuntu
Copyright (C) 2009 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /wrk/home/warmerda/mapserver/map2img...done.
(gdb)
Once you are at the “(gdb)” prompt you can use the run command with the arguments you would normally have passed to the mapserv or map2img executable.
(gdb) run -m test.map -o out.png
Starting program: /wrk/home/warmerda/mapserver/map2img -m test.map -o out.png
[Thread debugging using libthread_db enabled]
Program received signal SIGSEGV, Segmentation fault.
0x00007ffff67594a2 in JP2KAKDataset::Identify (poOpenInfo=0x0)
at jp2kakdataset.cpp:962
962 if( poOpenInfo->nHeaderBytes < (int) sizeof(jp2_header) )
Current language: auto
The current source language is "auto; currently c++".
(gdb)
If the program is crashing, you will generally get a report like the above indicating the function the crash occurred in, and some minimal information on why. It is often useful to request a traceback to see what functions led to the function that crashed. For this use the “where” command.
(gdb) where
#0 0x00007ffff67594a2 in JP2KAKDataset::Identify (poOpenInfo=0x0)
at jp2kakdataset.cpp:962
#1 0x00007ffff67596d2 in JP2KAKDataset::Open (poOpenInfo=0x7fffffffb6f0)
at jp2kakdataset.cpp:1025
#2 0x00007ffff6913339 in GDALOpen (
pszFilename=0x83aa60 "/home/warmerda/data/jpeg2000/spaceimaging_16bit_rgb.jp
2", eAccess=GA_ReadOnly) at gdaldataset.cpp:2170
#3 0x00007ffff69136bf in GDALOpenShared (
pszFilename=0x83aa60 "/home/warmerda/data/jpeg2000/spaceimaging_16bit_rgb.jp
2", eAccess=GA_ReadOnly) at gdaldataset.cpp:2282
#4 0x0000000000563c2d in msDrawRasterLayerLow (map=0x81e450, layer=0x839140,
image=0x83af90, rb=0x0) at mapraster.c:566
#5 0x000000000048928f in msDrawRasterLayer (map=0x81e450, layer=0x839140,
image=0x83af90) at mapdraw.c:1390
#6 0x0000000000486a48 in msDrawLayer (map=0x81e450, layer=0x839140,
image=0x83af90) at mapdraw.c:806
#7 0x00000000004858fd in msDrawMap (map=0x81e450, querymap=0) at mapdraw.c:459
#8 0x0000000000446410 in main (argc=5, argv=0x7fffffffd918) at map2img.c:300
(gdb)
It may also be helpful to examine variables used in the line where the crash occurred. Use the print command for this.
(gdb) print poOpenInfo
$1 = (GDALOpenInfo *) 0x0
In this case we see that the program crashed because poOpenInfo was NULL (zero). Including a traceback like the above in bug report can help the developers narrow down a problem more quickly, especially if it is one that is difficult for the developers to reproduce themselves.
Debugging Older Versions of MapServer (before 5.0)¶
Make sure that MapServer is compiled in debug mode (on unix this is enabled through ./configure –enable-debug).
You can verify that your build was compiled in debug mode, by executing the following at the commandline (look for “DEBUG=MSDEBUG”):
./mapserv -v MapServer version 4.10.2 OUTPUT=GIF OUTPUT=PNG OUTPUT=WBMP OUTPUT=SVG SUPPORTS=PROJ SUPPORTS=FREETYPE SUPPORTS=WMS_SERVER SUPPORTS=WMS_CLIENT SUPPORTS=WCS_SERVER SUPPORTS=THREADS SUPPORTS=GEOS INPUT=EPPL7 INPUT=POSTGIS INPUT=OGR INPUT=GDAL INPUT=SHAPEFILE DEBUG=MSDEBUG
Set the MS_ERRORFILE variable is in your mapfile, within the MAP object, such as:
MAP ... CONFIG "MS_ERRORFILE" "/ms4w/tmp/ms_error.txt" ... LAYER ... END END
If you don’t use the MS_ERRORFILE variable, you can use the LOG parameter in your WEB object of the mapfile, such as:
MAP ... WEB LOG "mapserver.log" END ... LAYER ... END END
Specify DEBUG ON in your MAP object, or in your LAYER objects, such as:
MAP ... WEB LOG "mapserver.log" END DEBUG ON ... LAYER ... END END
Note that only errors will be written to the log file; all DEBUG output goes to stderr, in the case of Apache that is Apache’s error_log file. If you are using Microsoft IIS, debug output is routed to stdout (i.e. the browser), so be sure to remove DEBUG ON statements if using IIS on a production server.
.