Handling of errors

The main goals of libvirt when it comes to error handling are:

  • provide as much detail as possible
  • provide the informations as soon as possible
  • dont force the library user into one style of error handling

As result the library provide both synchronous, callback based andasynchronous error reporting. When an error happens in the library code theerror is logged, allowing to retrieve it later and if the user registered anerror callback it will be called synchronously. Once the call to libvirt endsthe error can be detected by the return value and the full information forthe last logged error can be retrieved.

To avoid as much as prossible troubles with a global variable in amultithreaded environment, libvirt will associate when possible the errors tothe current connection they are related to, that way the error is stored in adynamic structure which can be made thread specific. Error callback can beset specifically to a connection with

So error handling in the code is the following:

  1. if the error can be associated to a connection for example when failingto look up a domain
    1. if there is a callback associated to the connection set with virConnSetErrorFunc,call it with the error informations
    2. otherwise if there is a global callback set with virSetErrorFunc,call it with the error information
    3. otherwise call virDefaultErrorFuncwhich is the default error function of the library issuing the erroron stderr
    4. save the error in the connection for later retrieval with virConnGetLastError
  2. otherwise like when failing to create an hypervisor connection:
    1. if there is a global callback set with virSetErrorFunc,call it with the error information
    2. otherwise call virDefaultErrorFuncwhich is the default error function of the library issuing the erroron stderr
    3. save the error in the connection for later retrieval with virGetLastError

In all cases the error informations are provided as a virErrorPtrpointer toread-only structure virErrorcontaining thefollowing fields:

  • code: an error number from the virErrorNumberenum
  • domain: an enum indicating which part of libvirt raised the error seevirErrorDomain
  • level: the error level, usually VIR_ERR_ERROR, though there is room forwarnings like VIR_ERR_WARNING
  • message: the full human-readable formatted string of the error
  • conn: if available a pointer to the virConnectPtrconnection to the hypervisor where this happened
  • dom: if available a pointer to the virDomainPtrdomaintargetted in the operation

and then extra raw informations about the error which may be initializedto 0 or NULL if unused

  • str1, str2, str3: string informations, usually str1 is the errormessage format
  • int1, int2: integer informations

So usually, setting up specific error handling with libvirt consist ofregistering an handler with with virSetErrorFuncorwith virConnSetErrorFunc,chech the value of the code value, take appropriate action, if needed letlibvirt print the error on stderr by calling virDefaultErrorFunc.For asynchronous error handing, set such a function doing nothing to avoidthe error being reported on stderr, and call virConnGetLastError orvirGetLastError when an API call returned an error value. It can be a goodidea to use virResetErroror virConnResetLastErroronce an error has been processed fully.

At the python level, there only a global reporting callback function atthis point, see the error.py example about it:

def handler(ctxt, err):
    global errno

    #print "handler(%s, %s)" % (ctxt, err)
    errno = err

libvirt.registerErrorHandler(handler, 'context') 

the second argument to the registerErrorHandler function is passed as thefist argument of the callback like in the C version. The error is a tuplecontaining the same field as a virError in C, but cast to Python.