Implement a basic version of failed log stashing 88/242588/3
authorMateusz Majewski <m.majewski2@samsung.com>
Tue, 25 Aug 2020 08:46:02 +0000 (10:46 +0200)
committerMateusz Majewski <m.majewski2@samsung.com>
Fri, 28 Aug 2020 13:04:48 +0000 (15:04 +0200)
This implements a simple solution of keeping logs that weren't sent;
saving them in the critical log file. It's off by default.

Change-Id: I08c18d4bfe6c413961dc551fe93009a686ce1414

configs/dlog.conf
src/libdlog/log.c

index 2beaeff..2ac2f83 100644 (file)
@@ -107,3 +107,8 @@ deduplicate_method=
 
 # One can also specify how long the time window is - "deduplicate_interval_ms" should be used.
 deduplicate_interval_ms=1
+
+# Failed log stashing. Allows the log sending application to take an action when they fail to send a log.
+# For example, on pipe backend, this can happen when the daemon dies or can't handle the logs being received.
+# Can be "critical" to store failed logs in the critical log file, or "" to disable the feature (default).
+stash_failed_log_method=
index f33df1a..c6ca0d1 100644 (file)
@@ -57,6 +57,9 @@
 int (*write_to_log)(log_id_t log_id, log_priority prio, const char *tag, const char *msg, struct timespec *tp_mono) = NULL;
 void (*destroy_backend)();
 
+int (*stash_failed_log)(log_id_t log_id, log_priority prio, const char *tag, const char *msg) = NULL;
+static int stash_critical(log_id_t log_id, log_priority prio, const char *tag, const char *msg);
+
 pthread_rwlock_t log_limiter_lock = PTHREAD_RWLOCK_INITIALIZER;
 static pthread_mutex_t log_construction_lock = PTHREAD_MUTEX_INITIALIZER;
 static bool is_initialized = false;
@@ -135,6 +138,14 @@ static void __configure_parameters(struct log_config *config)
        limiter_apply_to_all_buffers = log_config_get_int(config,
                                                                        "limiter_apply_to_all_buffers",
                                                                        DEFAULT_CONFIG_LIMITER_APPLY_TO_ALL_BUFFERS);
+
+       const char *stash_failed_log_method = log_config_get(config, "stash_failed_log_method");
+       if (stash_failed_log_method) {
+#ifndef UNIT_TEST
+               if (strcmp(stash_failed_log_method, "critical") == 0)
+                       stash_failed_log = stash_critical;
+#endif
+       }
 }
 
 void __update_plog(const struct log_config *conf)
@@ -356,13 +367,18 @@ static int __write_to_log_critical_section(log_id_t log_id, int prio, const char
                len = sizeof buf - 1;
 
        struct timespec tp;
+       int r;
        if (deduplicate_func && !clock_gettime(CLOCK_MONOTONIC, &tp)) {
                if (deduplicate_func(buf, len, &tp))
                        return DLOG_ERROR_NONE;
-               return write_to_log(log_id, prio, tag, buf, &tp);
-       }
+               r = write_to_log(log_id, prio, tag, buf, &tp);
+       } else
+               r = write_to_log(log_id, prio, tag, buf, NULL);
 
-       return write_to_log(log_id, prio, tag, buf, NULL);
+       if (r < 0 && stash_failed_log)
+               r = stash_failed_log(log_id, prio, tag, buf);
+
+       return r;
 }
 
 static int __write_to_log(log_id_t log_id, int prio, const char *tag, const char *fmt, va_list ap, bool check_should_log, bool secure_log)
@@ -389,6 +405,7 @@ static int __write_to_log(log_id_t log_id, int prio, const char *tag, const char
         * but giving this guarantee makes everything a lot simpler as it removes
         * the risk of something suddenly becoming NULL during processing. */
        if (!initialize() || !write_to_log)
+               // TODO: We could consider stashing the failed log here
                ret = DLOG_ERROR_NOT_PERMITTED;
        else if (secure_log && !enable_secure_logs)
                ret = 0;
@@ -550,6 +567,19 @@ void __critical_log(log_id_t log_id, int prio, const char *tag, const char *fmt,
        __critical_log_child(main_pid, main_tid, log_id, prio, tag, fmt, ap);
 }
 
+static void stash_critical_inner(log_id_t log_id, log_priority prio, const char *tag, const char *fmt, ...) {
+       va_list ap;
+
+       va_start(ap, fmt);
+       __critical_log(log_id, prio, tag, fmt, ap);
+       va_end(ap);
+}
+
+static int stash_critical(log_id_t log_id, log_priority prio, const char *tag, const char *msg) {
+       stash_critical_inner(log_id, prio, tag, "FAILED TO LOG: %s", msg);
+       return 0;
+}
+
 int __dlog_critical_print(log_id_t log_id, int prio, const char *tag, const char *fmt, ...)
 {
        va_list ap;