[libvirt] [PATCH] errors: Improve error reporting to log multiple errors instead of just the last one
This patch introduces a new structure called virErrorsPtr which can get all the errors that occurred since the connection open. The error callback function is being used as many times as necessary. The new public function called virGetAllErrors() has been introduced to get all the errors that occurred. Also, a new test called errorreport has been written to test the functionality of error logging for multiple error occurrences. Signed-off-by: Michal Novotny minov...@redhat.com --- include/libvirt/virterror.h | 14 ++ python/generator.py |1 + src/util/virterror.c | 99 src/util/virterror_internal.h |1 + tests/Makefile.am |9 +++- tests/errorreport.c | 74 ++ 6 files changed, 186 insertions(+), 12 deletions(-) create mode 100644 tests/errorreport.c diff --git a/include/libvirt/virterror.h b/include/libvirt/virterror.h index e896d67..c7a8018 100644 --- a/include/libvirt/virterror.h +++ b/include/libvirt/virterror.h @@ -118,6 +118,19 @@ struct _virError { see note above */ }; +/* + * virErrors: + * + * A libvirt Errors array instance + */ +typedef struct _virErrors virErrors; +typedef virErrors *virErrorsPtr; +struct _virErrors { +virErrorPtr lastError; +unsigned int nerrors; +virErrorPtr errors; +}; + /** * virErrorNumber: * @@ -261,6 +274,7 @@ typedef void (*virErrorFunc) (void *userData, virErrorPtr error); */ virErrorPtrvirGetLastError (void); +virErrorsPtr virGetAllErrors (void); virErrorPtrvirSaveLastError(void); void virResetLastError (void); void virResetError (virErrorPtr err); diff --git a/python/generator.py b/python/generator.py index 6fee3a4..315eb51 100755 --- a/python/generator.py +++ b/python/generator.py @@ -356,6 +356,7 @@ skip_impl = ( 'virDomainSnapshotListChildrenNames', 'virConnGetLastError', 'virGetLastError', +'virGetAllErrors', 'virDomainGetInfo', 'virDomainGetState', 'virDomainGetControlInfo', diff --git a/src/util/virterror.c b/src/util/virterror.c index 380dc56..b03ae7c 100644 --- a/src/util/virterror.c +++ b/src/util/virterror.c @@ -190,11 +190,17 @@ static const char *virErrorDomainName(virErrorDomain domain) { static void virLastErrFreeData(void *data) { -virErrorPtr err = data; -if (!err) +virErrorsPtr errs = data; +if (!errs) return; -virResetError(err); -VIR_FREE(err); + +if (errs-lastError) { +virResetError(errs-lastError); +VIR_FREE(errs-lastError); +} +if (errs-errors) +VIR_FREE(errs-errors); +VIR_FREE(errs); } @@ -262,14 +268,18 @@ virCopyError(virErrorPtr from, static virErrorPtr virLastErrorObject(void) { -virErrorPtr err; -err = virThreadLocalGet(virLastErr); -if (!err) { -if (VIR_ALLOC(err) 0) +virErrorsPtr errs = NULL; + +errs = virThreadLocalGet(virLastErr); +if (!errs) { +if (VIR_ALLOC(errs) 0) +return NULL; +if (VIR_ALLOC(errs-lastError) 0) return NULL; -virThreadLocalSet(virLastErr, err); +virThreadLocalSet(virLastErr, errs); } -return err; + +return errs-lastError; } @@ -292,6 +302,27 @@ virGetLastError(void) return err; } +/* + * virGetAllErrors: + * + * Provide a pointer to all errors caught at the library level + * + * The error object is kept in thread local storage, so separate + * threads can safely access this concurrently. + * + * Returns a pointer to all errors caught or NULL if none occurred. + */ +virErrorsPtr +virGetAllErrors(void) +{ +virErrorsPtr errs; + +errs = virThreadLocalGet(virLastErr); +if (!errs || errs-nerrors == 0) +return NULL; +return errs; +} + /** * virSetError: * @newerr: previously saved error object @@ -316,11 +347,56 @@ virSetError(virErrorPtr newerr) virResetError(err); ret = virCopyError(newerr, err); + +/* Add error into the error array */ +virAddError(newerr); cleanup: errno = saved_errno; return ret; } +/* + * virAddError: + * @err: error pointer + * + * Add the error to the array of error pointer + */ +void +virAddError(virErrorPtr err) +{ +virErrorsPtr errs; + +/* Discard all error codes that mean 'no error' */ +if (!err || err-code == VIR_ERR_OK) +return; + +errs = virThreadLocalGet(virLastErr); + +/* Shouldn't happen but doesn't hurt to check */ +if (!errs) +return; + +if (errs-errors == NULL) { +if (VIR_ALLOC(errs-errors) 0) +return; +errs-nerrors = 0; +} +else { +if (VIR_REALLOC_N(errs-errors, errs-nerrors + 1) 0) +return; +} + +/* Insert data into errors array element */ +
Re: [libvirt] [PATCH] errors: Improve error reporting to log multiple errors instead of just the last one
Oops, I'm sorry as this didn't pass the syntax check. To pass the syntax check the new add-on patch is necessary: diff --git a/src/util/virterror.c b/src/util/virterror.c index b03ae7c..55269b9 100644 --- a/src/util/virterror.c +++ b/src/util/virterror.c @@ -198,8 +198,7 @@ virLastErrFreeData(void *data) virResetError(errs-lastError); VIR_FREE(errs-lastError); } -if (errs-errors) -VIR_FREE(errs-errors); +VIR_FREE(errs-errors); VIR_FREE(errs); } With this applied on top of my patch it's working fine to pass all of the tests (make check) and also the syntax check. Also, when trying to debug the tests the gnulib tests are really annoying. Would somebody consider creating some alias like `make vircheck` to just do the libvirt tests, i.e. with bypassing the gnulib tests. If you debug some test then it's pretty annoying to run through the gnulib tests everytime you invoke `make check`. Michal On 01/19/2012 02:13 PM, Michal Novotny wrote: This patch introduces a new structure called virErrorsPtr which can get all the errors that occurred since the connection open. The error callback function is being used as many times as necessary. The new public function called virGetAllErrors() has been introduced to get all the errors that occurred. Also, a new test called errorreport has been written to test the functionality of error logging for multiple error occurrences. Signed-off-by: Michal Novotny minov...@redhat.com --- include/libvirt/virterror.h | 14 ++ python/generator.py |1 + src/util/virterror.c | 99 src/util/virterror_internal.h |1 + tests/Makefile.am |9 +++- tests/errorreport.c | 74 ++ 6 files changed, 186 insertions(+), 12 deletions(-) create mode 100644 tests/errorreport.c diff --git a/include/libvirt/virterror.h b/include/libvirt/virterror.h index e896d67..c7a8018 100644 --- a/include/libvirt/virterror.h +++ b/include/libvirt/virterror.h @@ -118,6 +118,19 @@ struct _virError { see note above */ }; +/* + * virErrors: + * + * A libvirt Errors array instance + */ +typedef struct _virErrors virErrors; +typedef virErrors *virErrorsPtr; +struct _virErrors { +virErrorPtr lastError; +unsigned int nerrors; +virErrorPtr errors; +}; + /** * virErrorNumber: * @@ -261,6 +274,7 @@ typedef void (*virErrorFunc) (void *userData, virErrorPtr error); */ virErrorPtr virGetLastError (void); +virErrorsPtr virGetAllErrors (void); virErrorPtr virSaveLastError(void); void virResetLastError (void); void virResetError (virErrorPtr err); diff --git a/python/generator.py b/python/generator.py index 6fee3a4..315eb51 100755 --- a/python/generator.py +++ b/python/generator.py @@ -356,6 +356,7 @@ skip_impl = ( 'virDomainSnapshotListChildrenNames', 'virConnGetLastError', 'virGetLastError', +'virGetAllErrors', 'virDomainGetInfo', 'virDomainGetState', 'virDomainGetControlInfo', diff --git a/src/util/virterror.c b/src/util/virterror.c index 380dc56..b03ae7c 100644 --- a/src/util/virterror.c +++ b/src/util/virterror.c @@ -190,11 +190,17 @@ static const char *virErrorDomainName(virErrorDomain domain) { static void virLastErrFreeData(void *data) { -virErrorPtr err = data; -if (!err) +virErrorsPtr errs = data; +if (!errs) return; -virResetError(err); -VIR_FREE(err); + +if (errs-lastError) { +virResetError(errs-lastError); +VIR_FREE(errs-lastError); +} +if (errs-errors) +VIR_FREE(errs-errors); +VIR_FREE(errs); } @@ -262,14 +268,18 @@ virCopyError(virErrorPtr from, static virErrorPtr virLastErrorObject(void) { -virErrorPtr err; -err = virThreadLocalGet(virLastErr); -if (!err) { -if (VIR_ALLOC(err) 0) +virErrorsPtr errs = NULL; + +errs = virThreadLocalGet(virLastErr); +if (!errs) { +if (VIR_ALLOC(errs) 0) +return NULL; +if (VIR_ALLOC(errs-lastError) 0) return NULL; -virThreadLocalSet(virLastErr, err); +virThreadLocalSet(virLastErr, errs); } -return err; + +return errs-lastError; } @@ -292,6 +302,27 @@ virGetLastError(void) return err; } +/* + * virGetAllErrors: + * + * Provide a pointer to all errors caught at the library level + * + * The error object is kept in thread local storage, so separate + * threads can safely access this concurrently. + * + * Returns a pointer to all errors caught or NULL if none occurred. + */ +virErrorsPtr +virGetAllErrors(void) +{ +virErrorsPtr errs; + +errs = virThreadLocalGet(virLastErr);
Re: [libvirt] [PATCH] errors: Improve error reporting to log multiple errors instead of just the last one
On Thu, Jan 19, 2012 at 02:13:59PM +0100, Michal Novotny wrote: This patch introduces a new structure called virErrorsPtr which can get all the errors that occurred since the connection open. The error callback function is being used as many times as necessary. The new public function called virGetAllErrors() has been introduced to get all the errors that occurred. This impl is effectively an unbounded memory leak, if you consider that applications will keep the same virConnectPtr open more or less forever. In addition any libvirt API that raises multiple errors should be considered broken, so I don't think we should have any such API for querying multiple errors. What is the situation that motivated this new API ? Regards, Daniel -- |: http://berrange.com -o-http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :| -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
Re: [libvirt] [PATCH] errors: Improve error reporting to log multiple errors instead of just the last one
On 01/19/2012 02:20 PM, Daniel P. Berrange wrote: On Thu, Jan 19, 2012 at 02:13:59PM +0100, Michal Novotny wrote: This patch introduces a new structure called virErrorsPtr which can get all the errors that occurred since the connection open. The error callback function is being used as many times as necessary. The new public function called virGetAllErrors() has been introduced to get all the errors that occurred. This impl is effectively an unbounded memory leak, if you consider that applications will keep the same virConnectPtr open more or less forever. In addition any libvirt API that raises multiple errors should be considered broken, so I don't think we should have any such API for querying multiple errors. What is the situation that motivated this new API ? This is simple. When you have situation with e.g. disk or domain creation. It fails but you don't know why. Sometimes the disk creation may fail on insufficient permissions and sometimes there may be not enough space etc... The same for domain creation. Also, we've been discussing this with Peter and we've both agreed that it would be a nice feature of libvirt to have some API like this. I'm CCing Peter for his feedback on this (not the patch rather than the reason of implementation) as I have to admit that this patch would like some tweaking most likely but the issue here is not different as you're asking whether we really need this. Peter, could you please provide Daniel any other example why you would like this implemented? Thanks, Michal -- Michal Novotny minov...@redhat.com, RHCE, Red Hat Virtualization | libvirt-php bindings | php-virt-control.org -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
Re: [libvirt] [PATCH] errors: Improve error reporting to log multiple errors instead of just the last one
On Thu, Jan 19, 2012 at 02:25:55PM +0100, Michal Novotny wrote: On 01/19/2012 02:20 PM, Daniel P. Berrange wrote: On Thu, Jan 19, 2012 at 02:13:59PM +0100, Michal Novotny wrote: This patch introduces a new structure called virErrorsPtr which can get all the errors that occurred since the connection open. The error callback function is being used as many times as necessary. The new public function called virGetAllErrors() has been introduced to get all the errors that occurred. This impl is effectively an unbounded memory leak, if you consider that applications will keep the same virConnectPtr open more or less forever. In addition any libvirt API that raises multiple errors should be considered broken, so I don't think we should have any such API for querying multiple errors. What is the situation that motivated this new API ? This is simple. When you have situation with e.g. disk or domain creation. It fails but you don't know why. Sometimes the disk creation may fail on insufficient permissions and sometimes there may be not enough space etc... The same for domain creation. But for any single API call into libvirt, there is only one error that is relevant upon failure. If you are making a sequence of multiple API calls, you should check each one for an error, before trying the next call. Not doing so is simply an application bug Daniel -- |: http://berrange.com -o-http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :| -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
Re: [libvirt] [PATCH] errors: Improve error reporting to log multiple errors instead of just the last one
On 01/19/2012 02:28 PM, Daniel P. Berrange wrote: On Thu, Jan 19, 2012 at 02:25:55PM +0100, Michal Novotny wrote: On 01/19/2012 02:20 PM, Daniel P. Berrange wrote: On Thu, Jan 19, 2012 at 02:13:59PM +0100, Michal Novotny wrote: This patch introduces a new structure called virErrorsPtr which can get all the errors that occurred since the connection open. The error callback function is being used as many times as necessary. The new public function called virGetAllErrors() has been introduced to get all the errors that occurred. This impl is effectively an unbounded memory leak, if you consider that applications will keep the same virConnectPtr open more or less forever. In addition any libvirt API that raises multiple errors should be considered broken, so I don't think we should have any such API for querying multiple errors. What is the situation that motivated this new API ? This is simple. When you have situation with e.g. disk or domain creation. It fails but you don't know why. Sometimes the disk creation may fail on insufficient permissions and sometimes there may be not enough space etc... The same for domain creation. But for any single API call into libvirt, there is only one error that is relevant upon failure. If you are making a sequence of multiple API calls, you should check each one for an error, before trying the next call. Not doing so is simply an application bug Daniel I can see your point Daniel and not I don't recall what we were talking about with Peter exactly. Maybe he can recall so I'll leave it to him but the truth is that I've been struggling with the reason of failure and finally just the logging using the LIBVIRT_DEBUG=1 when running the daemon helped me and I've been stuck before using it since the error was masked by something AFAIK. Michal -- Michal Novotny minov...@redhat.com, RHCE, Red Hat Virtualization | libvirt-php bindings | php-virt-control.org -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list