			 Condor User Log API

1. Introduction

Condor has many logs.  The "user log" is the log file written by the
condor_shadow which shows the progress of one or more jobs in a Condor
pool.  To specify that the condor_shadow should write a user log for a
given job, add:

  log = logfile

to your condor_submit command file, where "logfile" is the filename
(or path) where you want the user log created.  Multiple jobs can use
the same log file by specifying the same filename for each job
submission.

In Condor v5.62 and above, the user logs can be read and written using
a C++ API.  This document describes how to use the API.

2. Reading User Logs

The ReadUserLog class has the following interface:

  class ReadUserLog
  {
    public:
      int initialize (const char *file,
		      bool handle_rotation = false,
		      bool check_for_rotated = false );
      bool initialize (const ReadUserLog::FileState &state,
			bool handle_rotation = true );
      ULogEventOutcome readEvent (ULogEvent *&event);
  };

ReadUserLog objects must be initialized with the path to the user log
file before use.  The initialize method returns 1 on success.

The readEvent method is used to read events from the log.  If
readEvent returns ULOG_OK, then a pointer to a newly allocated
ULogEvent is returned in the event parameter.  The ULogEvent should be
deallocated using delete when no longer needed.

ULogEvent is a base class for the different event classes
(SubmitEvent, ExecuteEvent, CheckpointedEvent, etc.).  Use the
eventNumber member to determine the appropriate type for the
ULogEvent.

The ReadUserLog object can now export it's current state to an object that
the application can save off to disk.  To use this:

Always use InitFileState() to initialize this structure.  All of these
methods take a reference to a state buffer as their only parameter.
All of these methods return true upon success.

To save the state, do something like this:
	ReadUserLog		reader;
	ReadUserLog::FileState	statebuf;

	status = ReadUserLog::InitFileState( statebuf );

	status = reader.GetFileState( statebuf );
	write( fd, statebuf.buf, statebuf.size );
	...
	status = reader.GetFileState( statebuf );
	write( fd, statebuf.buf, statebuf.size );
	...

	status = UninitFileState( statebuf );


To restore the state, do something like this:
	ReadUserLog::FileState	statebuf;
	status = ReadUserLog::InitFileState( statebuf );

	read( fd, statebuf.buf, statebuf.size );

	ReadUserLog  		reader;
	status = userlog.initialize( statebuf );

	status = UninitFileState( statebuf );
	....


3. Writing User Logs

The WriteUserLog class has the following interface:

  class WriteUserLog
  {
    public:
      WriteUserLog();
      WriteUserLog(const char *owner, const char *file, int clu, int proc,
                   int sub);
      ~WriteUserLog();
      void initialize(const char *, const char *, int, int, int);
      int writeEvent (ULogEvent *);
  };

WriteUserLog objects can be initialized either through the provided
contructor or the initialize method.  To write an event to the log,
create the appropriate ULogEvent subclass object, fill in the
appropriate information, and pass a pointer to that object to the
writeEvent method.

4. Final Details

The WriteUserLog class is defined in write_user_log.h and the ReadUserLog
class is defined in read_user_log.h.  ULogEventNumber,
ULogEventOutcome, ULogEvent, and the event subclasses are defined in
condor_event.h.  You need to include read_user_log.h and/or
write_user_log.h in any code which uses the user log API and link with
libcondorapi.a.  For backward compatibility, user_log.c++.h is
distributed with Condor which includes write_user_log.h and
read_user_log.h.  Also for backward compatibility, UserLog is provided as
an alias type of WriteUserLog (via typedef).

Also, please #include <sys/time.h> before bringing in the user log API
header file. This brings in definitions needed by the user log header file.
