Reading List

The Selfish Gene
The Psychopath Test: A Journey Through the Madness Industry
Bad Science
The Feynman Lectures on Physics
The Theory of Everything: The Origin and Fate of the Universe


ifknot's favorite books »

Thursday 16 January 2014

Part (3/3): I'm a Lumberjack and I'm ok.

The Lumber has arrived!

Freshly hewn but unfinished pile of Code Lumber is below, ideal for building your debuggin' & audtin' & tree-house solutions.

The latest versions of the code and doxygen docs are all over at the libfbp git repository github.com/ifknot/libfbp




Logging Services

The logging services package is contained within the log namespace and consists of:

  • logger - the thread-safe policy based logging class that uses C++11 variadic templates and initializer lists.
  • stamp_policy - an abstract interface for classes providing std::string log stamps for log records.
  • line_number_stamp - a line number producer.
  • unix_time_stamp - a unix time stamp producer .
  • core_stamps - convenience header file of typical log record stamps.

N.B. 

I couldn't bring myself to implement the logger as a singleton. Although this might seem one of those (increasingly) rare cases where a singleton might  seem appropriate I can't bring myself to imagine that I would only ever want 1 logger. 

I am now completely won over by the arguments in this matter and have deprecated the singleton pattern.[2,3]

Serializing Services

However, logging services depend upon a second package in the io namespace that consists of:

  • serializor_policy - an abstract template interface for classes providing serializing[1] services.
  • null_serializor - a serializor that does nothing, which is handy when you don't want any output.
  • console_serializor - a serializor that displays output to the console, handy for debugging.
  • file_serializor - a serializor that directs output to disk.

Error Messages

Finally, logging services also rely on the error message constant strings defined in the errors.h header file within the doh namespace. Separating out the error messages into a separate header file enables the dual goals of:
  • fungibility - enabling interchangeable error messages for different language locales or audiences.
  • no magic strings - fighting the war on magic strings.[4]

Todo:

In order to work well with parallelizable concurrent FBP programs, as per the initial strategy described here, without imposing undue waits it is clear that logging should be buffered to a background thread.
  • asynchronous_serializor - a serializor that uses an active object to wrap more primitive serializors.

Listing 1: usage

Usage example for my logger class
Which produces the following output to the console:
And the following output to the test.log file:

Listing 2: logger

A policy based approach to fungibility for providing traces of execution in a log file(s). Policy-based design (a.k.a. policy-based class design or policy-based programming) being a computer programming design pattern based on a C++ template metaprogramming idiom as described in the book "Modern C++ Design" (Andrei Alexandrescu 2001) - I see it is a compile-time variant of the PIMPL pattern. 

Employs the Resource Aquisition Is Initialization (RAII) pattern, Bjarne Stroustrup(2000), where the basic idea is to represent a resource by a local object, so that the local object's destructor will release the resource. 

The write_policy is managed by the logger constructor and destructor and the log_mutex is managed by the std::lock_guard. A simple, eloquent and efficient way to deal with many situations where there is a risk of “leaking” memory or handles, failing to release file locks, mutexes, etc.

Listing 2: serializor policy

A design by contract abstract template interface to typesafe serialization resources. 

Design by contract(DbC) requires pre & post condition checking, typical public virtual interface design does not permit this behaviour. Rather, prefer the Non-Virtual Interface (NVI), Herb Sutter (2001), to enable DbC and separate the stable, non-virutal interface definition from virtual customizable behaviour. 

N.B. precondition: Object of type T must be serializable i.e. there exists an overloaded operator << such that... 

std::ostream& operator<<(std::ostream& s, const O& object) 

Also, unifies the approach to serialization within a framework.

Listing 4a: file serializor definition

Simple concrete serializor policy that writes string objects to the C++ std::ofstream to direct the output to the disk.

Listing 4b: file serializor implementation


Listing 5: error descriptions, english(UK), resource file

Error message string constants for the english(UK) locale.

Listing 6: log record stamp policy

A simple abstract NVI interface for unified access to stamp string resources. (see also io::serializor_policy

Stamp strings are used in log files to populate the fields of a log record. Log file records have an application specific file format, be that a server log, data log or audit trail, but fields commonly consist of e.g. date stamp, time-stamp, thread id, RFC 1413 user id. 
The interface mimics the std::stringstream accessor member function str()

Listing 7: unix time stamp

References:

No comments:

Post a Comment