Skip to content

Commit e6d1317

Browse files
authored
add stumpless_entry_to_string
1 parent dc78e49 commit e6d1317

File tree

5 files changed

+217
-1
lines changed

5 files changed

+217
-1
lines changed

include/stumpless/entry.h

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,34 @@ struct stumpless_entry {
123123
# endif
124124
};
125125

126+
/**
127+
* Returns all entry's elements in formatted string.
128+
* The character buffer should be freed when no longer is needed by the caller.
129+
*
130+
* **Thread Safety: MT-Safe**
131+
* This function is thread safe. A mutex is used to coordinate the read of the
132+
* element with other accesses and modifications.
133+
*
134+
* **Async Signal Safety: AS-Unsafe lock heap**
135+
* This function is not safe to call from signal handlers due to the use of a
136+
* non-reentrant lock to coordinate access and the use of memory management
137+
* functions to create the result.
138+
*
139+
* **Async Cancel Safety: AC-Unsafe lock heap**
140+
* This function is not safe to call from threads that may be asynchronously
141+
* cancelled, due to the use of a lock that could be left locked as well as
142+
* memory management functions.
143+
*
144+
*
145+
* @param entry The entry to get all elements
146+
*
147+
* @return The formatted string of each entry's elements. Each element is
148+
* formatted as element="value" and joined by " , ". And append each element's
149+
* string by stumpless_element_to_string
150+
*/
151+
STUMPLESS_PUBLIC_FUNCTION
152+
char *stumpless_entry_to_string( const struct stumpless_entry *entry );
153+
126154
/**
127155
* Adds an element to an entry. The element is appended to the end of the list
128156
* of elements in this entry.
@@ -1817,4 +1845,4 @@ vstumpless_set_entry_message( struct stumpless_entry *entry,
18171845
# ifdef __cplusplus
18181846
} /* extern "C" */
18191847
# endif
1820-
#endif /* __STUMPLESS_ENTRY_H */
1848+
#endif /* __STUMPLESS_ENTRY_H */

src/entry.c

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include <stdbool.h>
2121
#include <stddef.h>
2222
#include <string.h>
23+
#include <stdlib.h>
2324
#include <stumpless/element.h>
2425
#include <stumpless/entry.h>
2526
#include <stumpless/facility.h>
@@ -1483,3 +1484,117 @@ void
14831484
unlock_entry( const struct stumpless_entry *entry ) {
14841485
config_unlock_mutex( entry->mutex );
14851486
}
1487+
1488+
/*
1489+
* static function for stumpless_entry_to_string
1490+
* @param dest string to append formatted string
1491+
* @param size_t offset dest's offset
1492+
* @param key,value it is formatted to key="value",
1493+
* @return updated offset
1494+
*/
1495+
static size_t append_key_value_pair(char *dest, size_t offset, const char *key, size_t key_length, const char *value, size_t value_length) {
1496+
// key="
1497+
memcpy(dest + offset, key, key_length);
1498+
offset += key_length;
1499+
dest[offset++] = '=';
1500+
dest[offset++] = '"';
1501+
1502+
// value
1503+
memcpy(dest + offset, value, value_length);
1504+
offset += value_length;
1505+
1506+
1507+
// "
1508+
dest[offset++] = '"';
1509+
dest[offset++] = ',';
1510+
1511+
return offset;
1512+
}
1513+
1514+
char *stumpless_entry_to_string(const struct stumpless_entry *entry) {
1515+
VALIDATE_ARG_NOT_NULL(entry);
1516+
1517+
lock_entry(entry);
1518+
1519+
const char *app_name = entry->app_name;
1520+
size_t app_name_length = entry->app_name_length;
1521+
struct stumpless_element **elements = entry->elements;
1522+
size_t elements_count = entry->element_count;
1523+
const char *hostname = entry->hostname;
1524+
size_t hostname_length = entry->hostname_length;
1525+
char *message = entry->message;
1526+
size_t message_length = entry->message_length;
1527+
const char *message_id = entry->msgid;
1528+
size_t message_id_length = entry->msgid_length;
1529+
const char *process_id = entry->procid;
1530+
size_t process_id_length = entry->procid_length;
1531+
size_t entry_priority_value = entry->prival;
1532+
1533+
size_t format_total_length = 0;
1534+
1535+
format_total_length += 7 + 20; // "prival=" + entry_priority_value
1536+
format_total_length += 9 + app_name_length; // "app_name="
1537+
format_total_length += 10 + hostname_length; // "hostname="
1538+
format_total_length += 12 + message_id_length; // "message_id="
1539+
format_total_length += 12 + process_id_length; // "process_id="
1540+
format_total_length += 9 + message_length; // "message="
1541+
1542+
for (size_t i = 0; i < elements_count; i++) {
1543+
const char *element_str = stumpless_element_to_string(elements[i]);
1544+
if (element_str) {
1545+
format_total_length += strlen(element_str) + 1; // +1 for comma
1546+
free_mem(element_str);
1547+
}
1548+
}
1549+
1550+
char *return_format = alloc_mem(format_total_length+1);
1551+
if (!return_format) {
1552+
return NULL;
1553+
}
1554+
1555+
size_t offset = 0;
1556+
char temp[21];
1557+
1558+
// prival
1559+
sprintf(temp, "%zu", entry_priority_value);
1560+
offset = append_key_value_pair(return_format, offset, "prival", strlen("prival"), temp, strlen(temp));
1561+
1562+
// app_name
1563+
offset = append_key_value_pair(return_format, offset, "app_name", strlen("app_name"), app_name, app_name_length);
1564+
1565+
// hostname
1566+
offset = append_key_value_pair(return_format, offset, "hostname", strlen("hostname"), hostname, hostname_length);
1567+
1568+
// message_id
1569+
offset = append_key_value_pair(return_format, offset, "message_id", strlen("message_id"), message_id, message_id_length);
1570+
1571+
// process_id
1572+
offset = append_key_value_pair(return_format, offset, "process_id", strlen("process_id"), process_id, process_id_length);
1573+
1574+
// message
1575+
offset = append_key_value_pair(return_format, offset, "message", strlen("message"), message, message_length);
1576+
1577+
1578+
bool is_first_element = true;
1579+
for (size_t i = 0; i < elements_count; i++) {
1580+
const char *element_str = stumpless_element_to_string(elements[i]);
1581+
1582+
size_t len = strlen(element_str);
1583+
if (!is_first_element) {
1584+
return_format[offset++] = ',';
1585+
}
1586+
memcpy(return_format + offset, element_str, len);
1587+
offset += len;
1588+
is_first_element = false;
1589+
free_mem(element_str);
1590+
}
1591+
unlock_entry(entry);
1592+
1593+
//erase , if no element
1594+
if(is_first_element) {
1595+
offset--;
1596+
}
1597+
1598+
return_format[offset] = '\0';
1599+
return return_format;
1600+
}

src/windows/stumpless.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,3 +259,4 @@ EXPORTS
259259
stumpless_param_into_string @234
260260
stumpless_set_default_options @235
261261
stumpless_get_default_options @236
262+
stumpless_entry_to_string @237

test/function/entry.cpp

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,77 @@ namespace {
9797
}
9898
};
9999

100+
TEST_F( EntryTest, EntryToStringMallocFailure ) {
101+
void * (*set_malloc_result)(size_t);
102+
const char *result;
103+
104+
set_malloc_result = stumpless_set_malloc( MALLOC_FAIL );
105+
ASSERT_NOT_NULL( set_malloc_result );
106+
107+
result = stumpless_entry_to_string(basic_entry);
108+
EXPECT_ERROR_ID_EQ( STUMPLESS_MEMORY_ALLOCATION_FAILURE );
109+
EXPECT_NULL( result );
110+
111+
set_malloc_result = stumpless_set_malloc( malloc );
112+
EXPECT_TRUE( set_malloc_result == malloc );
113+
}
114+
115+
TEST_F(EntryTest, OutputFormatCheck) {
116+
char *result = stumpless_entry_to_string(basic_entry);
117+
ASSERT_NE(result, nullptr);
118+
119+
const char *expected_output =
120+
"prival=\"14\",app_name=\"basic-app-name\",hostname=\"\","
121+
"message_id=\"basic-msgid\",process_id=\"\","
122+
"message=\"basic message\","
123+
"basic-element=[basic-param=\"basic-value\"],"
124+
"basic-element-2";
125+
EXPECT_STREQ(result, expected_output);
126+
size_t len = strlen(result);
127+
EXPECT_NE(result[len - 1], ',');
128+
free(result);
129+
}
130+
131+
TEST_F(EntryTest, LastCommaCheck) {
132+
char *result = stumpless_entry_to_string(basic_entry);
133+
ASSERT_NE(result, nullptr);
134+
135+
size_t len = strlen(result);
136+
EXPECT_NE(result[len - 1], ',');
137+
138+
free(result);
139+
}
140+
141+
TEST_F(EntryTest, NullEntry) {
142+
char *result = stumpless_entry_to_string(NULL);
143+
EXPECT_EQ(result, nullptr);
144+
free(result);
145+
}
146+
147+
TEST_F(EntryTest, EmptyHostnameAndProcid) {
148+
char *result = stumpless_entry_to_string(basic_entry);
149+
ASSERT_NE(result, nullptr);
150+
EXPECT_TRUE(strstr(result, "hostname=\"\"") != nullptr);
151+
EXPECT_TRUE(strstr(result, "process_id=\"\"") != nullptr);
152+
EXPECT_TRUE(strstr(result, "message_id=\"basic-msgid\"") != nullptr);
153+
free(result);
154+
}
155+
156+
TEST_F(EntryTest, NoneOfElementCheck) {
157+
struct stumpless_entry *test_entry = create_empty_entry();
158+
char *result = stumpless_entry_to_string(test_entry);
159+
ASSERT_NE(result, nullptr);
160+
161+
const char *expected_output =
162+
"prival=\"14\",app_name=\"fixture-app-name\",hostname=\"\""
163+
",message_id=\"fixture-msgid\",process_id=\"\",message=\"fixture message\"";
164+
165+
EXPECT_STREQ(result, expected_output);
166+
167+
stumpless_destroy_entry_and_contents(test_entry);
168+
free(result);
169+
}
170+
100171
TEST_F( EntryTest, AddElement ) {
101172
struct stumpless_entry *entry;
102173
struct stumpless_element *element;

tools/check_headers/stumpless.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -428,6 +428,7 @@
428428
"stumpless_unset_option": "stumpless/target.h"
429429
"STUMPLESS_VERSION": "stumpless/config.h"
430430
"stumpless_version_to_string": "stumpless/version.h"
431+
"stumpless_entry_to_string": "stumpless/entry.h"
431432
"STUMPLESS_WEL_EVENT_ALERT": "stumpless/windows/default_events.h"
432433
"STUMPLESS_WEL_EVENT_CRITICAL": "stumpless/windows/default_events.h"
433434
"STUMPLESS_WEL_EVENT_DEBUG": "stumpless/windows/default_events.h"

0 commit comments

Comments
 (0)