cPanel® Blog

How to trace the cPanel API

At this point, cPanel’s APIs are not 100% documented.  We are working on it and hope to have complete API docs up in a few months.  I’ve written a CustomEventHandler that will print every API call made into cpanel’s error_log (/usr/local/cpanel/logs/error_log).

Installation
To use the API Tracer, you will need to download it, then place the Dumper.pm file at /usr/local/cpanel/perl/Dumper and the CustomEventHandler.pm file at /usr/local/cpanel/Cpanel.

Once this has been put into the proper location, cPanel will automatically start logging API calls to the error_log.  To view each call, you simply need to run tail -f /usr/local/cpanel/logs/error_log and login to a cPanel interface to start seeing data.

Filtering
90% of the information displayed by the API Tracer is probably not what you are looking for.  If you look at the code for this CustomEventHandler, you will see that the following pieces of information are passed to it:
my ( $apiv, $type, $module, $event, $cfgref, $dataref ) = @_;

Out of these, for the purpose of filtering, the only ones that we care about are the following variables:
$apiv - API Version
$module - The module of the function being called
$event - The name of the function being called

When a custom event handler runs, it is executed both before and after the call has been completed.  This is indicated by the $type variable which will pass “pre” before the event has been executed and “post” after the event has been executed.  The most important thing to note here is that in the event of a “pre” call, if CustomEventHandler returns a false value, it will stop execution of the event, so in this scenario it is very important to always return 1.  For example, if you are trying to filter an email event, you will see something like the following right after the first line of the event() function:
return 1 if $module ne ‘email’;

It is also important to note that modules and function names are passed in lowercase form to the CustomEventHandler.

If you want to filter for a very specific call, you would do something like the following
return 1 if module ne ‘email’ && $event ne ‘addpop’;

Understanding the Data passed to the tracer
Now that you understand how the tracer operates and how to make it report useful information, we need to talk about how to understand the data that it gives.

As you will see, the Tracer will print formatted text to the error log that looks something like this:
--------------------
mysql:adduserdb
$apiv = 1
$type = pre
-----
$cfgref

$VAR1 = {
          'param0' => 'cptest_dbname',
          'param1' => 'cptest_username',
          'param2' => 'ALTER CREATEROUTINE TEMPORARY CREATE DELETE DROP SELECT INSERT UPDATE REFERENCES INDEX LOCK '
        };

mysql:adduserdb
--------------------
mysql:adduserdb
$apiv = 1
$type = post
-----
$cfgref

$VAR1 = {
          'param0' => 'cptest_dbname',
          'param1' => 'cptest_username',
          'param2' => 'ALTER CREATEROUTINE TEMPORARY CREATE DELETE DROP SELECT INSERT UPDATE REFERENCES INDEX LOCK '
        };

-----
output

The first line indicates the module and the version, the second line describes which API version it’s using (either API1 (link) or API2 (link) ).  After this, it displays two variables, $cfgref and $dataref.  These two variables indicate the input ($cfgref) and output ($dataref) from the function in a Data::Dumper format.

Understanding $cfgrefAs API1 and API2 use different methods of input, they naturally have different methods of displaying within this module.  When using API1 you will see something like the following:$VAR1 = {
          'param0' => 'cptest_dbname',
          'param1' => 'cptest_',
          'param2' => 'ALTER CREATEROUTINE TEMPORARY CREATE DELETE DROP SELECT INSERT UPDATE REFERENCES INDEX LOCK '
        };

These indicate the order of parameters to API1, starting with param0 to paramn.  This data can be correlated to what input was given to the cPanel interface to determine the call.

With API2, since it uses named parameters, rather than ordered parameters you will see something like the following:
$cfgref
$VAR1 = {
          'quota' => 250,
          'password' => 'somepasswprd',
          'domain' => 'somedomain.com',
          'email' => 'someuser'
        };

With these, the parameter name maps directly to the parameter name for API2.  This is fairly easy to understand, however there are a few things that need to be noted.  Firstly, use of generic parameters that will probably not aid you.  There are a few of these mostly prefixed with “api2_”, are used for things like sorting, pagination, searching, etc.  The other main parameter to pay attention to is “cache_fix” which is used for browser caching and should always be ignored.

Understanding the output from $dataref
One thing that you will only see in “post” calls, is the $dataref being populated.  This contains the output from the Tracer. API1 output is usually straight forward, as they return strings rather than data structures. Take for example, Email::addpop, it will return the name of the email address:
email+domain.com

This will be populated with an error message in the case of an error.

API2, as it’s far more robust than API1, returns actual data structures.  These can be complex to work with.  Please refer to the API2 documentation (link) on how to work with this data.  When it is returned it will look like the following:
          {
            'diskquota' => 250,
            'humandiskquota' => '250 MB',
            'user' => 'asdge33',
            '_diskused' => 0,
            'humandiskused' => 'None',
            '_diskquota' => 262144000,
            'txtdiskquota' => 250,
            'diskusedpercent' => 0,
            'diskusedpercent20' => 0,
            'login' => 'asdge33@cptest.com',
            'domain' => 'cptest.com',
            'diskused' => 0,
            'email' => 'asdge33@cptest.com'
          },

This would be displayed in XML format via the XML-API by:

<data>
<_diskquota>262144000</_diskquota>
<_diskused>0</_diskused>
<diskquota>250</diskquota>
<diskused>0</diskused>
<diskusedpercent>0</diskusedpercent>
<diskusedpercent20>0</diskusedpercent20>
<domain>cptest.com</domain>
<email>asdge33@cptest.com</email>
<humandiskquota>250 MB</humandiskquota>
<humandiskused>None</humandiskused>
<login>asdge33@cptest.com</login>
<txtdiskquota>250</txtdiskquota>
<user>asdge33</user>
</data>

There are some shortcomings that need to be noted:

  1. This version of Tracer requires that /dev/shm to be writable, the path for the temp file can be edited within the script however /dev/shm is the fastest place.
  2. This means that usernames and passwords for anything created/modified through the cPanel interface will be written to the error_log.  You need to clear the error_log after enabling this, and be careful that it’s not left running on a production server due to the inherent security risks.

cPanel

The web hosting industry’s most reliable, intuitive control panel since 1997. With our first-class support and rich feature set, it’s easy to see why our customers and partners make cPanel & WHM their hosting platform of choice. For more information, visit cPanel.com.