Video Screencast Help
Symantec Appoints Michael A. Brown CEO. Learn more.
Endpoint Management Community Blog

{CWoc} Working on version 0.1.9 So Let's Get Structured, Shall We?

Created: 20 Dec 2009 • Updated: 21 Dec 2009 • 1 comment
Ludovic Ferre's picture
0 0 Votes
Login to vote

With 0.1.8 out the door and 0.1.9 coming on I thought it could be nice to actually plan for the features and improvements I'd like to see in the next tag (not necessarily 0.1.9).

Here's a brief overview of the required changes, with detailed explanations below (bear with me reader, as this is a work in progress):

  1. Naming of the resulting program (generally v0xx)
  2. Naming of the main source file (currently prog.c)
  3. Externalisation to purpose driven c files for major functions
  4. Implement a make file to handle the above changes?
  5. Logging out-source to a log_event function and handler
  6. Clean up code from global variables when possible
  7. Document the code and interfaces used as well as the flow

Here are some of the details for each point with pro and cons where applicable:

1. Naming of the resulting program (generally v0xx)

This is decided already, albeit it may not be the nicest name I am going for aila which stands for "Altiris IIS Log Analyzer" in lower case (no point shouting out the name). So it'll be easier to consistently generate the load module instead of using sometime random sometimes version based names.

pro(s): the name is simple and unlike anything I've seen anywhere else.
con(s): not the best sound in English, but it sounds exotic which isn't that bad (for me).

2. Naming of the main source file (currently prog.c)

That's an easy one. Moving away from a generic prog.c sounds like a good idea. But it couldn't be done without a program name before that. So prog.c should be move to aila.c or main.c (so it's clear to everyone reading the source once we have multiple c files which to start with?).

3. Externalisation to purpose driven c files for major functions

I haven't started this yet but I did a serious clean up this week end. Check commit of revision 53 if you want to see the details, but in short I've taken code out of main to create the following function

  • int output_file_statistics ( struct file_statistics * fs, const struct option_set * opt );
  • int output_file_detailed_statistics ( struct file_statistics * fs, const struct option_set * opt );
  • int parse_file ( const struct option_set * opt );
  • update_summary_stats ( struct file_statistics * file_stats, const struct request_summary * req_sum );
  • update_detailed_stats ( struct file_detailed_statistics * file_details, struct request_details * req_details );
  • int get_line_details ( char * line, struct request_details * details);
  • int _init_option_set ( struct option_set * opt );

This wasn't so much work and will definitely help out in getting the code into distinct files.

4. Implement a make file to handle the above changes?

This one was just added as I am writing this post. I think that this will be a must given I'll have multiple input files. Also there's not need to use brut force re-compile and linking of all object files if only a few do change (as it occurs during development and test).

5. Logging out-source to a log_event function and handler

This work has started and aims at providing Altiris Agent like logging options. It'll be easier for me to handle the output as currently I'm using fprintf to output verbose to stderr. This is a bit ugly because all output messages are treated the same, and pipping 2> <file_name> can become real huge when per line verbose is on (as it is right now).

Here's the current implementation I have (draft from this afternoon ~ not even committed to Google code):

/******************************************************************************
 * Logging function. Probably want to externalise it. This would allow fine 
 * grained logging with multi-severity options (error, warning, info, verbose,
 * debug) with output to file or stderr based on the desired log level (args to
 * be added).
 ******************************************************************************/
int log_event (int level, char * source, char * message){
	time_t now_insec = time ( &now_insec );
	if ( now_insec == -1 ) {
		perror ( "time" );
	}
	else {
		struct tm * now_cal;
		now_cal = localtime ( & now_insec );
		fprintf( stderr
			, "%d-%d-%d %d:%d:%d, Severity=\"%d\", Source=\"%s\", Message=\"%s\"\n"
			, 1900 + now_cal->tm_year
			, now_cal->tm_mon + 1	// Month are 0-11
			, now_cal->tm_mday		// but days are 1-31
			, now_cal->tm_hour
			, now_cal->tm_min
			, now_cal->tm_sec
			, level
			, source
			, message);		
	}
}

6. Clean up code from global variables when possible

This has already started. Currently I only have _DEBUG left and this is not even used (from the command line interpreter as it's setting a struct option_set.debug bool which doesn't get used by the fprintf function calls).

With the added log_event function it should be fairly simple to get rid of that one.

7. Document the code and interfaces used as well as the flow

Back to Google docs and presentation. We already have a draft of the flow as per my original design post (see below for a quick link and the image itself). But the interaction between the various function and interfacing would be definitely a good addition.

Initial {CWoC} aila post (back then un-named)
flowchart.png

Comments 1 CommentJump to latest comment

Ludovic Ferre's picture

Yes, I have forgotten one very important section for the above document! Features.

So one very important feature planned for the next tag is a String cache. But a very custom one. This string cache will be used to stored the string information (sorry, I have to state the obvious), match the string to a unique id (an int will be enough, with a couple of billions candidates on a 32-bit system) as well as add accounting capabilities (another int to count hits).

The string cache most likely will end up being implement in a structure with dynamic memory allocation (as we won't know the size before hand, or won't we?) or may be not.

Here's the struct prototype I have in mind for the cached data:

struct string_cache_entry {
	int string_id;
	char * string;
	int string_type; // Guid or ip_address, or else?
	int hit_counter;
};

So now that we have an outline we can wonder which of the dynamic or static allocation is best? Given right now we would have guids and ip address to be stored it is arguable that we have fixed size string. A guid is 38 char, whilst an ip address ultimately is only a 32-bit dotted decimal representation. So we could store 2 type of strings (one two different structs)  into a fix size cache (say client count x 10 array)? Or we'll have to do with the dynamic allocation anyway (I know I'll have to get over it soon in all cases) in order to ensure data storage efficiency versus ease of development :D.


Regarding the cache itself operations should be almost transparent to the user: call the string cache function to get a string_id (no need to know whether the string is already cached or not) for string to string_id transformation. On the other hand the look-up would return a char or char * (depending on how the storage would be implemented -> copy char to heap allocated memory and point to it in the cache structure or else???) if the string_id matches an existing cache entry. If not return a NULL pointer.

Well, I suspect I'll have this week to refine the design and next week end to implement, unless Christmas is taking over (but then I'll be on-leaves! Oh man, it's going to be a warm winter in-da-house).

I am currently off-net, on a retreat of some kind. I'll be back real soon, and you sure will hear from me then ;-).

Ludovic FERRÉ
Principal Remote Product Specialist
Symantec

-1
Login to vote