/snitchin

Snitches get Stich... errr .... logged?

Primary LanguagePHP

#Snitchin Out of the box, snitchin is a simple logger. However, it's purpose is much more than just this as I like to think of it as an emitter of sorts. Files, emails, slack channels, HTTP get/put requests and whatever else you can think of.

Before we dive into the specifics, lets first go over some terms.

###Glossary Snitcher - In short, it's a way to store information to a file, a curl request, an email, a slack channel, to the console or wherever else you can imagine putting this information. A callback that takes 2 parameters. The first being $log_entry which is an array that consists of a few basic values such as the timestamp, the message, the level and level text and a few others. The second being $options which is comprised of a mixed array needed to get the snitch up and running. An example for options would be a string of a filepath to save information to. Another quick example would be the slack channel url to post snitches.

Level - An integer value(presets are given) that you can customize that will determine if a snitch is to be called. Presets include the following:

  • fatal: 60
  • error: 50
  • warn: 40
  • info: 30
  • debug: 20
  • trace: 10

You can create new levels by using the levels() method. By default, if you create a new level without a numerical value, 61 will be assigned. The default emitter level is 60, meaning any custom levels you create will automatically be emitted.

Channels - A way to seperate different emitted events. You get a "default" channel out of the box, and you can create as many channels as needed. Some channels that might be of interest in creating: 'test','security','appspecific' etc ...

#Installation The easiest way is to use composer and packagist. The package name is "kcmerrill/snitchin"

#A quick but comprehensive demo

  <?php
  require_once 'vendor/autoload.php';
  use \kcmerrill\utility\snitchin as snitchin;

  $log = new snitchin($argv);
  $log->channel('security','slack|file|email|newcustomthingy');
  $log['security']->snitcher('file','/tmp/snitchin.txt');
  $log['security']->snitcher('slack','https://hooks.slack.com/services/_something_/_else_/_goes_here_');
  $log['security']->snitcher('email','kcmerrill@gmail.com');
  $log['security']->snitcher('newcustomthingy', function($log_entry, $options) {
    /*
      Do something really cool with log_entry! Here what the 'file' entry looks like. Mostly.
    */
    echo '[' . date('F j, Y, g:i a', $log_entry['timestamp']) . '] ' . str_pad(strtoupper($log_entry['level']['text']), 10, ' ', STR_PAD_RIGHT) . $log_entry['msg'] . ' ' . json_encode($log_entry['additional_params'], TRUE) . PHP_EOL
  });
  
  if(bad_csrf_token()){
    $log['security']->CSRF('Oh no! Is someone hacking our website? No CSRF token!'); 
  } else {
    $log->info('A valid CSRF token was passed!');
  }

#Lets go line by line

$log = new snitchin($argv);

Create a new snitchin. The snitchin class takes in two params. snitchin($level, $default_snitches). $Level can either be an integer value or it can be argv. On command lines you can use -vvvvvvvv(up to 15 v's) to determine the emit level. The next parameter of $default_snitches takes in a string, or an array of default snitches. There are many different types of snitches. HTTP, Slack, file, standard, json etc ...

$log->channel('security','slack|file|email|newcustomthingy');

Create a new channel called security. Let this channel use slack, file and email for events. Also, lets add a custom snitcher. Because it's security, anytime this channel is triggered, it must be important. You can access the security channel now by using it's name $log['security'].

$log['security']->snitcher('file','/tmp/snitchin.txt');
$log['security']->snitcher('slack','https://hooks.slack.com/services/_something_/_else_/_goes_here_', 61);
$log['security']->snitcher('email','kcmerrill@gmail.com');

Here we setup the security channel snitchers. The file snitcher takes in a string as it's option value. This tells the file snitcher where to save events The same thing holds true for the slack and email snitch. The slack snitcher takes in the webhook generated by slack, and the email snitcher takes in a string, which is the email address to send the information. One thing to note Notice how slack has an integer value where the rest do not? Basically, by default, whatever the default emitter level is, will be used for each snitcher unless otherwise declared. In this case, we only want to send things to slack, if the level is greater than or equal to 61.

$log['security']->snitcher('newcustomthingy', function($log_entry, $options) {
  /*
    Do something really cool with log_entry! Here what the 'file' entry looks like. Mostly.
  */
  echo '[' . date('F j, Y, g:i a', $log_entry['timestamp']) . '] ' . str_pad(strtoupper($log_entry['level']['text']), 10, ' ', STR_PAD_RIGHT) . $log_entry['msg'] . ' ' . json_encode($log_entry['additional_params'], TRUE) . PHP_EOL
});

This is where snitchin really comes in handy. It allows you to do whatever it is you need in order to emit customized snitches. In this case, it's a simple echo to the console. Again, whatever you can think of, you can put here. Send an email, curl a web page, send an email, send to slack. Etc ...

if(bad_csrf_token()){
  $log['security']->CSRF('Oh no! Is someone hacking our website? No CSRF token!');  
} else {
  $log->info('A valid CSRF token was passed!');
}

We will break this down a bit more in just a second. Just assume this is a form that was submitted and it had an invalid CSRF token. We want to send this message to the appropriate security channel along to the appropriate snitchers!

$log['security']->CSRF('Oh no! Is someone hacking our website? No CSRF token!');  

CSRF() only takes place on the security channel given it's usage $log['security']; What is CSRF(). It's a new level that we just created. On the fly! By default, levels created on the fly will have an emit level of 61! This means that custom levels will always be emitted in default scenarios. By performing the line above, it would be similiar to doing the following:

$log['security']->level('CSRF', 61);

The level() function if given a value as the second paramter will create a new emit level. Blank, it will try to return the value of the level.

$log->info('A valid CSRF token was passed!');

Remember how I mentioned above that by default, you're provided with a default channel? The above line is the same as doing this:

$log['default']->info('A valid CSRF token was passed!');

#Screenshots or it never happened Geez. Tough crowd. Here you go! In the example below, we are taking advantage of the standard snitcher(console output) and also the slack snitcher. You can see, I have my slack window open, and I have the slack snitcher only to repond to events emitted greater than 61(the default custom level).

Default snitchin behavior