Add metrics structure 91/225791/11
authorMateusz Majewski <m.majewski2@samsung.com>
Fri, 21 Feb 2020 13:46:01 +0000 (14:46 +0100)
committerMateusz Majewski <m.majewski2@samsung.com>
Thu, 30 Jul 2020 12:26:32 +0000 (14:26 +0200)
Change-Id: Iff76a4e86519f5a03517b69934ef6341825ecca8

Makefile.am
include/metrics.h [new file with mode: 0644]
src/shared/metrics.c [new file with mode: 0644]
src/tests/metrics.c [new file with mode: 0644]

index 8faf510..e5db3ea 100644 (file)
@@ -302,6 +302,7 @@ check_PROGRAMS = \
        src/tests/logutil_neg \
        src/tests/critical_log \
        src/tests/salvage_pipe_entry \
+       src/tests/metrics \
        src/tests/hash_test \
        src/tests/filters
 
@@ -569,6 +570,14 @@ src_tests_hash_test_SOURCES = src/tests/hash_test.c src/shared/hash.c
 src_tests_hash_test_CFLAGS = $(check_CFLAGS)
 src_tests_hash_test_LDFLAGS = $(AM_LDFLAGS)
 
+src_tests_metrics_SOURCES = src/tests/metrics.c \
+       src/shared/metrics.c \
+       src/shared/logcommon.c
+src_tests_metrics_DEPENDENCIES = libdlogutil.la
+src_tests_metrics_LDADD = libdlogutil.la
+src_tests_metrics_CFLAGS = $(check_CFLAGS)
+src_tests_metrics_LDFLAGS = $(AM_LDFLAGS)
+
 # conf file
 usrlibtmpfilesddir = /usr/lib/tmpfiles.d
 usrlibtmpfilesd_DATA = configs/dlog-run.conf
diff --git a/include/metrics.h b/include/metrics.h
new file mode 100644 (file)
index 0000000..ab40f53
--- /dev/null
@@ -0,0 +1,39 @@
+/* MIT License
+ *
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE. */
+
+#pragma once
+
+#include <dlogutil.h>
+
+struct metrics *metrics_create();
+void metrics_destroy(struct metrics *);
+
+bool metrics_add_log(struct metrics *, const dlogutil_entry_s *);
+
+struct metrics_info {
+       const char *tag;
+       pid_t pid;
+       int count[DLOG_PRIO_MAX];
+};
+
+struct metrics_info *metrics_get_info(const struct metrics *, int *count);
+
diff --git a/src/shared/metrics.c b/src/shared/metrics.c
new file mode 100644 (file)
index 0000000..fdce6df
--- /dev/null
@@ -0,0 +1,119 @@
+/* MIT License
+ *
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE. */
+
+#include <metrics.h>
+
+#include <assert.h>
+#include <stdlib.h>
+
+#define INITIAL_CAPACITY 128
+
+struct metrics {
+       struct metrics_info *inner;
+       int count;
+       int capacity;
+};
+
+struct metrics *metrics_create()
+{
+       return calloc(1, sizeof(struct metrics));
+}
+
+void metrics_destroy(struct metrics *m)
+{
+       if (!m)
+               return;
+
+       free(m->inner);
+       free(m);
+}
+
+bool metrics_add_log(struct metrics *m, const dlogutil_entry_s *e)
+{
+       assert(m);
+       assert(e);
+
+       const char *tag;
+       pid_t pid;
+       log_priority prio;
+       if (dlogutil_entry_get_tag(e, &tag))
+               return false;
+       if (dlogutil_entry_get_pid(e, &pid))
+               return false;
+       if (dlogutil_entry_get_priority(e, &prio))
+               return false;
+
+       for (int i = 0; i < m->count; ++i) {
+               if (pid != m->inner[i].pid || strcmp(tag, m->inner[i].tag) != 0)
+                       continue;
+
+               assert(prio < DLOG_PRIO_MAX);
+               m->inner[i].count[prio] += 1;
+               return true;
+       }
+
+       if (m->capacity == 0) {
+               m->inner = calloc(INITIAL_CAPACITY, sizeof(struct metrics_info));
+               if (!m->inner)
+                       return false;
+               m->capacity = INITIAL_CAPACITY;
+       } else if (m->count == m->capacity) {
+               typeof(m->inner) tmp = realloc(m->inner, 2 * m->capacity * sizeof *tmp);
+               if (!tmp)
+                       return false;
+               m->inner = tmp;
+               m->capacity *= 2;
+       }
+
+       char *const tag_copy = strdup(tag);
+       if (!tag_copy)
+               return false;
+       m->inner[m->count].tag = tag_copy;
+       m->inner[m->count].pid = pid;
+       for (int i = 0; i < (int) DLOG_PRIO_MAX; ++i)
+               m->inner[m->count].count[i] = 0;
+       m->inner[m->count].count[prio] = 1;
+       m->count += 1;
+       return true;
+}
+
+struct metrics_info *metrics_get_info(const struct metrics *m, int *count)
+{
+       assert(m);
+       assert(count);
+
+       if (m->count == 0) {
+               *count = 0;
+               return NULL;
+       }
+
+       struct metrics_info *ret = calloc(m->count, sizeof(struct metrics_info));
+       if (ret == NULL) {
+               *count = -1;
+               return NULL;
+       }
+
+       *count = m->count;
+       memcpy(ret, m->inner, m->count * sizeof(struct metrics_info));
+       return ret;
+}
+
diff --git a/src/tests/metrics.c b/src/tests/metrics.c
new file mode 100644 (file)
index 0000000..15282fd
--- /dev/null
@@ -0,0 +1,187 @@
+/* MIT License
+ *
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE. */
+
+#include <assert.h>
+#include <metrics.h>
+#include <queued_entry.h>
+
+int main()
+{
+       struct metrics *m = metrics_create();
+       assert(m);
+
+       int count;
+       struct metrics_info *info;
+
+       info = metrics_get_info(m, &count);
+       assert(info == NULL);
+       assert(count == 0);
+
+       const char msg0[] = "abc\0de";
+       const char msg1[] = "HELLO WORLD\0here";
+
+       struct dlogutil_entry_with_msg e0 = {
+               .header = {
+                       .len = sizeof(dlogutil_entry_s) + sizeof(msg0),
+                       .priority = DLOG_FATAL,
+                       .pid = 1337,
+                       .tag_len = strlen(msg0),
+               },
+       };
+       memcpy(&e0.msg, msg0, sizeof(msg0));
+
+       struct dlogutil_entry_with_msg e1 = {
+               .header = {
+                       .len = sizeof(dlogutil_entry_s) + sizeof(msg0),
+                       .priority = DLOG_DEBUG,
+                       .pid = 1337,
+                       .tag_len = strlen(msg0),
+               },
+       };
+       memcpy(&e1.msg, msg0, sizeof(msg0));
+
+       struct dlogutil_entry_with_msg e2 = {
+               .header = {
+                       .len = sizeof(dlogutil_entry_s) + sizeof(msg0),
+                       .priority = DLOG_FATAL,
+                       .pid = 31337,
+                       .tag_len = strlen(msg0),
+               },
+       };
+       memcpy(&e2.msg, msg0, sizeof(msg0));
+
+       struct dlogutil_entry_with_msg e3 = {
+               .header = {
+                       .len = sizeof(dlogutil_entry_s) + sizeof(msg1),
+                       .priority = DLOG_FATAL,
+                       .pid = 1337,
+                       .tag_len = strlen(msg1),
+               },
+       };
+       memcpy(&e3.msg, msg1, sizeof(msg1));
+
+       struct dlogutil_entry_with_msg e_loop = {
+               .header = {
+                       .len = sizeof(dlogutil_entry_s) + sizeof(msg1),
+                       .priority = DLOG_FATAL,
+                       .tag_len = strlen(msg1),
+               },
+       };
+       memcpy(&e_loop.msg, msg1, sizeof(msg1));
+
+       assert(metrics_add_log(m, &e0.header));
+       info = metrics_get_info(m, &count);
+       assert(info != NULL);
+       assert(count == 1);
+       assert(info[0].pid == e0.header.pid);
+       assert(!strcmp(info[0].tag, e0.msg));
+       assert(info[0].count[DLOG_FATAL] == 1);
+       assert(info[0].count[DLOG_ERROR] == 0);
+       assert(info[0].count[DLOG_WARN] == 0);
+       assert(info[0].count[DLOG_INFO] == 0);
+       assert(info[0].count[DLOG_DEBUG] == 0);
+       assert(info[0].count[DLOG_VERBOSE] == 0);
+       free(info);
+
+       assert(metrics_add_log(m, &e0.header));
+       info = metrics_get_info(m, &count);
+       assert(info != NULL);
+       assert(count == 1);
+       assert(info[0].pid == e0.header.pid);
+       assert(!strcmp(info[0].tag, e0.msg));
+       assert(info[0].count[DLOG_FATAL] == 2);
+       assert(info[0].count[DLOG_ERROR] == 0);
+       assert(info[0].count[DLOG_WARN] == 0);
+       assert(info[0].count[DLOG_INFO] == 0);
+       assert(info[0].count[DLOG_DEBUG] == 0);
+       assert(info[0].count[DLOG_VERBOSE] == 0);
+       free(info);
+
+       assert(metrics_add_log(m, &e1.header));
+       info = metrics_get_info(m, &count);
+       assert(info != NULL);
+       assert(count == 1);
+       assert(info[0].pid == e1.header.pid);
+       assert(!strcmp(info[0].tag, e1.msg));
+       assert(info[0].count[DLOG_FATAL] == 2);
+       assert(info[0].count[DLOG_ERROR] == 0);
+       assert(info[0].count[DLOG_WARN] == 0);
+       assert(info[0].count[DLOG_INFO] == 0);
+       assert(info[0].count[DLOG_DEBUG] == 1);
+       assert(info[0].count[DLOG_VERBOSE] == 0);
+       free(info);
+
+       assert(metrics_add_log(m, &e2.header));
+       info = metrics_get_info(m, &count);
+       assert(info != NULL);
+       assert(count == 2);
+       assert(info[1].pid == e2.header.pid);
+       assert(!strcmp(info[1].tag, e2.msg));
+       assert(info[1].count[DLOG_FATAL] == 1);
+       assert(info[1].count[DLOG_ERROR] == 0);
+       assert(info[1].count[DLOG_WARN] == 0);
+       assert(info[1].count[DLOG_INFO] == 0);
+       assert(info[1].count[DLOG_DEBUG] == 0);
+       assert(info[1].count[DLOG_VERBOSE] == 0);
+       free(info);
+
+       assert(metrics_add_log(m, &e3.header));
+       info = metrics_get_info(m, &count);
+       assert(info != NULL);
+       assert(count == 3);
+       assert(info[2].pid == e3.header.pid);
+       assert(!strcmp(info[2].tag, e3.msg));
+       assert(info[2].count[DLOG_FATAL] == 1);
+       assert(info[2].count[DLOG_ERROR] == 0);
+       assert(info[2].count[DLOG_WARN] == 0);
+       assert(info[2].count[DLOG_INFO] == 0);
+       assert(info[2].count[DLOG_DEBUG] == 0);
+       assert(info[2].count[DLOG_VERBOSE] == 0);
+       free(info);
+
+       assert(metrics_add_log(m, &e2.header));
+       info = metrics_get_info(m, &count);
+       assert(info != NULL);
+       assert(count == 3);
+       assert(info[1].pid == e2.header.pid);
+       assert(!strcmp(info[1].tag, e2.msg));
+       assert(info[1].count[DLOG_FATAL] == 2);
+       assert(info[1].count[DLOG_ERROR] == 0);
+       assert(info[1].count[DLOG_WARN] == 0);
+       assert(info[1].count[DLOG_INFO] == 0);
+       assert(info[1].count[DLOG_DEBUG] == 0);
+       assert(info[1].count[DLOG_VERBOSE] == 0);
+       free(info);
+
+       const int PIDS = 1200;
+
+       for (e_loop.header.pid = 1; e_loop.header.pid <= PIDS; ++e_loop.header.pid) {
+               assert(metrics_add_log(m, &e_loop.header));
+       }
+       info = metrics_get_info(m, &count);
+       assert(info != NULL);
+       assert(count == PIDS + 3);
+       free(info);
+
+       metrics_destroy(m);
+}
+