#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
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.
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
.
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:
The person's primary key (an autoincrementing integer).
The person's last name.
The person's first name.
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).
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/
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 consist of:
Metadata that includes an author reference, an authorship time, and optionally an associated run.
The note text, which is in markdown format.
A list of zero or more embedded images and where their links are in the note text.
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 . 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.
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.