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;
+}