Imagine you have developed a state-of-art website and after 30 days of worry-free time it finally happens:
Your clients visit the website (let’s imagine this one) and see anything but the expected result: a working web app.
The normal reaction is to call you (in the most unpropriate time) and ask you to fix it asap, because he/she is losing money or the world will end in pain just because this service is not working.
I am sure you will spend 5 min convincing him/her that you haven’t done anything wrong and most probably it’s their fault. Then you will spend another 5 min listening to other-side arguments and after that you will start fixing the problem, without even knowing what it is.
Let’s see how it should be done if we don’t want the user to wake you in the middle of the night and without fighting the “white screen of death”.
Let’s have a really simple JSON request and an error to be able to reproduce our case:
$json_data = '{"value":1,"apples":2,"name":3,"oranges":4,"last one":5}';
//we will simulate the json data, but imagine that this is the normal data
exchanged daily between your client’s website and a 3-rd party API
$ch = curl_init('http://talkweb.eu/labs/fr/json_callback.php');
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
curl_setopt($ch, CURLOPT_POSTFIELDS, $json_data);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'Content-Type: application/json',
'Content-Length: ' . strlen($json_data)));
//the normal CURL request, nothing strange here:
$result = curl_exec($ch);
//receiving the data back
$f_data = json_decode($result,true);
//showing a greeting with the output
echo “Welcome”. $f_data['username'];
If you visit the test website now, you will notice that definitely there is a problem and your client will notice it as well.
The question is - how he/she can report it faster with all the data you need to fight the bug:
- Json data,
- Server-side Javascript and XmlHttpsRequest errors,
- Some core PHP errors
- ...and meta data.
##Writing more code
Let’s add some more code to the example in order to see how we can collect the data we need. Introducing a really simple class to help me with the mission:
<?
class SendToUsersnap
{
var $m;
//Save all logs in a array. You can use an even more elegant approach but right now I need it to be simple.
function log ( $data, $type ) {
if( is_array( $data ) || is_object( $data ) ) {
$this->m[]= "console.".$type."('PHP: ".json_encode($data)."');";
} else {
$this->m[] = "console.".$type."('PHP: ".$data."');";
}
}
// Print all logs that have been set from the previous function. Let’s keep it simple.
function out (){
for ($i=0;$i<count($this->m);$i++)
{
echo $this->m[$i]."\n";
}
}
}
?>
Now let’s use this class to record all errors and logs we may need.
require_once('Usersnap.class.php');
$s = new SendToUsersnap;
$json_data = '{"value":1,"apples":2,"name":3,"oranges":4,"last one":5}';
$s->log('Initializing the JSON request',"info");
$s->log($json_data,"log");
$ch = curl_init('http://talkweb.eu/labs/fr/json_callback.php');
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
curl_setopt($ch, CURLOPT_POSTFIELDS, $json_data);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'Content-Type: application/json',
'Content-Length: ' . strlen($json_data)));
$result = curl_exec($ch);
$f_data = json_decode($result,true);
echo 'Welcome'. $f_data['usersname'];
$s->log($f_data,"log");
$s->log(error_get_last(),"error");
##Bring the data to the developer.
So, we have a bug, we also have all the data we need to debug it, but the data is on the client’s computer. We still don’t have a way to deliver the data to the developer or to the bug-tracking system.
##Now this is how to do it using the Usersnap widget
Let’s add the code-snippet at the end of our page and see what happens. (You may need an account to use this widget. Usersnap team offers free licenses for Open Source projects and a free testing period if you want to see the magic on your own project).
<script type="text/javascript">
(function() {
var s = document.createElement("script");
s.type = "text/javascript";
s.async = true;
s.src = '//api.usersnap.com/load/'+
'your-api-key-here.js';
var x = document.getElementsByTagName('script')[0];
x.parentNode.insertBefore(s, x);
})();
var _usersnapconfig = {
loadHandler: function() {
<?php
//just print all errors collected from the buffer.
$s->out(); ?>
}
};
</script>
The user will see a “report bug” button on the page and will write you a message “it’s now working, fix it asap” and you will get this beatiful error log attached to your bug:
Now you can see that there is initialization session in place:
$s->log('Initializing the JSON request',"info");
You can see the data we will send - the same as usual
$s->log($json_data,"log");
And you can see the output. Yes, the problem is there. Obviously there is an auth problem.
$s->log($f_data,"log");
You can get even the core PHP errors to help you with the debugging.
$s->log(error_get_last(),"error");
Your client will only have to the button once and you will get everything you need to fight the bug faster + even core PHP errors. When I am saying anything I do mean anything:
- Errors and Logs (covered by example above)
- Annotated screenshot - if the problem is more complex that this lousy example
- Screen size, Browser version, OS and the plugins installed on the browser
##A note about security Of course you can turn this feature on only when your client needs it, for example with passing 2 parameters to the request.php: ?debug=true&pass=[password-here] or using something else.
##A note about usefulness This is not a script-monitoring tool and will not deliver information automatically when and if the problem appears. This approach will work only if an user or a client reports a bug and you as developer or QA need more info on how to fight the bug. Imagine it as a remote debugger, but for client-side errors + events and data you send from PHP to the Javascript.
I’d love to answer all of your questions!