Repository: SINTEF/dlite (language: python)

Issue:
Add more context to error messages
It often difficult to see from the error messages in what plugin or what input file that triggered them.

Try to add more context to the error messages, like file names, line numbers etc. This might not always be easy since this context may not be available where the error is first triggered...



Discussion / hints:

Fix patch:
diff --git a/.github/workflows/cd_docs.yml b/.github/workflows/cd_docs.yml
index a8c537de9..e2193b884 100644
--- a/.github/workflows/cd_docs.yml
+++ b/.github/workflows/cd_docs.yml
@@ -43,6 +43,8 @@ jobs:
         run: |
           sudo apt-get update --fix-missing
           sudo apt-get install \
+            libxml2-dev \
+            libxslt-dev \
             libhdf5-dev \
             swig4.0 \
             doxygen \
diff --git a/src/utils/err.c b/src/utils/err.c
index c75c11fc8..e57c0694c 100644
--- a/src/utils/err.c
+++ b/src/utils/err.c
@@ -195,7 +195,6 @@ int _err_vformat(ErrLevel errlevel, int eval, int errnum, const char *file,
   int ignore_new_error = 0;
   ErrHandler handler = err_get_handler();
   ErrNameConv nameconv = err_get_nameconv();
-  int call_handler = handler && !tls->err_record->prev;
 
   /* Check warning mode */
   if (errlevel == errLevelWarn) {
@@ -218,6 +217,7 @@ int _err_vformat(ErrLevel errlevel, int eval, int errnum, const char *file,
     switch (override) {
     case errOverrideAppend:
       n = strlen(errmsg);
+      tls->err_record->pos = n;
       n += snprintf(errmsg + n, errsize - n, "%s", err_append_sep);
       break;
     case errOverrideWarnOld:
@@ -283,25 +283,25 @@ int _err_vformat(ErrLevel errlevel, int eval, int errnum, const char *file,
     tls->err_record->reraise = eval;
 
   /* If we are not within a ErrTry...ErrEnd clause */
-  if (call_handler) {
+  if (!tls->err_record->prev) {
 
     /* ...call the error handler */
-    handler(tls->err_record);
+    if (handler) handler(tls->err_record);
 
     /* ...check err_abort_mode */
     if (errlevel >= errLevelError) {
       if (abort_mode == errAbortExit) {
-        if (!call_handler) handler(tls->err_record);
+        if (!handler) err_default_handler(tls->err_record);
         exit(eval);
       } else if (abort_mode >= errAbortAbort) {
-        if (!call_handler) handler(tls->err_record);
+        if (!handler) err_default_handler(tls->err_record);
         abort();
       }
     }
 
     /* ...make sure that fatal errors always exit */
     if (errlevel >= errLevelFatal) {
-      if (!call_handler) handler(tls->err_record);
+      if (!handler) err_default_handler(tls->err_record);
       exit(eval);
     }
   }
@@ -449,6 +449,7 @@ void err_clear(void)
   tls->err_record->eval = 0;
   tls->err_record->errnum = 0;
   tls->err_record->msg[0] = '\0';
+  tls->err_record->pos = 0;
   tls->err_record->handled = 0;
   tls->err_record->reraise = 0;
   tls->err_record->state = 0;
@@ -673,15 +674,42 @@ int err_get_color_coded()
 void err_default_handler(const ErrRecord *record)
 {
   FILE *stream = err_get_stream();
-  if (err_get_color_coded()) {
-    //if ((stream == stderr || stream == stdout) && getenv("ERR_COLOR")) {
-    /* Output the first word of the error message in red and the remaining
-       of it in magenta. */
-    int n = strcspn(record->msg, ": ");
-    fprintf(stream, "\033[31m%.*s\033[35m%s\033[0m\n", n, record->msg,
-            record->msg+n);
+  const char *msg = record->msg + record->pos;
+  char *errmark = (record->pos) ? "" : "** ";
+  if (record->pos >= ERR_MSGSIZE) return;
+  if (record->pos) {
+    int m = strspn(msg, "\n");
+    int n = strlen(err_append_sep) - m;
+    fprintf(stream, "%.*s", n, msg+m);
+    msg += m+n;
+  }
+  if (stream && err_get_color_coded()) {
+    /* Print error message in colour. */
+    int n;
+    ThreadLocals *tls = get_tls();
+    Globals *g = tls->globals;
+    ErrDebugMode debug_mode = err_get_debug_mode();
+    if (g->err_prefix && *g->err_prefix) {
+      n = strlen(g->err_prefix) + 2;
+      if (!record->pos) fprintf(stream, "\033[02;31m%.*s", n, msg);
+      msg += n;
+    }
+    if (debug_mode >= 1) {
+      n = strcspn(msg, ":") + 1;
+      n += (msg[0] == '(') ? 1 : strcspn(msg+n, ":") + 2;
+      fprintf(stream, "\033[00;34m%.*s", n, msg);
+      msg += n;
+    }
+    if (debug_mode >= 2) {
+      n = strcspn(msg, ":") + 2;
+      fprintf(stream, "\033[02;32m%.*s", n, msg);
+      msg += n;
+    }
+    n = strcspn(msg, ": ");
+    fprintf(stream, "\033[00;31m%.*s\033[02;35m%s\033[0m\n", n, msg, msg+n);
   } else if (stream) {
-    fprintf(stream, "** %s\n", record->msg);
+    /* Print error message with error marker prepended. */
+    fprintf(stream, "%s%s\n", errmark, msg);
   }
 }
 
@@ -756,7 +784,6 @@ void _err_link_record(ErrRecord *record)
 void _err_unlink_record(ErrRecord *record)
 {
   ThreadLocals *tls = get_tls();
-  Globals *g = tls->globals;
   assert(record == tls->err_record);
   assert(tls->err_record->prev);
 
@@ -800,7 +827,7 @@ void _err_unlink_record(ErrRecord *record)
 
     if (!tls->err_record->prev) {
       ErrHandler handler = err_get_handler();
-      if (handler) g->err_handler(tls->err_record);
+      if (handler) handler(tls->err_record);
     }
 
     if ((abort_mode && record->level >= errLevelError) ||
diff --git a/src/utils/err.h b/src/utils/err.h
index bb1c2f4b7..ffe103c25 100644
--- a/src/utils/err.h
+++ b/src/utils/err.h
@@ -504,6 +504,7 @@ typedef struct ErrRecord {
   int eval;               /*!< @brief Error value. */
   int errnum;             /*!< @brief System error number. */
   char msg[ERR_MSGSIZE];  /*!< @brief Error message. */
+  int pos;                /*!< @brief Position of new appended error message. */
   int handled;            /*!< @brief Whether the error has been handled. */
   int reraise;            /*!< @brief Error value to reraise. */
   ErrTryState state;      /*!< @brief Where we are in ErrTry.. ErrEnd. */


Test patch:
diff --git a/.github/workflows/ci_tests.yml b/.github/workflows/ci_tests.yml
index 4f8c91db4..b170cbc92 100644
--- a/.github/workflows/ci_tests.yml
+++ b/.github/workflows/ci_tests.yml
@@ -14,6 +14,8 @@ jobs:
       run: |
         sudo apt-get update --fix-missing && \
         sudo apt-get install \
+          libxml2-dev \
+          libxslt-dev \
           libhdf5-dev \
           swig4.0 \
           doxygen \