velia: Use journald for logging

Current logging sink duplicates information like time and severity into
the journald which is not desirable. Use journald logging sink and
journald's capabilities if possible like in cla-sysrepo.

This code comes from cla-sysrepo,
commit 1d4aa45353f8e52dda29a8d5b453745c58c80913.

Change-Id: Ic4ae748d07edb4daa4ef0c15c3f8aab42fd8482e
diff --git a/src/main.cpp b/src/main.cpp
index f905dee..341b390 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -9,6 +9,7 @@
 #include "outputs/LedSysfsDriver.h"
 #include "outputs/callables.h"
 #include "utils/exceptions.h"
+#include "utils/journal.h"
 #include "utils/log-init.h"
 
 /** @short Extract log level from a CLI option */
@@ -53,7 +54,12 @@
 
 int main(int argc, char* argv[])
 {
-    std::shared_ptr<spdlog::sinks::sink> loggingSink = std::make_shared<spdlog::sinks::ansicolor_stderr_sink_mt>();
+    std::shared_ptr<spdlog::sinks::sink> loggingSink;
+    if (velia::utils::isJournaldActive()) {
+        loggingSink = velia::utils::create_journald_sink();
+    } else {
+        loggingSink = std::make_shared<spdlog::sinks::ansicolor_stderr_sink_mt>();
+    }
 
     auto args = docopt::docopt(usage, {argv + 1, argv + argc}, true, "veliad " VELIA_VERSION, true);
 
diff --git a/src/utils/journal.cpp b/src/utils/journal.cpp
new file mode 100644
index 0000000..9ea9a1f
--- /dev/null
+++ b/src/utils/journal.cpp
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2016-2019 CESNET, https://photonics.cesnet.cz/
+ *
+ * Written by Jan Kundrát <jan.kundrat@cesnet.cz>
+ *
+*/
+
+#include <cstdio>
+#include <cstdlib>
+#include <inttypes.h>
+#include <spdlog/sinks/systemd_sink.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include "utils/journal.h"
+
+namespace velia::utils {
+
+/** @short Is stderr connected to journald? Not thread safe. */
+bool isJournaldActive()
+{
+    const auto stream = ::getenv("JOURNAL_STREAM");
+    if (!stream) {
+        return false;
+    }
+    uintmax_t dev;
+    uintmax_t inode;
+    if (::sscanf(stream, "%" SCNuMAX ":%" SCNuMAX, &dev, &inode) != 2) {
+        return false;
+    }
+    struct stat buf;
+    if (fstat(STDERR_FILENO, &buf)) {
+        return false;
+    }
+    return static_cast<uintmax_t>(buf.st_dev) == dev && static_cast<uintmax_t>(buf.st_ino) == inode;
+}
+
+namespace impl {
+/** @short Provide better levels, see https://github.com/gabime/spdlog/pull/1292#discussion_r340777258 */
+template <typename Mutex>
+class journald_sink : public spdlog::sinks::systemd_sink<Mutex> {
+public:
+    journald_sink()
+    {
+        this->syslog_levels_ = {/* spdlog::level::trace      */ LOG_DEBUG,
+                                /* spdlog::level::debug      */ LOG_INFO,
+                                /* spdlog::level::info       */ LOG_NOTICE,
+                                /* spdlog::level::warn       */ LOG_WARNING,
+                                /* spdlog::level::err        */ LOG_ERR,
+                                /* spdlog::level::critical   */ LOG_CRIT,
+                                /* spdlog::level::off        */ LOG_ALERT};
+    }
+};
+}
+
+std::shared_ptr<spdlog::sinks::sink> create_journald_sink()
+{
+    return std::make_shared<impl::journald_sink<std::mutex>>();
+}
+}
diff --git a/src/utils/journal.h b/src/utils/journal.h
new file mode 100644
index 0000000..499046e
--- /dev/null
+++ b/src/utils/journal.h
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2016-2019 CESNET, https://photonics.cesnet.cz/
+ *
+ * Written by Jan Kundrát <jan.kundrat@cesnet.cz>
+ *
+*/
+
+#pragma once
+
+#include <memory>
+
+namespace spdlog {
+namespace sinks {
+class sink;
+}
+}
+
+namespace velia::utils {
+bool isJournaldActive();
+std::shared_ptr<spdlog::sinks::sink> create_journald_sink();
+}