Skip to content

How to enable and capture VDB log messages

kdurbrow edited this page May 31, 2016 · 6 revisions

VDB has extensive and detailed logging capabilities that user code can both hook into and capture. This document will demonstrate how a c++ program using VDB might do this.

#include <iostream>
#include <string>
#include <stdexcept>

// _DEBUGGING is needed to turn on debugging messages
#define _DEBUGGING 1
#include <klib/log.h>
#include <klib/debug.h>

class VDBLog
{
    void log(std::string const &message) {
        std::cerr << message << std::endl;
    }

    static rc_t receive(void *, char const *, size_t, size_t *);
public:
    /* version is XXYYZZZZ in hex; XX is major version, YY is minor version; ZZZZ is revision
     * it is only informational
     *
     * logLevel sets the minimum severity for messages to be logged; it is defined in log.h:
     *   klogFatal    fatal errors
     *   klogSys      errors from the system
     *   klogInt      internal software errors
     *   klogErr      ordinary errors, generally related to inputs and data
     *   klogWarn     non-errors which may indicate an unusual condition
     *   klogInfo     non-errors, like progress or success messages
     *   klogDebug    debugging message which are not removed in release code
     *
     * debugFlag is for turning on debug messages for a particular module. These messages are removed
     * in release builds. This facility is extensive and extensible. The values are structured strings
     * `module` or `module-condition`. Each module has its own set of condition codes; I won't document
     * them here. See klib/debug.h for the complete of current values. The modules currently defined are:
     *   ALIGN   generally concerning accessing of reference sequences
     *   KDB     low-level database access
     *   KFG     configuration
     *   KNS     low-level network access
     *   KRYPTO  crypto
     *   REF     object lifetimes
     *   VDB     high-level database access
     *   VFS     high-level network and file access
     */
    explicit VDBLog(char const program[], int version, int logLevel = klogErr, char const *debugFlag = 0);
    ~VDBLog();
};

static void doSomeVDBStuff(char const run[]); /// not implemented here; left as an exercise to the reader

int main(int argc, char *argv[])
{
    VDBLog log(argv[0], 0x1000000, klogDebug, "VFS");
    try {
        doSomeVDBStuff("ERR1417836");
    }
    catch (std::exception const &e) {
        std::cerr << e.what() << std::endl;
    }

    return 0;
}

rc_t VDBLog::receive(void *p, const char *buffer, size_t size, size_t *written) {
    VDBLog *const objp = static_cast<VDBLog *>(p);
    std::string const &message = std::string(buffer, size - 1);

    objp->log(message);
    *written = size;
    return 0;
}

VDBLog::VDBLog(const char program[], int version, int logLevel, const char *debugFlag)
{
    rc_t rc = 0;

    count[0] = count[1] = count[2] = count[3] = 0;

    rc = KWrtInit(program, version);
    if (rc) throw std::runtime_error("KWrtInit failed!");

    // to receive log messages from the library
    rc = KLogLibHandlerSet(VDBLog::receive, (void *)this);
    if (rc) throw std::runtime_error("KLogLibHandlerSet failed!");

    // to receive status messages from the library
    rc = KStsHandlerSet(VDBLog::receive, (void *)this);
    if (rc) throw std::runtime_error("KLogLibHandlerSet failed!");

    // to receive log messages from user code; yes you can generate your own log messages!
    // is not life grand!
    rc = KLogHandlerSet(VDBLog::receive, (void *)this);
    if (rc) throw std::runtime_error("KLogHandlerSet failed!");

    // log severity level
    rc = KLogLevelSet(logLevel);
    if (rc) throw std::runtime_error("KLogLevelSet failed!");

    if (debugFlag) {
        // to receive debugging messages; this doesn't do anything in release code
        rc = KDbgHandlerSet(VDBLog::receive, (void *)this);
        if (rc) throw std::runtime_error("KDbgHandlerSet failed!");

        // to turn on output from a particular module
        // this can actually be called many times to turn on multiple modules/conditions
        rc = KDbgSetString(debugFlag);
        if (rc) throw std::runtime_error("KDbgSetString failed!");
    }
}

VDBLog::~VDBLog(void)
{
    KDbgHandlerSetStdErr();
    KLogHandlerSetStdErr();
    KLogLibHandlerSetStdErr();
    KDbgHandlerSetStdErr();
}
Clone this wiki locally