UNIX and its variants provide only stdout and stderr as standard write streams available to fprintf(). When wanting to direct messages elsewhere, it is necessary to make other arrangements for output; either via a command-line redirect, through internal management within a program itself, or some other (most-likely) non-trivial method (think pipes and sockets).
Modern systems, however, are very often required to send messages to multiple destinations, e.g., a disk-file, a database logger, alert and monitoring systems, auto-updating web-sites, UI displays, e-mail and twitter accounts, other programs, and the list goes on. When multiple destinations are necessary for the same message, this message needs to be duplicated for each destination, making coding annyoing, repetitive, and increasingly difficult to manage.
But what if there were a way to write a message just once in your program, while elsewhere it can be handled and forwarded to any number or kind of destinations without headache?
And wouldn't it be even nicer to be able to use newly named write streams that allow message type deliniation through more than just the two standard streams provided? For example, why not extend the standard stream concept to include stdInfo, stdWarn, and stdDbug?
With this C source code library, a programmer can now:
- Redirect stdin, forwarding all incoming messages to your registered callback handler.
- Redirect stdout and stderr to multiple destinations, without having to rewrite any of your fprintf() statements.
- Create new streams that behave identically to stdout and stderr, using the new stream name directly, just like the standard streams.
- Define and register your own call-back routines, per stream, for program-specific handling of every message.
- Unlimited number of new streams may be created
- Unlimited number of callbacks may be registered per stream (and de-registered)
- Registration and De-Registration of callbacks can be made at any point in your program; that is, they may be turned on and off throughout the course of a program's execution.
- Caller can define and set the message delimiter, per stream
- Works with background programs or GUI programs equally well
- stdout and stderr streams originating from other libraries included in your program are also intercepted. For example, all MySQL error messages are sent through stderr and so could be intercepted by this library. This provides the opportunity for the programmer to act on these messages directly and immediately. For example, when receiving a crashed table message, your program could parse this message and automatically issue a repair table command, alleviating the user from having to do this themselves.
Works especially well when forking a program. Since all file descriptors are inherited by the child, all messages written by the child will be processed by the same callback routine, guaranteeing single concurrancy of message processing, i.e., no collisions regardless the number of children demanding attention.
It Is Extensible: In general, new streams can be created to be used as a channel to transmit anything to go anywhere and/or do anything.
- Example 1: Streams may also be created and used for other purposes. For example, counting an occurance of something, where this occurance happens in multiple locations of your code. In this situation, the callback maintains the system-wide counter, and can then carry out any necessary actions when the counter reaches a certain value. For example, a server program listening for client connections where connection management of all clients is a concern.
- Example 2: A new stream can be created that is responsible for executing one of many known tasks, essentially becoming a channel of "work". That is, anywhere in the program where a separate task must be performed, simply send a message through the stream and let the callback be reponsible for all logic and subsequent task execution.
- Example 3: And turning the concept around, it's possible to create streams not by message type, but by destination type. So, a stream may be designated to send information through the channel directly to a Database, a web-site, a twitter account, a UI display screen, a disk file, another program, a work queue, etc.
Creating a new stream is as simple as:
- Define the new stream name, in ustreams.c
- Add the extern declaration to ustreams.h file
- Add an equivalent USTREAMS_STREAM enum anywhere in the current list of known streams, in ustreams.h
- Add one line to the initialisation routine creating the stream itself, in ustreams.c
- Re-Compile the library
- Write the callbacks to handle the new stream's output
- New stream is now available for use everywhere in your program
- Retrieve and process all stdin messages as a simple callback
- Never have to deal with having to manage FILE* pointers, pipes, sockets, etc. directly in your app code ever again
- As new output requirements come to exist, no need to re-write existing code, just write a new callback handler.
- fprintf() now becomes a powerful tool of information transmission and routing; no longer just a statement to print a string
- All logic associated with data of a stream is now centrally located and fully de-coupled from your program at-large
- Using the stdDbug stream now simplifies necessary debugging statements. Write all your debug statements, and when you don't need the output, simply don't register a callback. And, since dynamic registration and de-registration of callbacks per stream is possible, it is trivial to isolate only those sections of the code requiring debug output for any given execution.
- Ideal for large systems employing many libraries and/or having a large code base.
- Because it's so easy to use/implement: If used during the Design Phase, new algorithms and solutions are now available, and trivial to implement.
- Source Code, Header Files, and makefile to create the ustreams.a library archive
- New streams stdInfo, stdWarn, and stdDbug provided for
- Complete Documentation describing all aspects of how to use the library, detailed instructions to create new streams, examples of extensibility,
- A completed example implementation (skinny version below) demonstrating how to forward messages to:
- Multiple Disk Files
- A Database
- Email Addresses or Twitter Accounts
- All UNIX/C developers interested in having precise control over program messages, their destinations, and any possible follow-on actions.
- Any programmer wishing to extend the concept of a write stream beyond using it simply for string messages; the possibilities are limitless.
- Up-to-date C compiler
- GTK+-2 installed on computer (though programming in GTK+-2 is not a requirement, everything is internalized). Gtk+-2 is standard on all *NIX platforms and should not be an issue.
- Library is provided as a single file source code, a header file, and externs header file for compilation.
- Makefile is provided to create an archive named ustreams.a, to be used when linking the final program.