diff --git a/include/stumpless/entry.h b/include/stumpless/entry.h index bcea3bbf..f8396ef1 100644 --- a/include/stumpless/entry.h +++ b/include/stumpless/entry.h @@ -123,6 +123,34 @@ struct stumpless_entry { # endif }; +/** + * Returns the entry as a formatted string. + * The character buffer should be freed when no longer is needed by the caller + * to avoid memory leaks. + * + * **Thread Safety: MT-Safe** + * This function is thread safe. A mutex is used to coordinate changes to the + * entry while it is being modified. + * + * **Async Signal Safety: AS-Unsafe lock heap** + * This function is not safe to call from signal handlers due to the use of a + * non-reentrant lock to coordinate changes and the use of memory management + * functions. + * + * **Async Cancel Safety: AC-Unsafe lock heap** + * This function is not safe to call from threads that may be asynchronously + * cancelled, due to the use of a lock that could be left locked as well as + * memory management functions. + * + * @param entry The entry whose string is returned. + * + * @return The string if no error was encountered. If an error is + * encountered, then NULL is returned and an error code is set appropriately. + */ +STUMPLESS_PUBLIC_FUNCTION +const char * +stumpless_entry_to_string ( const struct stumpless_entry *entry ); + /** * Adds an element to an entry. The element is appended to the end of the list * of elements in this entry. diff --git a/src/entry.c b/src/entry.c index 2ec6c947..f3108304 100644 --- a/src/entry.c +++ b/src/entry.c @@ -16,6 +16,7 @@ * limitations under the License. */ +#include #include #include #include @@ -48,6 +49,61 @@ static struct cache *entry_cache = NULL; +const char * +stumpless_entry_to_string ( const struct stumpless_entry* entry ) { + + VALIDATE_ARG_NOT_NULL ( entry ); + lock_entry ( entry ); + + struct strbuilder* entry_string_strbuilder = strbuilder_new (); + entry_string_strbuilder = strbuilder_append_buffer(entry_string_strbuilder, "prival=\"", 8); + entry_string_strbuilder = strbuilder_append_positive_int(entry_string_strbuilder, entry->prival); + entry_string_strbuilder = strbuilder_append_buffer(entry_string_strbuilder, "\", ", 3); + entry_string_strbuilder = strbuilder_append_buffer(entry_string_strbuilder, "hostname=\"", 10); + if ( entry->hostname_length > 0 ) + entry_string_strbuilder = strbuilder_append_buffer(entry_string_strbuilder, entry->hostname , entry->hostname_length); + else + entry_string_strbuilder = strbuilder_append_char(entry_string_strbuilder, '-'); + entry_string_strbuilder = strbuilder_append_buffer(entry_string_strbuilder, "\", ", 3); + entry_string_strbuilder = strbuilder_append_buffer(entry_string_strbuilder, "app_name=\"", 10); + entry_string_strbuilder = strbuilder_append_buffer(entry_string_strbuilder, entry->app_name, entry->app_name_length ); + entry_string_strbuilder = strbuilder_append_buffer(entry_string_strbuilder, "\", ", 3); + entry_string_strbuilder = strbuilder_append_buffer(entry_string_strbuilder, "procid=\"", 8); + if (entry -> procid_length > 0) + entry_string_strbuilder = strbuilder_append_buffer(entry_string_strbuilder, entry->procid , strlen( entry->procid ) ); + else + entry_string_strbuilder = strbuilder_append_procid( entry_string_strbuilder ); + entry_string_strbuilder = strbuilder_append_buffer(entry_string_strbuilder, "\", ", 3); + entry_string_strbuilder = strbuilder_append_buffer(entry_string_strbuilder, "msgid=\"", 7); + entry_string_strbuilder = strbuilder_append_buffer(entry_string_strbuilder, entry->msgid, entry->msgid_length); + entry_string_strbuilder = strbuilder_append_buffer(entry_string_strbuilder, "\", ", 3); + + for (size_t element_index = 0; element_index < (entry -> element_count) ; element_index++) + { + const char* element_str = stumpless_element_to_string ( entry->elements[element_index] ); + entry_string_strbuilder = strbuilder_append_buffer (entry_string_strbuilder, element_str, strlen(element_str)); + entry_string_strbuilder = strbuilder_append_buffer (entry_string_strbuilder, ", ", 2); + free_mem ( element_str ); + } + + if ( entry->message != NULL ) + { + entry_string_strbuilder = strbuilder_append_buffer(entry_string_strbuilder, "message=\"", 9); + entry_string_strbuilder = strbuilder_append_buffer(entry_string_strbuilder, entry->message, entry->message_length); + entry_string_strbuilder = strbuilder_append_buffer(entry_string_strbuilder, "\", ", 3); + } + + const char* final_entry_string = strbuilder_to_string( entry_string_strbuilder ); + strbuilder_destroy( entry_string_strbuilder ); + unlock_entry ( entry ); + clear_error(); //not sure about what this does + return final_entry_string; + +fail: + unlock_entry ( entry ); + return NULL; //Change this before commit +} + struct stumpless_entry * stumpless_add_element( struct stumpless_entry *entry, struct stumpless_element *element ) { diff --git a/test/function/entry.cpp b/test/function/entry.cpp index f6755b66..7d59b537 100644 --- a/test/function/entry.cpp +++ b/test/function/entry.cpp @@ -96,6 +96,84 @@ namespace { } }; + TEST_F( EntryTest, SimpleTestToString ) { + struct stumpless_entry * + stump_entry = stumpless_new_entry_str( STUMPLESS_FACILITY_USER, + STUMPLESS_SEVERITY_INFO, + basic_app_name, + basic_msgid, + basic_message ); + const char* stump_as_str = stumpless_entry_to_string( stump_entry ); + const char* basic_stump_str = + "prival=\"14\", hostname=\"\", app_name=\"basic-app-name\", procid=\"\", msgid=\"basic-msgid\", message=\"basic message\""; + + EXPECT_STREQ(stump_as_str, basic_stump_str); + free ( (void *) stump_as_str ); + stumpless_destroy_entry_and_contents( stump_entry ); + } + + TEST_F( EntryTest, ToStringAddOneElement ) { + struct stumpless_entry * + stump_entry = stumpless_new_entry_str( STUMPLESS_FACILITY_USER, + STUMPLESS_SEVERITY_INFO, + basic_app_name, + basic_msgid, + basic_message ); + struct stumpless_element * + element = stumpless_new_element( "test-new-element" ); + EXPECT_NO_ERROR; + ASSERT_NOT_NULL( element ); + + stump_entry = stumpless_add_element( stump_entry, element ); + + const char* stump_as_str = stumpless_entry_to_string( stump_entry ); + const char* basic_stump_str = + "prival=\"14\", hostname=\"\", app_name=\"basic-app-name\", procid=\"\", msgid=\"basic-msgid\", test-new-element, message=\"basic message\""; + + EXPECT_STREQ(stump_as_str, basic_stump_str); + free ( (void *) stump_as_str ); + stumpless_destroy_entry_and_contents( stump_entry ); + } + + TEST_F( EntryTest, ToStringAddOneElementWithParams ) { + struct stumpless_entry * + stump_entry = stumpless_new_entry_str( STUMPLESS_FACILITY_USER, + STUMPLESS_SEVERITY_INFO, + basic_app_name, + basic_msgid, + basic_message ); + struct stumpless_element * + element_with_params = stumpless_new_element( "element-with-params" ); + EXPECT_NO_ERROR; + ASSERT_NOT_NULL( element_with_params ); + struct stumpless_param * + param_1 = stumpless_new_param( "param1", "val1" ); + struct stumpless_param * + param_2 = stumpless_new_param( "param2", "val2" ); + + stumpless_add_param( element_with_params, param_1 ); + stumpless_add_param( element_with_params, param_2 ); + + stump_entry = stumpless_add_element( stump_entry, element_with_params ); + + const char* stump_as_str = stumpless_entry_to_string( stump_entry ); + const char* basic_stump_str = + "prival=\"14\", hostname=\"\", app_name=\"basic-app-name\", procid=\"\", msgid=\"basic-msgid\", element-with-params=[param1=\"val1\",param2=\"val2\"], message=\"basic message\""; + + EXPECT_STREQ(stump_as_str, basic_stump_str); + free ( (void *) stump_as_str ); + stumpless_destroy_entry_and_contents( stump_entry ); + } + + TEST_F( EntryTest, NullEntryToString ) { + struct stumpless_entry * + stump_entry = NULL; + const char* stump_as_str = stumpless_entry_to_string( stump_entry ); + + EXPECT_ERROR_ID_EQ( STUMPLESS_ARGUMENT_EMPTY ); + EXPECT_NULL(stump_as_str); + } + TEST_F( EntryTest, AddElement ) { struct stumpless_entry *entry; struct stumpless_element *element;