This is an automated email from the ASF dual-hosted git repository.

pengzheng pushed a commit to branch feature/527-manifest-improvement
in repository https://gitbox.apache.org/repos/asf/celix.git


The following commit(s) were added to 
refs/heads/feature/527-manifest-improvement by this push:
     new 3cea0d4c Log manifest's ERR message.
3cea0d4c is described below

commit 3cea0d4cae37de88175c4d4748be147903c96c41
Author: PengZheng <[email protected]>
AuthorDate: Mon Aug 14 18:56:30 2023 +0800

    Log manifest's ERR message.
    
    Add ERR logging interface to bundle context and framework. Add 
celix_err_getRawTssErr to avoid allocation triggered by reader.
---
 bundles/logging/log_helper/src/celix_log_helper.c  | 13 ++-----
 .../gtest/src/CxxBundleContextTestSuite.cc         |  7 ++++
 libs/framework/include/celix/BundleContext.h       |  8 +++++
 libs/framework/include/celix_bundle_context.h      |  7 ++++
 libs/framework/include/celix_log.h                 |  2 ++
 libs/framework/src/bundle_archive.c                |  2 ++
 libs/framework/src/bundle_context.c                |  4 +++
 libs/framework/src/celix_log.c                     | 13 ++++++-
 libs/framework/src/manifest.c                      |  7 ++--
 libs/utils/gtest/src/ErrTestSuite.cc               | 41 +++++++++++++++++++++-
 libs/utils/include/celix_err.h                     | 12 +++++++
 libs/utils/src/celix_err.c                         | 33 +++++++++++++----
 12 files changed, 126 insertions(+), 23 deletions(-)

diff --git a/bundles/logging/log_helper/src/celix_log_helper.c 
b/bundles/logging/log_helper/src/celix_log_helper.c
index 0e51608a..8e58df95 100644
--- a/bundles/logging/log_helper/src/celix_log_helper.c
+++ b/bundles/logging/log_helper/src/celix_log_helper.c
@@ -163,18 +163,11 @@ void celix_logHelper_vlogDetails(celix_log_helper_t* 
logHelper, celix_log_level_
 }
 
 void celix_logHelper_logTssErrors(celix_log_helper_t* logHelper, 
celix_log_level_e level) {
-    if (celix_err_getErrorCount() == 0) {
+    char buf[CELIX_ERR_BUFFER_SIZE] = {0};
+    if (celix_err_dump(buf, sizeof(buf), "[TssErr] ", NULL) == 0) {
+        // nothing to output
         return;
     }
-    char buf[512] = {0};
-    int ret;
-    int bytes = 0;
-    for (const char *errMsg = celix_err_popLastError(); errMsg != NULL && 
bytes < sizeof(buf); errMsg = celix_err_popLastError()) {
-        ret = snprintf(buf + bytes, sizeof(buf) - bytes, "[TssErr] %s\n", 
errMsg);
-        if (ret > 0) {
-            bytes += ret;
-        }
-    }
     celix_err_resetErrors();
     celix_logHelper_logDetails(logHelper, level, NULL, NULL, 0, "Detected tss 
errors:\n%s", buf);
 }
diff --git a/libs/framework/gtest/src/CxxBundleContextTestSuite.cc 
b/libs/framework/gtest/src/CxxBundleContextTestSuite.cc
index 004b87bd..8e40eb9c 100644
--- a/libs/framework/gtest/src/CxxBundleContextTestSuite.cc
+++ b/libs/framework/gtest/src/CxxBundleContextTestSuite.cc
@@ -23,6 +23,7 @@
 
 #include "service_tracker.h"
 #include "celix/BundleContext.h"
+#include "celix_err.h"
 #include "celix_framework_factory.h"
 #include "celix_framework.h"
 #include "service_tracker_customizer.h"
@@ -416,6 +417,12 @@ TEST_F(CxxBundleContextTestSuite, LoggingUsingContext) {
     ctx->logFatal("fatal");
 }
 
+TEST_F(CxxBundleContextTestSuite, LoggingTssErrorsTest) {
+    ctx->logTssErrors(CELIX_LOG_LEVEL_FATAL);
+    celix_err_push("Hello ERR");
+    ctx->logTssErrors(CELIX_LOG_LEVEL_FATAL);
+}
+
 TEST_F(CxxBundleContextTestSuite, GetFramework) {
     EXPECT_FALSE(ctx->getFramework()->getUUID().empty());
     
EXPECT_EQ(ctx->getFramework()->getFrameworkBundleContext()->getBundle().getId(),
 0);
diff --git a/libs/framework/include/celix/BundleContext.h 
b/libs/framework/include/celix/BundleContext.h
index 59134a8f..e217d60c 100644
--- a/libs/framework/include/celix/BundleContext.h
+++ b/libs/framework/include/celix/BundleContext.h
@@ -721,6 +721,14 @@ namespace celix {
             va_end(args);
         }
 
+        /**
+         * @brief Log celix per-thread error messages to the Celix framework 
logger using the provided log level.
+         * Silently ignores log level CELIX_LOG_LEVEL_DISABLED.
+         */
+        void logTssErrors(celix_log_level_e level) {
+            celix_bundleContext_logTssErrors(cCtx.get(), level);
+        }
+
         /**
          * @brief Wait until all Celix events for this bundle are completed.
          */
diff --git a/libs/framework/include/celix_bundle_context.h 
b/libs/framework/include/celix_bundle_context.h
index 6b211506..24ef1a5a 100644
--- a/libs/framework/include/celix_bundle_context.h
+++ b/libs/framework/include/celix_bundle_context.h
@@ -1458,6 +1458,13 @@ CELIX_FRAMEWORK_EXPORT void celix_bundleContext_vlog(
         const char* format,
         va_list formatArgs) __attribute__((format(printf,3,0)));
 
+/**
+ *
+ * @brief Logs celix thread-specific storage error messages(celix_err) ith the 
provided celix log level.
+ * Silently ignores log level CELIX_LOG_LEVEL_DISABLED.
+ */
+CELIX_FRAMEWORK_EXPORT void celix_bundleContext_logTssErrors(const 
celix_bundle_context_t* ctx,
+                                                             celix_log_level_e 
level);
 
 /**
  * @brief Get the config property for the given key.
diff --git a/libs/framework/include/celix_log.h 
b/libs/framework/include/celix_log.h
index 70fdf47e..47bee3ba 100644
--- a/libs/framework/include/celix_log.h
+++ b/libs/framework/include/celix_log.h
@@ -76,6 +76,8 @@ CELIX_FRAMEWORK_EXPORT void celix_framework_vlog(
         const char* format,
         va_list args) __attribute__((format(printf,6,0)));
 
+CELIX_FRAMEWORK_EXPORT void 
celix_framework_logTssErrors(celix_framework_logger_t*  logger, 
celix_log_level_e level);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/libs/framework/src/bundle_archive.c 
b/libs/framework/src/bundle_archive.c
index 57207296..e0243815 100644
--- a/libs/framework/src/bundle_archive.c
+++ b/libs/framework/src/bundle_archive.c
@@ -210,6 +210,7 @@ static celix_status_t 
celix_bundleArchive_createCacheDirectory(bundle_archive_pt
     status = manifest_createFromFile(manifestPath, manifestOut);
     celix_utils_freeStringIfNotEqual(pathBuffer, manifestPath);
     if (status != CELIX_SUCCESS) {
+        celix_framework_logTssErrors(archive->fw->logger, 
CELIX_LOG_LEVEL_ERROR);
         fw_log(archive->fw->logger, CELIX_LOG_LEVEL_ERROR, "Failed to 
initialize archive. Cannot read manifest.");
         return status;
     }
@@ -317,6 +318,7 @@ dir_failed:
 init_failed:
     bundleArchive_destroy(archive);
 calloc_failed:
+    celix_framework_logTssErrors(fw->logger, CELIX_LOG_LEVEL_ERROR);
     framework_logIfError(fw->logger, status, error, "Could not create 
archive.");
     return status;
 }
diff --git a/libs/framework/src/bundle_context.c 
b/libs/framework/src/bundle_context.c
index eb970f02..1e6640b1 100644
--- a/libs/framework/src/bundle_context.c
+++ b/libs/framework/src/bundle_context.c
@@ -1603,3 +1603,7 @@ void celix_bundleContext_log(const celix_bundle_context_t 
*ctx, celix_log_level_
 void celix_bundleContext_vlog(const celix_bundle_context_t *ctx, 
celix_log_level_e level, const char *format, va_list formatArgs) {
     celix_framework_vlog(ctx->framework->logger, level, NULL, NULL, 0, format, 
formatArgs);
 }
+
+void celix_bundleContext_logTssErrors(const celix_bundle_context_t *ctx, 
celix_log_level_e level) {
+    celix_framework_logTssErrors(ctx->framework->logger, level);
+}
\ No newline at end of file
diff --git a/libs/framework/src/celix_log.c b/libs/framework/src/celix_log.c
index 4c3bc530..d765ee9e 100644
--- a/libs/framework/src/celix_log.c
+++ b/libs/framework/src/celix_log.c
@@ -22,6 +22,7 @@
 #include <assert.h>
 #include <stdlib.h>
 
+#include "celix_err.h"
 #include "celix_errno.h"
 #include "celix_log.h"
 #include "celix_threads.h"
@@ -144,4 +145,14 @@ void celix_framework_logCode(celix_framework_logger_t*  
logger, celix_log_level_
     va_start(args, format);
     celix_framework_vlogInternal(logger, level, code, file, func, line, 
format, args);
     va_end(args);
-}
\ No newline at end of file
+}
+
+void celix_framework_logTssErrors(celix_framework_logger_t* logger, 
celix_log_level_e level) {
+    char buf[CELIX_ERR_BUFFER_SIZE] = {0};
+    if (celix_err_dump(buf, sizeof(buf), "[TssErr] ", NULL) == 0) {
+        // nothing to output
+        return;
+    }
+    celix_err_resetErrors();
+    celix_framework_log(logger, level, NULL, NULL, 0, "Detected tss 
errors:\n%s", buf);
+}
diff --git a/libs/framework/src/manifest.c b/libs/framework/src/manifest.c
index dee52b38..21747f8d 100644
--- a/libs/framework/src/manifest.c
+++ b/libs/framework/src/manifest.c
@@ -33,7 +33,6 @@
 #include "celix_stdio_cleanup.h"
 #include "manifest.h"
 #include "utils.h"
-#include "celix_log.h"
 
 int fpeek(FILE *stream);
 
@@ -258,7 +257,7 @@ static celix_status_t manifest_readAttributes(manifest_pt 
manifest, properties_p
         int len = strlen(lbuf);
 
         if (lbuf[--len] != '\n') {
-            celix_err_pushf("MANIFEST: Line too long");
+            celix_err_push("MANIFEST: Line too long");
             return CELIX_FILE_IO_EXCEPTION;
         }
         if (len > 0 && lbuf[len - 1] == '\r') {
@@ -289,12 +288,12 @@ static celix_status_t manifest_readAttributes(manifest_pt 
manifest, properties_p
             while (lbuf[i++] != ':') {
                 if (i >= len) {
 
-                    celix_err_pushf("MANIFEST: Invalid header");
+                    celix_err_push("MANIFEST: Invalid header");
                     return CELIX_FILE_IO_EXCEPTION;
                 }
             }
             if (lbuf[i++] != ' ') {
-                celix_err_pushf("MANIFEST: Invalid header");
+                celix_err_push("MANIFEST: Invalid header");
                 return CELIX_FILE_IO_EXCEPTION;
             }
             name[0] = '\0';
diff --git a/libs/utils/gtest/src/ErrTestSuite.cc 
b/libs/utils/gtest/src/ErrTestSuite.cc
index 81e8bd59..9d27a244 100644
--- a/libs/utils/gtest/src/ErrTestSuite.cc
+++ b/libs/utils/gtest/src/ErrTestSuite.cc
@@ -24,7 +24,9 @@
 class ErrTestSuite : public ::testing::Test {
 public:
     ErrTestSuite() = default;
-    ~ErrTestSuite() noexcept override = default;
+    ~ErrTestSuite() noexcept override {
+        celix_err_resetErrors();
+    }
 };
 
 TEST_F(ErrTestSuite, AddAndPopErrorTest) {
@@ -102,3 +104,40 @@ TEST_F(ErrTestSuite, PrintErrorsTest) {
     EXPECT_EQ(0, celix_err_getErrorCount());
     free(buf);
 }
+
+#define ERR_TEST_PREFIX "<"
+#define ERR_TEST_POSTFIX ">"
+
+TEST_F(ErrTestSuite, DumpErrorsTest) {
+    char buf[CELIX_ERR_BUFFER_SIZE] = {0};
+    // empty ERR
+    EXPECT_EQ(0, celix_err_dump(buf, CELIX_ERR_BUFFER_SIZE, NULL, NULL));
+
+    // log messages
+    int logCnt = 0;
+    for (logCnt = 0; logCnt < 5; ++logCnt) {
+        celix_err_pushf("celix error message%d", logCnt);
+    }
+    EXPECT_EQ(115, celix_err_dump(buf, CELIX_ERR_BUFFER_SIZE, ERR_TEST_PREFIX, 
ERR_TEST_POSTFIX"\n"));
+    char* p = buf;
+    char data[32]={0};
+    while(logCnt--)
+    {
+        sscanf(p,"%[^\n]",data);
+        char expected[64];
+        sprintf(expected, "<celix error message%d>", logCnt);
+        EXPECT_STREQ(data, expected);
+        p = p+strlen(data)+1;//skip '\n'
+    }
+}
+
+TEST_F(ErrTestSuite, DumpedErrorsAlwaysNulTerminatedTest) {
+    char buf[CELIX_ERR_BUFFER_SIZE] = {0};
+    //celix error messages total length is greater than 512
+    int logCnt = 0;
+    for (logCnt = 0; logCnt < 64; ++logCnt) {
+        celix_err_pushf("celix error message%d", logCnt);
+    }
+    EXPECT_LE(CELIX_ERR_BUFFER_SIZE, celix_err_dump(buf, 
CELIX_ERR_BUFFER_SIZE, ERR_TEST_PREFIX, ERR_TEST_POSTFIX"\n"));
+    EXPECT_EQ('\0', buf[CELIX_ERR_BUFFER_SIZE-1]);
+}
diff --git a/libs/utils/include/celix_err.h b/libs/utils/include/celix_err.h
index c78802dc..854b8a51 100644
--- a/libs/utils/include/celix_err.h
+++ b/libs/utils/include/celix_err.h
@@ -20,6 +20,7 @@
 #ifndef CELIX_CELIX_ERR_H
 #define CELIX_CELIX_ERR_H
 
+#include <stdbool.h>
 #include <stdio.h>
 
 #include "celix_err_constants.h"
@@ -82,6 +83,17 @@ CELIX_UTILS_EXPORT void celix_err_resetErrors();
  */
 CELIX_UTILS_EXPORT void celix_err_printErrors(FILE* stream, const char* 
prefix, const char* postfix);
 
+/**
+ * @brief Dump error messages from the current thread to the provided buffer.
+ * @param[in] buf The buffer to dump the error messages to.
+ * @param[in] size The size of the buffer.
+ * @param[in] prefix The prefix to print before each error message. If NULL no 
prefix is printed.
+ * @param[in] postfix The postfix to print after each error message. If NULL, 
a '\n' postfix is printed.
+ * @return the number of characters written to the buffer (excluding the 
terminating null character).
+ * A return value of size or more means that the output was truncated. See 
also snprintf.
+ */
+CELIX_UTILS_EXPORT int celix_err_dump(char* buf, size_t size, const char* 
prefix, const char* postfix);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/libs/utils/src/celix_err.c b/libs/utils/src/celix_err.c
index 41bad141..edc76329 100644
--- a/libs/utils/src/celix_err.c
+++ b/libs/utils/src/celix_err.c
@@ -44,6 +44,15 @@ static void celix_err_destroyTssErr(void* data) {
     }
 }
 
+
+static celix_err_t* celix_err_getRawTssErr() {
+    if (!celix_err_tssKeyInitialized) {
+        return NULL;
+    }
+    return celix_tss_get(celix_err_tssKey);
+}
+
+
 celix_err_t* celix_err_getTssErr() {
     if (!celix_err_tssKeyInitialized) {
         fprintf(stderr, "celix_err_tssKey is not initialized\n");
@@ -93,7 +102,7 @@ __attribute__((destructor)) void 
celix_err_deinitThreadSpecificStorageKey() {
 
 const char* celix_err_popLastError() {
     const char* result = NULL;
-    celix_err_t* err = celix_err_getTssErr();
+    celix_err_t* err = celix_err_getRawTssErr();
     if (err && err->pos > 0) {
         //move back to start last error message
         err->pos -= 1; //move before \0 in last error message
@@ -107,11 +116,7 @@ const char* celix_err_popLastError() {
 
 int celix_err_getErrorCount() {
     int result = 0;
-    if (!celix_err_tssKeyInitialized) {
-        fprintf(stderr, "celix_err_tssKey is not initialized\n");
-        return 0;
-    }
-    celix_err_t* err = celix_tss_get(celix_err_tssKey);
+    celix_err_t* err = celix_err_getRawTssErr();
     for (int i = 0; err && i < err->pos; ++i) {
         if (err->buffer[i] == '\0') {
             result += 1;
@@ -121,7 +126,7 @@ int celix_err_getErrorCount() {
 }
 
 void celix_err_resetErrors() {
-    celix_err_t* err = celix_err_getTssErr();
+    celix_err_t* err = celix_err_getRawTssErr();
     if (err) {
         err->pos = 0; //no entry
     }
@@ -169,3 +174,17 @@ void celix_err_printErrors(FILE* stream, const char* 
prefix, const char* postfix
         fprintf(stream, "%s%s%s", pre, errMsg, post);
     }
 }
+
+int celix_err_dump(char* buf, size_t size, const char* prefix, const char* 
postfix) {
+    int ret;
+    int bytes = 0;
+    const char* pre = prefix == NULL ? "" : prefix;
+    const char* post = postfix == NULL ? "\n" : postfix;
+    for (const char *errMsg = celix_err_popLastError(); errMsg != NULL && 
bytes < size; errMsg = celix_err_popLastError()) {
+        ret = snprintf(buf + bytes, size - bytes, "%s%s%s", pre, errMsg, post);
+        if (ret > 0) {
+            bytes += ret;
+        }
+    }
+    return bytes;
+}

Reply via email to