CodeIgniter on Google AppEngine for PHP: The Logging Class

CodeIgniter Logging Class

Following the first article on how to deploy CodeIgniter on Google App Engine, the second article of the series is the Logging Class. In order to develop a successful application a developer must be able to consistently debug it. Throughout CodeIgniter and other user contributed libraries the log_message() function is the one up to the challenge.

From the CodeIgniter User Guide – Error Handling Section:

log_message() function lets you write messages to your log files. You must supply one of three “levels” in the first parameter, indicating what type of message it is (debug, error, info), with the message itself in the second parameter.

if ($some_var == "")
{
    log_message('error', 'Some variable did not contain a value.');
}
else
{
    log_message('debug', 'Some variable was correctly set');
}

log_message('info', 'The purpose of some variable is to provide some value.');

Extendind the Core?

Of course, our first problem is that in Google App Engine for PHP writing to the filesystem is disabled, so log_message() function is of no use. Writing a complete new function in order to utilize the PHP Runtime Environment Logging would mean re-writing all the core and contributed code utilizing log_message() so the correct path of action has two options:

  • Extend Log Class Library to utilize Google recommended syslog() function
  • Replace Log Class Library to utilize Google recommended syslog() function

Completely rewriting and replacing the Log Class Library is a good idea: When we migrate to Google App Engine we just copy the new Library classes and the framework will be up and running with the replacement functions. (And if any day we want to migrate back to another hosting server we’ll just have to delete these custom classes and voilá).

The downside is that when debugging on our localhost, the custom classes will be used and thus we won´t be able to correctly debug the code.

Extending the library could be the solution. We create a global switch: If the config file says we are local then the core function will be used, otherwise our custom function will kick in and override the default behavior. Of course, more configuration will be needed.

Anyway, for the purpose of this tutorial (and keeping it nice and easy) we’ll create a whole new Log.php file based (almost copied) on the original Log.php that comes with the core.

Hands-On Code

This is the full Log.php file. You should place it in:

application/libraries/Log.php
<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');

/**
 * Logging Class using Google App Engine syslog function
 *
 * @package		CodeIgniter
 * @subpackage	Libraries
 * @category	Logging
 * @author		Alejandro Blanco
 * @link		http://www.programming4design.com
 */

class CI_Log {

	protected $_threshold	= 1;
	protected $_date_fmt	= 'Y-m-d H:i:s';
	protected $_enabled	= TRUE;
	protected $_levels	= array('ERROR' => '1', 'DEBUG' => '2',  'INFO' => '3', 'ALL' => '4');
	protected $_syslog	= array('ERROR' => LOG_ERR, 'DEBUG' => LOG_DEBUG,  'INFO' => LOG_INFO, 'ALL' => LOG_NOTICE);

	/**
	 * Constructor
	 */
	public function __construct()
	{
		$config =& get_config();

		if (is_numeric($config['log_threshold']))
		{
			$this->_threshold = $config['log_threshold'];
		}

		if ($config['log_date_format'] != '')
		{
			$this->_date_fmt = $config['log_date_format'];
		}
	}

	// --------------------------------------------------------------------

	/**
	 * Write Log File
	 *
	 * Generally this function will be called using the global log_message() function
	 *
	 * @param	string	the error level
	 * @param	string	the error message
	 * @param	bool	whether the error is a native PHP error
	 * @return	bool
	 */
	public function write_log($level = 'error', $msg, $php_error = FALSE)
	{
		if ($this->_enabled === FALSE)
		{
			return FALSE;
		}

		$level = strtoupper($level);

		if ( ! isset($this->_levels[$level]) OR ($this->_levels[$level] > $this->_threshold))
		{
			return FALSE;
		}

		$message  = '';

		$message .= $level.' '.(($level == 'INFO') ? ' -' : '-').' '.date($this->_date_fmt). ' --> '.$msg."\n";

		syslog($this->_syslog[$level], $message);

		return TRUE;
	}

}
// END Log Class

/* End of file Log.php */
/* Location: ./application/libraries/Log.php */

Explanation

A few modifications were made to the original file.First, we created $_syslog variable to hold the php error level parameter (For more info: http://php.net/manual/en/function.syslog.php)

Secondly, all filesystem related code was removed. And lastly the fwrite() to the log was replaced with a syslog() call.

All core functionality was mantained. Logging enabling/disabling and thresholding through configuration has been kept identical, thus this library is 100% compatible with core and contributed libraries.

Test usage

I created a small testing function inside my welcome controller:

	public function testing_logging_library()
	{
		log_message('error', 'Ahoy! Log Reader');
		echo 'Log Written!';
	}

We call the function, a blank page with Log Written! comes up and time for the truth.

Logs screenshot

Logging works!

So it works! As PHP syslog() function has 8 posible parameters: LOG_EMERG, LOG_ALERT, LOG_CRIT, LOG_ERR, LOG_WARNING, LOG_NOTICE, LOG_INFO & LOG_DEBUG, we could further enhance our class to be able to log beyond the four only priorities found in CodeIgniter but that will up to you.

Now that we are able to debug our code it’s time to move onto testing some more complex classes. Stay tuned!

CodeIgniter on Google AppEngine for PHP

Google App Engine has recently announced its support for PHP, and as a CodeIgniter developer I decided to test its functionality on this great platform.

Browsing the web I found that someone had already made a port of CodeIgniter compiling it into Java applets (thru Quercus) You can check out his application here: http://fillanocode.appspot.com/

I’ll be testing it with the newly launched native PHP support, and using the most interesting Google Cloud products for a PHP developer: Google Cloud SQL, Cloud Storage, Memcache and AppEngine PHP-SDK Libraries.

This post is not a tutorial for Google AppEngine PHP Runtime (They already have some great documentation) nor for CodeIgniter. You are invited to consult their respective documentation if needed.

Installing AppEngine for PHP and CodeIgniter

The first steps will be to get a copy of the PHP SDK. It comes in different flavours: Linux, OS X and Windows. Check them out here. You will also get bundled a local python webserver, and an uploading tool.

Next, we’ll get the latest version of the CodeIgniter framework directly from GitHub (2.1.4 will be used for this post) Link here.

Putting everything together

To allow an application to run on AppEngine, we need to create app.yaml file in the root directory of the application.

application: codeigniter-dev
version: 1
runtime: php
api_version: 1
threadsafe: false

handlers:
- url: /favicon.ico
  static_files: /favicon.ico
  upload: /favicon.ico
  expiration: 30d

# make the user_guide a static dir!
# you dont need to include it in every project you make
- url: /user_guide
  static_dir: user_guide

- url: /.*
  script: index.php

codeigniter-dev is our application name and you’ll need to change it by the one you have chosen for your application before uploading it.

After this first configuration step, we can launch the application by using the Local Web server included in the App Engine SDK, or we could just use our preferred Web Server (In my case, I run a local LAMPP environment.

First upload to Google App Engine

If you don’t have done it before, we invite you to create an App Engine application (https://appengine.google.com/) and to subscribe to the App Engine for PHP beta program (https://gaeforphp.appspot.com/) in order to allow the upload of a PHP application to your App Engine instance. Indeed, the PHP runtime that has been announced at the last Google I/O conference is still in beta and Google authorizes progressively its roll out.

We then upload the application to the App Engine using the following command that you need to adapt to your environment:

../google_appengine/appcfg.py -R --oauth2 update ./

And the answer is:

11:26 AM Host: appengine.google.com
11:26 AM Application: codeigniter-dev; version: 1
11:26 AM Starting update of app: codeigniter-dev, version: 1
11:26 AM Getting current resource limits.
11:26 AM Scanning files on local disk.
11:26 AM Cloning 184 application files.
11:26 AM Uploading 184 files and blobs.
11:26 AM Uploaded 184 files and blobs
11:26 AM Compilation starting.
11:26 AM Compilation completed.
11:26 AM Starting deployment.
11:26 AM Checking if deployment succeeded.
11:26 AM Deployment successful.
11:26 AM Checking if updated app version is serving.
11:26 AM Completed update of app: codeigniter-dev, version: 1

We then try to access the application through the codeigniter-dev.appspot.com url, and voilá, almost no hassles: Behold CodeIgniter natively working on Google AppEngine on http://codeigniter-dev.appspot.com/

CodeIgniter almost working on Google App Engine

CodeIgniter almost working on Google App Engine

Just a small PHP warning saying that php_sapi_name() function isn’t working. I did a quick Google search, and it’s indeed disabled by default by Google, and it can be enabled by uploading a custom php.ini file:

google_app_engine.enable_functions = "php_sapi_name"

So I create the file, add just that line, re-upload, re-fresh the screen and:

Default CodeIgniter installation working on Google App Engine

Default CodeIgniter installation running natively on Google App Engine

It’s working and I’ll leave it this way for now. My next goal, which I’ll cover in future posts will be to thoroughly test each and every function!

References

CodeIgniter y Frameworks para PHP

Frameworks para PHP

La adopción de un framework es un hito importante para cualquier desarrollador de software, ya sea un freelancer o una gran organización.

Ser experto en uno nos permite además de contar con las librerías nativas, reutilizar y estandarizar nuestro código, agilizar el desarrollo de nuestros proyectos y trabajar de una forma más eficiente.

Algunas otras ventajas son:

  • Simplifican el debugging.
  • Naturalmente seguras.
  • Fáciles de instalar y de usar.
  • Compatibles con diferentes plataformas.

Habiendo tantos frameworks para PHP hoy en día hay que ser criterioso y analizar los pros y contras de cada uno, ya que el que más funciones tiene puede ser demasiado para nuestro trabajo o contrariamente un framework con pocas funcionalidades puede quedarnos chico para nuestro día a día.

CodeIgniter (CI)

CodeIgniter es mantenido por la gente de EllisLab.com

En www.programming4design.com utilizamos principalmente CodeIgniter ya que es lo suficientemente sencillo como para que cualquier programador Jr. lo utilice sin muchas explicaciones y permite a su vez el desarrollo de aplicaciones complejas.

Utiliza el patrón MVC (Model – View – Controller) (http://es.wikipedia.org/wiki/Modelo_Vista_Controlador) dándole robustez al sitio y haciendo sencillo entender donde esta cada cosa. Al mismo tiempo, el código de CI puede ser portado a desde y hacia otros frameworks con facilidad

Las funcionalidades sobresalientes son:

  • Documentación

Sencillamente impecable. La documentación se encuentra siempre actualizada y explicada de una manera clara y concisa. Desde los conceptos básicos a los más avanzados cada función es descripta en profundidad y con abundantes ejemplos. Y como si fuera poco, de ser necesario se puede recurrir al foro donde hay una comunidad grande y cooperativa.

  • Simplicidad

CodeIgniter tiene un funcionamiento muy simple internamente. Solo se cargan los componentes que le pedimos lo que hace que cada página tenga solo lo necesario para funcionar haciendo que funcione muy pero muy rápido.

  • Abstracción de Base de Datos

Las clases que se utilizan en los modelos permiten una abstracción total de la Base de Datos y cambiar de back-end de forma muy sencilla sin modificar el código.
El Active Record que se utiliza merece una mención especial; es simple, cómodo y una vez acostumbrados, no van a querer volver a escribir una sentencia SQL de forma manual en su vida.

  • Validación de datos

Validar los datos que nos llegan via POST o GET y que debemos insertar a la base de datos suele ser un punto importante y central para el funcionamiento sano de cualquier aplicación. Acá CodeIgniter toma el control y maneja de forma automática la validación de datos, lo que agrega una capa de seguridad importante y de ser necesario podemos establecer manualmente nuestras reglas de validación.

Otros puntos a favor:

  • La migración e instalación de un sistema a otro es muy sencilla.
  • También lo es la actualización a nuevas versiones ya que es backwards-compatible.
  • Tiene una buena base de librerías además de ser sencillo su desarrollo y la posibilidad de conseguir otras online.
  • Pueden manejarse múltiples sitios desde una sola instalación, lo que permite que al actualizar el core, todos los sitios queden actualizados.
  • El código es abierto y es bien mantenido y actualizado.

Les dejo un link para que puedan verlo por uds. mismos: http://ellislab.com/codeigniter

Agradecimientos a la gente de http://macronimous.com/ por las ideas para este post