Jumat, 19 November 2010

Outputting pretty data structure on console programs

Our application has a command-line API interface for convenient access via shell/console. It used to output API result data in YAML:



# /c/sbin/spanel api --yaml File list --account steven --volume data --dir /public
---
dir:
atime: '1270675429'
ctime: '1285916065'
gid: 1023
group: steven
is_dir: 1
mtime: '1285916065'
perms: 493
uid: 1012
url: ~
user: steven
entries:
-
atime: '1284665000'
ctime: '1289609859'
dir: /public
gid: 1023
group: steven
icon_file: folder.gif
inode: 1984908
is_dir: 1
is_link: 0
mtime: '1289609859'
name: git
perms: 493
reldir: ''
size: 4096
uid: 1012
url: ~
user: steven
-
atime: '1270675424'
ctime: '1285130140'
dir: /public
gid: 1023
group: steven
icon_file: text.gif
inode: 1976727
is_dir: 0
is_link: 0
mtime: '1155368486'
name: .htaccess
perms: 436
reldir: ''
size: 48
uid: 1012
url: ~
user: steven
-
atime: '1270675424'
ctime: '1285130140'
dir: /public
gid: 1023
group: steven
icon_file: unknown.gif
inode: 1976725
is_dir: 0
is_link: 0
mtime: '1155368397'
name: .htaccess~
perms: 436
reldir: ''
size: 63
uid: 1012
url: ~
user: steven
total_num_entries: 3
url: ~


YAML is relatively readable if you compare to JSON or (shudder) XML, but I soon grew tired of reading YAML for data that should be tabulated and better formatted for human consumption.



Thus, Data::Format::Pretty::Console. The idea is for me, a lazy programmer, to throw it data structure of various kind and it will display it nicely suitable for console viewing. The command line API interface now by default shows nicely formatted text for API result data (but still provides --yaml and --json option). Please bear with this blog post's misformatting and assume it's all pretty:



dir:
.---------------------.
| key | value |
+--------+------------+
| atime | 1270675429 |
| ctime | 1285916065 |
| gid | 1023 |
| group | steven |
| is_dir | 1 |
| mtime | 1285916065 |
| perms | 493 |
| uid | 1012 |
| url | |
| user | steven |
'--------+------------'

entries:
.----------------------------------------------------------------------------------------------------------------------------------------------------------------------.
| atime | ctime | dir | gid | group | icon_file | inode | is_dir | is_link | mtime | name | perms | reldir | size | uid | url | user |
+------------+------------+---------+------+--------+-------------+---------+--------+---------+------------+------------+-------+--------+------+------+-----+--------+
| 1284665000 | 1289609859 | /public | 1023 | steven | folder.gif | 1984908 | 1 | 0 | 1289609859 | git | 493 | | 4096 | 1012 | | steven |
| 1270675424 | 1285130140 | /public | 1023 | steven | text.gif | 1976727 | 0 | 0 | 1155368486 | .htaccess | 436 | | 48 | 1012 | | steven |
| 1270675424 | 1285130140 | /public | 1023 | steven | unknown.gif | 1976725 | 0 | 0 | 1155368397 | .htaccess~ | 436 | | 63 | 1012 | | steven |
'------------+------------+---------+------+--------+-------------+---------+--------+---------+------------+------------+-------+--------+------+------+-----+--------'

total_num_entries:
3

url:


Rabu, 17 November 2010

Comparison of INI-format modules on CPAN

I'm not terribly happy with the state of Perl/CPAN support for the INI file format.

I have this requirement of modifying php.ini files programmatically from Perl like: set register_globals to On/Off, add/remove some extension (via the extension=foo lines), adding/removing some functions from the disabled_functions list, etc. So I would like to find a CPAN module that can just set/unset a parameter and leave formatting/comments alone as much as possible.

Turns out that among a dozen or so of INI modules on CPAN, a few of them do not do writes at all (e.g. Config::INI::Access or Config::Format::INI). And a few that do, write a la dump. That is, they just rewrite the whole INI file with the in-memory structure. All comments and formatting (even ordering, in some cases) are lost. Example: Config::INI::Writer and Tie::Cfg. And, last time I tried, I couldn't even install Config::IniHash from the CPAN client. Not good.

So I ended up with Config::IniFiles. And I needed to patch two features in before I could even read php.ini and write to it properly. This is an old module, which although still maintained, probably needs a rewrite or modernization. One reviewer in CPAN Ratings also wrote that this module fails in edge cases and the test suite is incomplete.

But, at least this module gets the work done. It tries to maintain comments, and even has a host of other features like delta, multiline, default section, etc. Most features seem to be rather exotic to me personally, but then none of the other INI modules on CPAN has the basic features that I needed.

(Short, grossly incomplete) comparison of Perl logging frameworks

After doing this post on comparison of Perl serialization modules, I intended to continue with other comparisons, and even thought on setting up a wiki or creating/maintaining a section on the Official Perl 5 Wiki, which already has a Recommended Modules section, although there is not much comparison being written for each recommendation. (Btw, I just noticed a change of domain for the Wiki, from perlfoundation.org to socialtext.net).

But of course other tasks soon took precedence, so until the Wiki idea is realized, I thought I'll just continue posting on the blog as usual.

There are **seriously** too many Perl logging frameworks out there. As the Log4perl FAQ mentions, "Writing a logging module is like a rite of passage for every Perl programmer, just like writing your own templating system."

So I'm not going to pretend like I've evaluated even half of logging modules that are on CPAN. Instead I'm just going to include a few worth mentioning.

Log::Dispatch and Log::Log4perl. Two of the arguably most popular Perl logging frameworks are Log::Dispatch and Log::Log4perl. They are like the Moose of logging frameworks: mature, feature rich, flexible, has a lot of support/extra/3rd party modules, but... "slow". I quote the slow part because first of all, speed is not an issue for the majority of applications. And second of all, they are not relatively slow at all compared to other modules until they actually log stuff to output. For example, doing debug() on a warn level is around 1,5mils/sec with with Log4perl, and 3mils/sec with Log::Fast. But for actual logging, Log::Fast can be 10-45 times faster than these two.

Log::Any. For most people, Log::Dispatch and Log4perl should suffice. I personally haven't been unable to produce a case where I can't customize Log4perl they way I want. This shows the flexibility of the module. So the only thing left for flexibility is a thin wrapper where you might want to switch logging framework (kind of like Any::Moose for logging). There are a few of these on CPAN, but I prefer Log::Any (and I've also made a thin wrapper for *that*, Log::Any::App). RJBS also made one: Log::Dispatchoulli. You might be interested in using it if you are interested in using String::Flogger.

Performance-wise, as with Moose, there are other alternatives: Log::Fast, for one. There are also a few other minimalistic frameworks, but I do not recommend using them as many of them are not flexible at all. Unless your application is really performance-critical.

I've most probably left out a lot of possibly interesting alternatives.