LogBook

Name

LogBook -- Top Level Logbook C++ API

Synopsis


#include <LogBookh>

class LogBook
{
public:
    class Exception : public std::exception{
    public:
        Exception(const char* message) noexcept;
        Exception(const std::string& message) noexcept;
        Exception(const CSqliteExceptionamp; reason, const char* doing) noexcept;
        Exception(const CSqliteException& reason, const std::string& doing) noexcept;
        
        Exception(const Exception& rhs) noexcept;
        Exception& operator=(const Exception& rhs) noexcept;
        
        virtual ~Exception();
        virtual const char* what() const noexcept;
        
        static void rethrowSqliteException(CSqliteException& e, const char* doing);
        static void rethrowSqliteException(CSqliteException& e, std::string doing);
    };
    
public:
    static std::string m_tempdir;
public:
    static void create(
       const char* pFilename, const char* pExperiment,
       const char* pSpokesperson, const char* purpose
    );
    
    LogBook(const char* pFilename);
    virtual ~LogBook();


public:
 // Api for person
    LogBookPerson* addPerson(const char* lastName, const char* firstName, const char* salutation);
    std::vector<LogBookPerson*> findPeople(const char* where=nullptr);
    std::vector<LogBookPerson*> listPeople();
    LogBookPerson* getPerson(int id);
    
    // Api for shifts:
    
    LogBookShift* getShift(int id);
    void          addShiftMember(LogBookShift* pShift, LogBookPerson* pPerson);
    void          removeShiftMember(LogBookShift* pShift, LogBookPerson* pPerson);
    LogBookShift* createShift(const char* name);
    LogBookShift* createShift(
      const char* name, const std::vector<LogBookPerson*>& members
    );
    std::vector<LogBookShift*> listShifts();
    LogBookShift*   findShift(const char* name);
    void setCurrentShift(LogBookShift* pShift);
    LogBookShift* getCurrentShift();
    
    // API for runs:
    
    LogBookRun* getRun(int id);
    int         runId(int runNumber);
    LogBookRun* currentRun();
    LogBookRun* begin(int number, const char* title, const char* remark=nullptr);
    void        end(LogBookRun*& pRun, const char* remark = nullptr);
    void        pause(LogBookRun*& pRun, const char* remark = nullptr);
    void        resume(LogBookRun*& pRun, const char* remark = nullptr);
    void        emergencyStop(LogBookRun*& pRun, const char* remark = nullptr);
    std::vector<LogBookRun*> listRuns();
    LogBookRun* findRun(int number);
    
    // API for notes:
    
    LogBookNote*  createNote(
        LogBookPerson& author, const char* note, const std::vector<std::string>& imageFiles,
        const std::vector<size_t>& imageOffsets,
        LogBookRun* pRun = nullptr
    );
    LogBookNote* createNote(LogBookPerson& author, const char* note, LogBookRun* pRun = nullptr);
    LogBookNote* getNote(int id);
    std::vector<LogBookNote*> listAllNotes();
    std::vector<LogBookNote*> listNotesForRunId(int runId);
    std::vector<LogBookNote*> listNotesForRun(int runNumber);
    std::vector<LogBookNote*> listNotesForRun(const LogBookRun* pRun);
    std::vector<LogBookNote*> listNonRunNotes();
    LogBookRun* getNoteRun(LogBookNote& note);
    LogBookPerson* getNoteAuthor(LogBookNote& note);
    
    // API for key value store
    
    bool kvExists(const char* key);
    std::string kvGet(const char* key);
    void kvSet(const char* key, const char* value);
    void kvCreate(const char* key, const char* value);
    

};


      

... -I$DAQINC -L$DAQLIB -lLogbook -Wl,-rpath=$DAQLIB

DESCRIPTION

This class represents the top level C++ API for the logbook. In addition to providing the API, it encapsulates a nested public class: LogBook::Exception used to report errors via exceptions.

In addition, for some operations, the logbook subsystem requires a directory in which to export data from the logbook database into the file system. For example, when rendering a note as markup text with image references, the images themselves must live in the filesystem. The member variable LogBook::m_tempdir contains the name of this directory. Note that currently this is initially ~/.nscl-logbook, however it is perfectly legal for a client program to alter that value to point to any other existing directory in the filesystem.

The remainder of this manpage will first document the LogBook::Exception class and its methods and then the LogBook class itself.

LogBook::Exception METHODS

All errors detected by the logbook system are reported by throwing LogBook::Exception exceptions. This exception is derived from std::exception. This section describes the methods (most importantly the mechanisms for constructing instancde) of this class.

noexcept Exception(const char* message);

Constructs an instance with the specified message. The message text is copied into internal object storage so the lifetime of the message is not an instance as the call-stack is unrolled. This method is most convenient when the message text is hard coded.

noexcept Exception((const std::string& message);

Constructs the exception given a reference to a std::string object. This is convenient to use when the error message is programmatically constructed. For example, within the library, a common pattern is to instantiate an std::stringstream object and write into that both constant text and parameters of the failing call. From this stream a std::string is constructed and that string used, in turn to construct a LogBook::Exception object which is then thrown.

In all cases, the final exception text (returned by the what method) is stored internally to avoid life-time issues.

noexcept Exception(const CSqliteExceptionamp; reason, const char* doing);

Constructs an instance creating the error text from that encapsulated within a CSqliteException object and a character string. This is used to map failures reported by the Sqlite class library, the logbook facility is built on, to LogBook::Exception objects when the additional string (which usually describes what the library was trying to do) is a constant.

See, as well the overloaded rethrowSqliteException methods which both construct and then throw the resulting LogBook::Exception object.

noexcept Exception(const CSqliteException& reason, const std::string& doing);

Same as the previous constructor but the additiona text is provided as a reference to a std::string which in general provides mechanisms for a more dynamic construction of that message.

const noexcept virtual const char* what();

This method must be provided by all classes derived from std::exception, it provides a pointer to the error message encapsulated by exception classes.

static void rethrowSqliteException(CSqliteException& e, const char* doing);

Convenience method that constructs a LogBook::Exception and throws it. This is used within the library to convert exceptions thrown by the C++ encapsulation of the Sqlite3 API into LogBook::Exception throws.

static void rethrowSqliteException(CSqliteException& e, std::string doing);

Same as above convenience method used to convert a caught CSqliteException object into a LogBook::Exception throw.

LogBook METHODS

The LogBook methods are divided into several sub-categories, each dealing with a subset of the responsibilities of the logbook subsystem. This section will describe, in turn, the methods that make up each of the sub-categories.

ADMINISTRATIVE METHODS

These methods are responsible for creating and accessing logbook databases:

static void create (const char* pFilename, const char* pExperiment, const char* pSpokesperson, const char* purpose);

Creates a new database file initialized to hold a logbook. pFilename is the path to the file that will be created. It is an error for that file to already exist. pExperiment provides the experiment identifier. This value is stored in the key value store with the key experiment

pSpokesperson is intended to provide the name of the spokesperson of the experiment. Note that at this point there are no entries in the People subsection of the logbook. This is therefore, just free text. The value is stored in the key value store with the key spokesperson

purpose is intended to provide the purpose of the experiment. This is stored in the key value store under the key purpose

An additional key is created: version. This is intended to future proof the database by allowing us to detect and, hopefully adapt to, future database schema.

LogBook(const char* pFilename);

Constructs an instance of LogBook. The methods of that class allow us access to the logbook stored in the file whose path is pFilename. Note that pFilename must exist and have come into being by calling LogBook::create.

PEOPLE METHODS

This set of methods defines, retrieves and searches for people in the logbook database. Persons are encapsulated in LogBookPerson instances. This calss and its methods are described in LogBookPerson

Methods that return pointers to LogBookPerson object either individually or as vectors of pointers are returning pointers to dynamically allocated objects. It's important to delete all of these objects after use in order top prevent memory leaks.

Note that these methods can throw LogBook::Exception objects and a well constructed program must be capable of, at some level, handling those.

LogBookPerson* addPerson(const char* lastName, const char* firstName, const char* salutation);

This method creates a new person with the attributes provided. Note that normally a salutation is considered optional. Provide a pointer to an empty string if that's what you want

The method returns a pointer to a LogBookPerson object that encapsulates the new person in the database.

std::vector<LogBookPerson*> findPeople(const char* where = nullptr);

Does a generic find for persons in the database. The where parameter is valid Sqlite3 WHERE clause (without the WHERE keyword) that qualifies the search. If it is nullptr, the call is functionally equivalent to listPeople.

The fields you can include in the where clause are:

id

The person's primary key (an autoincrementing integer).

lastname

The person's last name.

firstname

The person's first name.

salutation

The salutation of the people you want.

The where clause can be arbitrarily complex as it will just be appended (after a WHERE) to the prepared statement used to return the data needed to construct the vector of LogBookPerson objects whose pointers are returned.

std::vector<LogBookPerson*> listPeople();

Returns a vector of pointers to LogBookPerson objects encapsulating all people defined to the logbook.

LogBookPerson* getPerson(int id);

Returns a pointer to a LogBookPerson object that encapsulates the entry for a person with the primary key id. This is like doing a findPeople call with where = id=id (the second id in the text above is the value of the id parameter to this call).

SHIFT API

Shifts are collections of people. In addition there's the concept of a current, or on-duty shift that, during data taking is associated with data taking state transitions. Shifts are encapsulated by LogBookShift objects. LogBookShift is documented in LogBookShift

Pointer to LogBookShift object returned by these methods, either individually or in vectors, point to dynamically allocated objects. As such when no longer needed, they must be deleted in order to prevent memory leaks.

LogBookShift* getShift(int id);

Returns the shift with the primary key id

The primary key is a sequentially assigned unique integer.

void addShiftMember(LogBookShift* pShift, LogBookPerson* pPerson);

Adds a member to an existing shift pShift is a pointer to that shift and p pPerson is a pointer to the person to add.

void removeShiftMember(LogBookShift* pShift, LogBookPerson* pPerson);

Removes a person represented by pPerson from a shift represented by pShift.

LogBookShift* createShift(const char* name);

Creates a new shift named name. The shift, thus created, has no members. Use addShiftMember to populate the shift or, alternatively use the overload of this method that provides the ability to pass in members.

The return value is a pointer to the object encapsulating the shift that was coreated.

LogBookShift* createShift(const char* name, const std::vector<LogBookPerson*>& members);

Creates a new shift named name. The shift is initially stocked with the members encapsulated by the object pointed to in the vecto members.

The return value is a pointer to a LogBookShift that encapsulates the new shift.

std::vector<LogBookShift*> listShifts();

Returns a vector containing pointers to all of the shifts that have been defined.

LogBookShift* findShift(const char* name);

If there is a shift named name, returns a pointer to an object that encapsulates it. If there is no matching shift, this returns a nullptr.

void setCurrentShift(LogBookShift* pShift);

Sets the current shift to the shift pointed to by pShift. Until the current shift is set again, all run state transitions logged will be attributed to this shift.

LogBookShift* getCurrentShift();

Returns a pointer to the current shift. If no current shift has ever been set, this returns a nullptr/

RUNS API

This section of the API provides methods for creatin runs and cycling them through legal state transitions. Furthermore, runs can be retrieved and searched for by run number.

Runs are encapsulated by instances of LogBookRun. This class is descdribed in LogBookRun. All pointers to LogBookRun objects point to dynamically allocated objects. When you are done using them you must destroy them using delete to avoid application memory leaks.

There is a coupling between shifts and runs. Several of the methods in this section of the API log run state transitions. In order to succeed a current shift must have been established. The current shift is associated with the state transition log entries.

LogBookRun* getRun(int id);

Returns a pointer to the run whose primary key is id. The primary key for runs is a unique integer for each run.

int runId(int runNumber);

Returns the primary key of the run whose run number is runNumber. If there is no such run a LogBook::Exception is thrown.

LogBookRun* currentRun();

Returns a pointer to an encapsulation of thecurrent run. If there is no current run a nullptr is returned.

LogBookRun* begin(int number, const char* title, const char* remark = nullptr);

Logs the beginning of a new run. There must be no active (current) run. The new run is assigned the run number number. There must not be a run with that number.

The title is associated with the run as its title. remark is an additional remark that is associated with the run.

The returned value is a pointer to an object that encapsulates the run. If any of the preconditions described above were not met a LogBook::Exception is thrown.

void end(LogBookRun*& pRun, const char* remark = nullptr);

Logs an end to the run that is encapsulated by pRun. remark provides an optional remark associated with the transition. To be ended a run must be either active or paused. If that's not the case, a LogBook::Exception is thrown.

void pause(LogBookRun*& pRun, const char* remark = nullptr);

Logs a pause to the run encapsulated by pRun. The logbook state of the run must be active or else an exception is thrown. The optional remark provides a remark to be associated with the state change.

void resume(LogBookRun*& pRun, const char* remark = nullptr);

Logs a resume run for the run pointed to by pRun. The run must be in the paused state or an exception will be thrown. The remark is text that will be associated with the state change.

void emergencyStop(LogBookRun*& pRun, const char* remark = nullptr);

Logs an emergency stop for the run identified by pRun. The run must be either active or paused. Emergency stops are intended to end runs that ended improperly (e.g. data acquisition failures). An emergency stop indicates something very wrong happened to a run to prevent it from having a properly logged end. remark is remark text that's associated with the transition.

std::vector<LogBookRun*> listRuns();

Returns all of the runs that have been logged in the logbook.

LogBookRun* findRun(int number);

Given the run number number, returns an encapsulation of that run. If there is no such run, nullptr is returned.

NOTES methods

Notes consist of:

The note API is one of the more complext bits of interface in the LogBook class. Note that, as with other parts of the API, a class has been designed to encapsulate notes; LogBookNote; which is documented in LogBookNote.

API elements that return LogBookNote* values or containers are returning pointers to dynamically allocated objects that must be disposed of when no longer needed using delete.

LogBookNote* createNote(LogBookPerson& author, const char* note, const std::vector<std::string>& imageFiles, const std::vector<size_t>& imageOffsets, LogBookRun* pRun = nullptr);

Fully creates a note. The return value is a pointer to an encapsulation of the note created.

author is a pointer to an encapsulation of the person who's written the note. note is a pointer to the note text. The note is assumed to be in markdown format.

imageFiles is a vector of images file paths that are referenced by image links in the markdown. These images will be imported into the database. This information could be scraped by your application from the note text. imageOffsets are the byte offsets into the note text at which the first character of the corresponding image link is. Recall that image links look like ![somet text](image-path). These offsets must be the offsets of the !.

If the note is associated with a run, pRun points to the run object that encpapsulates the run. If not, either omit the parameter or explicitly pass a nullptr if your program flow makes that impossible or contorted.

Once the note is created, any image references you've passed are no longer needed as the image file contents have been sucked into the logbook database.

LogBookNote* createNote(LogBookPerson& author, const char* note, LogBookRun* pRun = nullptr);

Creates a note with no image links. See the prior overload for the parameters we do have. They are have the same meaning. In fact, this method just invokes the previous methos passing empty vectors for the image files and image file offset vectors.

LogBookNote* getNote(int id);

Retrieves an encapsulation fo the note with the primary key value id. The primary key is a unique integer value assigned to each note.

std::vector<LogBookNote*> listAllNotes();

Returns a vector containing pointers to encapsulations of all of the notes entered in the database.

std::vector<LogBookNote*> listNotesForRunId(int runId);

Returns the notes that are associated with a run given its primary key. That is a value that was returned from the runId method e.g.

std::vector<LogBookNote*> listNotesForRun(int runNumber);

Returns the notes associated with a run that has the run number runNumber.

std::vector<LogBookNote*> listNonRunNotes();

Returns the notes that are not associated with any run.

LogBookRun* getNoteRun(LogBookNote& note);

Returns a pointer to an encapsulated run object for the run associated with note. If there is no assciated run, nullptr is returned. Note that the returned value points to a dynamically allocated object. When no longer needed it must be disposed using delete.

LogBookPerson* getNoteAuthor(LogBookNote& note);

Returns the encapsulated author of the note. This is a pointer to a dynamically allocated object. When you no longer need the author, you must use delete to dispose of it.

KEY VALUE STORE api

The logbook database includes a key value store. A key value store is a table of keys and associated values. They key value store is used to store metatdata about the logbook itself and can be used for simple application specific extension to the database to meet unanticipated use cases. Key Value will be abbreviated KV below.

bool kvExists(const char* key);

Returns true if there's an entry with the key key in the KV store. If not returns false

std::string kvGet(const char* key);

Returns the value of the key in the KV store if the key exists. If not a LogBook::Exception is thrown.

void kvSet(const char* key, const char* value);

Sets a new value for the existing key. If there is no key key, a new KV pair are created.

void kvCreate(const char* key, const char* value);

Creates a new KV entry in the KV store. The key will be key and the value will be value. If there is already a KV entry for key, a LogBook::Exception is thrown.