DGD Library
Version: 0.1.0.14 | Updated: Thu Aug 10 16:59:34 2006
Home
DGD News
FAQ
Code Documentation
DGD Installation Guide
Bugs-n-Features
DGD at Sourceforge.net
Download DGD
Subversion
Code Documentation
Documentation
Namespaces
Class Hierarchy
Class List
File List
Namespace Members
Functions
Globals
Tutorial
Main Page   Namespace List   Class Hierarchy   Compound List   File List   Namespace Members   Compound Members   File Members   Related Pages  

DGD Basics - Hello World

Simple Tracing with DGD

The best way to learn about any software library is to step over the code line by line. DGD is not exception. The number of sections below will demonstrate DGD features from the basic ones to more advanced.

The "Algorithm"

The following code example represents some "algorithm" with tracing to std::cout.

Here filling-up the list with sequence of integers is followed by printing the list in a loop.

#include <iostream>
#include <list>

struct MyStruct {
      int my_field;
      
      MyStruct( int val ): my_field( val ) {}
};

std::ostream& operator << ( std::ostream& ostr, const MyStruct& data ) {
   ostr << "[" << data.my_field << "]";
   return ostr;
}

int main( int argc, char** argv ) {
   std::list<MyStruct> my_data;
   int i;

   for( i = 0; i < 10; i++ ) my_data.push_back( i );

   std::list<MyStruct>::const_iterator iter = my_data.begin();

   while( iter != my_data.end() ) std::cout << *iter++ << " ";
   std::cout << std::endl;

   return 0;
}

Here is the output of the example:

[0] [1] [2] [3] [4] [5] [6] [7] [8] [9] 

Basic DGD tracing

Lets consider the changes required to do same thing with DGD.

#include <iostream>
#include <list>

#include <dgDebug.h>

using namespace DGD;

struct MyStruct {
      int my_field;
      
      MyStruct( int val ): my_field( val ) {}
};

std::ostream& operator << ( std::ostream& ostr, const MyStruct& data ) {
   ostr << "[" << data.my_field << "]";
   return ostr;
}

int main( int argc, char** argv ) {
   std::list<MyStruct> my_data;
   int i;
   
   Debug::debug_factory_ref dout = Debug::create_factory( argc, argv );

   for( i = 0; i < 10; i++ ) my_data.push_back( i );

   dgd_trace( main, dgd_expand(my_data) << std::endl );
   
   return 0;
}

The output of this program is a little bit different:

Content-type: text/plain

Channel: main
Time: Wed Feb 04 18:49:26 2004


my_data = {
        [0]
        [1]
        [2]
        [3]
        [4]
        [5]
        [6]
        [7]
        [8]
        [9]
}

Now, lets review the most important changes brought by DGD. The easiest way to use DGD definitions is by including dgDebug.h file. All DGD classes and variables (except macros!) are members of DGD namespace, so it is convinient to import the namespace by 'using' directive.

#include <iostream>
using namespace DGD;

Pay attention that no changes were required to the output operator, this is due to design of DGD - you need not change or rewrite the existing tracing code. Sometimes it is desirable to keep two sets of tracing operators - one for generic std::ostream and one DGD::channel specific. The later one is usually needed when there is a strong need to enhance tracing provided by third party and allows to use special DGD features like trace stream manipulators.

The next important thing appears at the beginning of function main():

   Debug::debug_factory_ref dout = Debug::create_factory( argc, argv );
This line creates the global DGD::Debug object, called channel factory or the factory. There are two most important uses for this object:
  • it is used as a container of all known tracing channels. This is convenient, all channels can be accessed by name from any point of the program.
  • it is automatically destroyed upon application exit or crash. This is important primary for flushing streams on exceptions. To understand how this mechanism works pay attention on the type of the object returned by create_factory(). It is smart pointer to the factory. When main() function exits (probably abnormally, because exception) destructor of the smart pointer will destroy the global factory. The factory destructor will flush all the streams.

There are thread-safety issues caused by using globals can arise. To avoid these you can create Debug objects on the local stack or alternatively, by using a convenction. Try to use the factory as a read-only object most of the time, while updating/changing it from the main thread only.

The next interesting line contains tracing statements:

   dgd_trace( main, dgd_expand(my_data) << std::endl );
First of all dgd_trace() is a macro. The first parameter of this macro must be channel name (used as bare-word for simplicity) and the second parameter is the output operator to perform. This macro performs a number of tasks:
  • If this program is compiled without _TRACE macro, this macro (and all other DGD macros) will be compiled as empty code.
  • The global factory object may be not initialized. In this case dgd_trace will do nothing.
  • The default 'main' channel can be closed or deleted by the user. In this case dgd_trace() will skip output operation.
  • If all the checks are successful, the output operator attached to the channel and executed.

The second interesting macro is dgd_expand(). This one used for convenience only. It substitutes string 'a' with sting '"a = " << a' for readable output.

Note that the for statement which was used to print the list is now missing. This is due generic output operators for STL data structures defined by DGD. Note also, that the format of the output has also changed, and the new format is also defined by the build-in operator. To override this you can either define output operator for specific type or define output operator for DGD::channel.

Controlling DGD::Debug with command line.

If you compiled the example from Basic DGD tracing "the previous section" you may figured out that nothing happens when you run it. By default tracing is turned off. In order to run the example and get its output you need to use at least one special command line switch. For our example:
 example1_simple1 --trace-enable 
The first option enables tracing explicitly. The output is written to standard error. The full list of the supported options can be obtained from Debug::process_options or by running
 example1_simple1 --trace-help

Generated on Thu Aug 10 16:48:29 2006 for DGD Library by doxygen1.3

SourceForge.net Logo Powered by Mason Powered by Perl
Web design derived from Pasilda design found on www.oswd.org.
Copyright (c) 2002, 2003. Dimitry Kloper <kloper@users.sourceforge.net>