Import logger from upstream
authorsangwan.kwon <sangwan.kwon@samsung.com>
Tue, 14 May 2019 07:04:03 +0000 (16:04 +0900)
committersangwan.kwon <sangwan.kwon@samsung.com>
Tue, 14 May 2019 07:04:03 +0000 (16:04 +0900)
The logger plugin that you use to define your config receiver can be
defined via a command-line flag, however, if you don't define a logger
plugin to use via the command-line, then the logger receiver which is
represented by the string stored kDefaultLogReceiverName will be used.

Signed-off-by: sangwan.kwon <sangwan.kwon@samsung.com>
include/osquery/logger.h [new file with mode: 0644]
include/osquery/logger/plugin.h [new file with mode: 0644]
osquery/CMakeLists.txt
osquery/logger/CMakeLists.txt [new file with mode: 0644]
osquery/logger/logger.cpp [new file with mode: 0644]
osquery/logger/logger_tests.cpp [new file with mode: 0644]
osquery/logger/plugins/filesystem.cpp [new file with mode: 0644]
packaging/osquery.spec

diff --git a/include/osquery/logger.h b/include/osquery/logger.h
new file mode 100644 (file)
index 0000000..e667c48
--- /dev/null
@@ -0,0 +1,73 @@
+// Copyright 2004-present Facebook. All Rights Reserved.
+
+#pragma once
+
+#include <future>
+#include <string>
+#include <vector>
+
+#include "osquery/status.h"
+#include "osquery/database.h"
+
+namespace osquery {
+
+/**
+ * @brief A string which represents the default logger receiver
+ *
+ * The logger plugin that you use to define your config receiver can be
+ * defined via a command-line flag, however, if you don't define a logger
+ * plugin to use via the command-line, then the logger receiver which is
+ * represented by the string stored kDefaultLogReceiverName will be used.
+ */
+extern const std::string kDefaultLogReceiverName;
+
+/**
+ * @brief Log a string using the default logger receiver.
+ *
+ * Note that this method should only be used to log results. If you'd like to
+ * log normal osquery operations, use Google Logging.
+ *
+ * @param s the string to log
+ *
+ * @return an instance of osquery::Status, indicating the success or failure
+ * of the operation.
+ */
+osquery::Status logString(const std::string& s);
+
+/**
+ * @brief Log a string using a specific logger receiver.
+ *
+ * Note that this method should only be used to log results. If you'd like to
+ * log normal osquery operations, use Google Logging.
+ *
+ * @param s the string to log
+ * @param receiver a string representing the log receiver to use
+ *
+ * @return an instance of osquery::Status, indicating the success or failure
+ * of the operation.
+ */
+osquery::Status logString(const std::string& s, const std::string& receiver);
+
+/**
+ * @brief Directly log results of scheduled queries to the default receiver
+ *
+ * @param item a struct representing the results of a scheduled query
+ *
+ * @return an instance of osquery::Status, indicating the success or failure
+ * of the operation.
+ */
+osquery::Status logScheduledQueryLogItem(
+    const osquery::ScheduledQueryLogItem& item);
+
+/**
+ * @brief Directly log results of scheduled queries to a specified receiver
+ *
+ * @param item a struct representing the results of a scheduled query
+ * @param receiver a string representing the log receiver to use
+ *
+ * @return an instance of osquery::Status, indicating the success or failure
+ * of the operation.
+ */
+osquery::Status logScheduledQueryLogItem(
+    const osquery::ScheduledQueryLogItem& item, const std::string& receiver);
+}
diff --git a/include/osquery/logger/plugin.h b/include/osquery/logger/plugin.h
new file mode 100644 (file)
index 0000000..34f5346
--- /dev/null
@@ -0,0 +1,69 @@
+// Copyright 2004-present Facebook. All Rights Reserved.
+
+#pragma once
+
+#include <memory>
+
+#include "osquery/registry.h"
+#include "osquery/status.h"
+
+namespace osquery {
+
+/**
+ * @brief Superclass for the pluggable config component.
+ *
+ * In order to make the logging of osquery results easy to integrate into your
+ * environment, we take advantage of a plugin interface which allows you to
+ * integrate osquery with your internal large-scale logging infrastructure.
+ * You may use flume, splunk, syslog, scribe, etc. In order to use your
+ * specific upstream logging systems, one simply needs to create a custom
+ * subclass of LoggerPlugin. That subclass should implement the
+ * LoggerPlugin::logString method.
+ *
+ * Consider the following example:
+ *
+ * @code{.cpp}
+ *   class TestLoggerPlugin : public ConfigPlugin {
+ *    public:
+ *     virtual osquery::Status logString(const std::string& s) {
+ *       int i = 0;
+ *       internal::logStringToFlume(s, i);
+ *       std::string message;
+ *       if (i == 0) {
+ *         message = "OK";
+ *       } else {
+ *         message = "Failed";
+ *       }
+ *       return osquery::Status(i, message);
+ *     }
+ *  };
+ *
+ *  REGISTER_LOGGER_PLUGIN(
+ *      "test", std::make_shared<osquery::TestLoggerPlugin>());
+ * @endcode
+ */
+class LoggerPlugin {
+ public:
+  /** @brief Virtual method which should implement custom logging.
+   *
+   *  LoggerPlugin::logString should be implemented by a subclass of
+   *  LoggerPlugin which needs to log a string in a custom way.
+   *
+   *  @return an instance of osquery::Status which indicates the success or
+   *  failure of the operation.
+   */
+  virtual osquery::Status logString(const std::string& s) = 0;
+
+  /// Virtual destructor
+  virtual ~LoggerPlugin() {}
+};
+}
+
+DECLARE_REGISTRY(LoggerPlugins,
+                 std::string,
+                 std::shared_ptr<osquery::LoggerPlugin>)
+
+#define REGISTERED_LOGGER_PLUGINS REGISTRY(LoggerPlugins)
+
+#define REGISTER_LOGGER_PLUGIN(name, decorator) \
+  REGISTER(LoggerPlugins, name, decorator)
index a593be675129b91dcb74b74b5485cc404be04fc0..d99f22411d720fe9e76c1232c9690cff4a3320b1 100644 (file)
@@ -55,6 +55,7 @@ ADD_SUBDIRECTORY(config)
 ADD_SUBDIRECTORY(database)
 ADD_SUBDIRECTORY(registry)
 ADD_SUBDIRECTORY(filesystem)
+ADD_SUBDIRECTORY(logger)
 
 ADD_LIBRARY(${TARGET_OSQUERY_LIB} STATIC main/lib.cpp ${${TARGET_OSQUERY_LIB}_SRCS})
 TARGET_LINK_LIBRARIES(${TARGET_OSQUERY_LIB} ${${TARGET_OSQUERY_LIB}_DEP})
diff --git a/osquery/logger/CMakeLists.txt b/osquery/logger/CMakeLists.txt
new file mode 100644 (file)
index 0000000..9402273
--- /dev/null
@@ -0,0 +1,4 @@
+ADD_OSQUERY_LIBRARY(osquery_logger logger.cpp
+                                                                  plugins/filesystem.cpp)
+
+ADD_OSQUERY_TEST(osquery_logger_tests logger_tests.cpp)
diff --git a/osquery/logger/logger.cpp b/osquery/logger/logger.cpp
new file mode 100644 (file)
index 0000000..3e62359
--- /dev/null
@@ -0,0 +1,52 @@
+// Copyright 2004-present Facebook. All Rights Reserved.
+
+#include "osquery/logger.h"
+#include "osquery/logger/plugin.h"
+
+#include <algorithm>
+#include <thread>
+
+#include <gflags/gflags.h>
+#include <glog/logging.h>
+
+using osquery::Status;
+
+namespace osquery {
+
+const std::string kDefaultLogReceiverName = "filesystem";
+
+DEFINE_string(log_receiver,
+              kDefaultLogReceiverName,
+              "The upstream log receiver to log messages to.");
+
+Status logString(const std::string& s) {
+  return logString(s, FLAGS_log_receiver);
+}
+
+Status logString(const std::string& s, const std::string& receiver) {
+  if (REGISTERED_LOGGER_PLUGINS.find(receiver) ==
+      REGISTERED_LOGGER_PLUGINS.end()) {
+    LOG(ERROR) << "Logger receiver " << receiver << " not found";
+    return Status(1, "Logger receiver not found");
+  }
+  auto log_status = REGISTERED_LOGGER_PLUGINS.at(receiver)->logString(s);
+  if (!log_status.ok()) {
+    return log_status;
+  }
+  return Status(0, "OK");
+}
+
+Status logScheduledQueryLogItem(const osquery::ScheduledQueryLogItem& results) {
+  return logScheduledQueryLogItem(results, FLAGS_log_receiver);
+}
+
+Status logScheduledQueryLogItem(const osquery::ScheduledQueryLogItem& results,
+                                const std::string& receiver) {
+  std::string json;
+  auto s = osquery::serializeScheduledQueryLogItemJSON(results, json);
+  if (!s.ok()) {
+    return s;
+  }
+  return logString(json, receiver);
+}
+}
diff --git a/osquery/logger/logger_tests.cpp b/osquery/logger/logger_tests.cpp
new file mode 100644 (file)
index 0000000..f1db38e
--- /dev/null
@@ -0,0 +1,42 @@
+// Copyright 2004-present Facebook. All Rights Reserved.
+
+#include "osquery/logger.h"
+#include "osquery/logger/plugin.h"
+
+#include <gtest/gtest.h>
+#include <glog/logging.h>
+
+#include "osquery/core.h"
+
+using osquery::Status;
+
+namespace osquery {
+
+class LoggerTests : public testing::Test {
+ public:
+  LoggerTests() { osquery::InitRegistry::get().run(); }
+};
+
+class TestLoggerPlugin : public LoggerPlugin {
+ public:
+  TestLoggerPlugin() {}
+
+  Status logString(const std::string& s) { return Status(0, s); }
+
+  virtual ~TestLoggerPlugin() {}
+};
+
+REGISTER_LOGGER_PLUGIN("test", std::make_shared<osquery::TestLoggerPlugin>())
+
+TEST_F(LoggerTests, test_plugin) {
+  auto s = REGISTERED_LOGGER_PLUGINS.at("test")->logString("foobar");
+  EXPECT_EQ(s.ok(), true);
+  EXPECT_EQ(s.toString(), "foobar");
+}
+}
+
+int main(int argc, char* argv[]) {
+  testing::InitGoogleTest(&argc, argv);
+  osquery::initOsquery(argc, argv);
+  return RUN_ALL_TESTS();
+}
diff --git a/osquery/logger/plugins/filesystem.cpp b/osquery/logger/plugins/filesystem.cpp
new file mode 100644 (file)
index 0000000..9e114ae
--- /dev/null
@@ -0,0 +1,47 @@
+// Copyright 2004-present Facebook. All Rights Reserved.
+
+#include "osquery/logger/plugin.h"
+
+#include <algorithm>
+#include <exception>
+#include <ios>
+#include <fstream>
+#include <mutex>
+#include <thread>
+
+#include <gflags/gflags.h>
+#include <glog/logging.h>
+
+using osquery::Status;
+
+namespace osquery {
+
+std::mutex filesystemLoggerPluginMutex;
+
+class FilesystemLoggerPlugin : public LoggerPlugin {
+ public:
+  std::string log_path;
+  FilesystemLoggerPlugin() {
+    log_path = FLAGS_log_dir + "osqueryd.results.log";
+  }
+
+  virtual Status logString(const std::string& s) {
+    std::lock_guard<std::mutex> lock(filesystemLoggerPluginMutex);
+    try {
+      VLOG(3) << "filesystem logger plugin: logging to " << log_path;
+      std::ofstream log_stream(log_path,
+                               std::ios_base::app | std::ios_base::out);
+      if (log_stream.fail()) {
+        return Status(1, "error opening file: " + log_path);
+      }
+      log_stream << s << std::endl;
+    } catch (const std::exception& e) {
+      return Status(1, e.what());
+    }
+    return Status(0, "OK");
+  }
+};
+
+REGISTER_LOGGER_PLUGIN("filesystem",
+                       std::make_shared<osquery::FilesystemLoggerPlugin>())
+}
index 12c285a04bae3e97ac5cbe256ef1c1e1704b0cda..0d752ed020cdd1fb833680c5348c3b493d435ba2 100644 (file)
@@ -75,3 +75,4 @@ Testcases for osquery
 %{_bindir}/osquery_sqlite_util_tests
 %{_bindir}/osquery_test_util_tests
 %{_bindir}/osquery_text_tests
+%{_bindir}/osquery_logger_tests