--- /dev/null
+/* 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);
+
--- /dev/null
+/* 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;
+}
+
--- /dev/null
+/* 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);
+}
+