Critical logs: introduce rotation 37/223537/14
authorMichal Bloch <m.bloch@samsung.com>
Mon, 3 Feb 2020 15:45:05 +0000 (16:45 +0100)
committerMichal Bloch <m.bloch@samsung.com>
Thu, 13 Feb 2020 13:35:35 +0000 (14:35 +0100)
Change-Id: I5afff333ef105c8a13142457bef0cbea3c9c319c
Signed-off-by: Michal Bloch <m.bloch@samsung.com>
configure.ac
packaging/dlog.spec
src/log-critical/log-critical.cpp

index 724452e..fdfff75 100644 (file)
@@ -59,6 +59,14 @@ AC_ARG_ENABLE([critical-logfile],
 AC_DEFINE_UNQUOTED([DLOG_CRITICAL_LOGFILE_PATH], "$critical_logfile")
 AC_SUBST([DLOG_CRITICAL_LOGFILE_PATH], "$critical_logfile")
 
+critical_logfile_size_default=1048576 # 1 MB
+AC_ARG_ENABLE([critical-logsize],
+       AS_HELP_STRING([--critical-log-size=SIZE], [size of the critical log file in bytes (default: $critical_logfile_size_default)]),
+       [critical_logsize=$enableval],
+       [critical_logsize=$critical_logfile_size_default])
+AC_DEFINE_UNQUOTED([DLOG_CRITICAL_LOGFILE_SIZE], [$critical_logsize])
+AC_SUBST([DLOG_CRITICAL_LOGFILE_SIZE], [$critical_logsize])
+
 AC_ARG_ENABLE([android-monotonic],
         AS_HELP_STRING([--enable-android-monotonic], [use monotonic send timestamp with log message when using android backend (EXPERIMENTAL)]),
         [android_monotonic=true],
index 93b95ff..c0de3dd 100644 (file)
@@ -246,9 +246,10 @@ chsmack %{_bindir}/dlogctl -a "System::Tools"
 /sbin/ldconfig
 systemctl daemon-reload
 chsmack -a System /var/log/dlog
-touch /var/log/dlog/critical
-chmod 660 /var/log/dlog/critical
-chown log:log /var/log/dlog/critical
+touch /var/log/dlog/critical.a
+touch /var/log/dlog/critical.b
+chmod 660 /var/log/dlog/critical*
+chown log:log /var/log/dlog/critical*
 chsmack -e 'System' %{_libexecdir}/dlog-log-critical
 
 %postun -n libdlog -p /sbin/ldconfig
index 6c377bc..055a86e 100644 (file)
@@ -16,6 +16,7 @@
 #include <fcntl.h>
 #include <unistd.h>
 #include <sys/file.h>
+#include <sys/stat.h>
 
 // C++
 #include <iostream>
@@ -60,9 +61,33 @@ public:
                if (wr < 0)
                        throw throwable_errno ();
        }
+
+       void truncate () const
+       {
+               if (ftruncate(fd, 0) < 0)
+                       throw throwable_errno ();
+       }
+
+       virtual struct stat get_stat () const
+       {
+               struct stat s;
+               if (fstat (fd, &s) < 0)
+                       throw throwable_errno ();
+               return s;
+       }
 };
 
 class LockedFD final : public FD {
+private:
+       /* Since we've locked the file, nobody else
+        * can modify it so fstat() will return the
+        * same values every time (well, not really
+        * but to the extent we're interested in, at
+        * any rate). Therefore, we can cache it to
+        * avoid multiple syscalls. */
+       struct stat s;
+       bool s_cached;
+
 public:
        /* Note: we're using advisory locks instead
         * of mandatory locks. This is because:
@@ -88,6 +113,8 @@ public:
 
        LockedFD (const char * path, int flags)
        : FD (path, flags)
+       , s {}
+       , s_cached {false}
        {
                struct flock f;
                f.l_type   = F_WRLCK;
@@ -114,15 +141,44 @@ public:
 
                (void) fcntl (fd, F_SETLK, &f);
        }
+
+       struct stat get_stat () const final override
+       {
+               if (!s_cached) {
+                       /* Could use a mutex for reusability,
+                        * but let's not overengineer for now. */
+                       const_cast <LockedFD *> (this)->s_cached = true;
+                       const_cast <LockedFD *> (this)->s = FD::get_stat ();
+               }
+
+               return s;
+       }
 };
 
+bool operator < (const struct timespec & a, const struct timespec & b)
+{
+       return (a.tv_sec <  b.tv_sec)
+           || (a.tv_sec == b.tv_sec && a.tv_nsec < b.tv_nsec);
+}
+
 int main (int argc, char **argv) try
 {
        if (argc != 2)
                throw std::invalid_argument ("Usage: ./dlog-log-critical \"formatted-message\"");
 
-       LockedFD logfile (DLOG_CRITICAL_LOGFILE_PATH, O_WRONLY | O_APPEND | O_SYNC);
-       logfile.write(argv[1]);
+       LockedFD logfile_a (DLOG_CRITICAL_LOGFILE_PATH ".a", O_WRONLY | O_APPEND | O_SYNC),
+                logfile_b (DLOG_CRITICAL_LOGFILE_PATH ".b", O_WRONLY | O_APPEND | O_SYNC);
+
+       const bool is_a_older = logfile_a.get_stat().st_mtime < logfile_b.get_stat().st_mtime;
+       auto older = is_a_older ? &logfile_a : &logfile_b;
+       auto newer = is_a_older ? &logfile_b : &logfile_a;
+
+       if (newer->get_stat().st_size > DLOG_CRITICAL_LOGFILE_SIZE) {
+               older->truncate();
+               std::swap(older, newer);
+       }
+
+       newer->write(argv[1]);
 
        return EXIT_SUCCESS;
 } catch (const std::exception & ex) {