In previous posts I’ve mentioned that once you get an app on Azure it’s often difficult to gain visibility on errors that occur on staging and production. The problem is compounded when (as in my Azure App) you have a number of remote workers processing tasks with little feedback on the results of each task.
To that end I’ve developed a little application to demonstrate using Azure’s blob storage to log events in your application to a blob you can retrieve and view.
The mini Zend Framework application consists of two parts: setting up an instance of Zend_Log and using it to log events and retrieving a list of the events and displaying them on screen.
The demo code is available here: https://github.com/benwaine/Application-Logging-On-Azure
Part One: Set Up
Blob storage is a means of writing files to a permanent cloud storage medium. The Azure cloud storage platform has an API. Using the API users can create containers and blobs. This of containers as folders and blobs of files. There are some differences, for example it’s not possible to nest containers. Although it is possible to using a naming convention to simulate a folder structure within a container.
Microsoft have supplied a comprehensive SDK for the Windows Azure Platform. This makes the task of interfacing with Blob storage a breeze. The SDK is included in the source of the demo but you can download it and read about it on the projects site on codeplex.
The SDK provides a means of accessing blob storage using streams. Zend_Log supports a number of writing classes, one of which uses writes to streams. The of setting up Zend_Log and Zend_Log_Witter_Stream is accomplished in the applications Bootstrap class.
class Bootstrap extends Zend_Application_Bootstrap_Bootstrap { protected function _initAutoload() { Microsoft_AutoLoader::Register(); } protected function _initBlob() { $this->getResource('autoload'); $opts = $this->getOption('azure'); $blob = $opts['blob']; $storageClient = new Microsoft_WindowsAzure_Storage_Blob( $blob['host'], $blob['acname'], $blob['paccess']); $storageClient->registerStreamWrapper('blob'); return $storageClient; } protected function _initLog() { $opts = $this->getOption('azure'); $blob = $opts['blob']; $storageClient = $this->getResource('blob'); if(!$storageClient->containerExists($blob['logs']['container'])) { $storageClient->createContainer($blob['logs']['container']); } if(!$storageClient->blobExists($blob['logs']['container'], $blob['logs']['log'])) { file_put_contents($blob['logs']['stream'], "\n"); } $writer = new Zend_Log_Writer_Stream($blob['logs']['stream']); $log = new Zend_Log($writer); $log->info('Logging Initialized'); return $log; } }
1) Ensure Zend Framework and the Microsoft Azure SDK are on the include path. (Tip: Add both to the library/ directory in the root directory).
2) Rename the example configuration file in the application/configs directory to ‘application.ini’. Replace the dummy settings with the details of your Azure subscription.
2) In the Bootstrap class we can see that first we add the Microsfot SDK autoloader to the autoloader stack.
3) On line 10 in the _initBlob() method a new instance of the Azure Blog storage client is initialised. It is returned by the method and is stored in Zend_Application’s resource registry for use later.
4) The _initLog() method on line 24 grabs the blob resource from the previous step and uses it to check if both the container and blob specified in the application.ini file actually exist. Note we can see that if the blob isn’t present it must be initialised, otherwise a error is thrown.
5) The Zend log is created and returned. The log is now part of Zend_Application’s resource registry and can be accessed from any action controller or even injected into your domain models to provide richer logging.
Part Two – Retrieving Logs
Retrieving the logs from blob storage is a piece of cake. In this simple application I put all the code in a controller action. It simply opens the file using the storage client set up in the bootstrap process, explodes the string into an array and assigns this to the view.
class IndexController extends Zend_Controller_Action { public function init() { /* Initialize action controller here */ } public function indexAction() { $bootstrap = $this->getInvokeArg('bootstrap'); $storageClient = $bootstrap->getResource('blob'); /** @var $storageClient Microsoft_WindowsAzure_Storage_Blob **/ $config = $bootstrap->getOption('azure'); $project = $bootstrap->getOption('project'); $fileStr = file_get_contents($config['blob']['logs']['stream']); $logAr = explode("\n", $fileStr); $this->view->projectName = $project['name']; $this->view->logs = $logAr; }
1) Options and resources are retrieved from the bootstrap.
2) file_get_contents is used to retrieve the content of the blob.
3) The string from the blob is exploded into an array.
4) Project name and log array are both assigned to the view.
5) In the view script the log array is iterated over and each line of output is echoed.
The result is a page full of log information.
Tips
Azure blob storage is accessed via a RESTful web service. While this is a great tool getting some visibility on what’s happening in your application while it’s on staging there is definitely a performance hit incured by the latency of talking to a remote service.
Even initialising the log incurs a performance penalty as the you can see that a check for both the container and the blob is made in the bootstrap. I recommend using this technique on staging and disabling it when in production.
In the future I’m going to add some ajax support so that the log refreshes in real time, similar to the way in which linux developers offten use the tail -f command to watch logs during development.
Feel free to use the code and if you have an suggestions please comment.
Tags: #phpazurecontest, azure, PHP


