Sunday, August 18, 2013

The Appenders: Less spoken but powerful aspect of logger package


Logging is one of the fundamental and very important features of an application that helps both developers and maintainers in debugging any issues either during development or in production.

In Tcl, as part of tcllib, we have log and logger packages that support logging facility. A lot of information available on wiki and their reference documentation.

In this article, I would like to highlight one of the less spoken but a powerful aspect of logger package, that is, appender.

An appender is the one that does the actual job of appending the log message to its destination. You can notice that, by default, logger package logs the messages onto standard output / console. This is because, the logger package by default is configured with an appender called "console".

You can change this default behavior of logging messages to  standard output by configuring the logger package with a different appender. To do this configuration you call the proc: 

::logger::utils::applyAppender -appender appenderType  ? options... ?
In addition to "console", there is also an appender provided by logger package is: colorConsole. By invoking applyAppender as:
::logger::utils::applyAppender -appender colorConsole
you can see that your log messages are not just sent to standard output, but they are also formatted with colors.

Now, comes the secret.... an undocumented feature of logger package.... is that there is an another appender available in the package called fileAppend. This appender sends the log messages to a given output channel. You can use this appender to log messages to a file on the file system...something that all applications in the production will need. To configure the logger package with fileAppend appender, you invoke:
set chan [open /log/file/path]
fconfigure $chan -buffering none
::logger::utils::applyAppender -appender fileAppend -outputChannel  $chan
While there are only 3 appenders provided by logger package, you can write your own appenders and make them part of logger package. We will see how to write your own appenders in a different article.

One can use the applyAppender command to configure specific set of services and / or specific set of logger object instances (returned by logger::init command) and / or for specific set of log levels. This makes application's logging facility to be highly configurable with any level of granularity that you want. You can enable logging for only some parts of the application, different parts of the application being able to send messages to different destinations as per the configuration and different parts of the application logging messages at different log levels.

That is the power of logger package in tcllib.


Tuesday, August 13, 2013

tclIndex files and freeWrap incompatibility...


The auto_mkindex command of Tcl generates an index of all the Tcl command procedures defined in Tcl files, and stores the index information in a file named tclIndex that is suitable for auto_load.

The tclIndex files generated by auto_mkindex command contain relative paths with '.' in them (Tested on of Tcl 8.5.14). An example line from tclIndex: 
set auto_index(::MyNameSpace::mycmd) [list source  [file join $dir . myscript.tcl]]
Applications freeWrap-ed with these tclIndex files fail to load/source files using relative paths. Note the following warning from freeWrap documentation:
You should use the paths to the files as they exist at the time of wrapping. Wrapping takes a "snapshot" of the file path for all wrapped files. Do not use relative paths to refer to wrapped files within the application since relative paths will not be found.
As a workaround, I modify tclIndex (using shell scripts) files to use [file normalize] command around [file join] command. The [file normalize] command  returns a normalized path. A normalized path is an absolute path which has all “../” and “./” removed. Also it is one which is in the “standard” format for the native platform. Hence, the modified tclIndex line looks like: 
set auto_index(::MyNameSpace::mycmd) [list source  [file normalize [file join $dir . myscript.tcl]]]
The shell command I used to automate the modification of tclIndex files is: 
sed -e 's/^set auto_index(.*) \[list source /& \[file normalize /' -e 's/\]$/\]\]/' -i tclIndex
Hope this helps you..... in case if you encounter this problem when using tclIndex files with freeWrap.


Reasons for using tclfcgi

For server side programming of Tcl based web applications, there are many alternatives available.

Initially I used Apache-Rivet. This needs the server side code to be distributed in source form. But, I wanted my code to be protected either as a compiled executable or password protected (at least making it difficult for normal users to see the source code).

Building a Tcl executable that is password protected can be achieved by using freeWrap. Another advantage I get by using freewrap is that it has Tcl interpreter built in. So, there is no need for users to install Tcl on their machine to use my server side code. Freewrap documentation provides instructions on how to build your version of freewrap. Building your own version of freewrap is important as it advised in the freewrap documentation:

Remember, due to freeWrap's ability to mount ZIP files as a subdirectory, a person having the same version of freeWrap (with the same password) can easily read the encrypted files within your application. Therefore, those people interested in securing the files that make up their application should use a copy of freeWrap (built with its own unique password) that no one else has access to.
To run an executable that serves htpp requests from a web server, CGI is an option. Hence, I hosted my application under Apache mod_cgi module. One disadvantage, I found, of this approach was that entire application will get loaded every time to serve every individual request. This is very inefficient and loads the server.

So, I started looking for an option that will facilitate loading the application only once but serve the subsequent requests in a loop without reloading the application again and again. FastCGI provides this option of having a CGI script loaded only once and serve requests in a loop. Using FastCGI also gives an advantage of having your application code being independent of any specific web server platform. So, now my code is ready to be moved to any Web Server / Framework that will support FastCGI.

Hence, for now, I am settled with using tclfcgi for my Tcl FastCGI scripts running under mod_fastcgi module of Apache2 web server.

To summarize, the reasons that lead me to use tclfcgi are:
  1. Source code protection
  2. No need for installing Tcl at the user site
  3. One time application initialization (No reloading of the app for every request)
  4. Web server platform independence and portability
Please note that at this point in time, following points are for me to explore futher:
  1. I need to explore the mod_fcgid module of Apache2 as an alternative to mod_fastcgi
  2. +Donal Fellows and +Steve Landers suggest that SCGI could be an alternative to FCGI.

Monday, August 5, 2013

tclfcgi - Tcl binding to FastCGI - Linux


This creates a Tcl package (Fcgi) that can be used by Tcl based FastCGI scripts. This package is tested on Debian Wheezy (3.2.0-4-686-pae) with Apache Apache/2.2.22 mod_fastcgi and Tcl8.5.14
Download from github:
https://github.com/nagarajanchinnasamy/tclfcgi
Pre-requisite:
sudo apt-get install libfcgi-dev libfcgi0ldbl
Build & Install:
cd c-src
make
sudo make install
Apache Setup:

1. Enable fastcgi module in apache2 using:

 sudo a2enmod fastcgi

2. Place following lines in /etc/apache2/conf.d/httpd.conf

 ScriptAlias /appname/ /my/path/to/fcgi-bin/

 <Directory "/my/path/to/fcgi-bin/">
     SetHandler fastcgi-script
     AllowOverride None
     Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch
     Order allow,deny
     Allow from all
 </Directory>

3. Place your FCGI scripts in /my/path/to/fcgi-bin and set executable permission to the scripts. Example Tcl FCGI script (example.fcg):

do_one_time_app_initialization_here
while {[FCGI_Accept] >= 0 } {

    ::ncgi::parse
    set var1 [::ncgi::value var1]
    set var2 [::ncgi::value var2]

    set result [do_processing $var1 $var2] 
        ::ncgi::header
        puts $result
        ::ncgi::reset
  }

4. Access your FCGI script from browser using:

http://your.com/appname/example.fcg
References:
http://www.fastcgi.com/devkit/doc/fcgi-tcl.htm
http://sourceforge.net/projects/tcl-fastcgi/